From b1ea74bbeb08a7531a6c0bc52472e350e5d30037 Mon Sep 17 00:00:00 2001 From: Packit Service Date: Dec 09 2020 13:37:20 +0000 Subject: freerdp-2.2.0 base --- diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..33a6584 --- /dev/null +++ b/.clang-format @@ -0,0 +1,125 @@ +--- +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Left +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: false +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Allman +BreakBeforeInheritanceComma: false +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakStringLiterals: true +ColumnLimit: 100 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: false +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: false +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + - Regex: '.*' + Priority: 1 +IncludeIsMainRegex: '(Test)?$' +IndentCaseLabels: true +IndentPPDirectives: None +IndentWidth: 4 +IndentWrappedFunctionNames: false +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Left +ReflowComments: true +SortIncludes: false +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +TabWidth: 4 +UseTab: ForIndentation +... +Language: Cpp +Standard: Auto +NamespaceIndentation: All +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +... +Language: ObjC +PointerBindsToType: false +ObjCSpaceAfterProperty: true +SortIncludes: false +ObjCBlockIndentWidth: 4 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +... +Language: Java +BreakAfterJavaFieldAnnotations: false +... +Language: JavaScript +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +... +Language: Proto +... +Language: TableGen +... +Language: TextProto +... diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 4d3c855..8ee9f39 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -30,7 +30,7 @@ A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. -** Application details +**Application details** * Version of FreeRDP * Command line used * output of `/buildconfig` diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index f76bc12..91a1cef 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -5,7 +5,8 @@ ## Preparations before creating a pull * Rebase your branch to current master, no merges allowed! * Try to clean up your commit history, group changes to commits -* Check your formatting! A _astyle_ script can be found at ```./scripts/format_code.sh``` +* Check your formatting! A _clang-format_ script can be found at ```.clang-format``` + * The cmake target ```clangformat``` reformats the whole codebase * Optional (but higly recommended) * Run a clang scanbuild before and after your changes to avoid introducing new bugs * Run your compiler at pedantic level to check for new warnings diff --git a/.gitignore b/.gitignore index b63a86e..c844922 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,9 @@ +#ninja +.ninja_deps +.ninja_log +build.ninja +rules.ninja + # CMake CMakeFiles/ CMakeScripts/ @@ -80,6 +86,8 @@ RelWithDebInfo *.embed.manifest* *.intermediate.manifest* version.rc +*.VC.db +*.VC.opendb # Binaries *.a @@ -93,10 +101,10 @@ cunit/test_freerdp client/X11/xfreerdp client/Mac/xcode client/Sample/sfreerdp -client/DirectFB/dfreerdp client/Wayland/wlfreerdp server/Sample/sfreerdp-server server/X11/xfreerdp-server +server/proxy/freerdp-proxy xcode libfreerdp/codec/test/TestOpenH264ASM @@ -124,7 +132,7 @@ TAGS # generated packages *.zip *.exe -*.sh +#*.sh *.deb *.rpm *.dmg @@ -132,7 +140,7 @@ TAGS *.tar.gz # packaging related files -!packaging/scripts/prepare_deb_freerdp-nightly.sh +!packaging/**.sh packaging/deb/freerdp-nightly/freerdp-nightly packaging/deb/freerdp-nightly/freerdp-nightly-dev packaging/deb/freerdp-nightly/freerdp-nightly-dbg @@ -142,4 +150,5 @@ packaging/deb/freerdp-nightly/freerdp-nightly-dbg .idea # VisualStudio Code -.vscode \ No newline at end of file +.vscode +cache/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 0199269..97ba2f9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,10 @@ endif() include(CheckCmakeCompat) # Include cmake modules +if(WITH_CLANG_FORMAT) + include(ClangFormat) +endif() + include(CheckIncludeFiles) include(CheckLibraryExists) include(CheckSymbolExists) @@ -77,22 +81,22 @@ if ($ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(RAW_VERSTION_STRING "2.0.0-rc4") +set(RAW_VERSION_STRING "2.2.0") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") - file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSTION_STRING) + file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) git_get_exact_tag(_GIT_TAG --tags --always) if (NOT ${_GIT_TAG} STREQUAL "n/a") - set(RAW_VERSTION_STRING ${_GIT_TAG}) + set(RAW_VERSION_STRING ${_GIT_TAG}) endif() endif() -string(STRIP ${RAW_VERSTION_STRING} RAW_VERSTION_STRING) +string(STRIP ${RAW_VERSION_STRING} RAW_VERSION_STRING) set(VERSION_REGEX "^.?([0-9]+)\\.([0-9]+)\\.([0-9]+)-?(.*)") -string(REGEX REPLACE "${VERSION_REGEX}" "\\1" FREERDP_VERSION_MAJOR "${RAW_VERSTION_STRING}") -string(REGEX REPLACE "${VERSION_REGEX}" "\\2" FREERDP_VERSION_MINOR "${RAW_VERSTION_STRING}") -string(REGEX REPLACE "${VERSION_REGEX}" "\\3" FREERDP_VERSION_REVISION "${RAW_VERSTION_STRING}") -string(REGEX REPLACE "${VERSION_REGEX}" "\\4" FREERDP_VERSION_SUFFIX "${RAW_VERSTION_STRING}") +string(REGEX REPLACE "${VERSION_REGEX}" "\\1" FREERDP_VERSION_MAJOR "${RAW_VERSION_STRING}") +string(REGEX REPLACE "${VERSION_REGEX}" "\\2" FREERDP_VERSION_MINOR "${RAW_VERSION_STRING}") +string(REGEX REPLACE "${VERSION_REGEX}" "\\3" FREERDP_VERSION_REVISION "${RAW_VERSION_STRING}") +string(REGEX REPLACE "${VERSION_REGEX}" "\\4" FREERDP_VERSION_SUFFIX "${RAW_VERSION_STRING}") set(FREERDP_API_VERSION "${FREERDP_VERSION_MAJOR}") set(FREERDP_VERSION "${FREERDP_VERSION_MAJOR}.${FREERDP_VERSION_MINOR}.${FREERDP_VERSION_REVISION}") @@ -337,106 +341,99 @@ if(${CMAKE_C_COMPILER_ID} STREQUAL "Clang") endif() endif() +set(THREAD_PREFER_PTHREAD_FLAG TRUE) + +if(NOT IOS) + find_package(Threads REQUIRED) +endif() + +if(NOT WIN32) + CHECK_SYMBOL_EXISTS(pthread_mutex_timedlock pthread.h HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL) + if (NOT HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL) + CHECK_LIBRARY_EXISTS(pthread pthread_mutex_timedlock "" HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB) + endif (NOT HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL) + if (NOT HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB) + CHECK_LIBRARY_EXISTS(pthreads pthread_mutex_timedlock "" HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIBS) + endif (NOT HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB) + + if (HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL OR HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB OR HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIBS) + set(HAVE_PTHREAD_MUTEX_TIMEDLOCK ON) + endif (HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL OR HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB OR HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIBS) +endif() + # Enable address sanitizer, where supported and when required if(${CMAKE_C_COMPILER_ID} STREQUAL "Clang" OR CMAKE_COMPILER_IS_GNUCC) - set(CMAKE_REQUIRED_FLAGS_SAVED ${CMAKE_REQUIRED_FLAGS}) - CHECK_C_COMPILER_FLAG ("-fno-omit-frame-pointer" fno-omit-frame-pointer) + if (fno-omit-frame-pointer) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer") + endif() + + set(CMAKE_REQUIRED_LINK_OPTIONS_SAVED ${CMAKE_REQUIRED_LINK_OPTIONS}) file(WRITE ${CMAKE_BINARY_DIR}/foo.txt "") if(WITH_SANITIZE_ADDRESS) - set(CMAKE_REQUIRED_FLAGS "-fsanitize=address") + list(APPEND CMAKE_REQUIRED_LINK_OPTIONS "-fsanitize=address") CHECK_C_COMPILER_FLAG ("-fsanitize=address" fsanitize-address) CHECK_C_COMPILER_FLAG ("-fsanitize-blacklist=${CMAKE_BINARY_DIR}/foo.txt" fsanitize-blacklist) CHECK_C_COMPILER_FLAG ("-fsanitize-address-use-after-scope" fsanitize-address-use-after-scope) - unset(CMAKE_REQUIRED_FLAGS) - - if(fsanitize-address) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=address") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address") - if(fsanitize-blacklist) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-blacklist=${CMAKE_SOURCE_DIR}/scripts/blacklist-address-sanitizer.txt") - endif(fsanitize-blacklist) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=address") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address") - if(fsanitize-address-use-after-scope) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-address-use-after-scope") - endif(fsanitize-address-use-after-scope) + if(fsanitize-blacklist) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-blacklist=${CMAKE_SOURCE_DIR}/scripts/blacklist-address-sanitizer.txt") + endif(fsanitize-blacklist) - else(fsanitize-address) - message(WARNING "Missing support for address sanitizer!") - endif(fsanitize-address) - - if(fno-omit-frame-pointer) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer") - endif() + if(fsanitize-address-use-after-scope) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-address-use-after-scope") + endif(fsanitize-address-use-after-scope) elseif(WITH_SANITIZE_MEMORY) - set(CMAKE_REQUIRED_FLAGS "-fsanitize=memory") + list(APPEND CMAKE_REQUIRED_LINK_OPTIONS "-fsanitize=memory") CHECK_C_COMPILER_FLAG ("-fsanitize=memory" fsanitize-memory) CHECK_C_COMPILER_FLAG ("-fsanitize-blacklist=${CMAKE_BINARY_DIR}/foo.txt" fsanitize-blacklist) CHECK_C_COMPILER_FLAG ("-fsanitize-memory-use-after-dtor" fsanitize-memory-use-after-dtor) CHECK_C_COMPILER_FLAG ("-fsanitize-memory-track-origins" fsanitize-memory-track-origins) - unset(CMAKE_REQUIRED_FLAGS) - - if(fsanitize-memory) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=memory") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=memory") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=memory") - if(fsanitize-blacklist) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-blacklist=${CMAKE_SOURCE_DIR}/scripts/blacklist-memory-sanitizer.txt") - endif(fsanitize-blacklist) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=memory") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=memory") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=memory") - if (fsanitize-memory-use-after-dtor) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-memory-use-after-dtor") - endif(fsanitize-memory-use-after-dtor) + if(fsanitize-blacklist) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-blacklist=${CMAKE_SOURCE_DIR}/scripts/blacklist-memory-sanitizer.txt") + endif(fsanitize-blacklist) - if (fsanitize-memory-track-origins) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-memory-track-origins") - endif(fsanitize-memory-track-origins) + if (fsanitize-memory-use-after-dtor) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-memory-use-after-dtor") + endif(fsanitize-memory-use-after-dtor) - else(fsanitize-memory) - message(WARNING "Missing support for memory sanitizer!") - endif(fsanitize-memory) - - if(fno-omit-frame-pointer) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer") - endif() + if (fsanitize-memory-track-origins) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-memory-track-origins") + endif(fsanitize-memory-track-origins) elseif(WITH_SANITIZE_THREAD) + list(APPEND CMAKE_REQUIRED_LINK_OPTIONS "-fsanitize=thread") CHECK_C_COMPILER_FLAG ("-fsanitize=thread" fsanitize-thread) CHECK_C_COMPILER_FLAG ("-fsanitize-blacklist=${CMAKE_BINARY_DIR}/foo.txt" fsanitize-blacklist) - unset(CMAKE_REQUIRED_FLAGS) - if(fsanitize-thread) - set(CMAKE_REQUIRED_FLAGS "-Werror -fsanitize=thread") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread") - if(fsanitize-blacklist) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-blacklist=${CMAKE_SOURCE_DIR}/scripts/blacklist-thread-sanitizer.txt") - endif(fsanitize-blacklist) - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=thread") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=thread") - else(fsanitize-thread) - message(WARNING "Missing support for thread sanitizer!") - endif(fsanitize-thread) - - if(fno-omit-frame-pointer) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer") - endif() + + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread") + if(fsanitize-blacklist) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-blacklist=${CMAKE_SOURCE_DIR}/scripts/blacklist-thread-sanitizer.txt") + endif(fsanitize-blacklist) + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=thread") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=thread") endif() file(REMOVE ${CMAKE_BINARY_DIR}/foo.txt) + set(CMAKE_REQUIRED_LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS_SAVED}) if (WITH_NO_UNDEFINED) - set(CMAKE_REQUIRED_FLAGS "-Wl,--no-undefined") CHECK_C_COMPILER_FLAG (-Wl,--no-undefined no-undefined) - unset(CMAKE_REQUIRED_FLAGS) if(no-undefined) + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--no-undefined" ) SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined" ) endif() endif() - - set(CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS_SAVED}) endif() if(MSVC) @@ -482,7 +479,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,16 +487,10 @@ 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) - set(CMAKE_WINDOWS_VERSION "WINXP") + set(CMAKE_WINDOWS_VERSION "WIN7") endif() if(CMAKE_WINDOWS_VERSION STREQUAL "WINXP") @@ -512,6 +503,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() @@ -611,7 +608,7 @@ if(ANDROID) endif() endif() - list (APPEND CMAKE_INCLUDE_PATH ${FREERDP_EXTERNAL_PATH}/include) + list (APPEND CMAKE_INCLUDE_PATH ${FREERDP_EXTERNAL_PATH}/${ANDROID_ABI}/include) list (APPEND CMAKE_LIBRARY_PATH ${FREERDP_EXTERNAL_PATH}/${ANDROID_ABI}/ ) set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH ) set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH ) @@ -622,26 +619,6 @@ if(ANDROID) endif(WITH_GPROF) endif() -set(CMAKE_THREAD_PREFER_PTHREAD TRUE) - -if(NOT IOS) - find_package(Threads REQUIRED) -endif() - -if(NOT WIN32) - CHECK_SYMBOL_EXISTS(pthread_mutex_timedlock pthread.h HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL) - if (NOT HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL) - CHECK_LIBRARY_EXISTS(pthread pthread_mutex_timedlock "" HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB) - endif (NOT HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL) - if (NOT HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB) - CHECK_LIBRARY_EXISTS(pthreads pthread_mutex_timedlock "" HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIBS) - endif (NOT HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB) - - if (HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL OR HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB OR HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIBS) - set(HAVE_PTHREAD_MUTEX_TIMEDLOCK ON) - endif (HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL OR HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB OR HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIBS) -endif() - if(WITH_VALGRIND_MEMCHECK) check_include_files(valgrind/memcheck.h HAVE_VALGRIND_MEMCHECK_H) else() @@ -667,6 +644,10 @@ if(UNIX OR CYGWIN) list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES m) set(X11_FEATURE_TYPE "RECOMMENDED") set(WAYLAND_FEATURE_TYPE "RECOMMENDED") + + include(CheckFunctionExists) + + check_function_exists(getlogin_r HAVE_GETLOGIN_R) else() set(X11_FEATURE_TYPE "DISABLED") set(WAYLAND_FEATURE_TYPE "DISABLED") @@ -682,10 +663,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") @@ -710,15 +687,15 @@ set(ALSA_FEATURE_TYPE "RECOMMENDED") set(ALSA_FEATURE_PURPOSE "sound") set(ALSA_FEATURE_DESCRIPTION "audio input, audio output and multimedia redirection") -set(PULSE_FEATURE_TYPE "OPTIONAL") +set(PULSE_FEATURE_TYPE "RECOMMENDED") set(PULSE_FEATURE_PURPOSE "sound") set(PULSE_FEATURE_DESCRIPTION "audio input, audio output and multimedia redirection") -set(CUPS_FEATURE_TYPE "OPTIONAL") +set(CUPS_FEATURE_TYPE "RECOMMENDED") set(CUPS_FEATURE_PURPOSE "printing") set(CUPS_FEATURE_DESCRIPTION "printer device redirection") -set(PCSC_FEATURE_TYPE "OPTIONAL") +set(PCSC_FEATURE_TYPE "RECOMMENDED") set(PCSC_FEATURE_PURPOSE "smart card") set(PCSC_FEATURE_DESCRIPTION "smart card device redirection") @@ -730,14 +707,6 @@ set(VAAPI_FEATURE_TYPE "OPTIONAL") set(VAAPI_FEATURE_PURPOSE "multimedia") set(VAAPI_FEATURE_DESCRIPTION "VA-API hardware acceleration for video playback") -set(GSTREAMER_0_10_FEATURE_TYPE "OPTIONAL") -set(GSTREAMER_0_10_FEATURE_PURPOSE "multimedia") -set(GSTREAMER_0_10_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback, gstreamer 0.10 version") - -set(GSTREAMER_1_0_FEATURE_TYPE "RECOMMENDED") -set(GSTREAMER_1_0_FEATURE_PURPOSE "multimedia") -set(GSTREAMER_1_0_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback") - set(IPP_FEATURE_TYPE "OPTIONAL") set(IPP_FEATURE_PURPOSE "performance") set(IPP_FEATURE_DESCRIPTION "Intel Integrated Performance Primitives library") @@ -754,6 +723,10 @@ set(OPENH264_FEATURE_TYPE "OPTIONAL") set(OPENH264_FEATURE_PURPOSE "codec") set(OPENH264_FEATURE_DESCRIPTION "use OpenH264 library") +set(OPENCL_FEATURE_TYPE "OPTIONAL") +set(OPENCL_FEATURE_PURPOSE "codec") +set(OPENCL_FEATURE_DESCRIPTION "use OpenCL library") + set(GSM_FEATURE_TYPE "OPTIONAL") set(GSM_FEATURE_PURPOSE "codec") set(GSM_FEATURE_DESCRIPTION "GSM audio codec library") @@ -782,7 +755,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") @@ -790,16 +762,12 @@ if(WIN32) set(PCSC_FEATURE_TYPE "DISABLED") set(FFMPEG_FEATURE_TYPE "DISABLED") set(VAAPI_FEATURE_TYPE "DISABLED") - set(GSTREAMER_1_0_FEATURE_TYPE "DISABLED") - set(GSTREAMER_0_10_FEATURE_TYPE "OPTIONAL") set(OPENSLES_FEATURE_TYPE "DISABLED") 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") set(X11_FEATURE_TYPE "OPTIONAL") set(WAYLAND_FEATURE_TYPE "DISABLED") set(OSS_FEATURE_TYPE "DISABLED") @@ -809,8 +777,6 @@ if(APPLE) set(PULSE_FEATURE_TYPE "DISABLED") set(CUPS_FEATURE_TYPE "DISABLED") set(PCSC_FEATURE_TYPE "DISABLED") - set(GSTREAMER_1_0_FEATURE_TYPE "DISABLED") - set(GSTREAMER_0_10_FEATURE_TYPE "DISABLED") endif() set(OPENSLES_FEATURE_TYPE "DISABLED") endif() @@ -833,7 +799,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") @@ -841,17 +806,11 @@ if(ANDROID) set(PCSC_FEATURE_TYPE "DISABLED") set(FFMPEG_FEATURE_TYPE "DISABLED") set(VAAPI_FEATURE_TYPE "DISABLED") - set(GSTREAMER_1_0_FEATURE_TYPE "DISABLED") - set(GSTREAMER_0_10_FEATURE_TYPE "DISABLED") set(OPENSLES_FEATURE_TYPE "REQUIRED") 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}) @@ -867,12 +826,10 @@ find_feature(PCSC ${PCSC_FEATURE_TYPE} ${PCSC_FEATURE_PURPOSE} ${PCSC_FEATURE_DE find_feature(FFmpeg ${FFMPEG_FEATURE_TYPE} ${FFMPEG_FEATURE_PURPOSE} ${FFMPEG_FEATURE_DESCRIPTION}) -find_feature(GStreamer_0_10 ${GSTREAMER_0_10_FEATURE_TYPE} ${GSTREAMER_0_10_FEATURE_PURPOSE} ${GSTREAMER_0_10_FEATURE_DESCRIPTION}) -find_feature(GStreamer_1_0 ${GSTREAMER_1_0_FEATURE_TYPE} ${GSTREAMER_1_0_FEATURE_PURPOSE} ${GSTREAMER_1_0_FEATURE_DESCRIPTION}) - find_feature(JPEG ${JPEG_FEATURE_TYPE} ${JPEG_FEATURE_PURPOSE} ${JPEG_FEATURE_DESCRIPTION}) find_feature(x264 ${X264_FEATURE_TYPE} ${X264_FEATURE_PURPOSE} ${X264_FEATURE_DESCRIPTION}) find_feature(OpenH264 ${OPENH264_FEATURE_TYPE} ${OPENH264_FEATURE_PURPOSE} ${OPENH264_FEATURE_DESCRIPTION}) +find_feature(OpenCL ${OPENCL_FEATURE_TYPE} ${OPENCL_FEATURE_PURPOSE} ${OPENCL_FEATURE_DESCRIPTION}) find_feature(GSM ${GSM_FEATURE_TYPE} ${GSM_FEATURE_PURPOSE} ${GSM_FEATURE_DESCRIPTION}) find_feature(LAME ${LAME_FEATURE_TYPE} ${LAME_FEATURE_PURPOSE} ${LAME_FEATURE_DESCRIPTION}) find_feature(FAAD2 ${FAAD2_FEATURE_TYPE} ${FAAD2_FEATURE_PURPOSE} ${FAAD2_FEATURE_DESCRIPTION}) @@ -881,6 +838,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) + option(WITH_OPENH264_LOADING "Use LoadLibrary to load openh264 at runtime" 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,16 +906,13 @@ endif() if(OPENSSL_FOUND) add_definitions("-DWITH_OPENSSL") message(STATUS "Using OpenSSL Version: ${OPENSSL_VERSION}") + include_directories(${OPENSSL_INCLUDE_DIR}) endif() if(MBEDTLS_FOUND) add_definitions("-DWITH_MBEDTLS") endif() -if (TARGET_ARCH MATCHES "sparc") - set(HAVE_ALIGNED_REQUIRED 1) -endif() - if (WITH_X264 OR WITH_OPENH264 OR WITH_MEDIA_FOUNDATION OR WITH_FFMPEG) set(WITH_GFX_H264 ON) else() @@ -963,23 +921,34 @@ endif() # Android expects all libraries to be loadable # without paths. -if (ANDROID) - set(FREERDP_DATA_PATH "share") - set(FREERDP_INSTALL_PREFIX ".") - set(FREERDP_LIBRARY_PATH ".") - set(FREERDP_PLUGIN_PATH ".") - set(FREERDP_ADDIN_PATH ".") -else (ANDROID) +if (ANDROID OR WIN32 OR MAC_BUNDLE) + set(FREERDP_DATA_PATH "share") + if (NOT FREERDP_INSTALL_PREFIX) + set(FREERDP_INSTALL_PREFIX ".") + endif() + set(FREERDP_LIBRARY_PATH ".") + set(FREERDP_PLUGIN_PATH ".") +else() set(FREERDP_DATA_PATH "${CMAKE_INSTALL_PREFIX}/share/freerdp${FREERDP_VERSION_MAJOR}") - set(FREERDP_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") + if (NOT FREERDP_INSTALL_PREFIX) + set(FREERDP_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") + endif() set(FREERDP_LIBRARY_PATH "${CMAKE_INSTALL_LIBDIR}") set(FREERDP_PLUGIN_PATH "${CMAKE_INSTALL_LIBDIR}/freerdp${FREERDP_VERSION_MAJOR}") - set(FREERDP_ADDIN_PATH "${FREERDP_PLUGIN_PATH}") -endif(ANDROID) +endif() +set(FREERDP_ADDIN_PATH "${FREERDP_PLUGIN_PATH}") # Path to put extensions set(FREERDP_EXTENSION_PATH "${CMAKE_INSTALL_FULL_LIBDIR}/freerdp${FREERDP_VERSION_MAJOR}/extensions") +# Proxy plugins path +if(NOT DEFINED PROXY_PLUGINDIR) + message("using default plugins location") + set(FREERDP_PROXY_PLUGINDIR "${CMAKE_BINARY_DIR}/server/proxy/plugins") +else() + set(FREERDP_PROXY_PLUGINDIR "${PROXY_PLUGINDIR}") +endif() + # Include directories include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories(${CMAKE_CURRENT_BINARY_DIR}/include) @@ -1062,7 +1031,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 b7f6656..1e98eab 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,134 @@ +# 2020-07-20 Version 2.2.0 + +Important notes: +* CVE-2020-15103 - Integer overflow due to missing input sanitation in rdpegfx channel + +Noteworty changes: +* fix: memory leak in nsc +* urbdrc + * some fixes and improvements +* build + * use cmake to detect getlogin_r + * improve asan checks/detection +* server/proxy + * new: support for heartbeats + * new: support for rail handshake ex flags + * fix: possible race condition with redirects + +Fixed issues: +* #6263 Sound & mic - filter GSM codec for microphone redirection +* #6335: windows client title length +* #6370 - "Alternate Secondary Drawing Order UNKNOWN" +* #6298 - remoteapp with dialog is disconnecting when it loses focus +* #6299 - v2.1.2: Can't connect to Windows7 + +For a complete and detailed change log since the last release run: +git log 2.1.2..2.2.0 + + +# 2020-06-22 Version 2.1.2 + +Important notes: +* CVE-2020-4033 Out of bound read in RLEDECOMPRESS +* CVE-2020-4031 Use-After-Free in gdi_SelectObject +* CVE-2020-4032 Integer casting vulnerability in `update_recv_secondary_order` +* CVE-2020-4030 OOB read in `TrioParse` +* CVE-2020-11099 OOB Read in license_read_new_or_upgrade_license_packet +* CVE-2020-11098 Out-of-bound read in glyph_cache_put +* CVE-2020-11097 OOB read in ntlm_av_pair_get +* CVE-2020-11095 Global OOB read in update_recv_primary_order +* CVE-2020-11096 Global OOB read in update_read_cache_bitmap_v3_order +* Gateway RPC fixes for windows +* Fixed resource fee race resulting in double free in USB redirection +* Fixed wayland client crashes +* Fixed X11 client mouse mapping issues (X11 mapping on/off) +* Some proxy related improvements (capture module) +* Code cleanup (use getlogin_r, ...) + +For a complete and detailed change log since the last release candidate run: +git log 2.1.1..2.1.2 + + +# 2020-05-20 Version 2.1.1 + +Important notes: +* CVE: GHSL-2020-100 OOB Read in ntlm_read_ChallengeMessage +* CVE: GHSL-2020-101 OOB Read in security_fips_decrypt due to uninitialized value +* CVE: GHSL-2020-102 OOB Write in crypto_rsa_common +* Enforce synchronous legacy RDP encryption count (#6156) +* Fixed some leaks and crashes missed in 2.1.0 +* Removed dynamic channel listener limits +* Lots of resource cleanup fixes (clang sanitizers) +* A couple of performance improvements +* Various small annoyances eliminated (typos, prefilled username for windows client, ...) + + +For a complete and detailed change log since the last release candidate run: +git log 2.1.0..2.1.1 + + +# 2020-05-05 Version 2.1.0 + +Important notes: + +* fix multiple CVEs: CVE-2020-11039, CVE-2020-11038, CVE-2020-11043, CVE-2020-11040, CVE-2020-11041, + CVE-2020-11019, CVE-2020-11017, CVE-2020-11018 +* fix multiple leak and crash issues (#6129, #6128, #6127, #6110, #6081, #6077) + +Noteworthy features and improvements: +* Fixed sound issues (#6043) +* New expert command line options /tune and /tune-list to modify all client + settings in a generic way. +* Fixes for smartcard cache, this improves compatibility of smartcard devices + with newer smartcard channel. +* Shadow server can now be instructed to listen to multiple interfaces. +* Improved server certificate support (#6052) +* Various fixes for wayland client (fullscreen, mouse wheel, ...) +* Fixed large mouse pointer support, now mouse pointers > 96x96 pixel are visible. +* USB redirection command line improvements (filter options) +* Various translation improvements for android and ios clients + +For a complete and detailed change log since the last release candidate run: +git log 2.0.0..2.1.0 + + +# 2020-04-09 Version 2.0.0 + +Important notes: + +* fix multiple CVEs: CVE-2020-11521 CVE-2020-11522 CVE-2020-11523 CVE-2020-11524 CVE-2020-11525 CVE-2020-11526 +* fix multiple other security related issues (#6005, #6006, #6007, #6008, #6009, #6010, #6011, #6012, #6013) +* sha256 is now used instead of sha1 to fingerprint certificates. This will + invalidate all hosts in FreeRDP known_hosts2 file and causes a prompt if a + new connection is established after the update + +Noteworthy features and improvements: + +* First version of the RDP proxy was added (#5372) - thanks to @kubistika +* Smartcard received some refactoring. Missing functions were added and input + validation was improved (#5884) +* A new option /cert that unifies all certificate related options (#5880) + The old options (cert-ignore, cert-deny, cert-name, cert-tofu) are still + available but marked as deprecated +* Support for Remote Assistance Protocol Version 2 [MS-RA] +* The DirectFB client was removed because it was unmaintained +* Unified initialization of OrderSupport +* Fix for licensing against Windows Server 2003 +* Font smoothing is now enabled per default +* Flatpack support was added +* Smart scaling for Wayland using libcairo was added (#5215) +* Unified update->BeginPaint and update->EndPaint +* An image scaling API for software drawing was added +* Rail was updated to the latest spec version 28.0 +* Support for H.264 in the shadow server is now detected at runtime +* Add mask= option for /gfx and /gfx-h264 (#5771) +* Code reformatting (#5667) +* A new option /timeout was added to adjust the TCP ACK timeout (#5987) + +For a complete and detailed change log since the last release candidate run: +git log 2.0.0-rc4..2.0.0 + + # 2018-11-19 Version 2.0.0-rc4 FreeRDP 2.0.0-rc4 is the fifth release candidate for 2.0.0. Although it mainly diff --git a/README.md b/README.md new file mode 100644 index 0000000..70cf40d --- /dev/null +++ b/README.md @@ -0,0 +1,30 @@ +# FreeRDP: A Remote Desktop Protocol Implementation + +FreeRDP is a free implementation of the Remote Desktop Protocol (RDP), released under the Apache license. +Enjoy the freedom of using your software wherever you want, the way you want it, in a world where +interoperability can finally liberate your computing experience. + +## Resources + +Project website: https://www.freerdp.com/ +Issue tracker: https://github.com/FreeRDP/FreeRDP/issues +Sources: https://github.com/FreeRDP/FreeRDP/ +Downloads: https://pub.freerdp.com/releases/ +Wiki: https://github.com/FreeRDP/FreeRDP/wiki +API documentation: https://pub.freerdp.com/api/ + +IRC channel: #freerdp @ irc.freenode.net +Mailing list: https://lists.sourceforge.net/lists/listinfo/freerdp-devel + +## Microsoft Open Specifications + +Information regarding the Microsoft Open Specifications can be found at: +http://www.microsoft.com/openspecifications/ + +A list of reference documentation is maintained here: +https://github.com/FreeRDP/FreeRDP/wiki/Reference-Documentation + +## Compilation + +Instructions on how to get started compiling FreeRDP can be found on the wiki: +https://github.com/FreeRDP/FreeRDP/wiki/Compilation diff --git a/channels/CMakeLists.txt b/channels/CMakeLists.txt index 76a5716..882fef7 100644 --- a/channels/CMakeLists.txt +++ b/channels/CMakeLists.txt @@ -32,7 +32,8 @@ macro(define_channel_options) string(TOUPPER "CHANNEL_${CHANNEL_NAME}" CHANNEL_OPTION) string(TOUPPER "CHANNEL_${CHANNEL_NAME}_CLIENT" CHANNEL_CLIENT_OPTION) string(TOUPPER "CHANNEL_${CHANNEL_NAME}_SERVER" CHANNEL_SERVER_OPTION) - + string(TOUPPER "${CHANNEL_TYPE}" CHANNEL_TYPE) + if(${${CHANNEL_CLIENT_OPTION}}) set(OPTION_CLIENT_DEFAULT ${${CHANNEL_CLIENT_OPTION}}) endif() @@ -52,23 +53,30 @@ macro(define_channel_options) set(CHANNEL_DEFAULT ${OPTION_DEFAULT}) set(CHANNEL_OPTION_DOC "Build ${CHANNEL_NAME} ${CHANNEL_TYPE} channel") - option(${CHANNEL_OPTION} "${CHANNEL_OPTION_DOC}" ${CHANNEL_DEFAULT}) + + if ("${CHANNEL_TYPE}" STREQUAL "DYNAMIC") + CMAKE_DEPENDENT_OPTION(${CHANNEL_OPTION} "${CHANNEL_OPTION_DOC}" ${CHANNEL_DEFAULT} "CHANNEL_DRDYNVC" OFF) + else() + option(${CHANNEL_OPTION} "${CHANNEL_OPTION_DOC}" ${CHANNEL_DEFAULT}) + endif() endmacro(define_channel_options) macro(define_channel_client_options _channel_client_default) string(TOUPPER "CHANNEL_${CHANNEL_NAME}_CLIENT" CHANNEL_CLIENT_OPTION) + string(TOUPPER "CHANNEL_${CHANNEL_NAME}" CHANNEL_OPTION) set(CHANNEL_CLIENT_OPTION_DOC "Build ${CHANNEL_NAME} ${CHANNEL_TYPE} channel client") - option(${CHANNEL_CLIENT_OPTION} "${CHANNEL_CLIENT_OPTION_DOC}" ${_channel_client_default}) - cmake_dependent_option(${CHANNEL_CLIENT_OPTION} "${CHANNEL_CLIENT_OPTION_DOC}" + + CMAKE_DEPENDENT_OPTION(${CHANNEL_CLIENT_OPTION} "${CHANNEL_CLIENT_OPTION_DOC}" ${_channel_client_default} "${CHANNEL_OPTION}" OFF) endmacro(define_channel_client_options) macro(define_channel_server_options _channel_server_default) string(TOUPPER "CHANNEL_${CHANNEL_NAME}_SERVER" CHANNEL_SERVER_OPTION) + string(TOUPPER "CHANNEL_${CHANNEL_NAME}" CHANNEL_OPTION) set(CHANNEL_SERVER_OPTION_DOC "Build ${CHANNEL_NAME} ${CHANNEL_TYPE} channel server") - option(${CHANNEL_SERVER_OPTION} "${CHANNEL_SERVER_OPTION_DOC}" ${_channel_server_default}) - cmake_dependent_option(${CHANNEL_SERVER_OPTION} "${CHANNEL_SERVER_OPTION_DOC}" + + CMAKE_DEPENDENT_OPTION(${CHANNEL_SERVER_OPTION} "${CHANNEL_SERVER_OPTION_DOC}" ${_channel_server_default} "${CHANNEL_OPTION}" OFF) endmacro(define_channel_server_options) @@ -167,7 +175,12 @@ macro(client_channel_install _targets _destination) endmacro(client_channel_install) macro(add_channel_client_library _module_prefix _module_name _channel_name _dynamic _entry) - if(${_dynamic} AND (NOT BUILTIN_CHANNELS)) + set(_lnk_dir ${${_module_prefix}_LINK_DIRS}) + if (NOT "${_lnk_dir}" STREQUAL "") + link_directories(${_lnk_dir}) + endif() + + if(${_dynamic} AND (NOT BUILTIN_CHANNELS)) # On windows create dll version information. # Vendor, product and year are already set in top level CMakeLists.txt if (WIN32) @@ -185,22 +198,30 @@ macro(add_channel_client_library _module_prefix _module_name _channel_name _dyna set ( ${_module_prefix}_SRCS ${${_module_prefix}_SRCS} ${CMAKE_CURRENT_BINARY_DIR}/version.rc) endif() - add_library(${_module_name} ${${_module_prefix}_SRCS}) - client_channel_install(${_module_name} ${FREERDP_ADDIN_PATH}) - else() - set(${_module_prefix}_STATIC ON PARENT_SCOPE) - set(${_module_prefix}_NAME ${_module_name} PARENT_SCOPE) - set(${_module_prefix}_CHANNEL ${_channel_name} PARENT_SCOPE) - set(${_module_prefix}_ENTRY ${_entry} PARENT_SCOPE) - add_library(${_module_name} STATIC ${${_module_prefix}_SRCS}) - if (${CMAKE_VERSION} VERSION_LESS 2.8.12 OR NOT BUILD_SHARED_LIBS) - client_channel_install(${_module_name} ${FREERDP_ADDIN_PATH}) - endif() - endif() + add_library(${_module_name} ${${_module_prefix}_SRCS}) + target_link_libraries(${_module_name} ${${_module_prefix}_LIBS}) + client_channel_install(${_module_name} ${FREERDP_ADDIN_PATH}) + else() + set(${_module_prefix}_STATIC ON PARENT_SCOPE) + set(${_module_prefix}_NAME ${_module_name} PARENT_SCOPE) + set(${_module_prefix}_CHANNEL ${_channel_name} PARENT_SCOPE) + set(${_module_prefix}_ENTRY ${_entry} PARENT_SCOPE) + add_library(${_module_name} STATIC ${${_module_prefix}_SRCS}) + target_link_libraries(${_module_name} ${${_module_prefix}_LIBS}) + + if (${CMAKE_VERSION} VERSION_LESS 2.8.12 OR NOT BUILD_SHARED_LIBS) + client_channel_install(${_module_name} ${FREERDP_ADDIN_PATH}) + endif() + endif() endmacro(add_channel_client_library) macro(add_channel_client_subsystem_library _module_prefix _module_name _channel_name _type _dynamic _entry) - if(${_dynamic} AND (NOT BUILTIN_CHANNELS)) + set(_lnk_dir ${${_module_prefix}_LINK_DIRS}) + if (NOT "${_lnk_dir}" STREQUAL "") + link_directories(${_lnk_dir}) + endif() + + if(${_dynamic} AND (NOT BUILTIN_CHANNELS)) # On windows create dll version information. # Vendor, product and year are already set in top level CMakeLists.txt if (WIN32) @@ -218,21 +239,29 @@ macro(add_channel_client_subsystem_library _module_prefix _module_name _channel_ set ( ${_module_prefix}_SRCS ${${_module_prefix}_SRCS} ${CMAKE_CURRENT_BINARY_DIR}/version.rc) endif() - add_library(${_module_name} ${${_module_prefix}_SRCS}) - client_channel_install(${_module_name} ${FREERDP_ADDIN_PATH}) - else() - set(${_module_prefix}_STATIC ON PARENT_SCOPE) - set(${_module_prefix}_NAME ${_module_name} PARENT_SCOPE) - set(${_module_prefix}_TYPE ${_type} PARENT_SCOPE) - add_library(${_module_name} STATIC ${${_module_prefix}_SRCS}) - if (${CMAKE_VERSION} VERSION_LESS 2.8.12 OR NOT BUILD_SHARED_LIBS) - client_channel_install(${_module_name} ${FREERDP_ADDIN_PATH}) - endif() - endif() + add_library(${_module_name} ${${_module_prefix}_SRCS}) + target_link_libraries(${_module_name} ${${_module_prefix}_LIBS}) + client_channel_install(${_module_name} ${FREERDP_ADDIN_PATH}) + else() + set(${_module_prefix}_STATIC ON PARENT_SCOPE) + set(${_module_prefix}_NAME ${_module_name} PARENT_SCOPE) + set(${_module_prefix}_TYPE ${_type} PARENT_SCOPE) + + add_library(${_module_name} STATIC ${${_module_prefix}_SRCS}) + target_link_libraries(${_module_name} ${${_module_prefix}_LIBS}) + if (${CMAKE_VERSION} VERSION_LESS 2.8.12 OR NOT BUILD_SHARED_LIBS) + client_channel_install(${_module_name} ${FREERDP_ADDIN_PATH}) + endif() + endif() endmacro(add_channel_client_subsystem_library) macro(add_channel_server_library _module_prefix _module_name _channel_name _dynamic _entry) - if(${_dynamic} AND (NOT BUILTIN_CHANNELS)) + set(_lnk_dir ${${_module_prefix}_LINK_DIRS}) + if (NOT "${_lnk_dir}" STREQUAL "") + link_directories(${_lnk_dir}) + endif() + + if(${_dynamic} AND (NOT BUILTIN_CHANNELS)) # On windows create dll version information. # Vendor, product and year are already set in top level CMakeLists.txt if (WIN32) @@ -266,6 +295,23 @@ endmacro(add_channel_server_library) set(FILENAME "ChannelOptions.cmake") file(GLOB FILEPATHS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*/${FILENAME}") +# We need special treatement for drdynvc: +# It needs to be the first entry so that every +# dynamic channel has the dependent options available. +set(DRDYNVC_MATCH "") + +foreach(FILEPATH ${FILEPATHS}) + if(${FILEPATH} MATCHES "^([^/]*)drdynvc/+${FILENAME}") + set(DRDYNVC_MATCH ${FILEPATH}) + endif() +endforeach() + +if (NOT "${DRDYNVC_MATCH}" STREQUAL "") + list(REMOVE_ITEM FILEPATHS ${DRDYNVC_MATCH}) + list(APPEND FILEPATHS ${DRDYNVC_MATCH}) + list(REVERSE FILEPATHS) # list PREPEND is not available on old CMake3 +endif() + foreach(FILEPATH ${FILEPATHS}) if(${FILEPATH} MATCHES "^([^/]*)/+${FILENAME}") string(REGEX REPLACE "^([^/]*)/+${FILENAME}" "\\1" DIR ${FILEPATH}) diff --git a/channels/audin/client/alsa/audin_alsa.c b/channels/audin/client/alsa/audin_alsa.c index 169422a..60e9fd8 100644 --- a/channels/audin/client/alsa/audin_alsa.c +++ b/channels/audin/client/alsa/audin_alsa.c @@ -87,34 +87,36 @@ static snd_pcm_format_t audin_alsa_format(UINT32 wFormatTag, UINT32 bitPerChanne } } -static BOOL audin_alsa_set_params(AudinALSADevice* alsa, - snd_pcm_t* capture_handle) +static BOOL audin_alsa_set_params(AudinALSADevice* alsa, snd_pcm_t* capture_handle) { int error; + SSIZE_T s; UINT32 channels = alsa->aformat.nChannels; snd_pcm_hw_params_t* hw_params; - snd_pcm_format_t format = audin_alsa_format(alsa->aformat.wFormatTag, alsa->aformat.wBitsPerSample); + snd_pcm_format_t format = + audin_alsa_format(alsa->aformat.wFormatTag, alsa->aformat.wBitsPerSample); if ((error = snd_pcm_hw_params_malloc(&hw_params)) < 0) { - WLog_Print(alsa->log, WLOG_ERROR, "snd_pcm_hw_params_malloc (%s)", - snd_strerror(error)); + WLog_Print(alsa->log, WLOG_ERROR, "snd_pcm_hw_params_malloc (%s)", snd_strerror(error)); return FALSE; } snd_pcm_hw_params_any(capture_handle, hw_params); - snd_pcm_hw_params_set_access(capture_handle, hw_params, - SND_PCM_ACCESS_RW_INTERLEAVED); + snd_pcm_hw_params_set_access(capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); snd_pcm_hw_params_set_format(capture_handle, hw_params, format); - snd_pcm_hw_params_set_rate_near(capture_handle, hw_params, - &alsa->aformat.nSamplesPerSec, NULL); - snd_pcm_hw_params_set_channels_near(capture_handle, hw_params, - &channels); + snd_pcm_hw_params_set_rate_near(capture_handle, hw_params, &alsa->aformat.nSamplesPerSec, NULL); + snd_pcm_hw_params_set_channels_near(capture_handle, hw_params, &channels); snd_pcm_hw_params(capture_handle, hw_params); snd_pcm_hw_params_free(hw_params); snd_pcm_prepare(capture_handle); - alsa->aformat.nChannels = channels; - alsa->bytes_per_frame = snd_pcm_format_size(format, 1) * channels; + if (channels > UINT16_MAX) + return FALSE; + s = snd_pcm_format_size(format, 1); + if ((s < 0) || (s > UINT16_MAX)) + return FALSE; + alsa->aformat.nChannels = (UINT16)channels; + alsa->bytes_per_frame = (size_t)s * channels; return TRUE; } @@ -123,12 +125,11 @@ static DWORD WINAPI audin_alsa_thread_func(LPVOID arg) long error; BYTE* buffer; snd_pcm_t* capture_handle = NULL; - AudinALSADevice* alsa = (AudinALSADevice*) arg; + AudinALSADevice* alsa = (AudinALSADevice*)arg; DWORD status; WLog_Print(alsa->log, WLOG_DEBUG, "in"); - if ((error = snd_pcm_open(&capture_handle, alsa->device_name, - SND_PCM_STREAM_CAPTURE, 0)) < 0) + if ((error = snd_pcm_open(&capture_handle, alsa->device_name, SND_PCM_STREAM_CAPTURE, 0)) < 0) { WLog_Print(alsa->log, WLOG_ERROR, "snd_pcm_open (%s)", snd_strerror(error)); error = CHANNEL_RC_INITIALIZATION_ERROR; @@ -141,7 +142,8 @@ static DWORD WINAPI audin_alsa_thread_func(LPVOID arg) goto out; } - buffer = (BYTE*) calloc(alsa->frames_per_packet + alsa->aformat.nBlockAlign, alsa->bytes_per_frame); + buffer = + (BYTE*)calloc(alsa->frames_per_packet + alsa->aformat.nBlockAlign, alsa->bytes_per_frame); if (!buffer) { @@ -181,12 +183,13 @@ static DWORD WINAPI audin_alsa_thread_func(LPVOID arg) break; } - error = alsa->receive(&alsa->aformat, - buffer, error * alsa->bytes_per_frame, alsa->user_data); + error = + alsa->receive(&alsa->aformat, buffer, error * alsa->bytes_per_frame, alsa->user_data); if (error) { - WLog_Print(alsa->log, WLOG_ERROR, "audin_alsa_thread_receive failed with error %ld", error); + WLog_Print(alsa->log, WLOG_ERROR, "audin_alsa_thread_receive failed with error %ld", + error); break; } } @@ -200,8 +203,7 @@ out: WLog_Print(alsa->log, WLOG_DEBUG, "out"); if (error && alsa->rdpcontext) - setChannelError(alsa->rdpcontext, error, - "audin_alsa_thread_func reported an error"); + setChannelError(alsa->rdpcontext, error, "audin_alsa_thread_func reported an error"); ExitThread(error); return error; @@ -214,7 +216,7 @@ out: */ static UINT audin_alsa_free(IAudinDevice* device) { - AudinALSADevice* alsa = (AudinALSADevice*) device; + AudinALSADevice* alsa = (AudinALSADevice*)device; if (alsa) free(alsa->device_name); @@ -223,8 +225,7 @@ static UINT audin_alsa_free(IAudinDevice* device) return CHANNEL_RC_OK; } -static BOOL audin_alsa_format_supported(IAudinDevice* device, - const AUDIO_FORMAT* format) +static BOOL audin_alsa_format_supported(IAudinDevice* device, const AUDIO_FORMAT* format) { if (!device || !format) return FALSE; @@ -232,8 +233,7 @@ static BOOL audin_alsa_format_supported(IAudinDevice* device, switch (format->wFormatTag) { case WAVE_FORMAT_PCM: - if (format->cbSize == 0 && - (format->nSamplesPerSec <= 48000) && + if (format->cbSize == 0 && (format->nSamplesPerSec <= 48000) && (format->wBitsPerSample == 8 || format->wBitsPerSample == 16) && (format->nChannels == 1 || format->nChannels == 2)) { @@ -261,7 +261,7 @@ static BOOL audin_alsa_format_supported(IAudinDevice* device, static UINT audin_alsa_set_format(IAudinDevice* device, const AUDIO_FORMAT* format, UINT32 FramesPerPacket) { - AudinALSADevice* alsa = (AudinALSADevice*) device; + AudinALSADevice* alsa = (AudinALSADevice*)device; if (!alsa || !format) return ERROR_INVALID_PARAMETER; @@ -280,10 +280,9 @@ static UINT audin_alsa_set_format(IAudinDevice* device, const AUDIO_FORMAT* form * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_alsa_open(IAudinDevice* device, AudinReceive receive, - void* user_data) +static UINT audin_alsa_open(IAudinDevice* device, AudinReceive receive, void* user_data) { - AudinALSADevice* alsa = (AudinALSADevice*) device; + AudinALSADevice* alsa = (AudinALSADevice*)device; if (!device || !receive || !user_data) return ERROR_INVALID_PARAMETER; @@ -297,8 +296,7 @@ static UINT audin_alsa_open(IAudinDevice* device, AudinReceive receive, goto error_out; } - if (!(alsa->thread = CreateThread(NULL, 0, - audin_alsa_thread_func, alsa, 0, NULL))) + if (!(alsa->thread = CreateThread(NULL, 0, audin_alsa_thread_func, alsa, 0, NULL))) { WLog_Print(alsa->log, WLOG_ERROR, "CreateThread failed!"); goto error_out; @@ -319,7 +317,7 @@ error_out: static UINT audin_alsa_close(IAudinDevice* device) { UINT error = CHANNEL_RC_OK; - AudinALSADevice* alsa = (AudinALSADevice*) device; + AudinALSADevice* alsa = (AudinALSADevice*)device; if (!alsa) return ERROR_INVALID_PARAMETER; @@ -331,7 +329,8 @@ static UINT audin_alsa_close(IAudinDevice* device) if (WaitForSingleObject(alsa->thread, INFINITE) == WAIT_FAILED) { error = GetLastError(); - WLog_Print(alsa->log, WLOG_ERROR, "WaitForSingleObject failed with error %"PRIu32"", error); + WLog_Print(alsa->log, WLOG_ERROR, "WaitForSingleObject failed with error %" PRIu32 "", + error); return error; } @@ -346,28 +345,24 @@ static UINT audin_alsa_close(IAudinDevice* device) return error; } -static COMMAND_LINE_ARGUMENT_A audin_alsa_args[] = -{ - { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "audio device name" }, - { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } -}; - /** * Function description * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_alsa_parse_addin_args(AudinALSADevice* device, - ADDIN_ARGV* args) +static UINT audin_alsa_parse_addin_args(AudinALSADevice* device, ADDIN_ARGV* args) { int status; DWORD flags; COMMAND_LINE_ARGUMENT_A* arg; - AudinALSADevice* alsa = (AudinALSADevice*) device; - flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | - COMMAND_LINE_IGN_UNKNOWN_KEYWORD; - status = CommandLineParseArgumentsA(args->argc, args->argv, - audin_alsa_args, flags, alsa, NULL, NULL); + AudinALSADevice* alsa = (AudinALSADevice*)device; + COMMAND_LINE_ARGUMENT_A audin_alsa_args[] = { { "dev", COMMAND_LINE_VALUE_REQUIRED, "", + NULL, NULL, -1, NULL, "audio device name" }, + { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } }; + flags = + COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; + status = CommandLineParseArgumentsA(args->argc, args->argv, audin_alsa_args, flags, alsa, NULL, + NULL); if (status < 0) return ERROR_INVALID_PARAMETER; @@ -379,8 +374,7 @@ static UINT audin_alsa_parse_addin_args(AudinALSADevice* device, if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) continue; - CommandLineSwitchStart(arg) - CommandLineSwitchCase(arg, "dev") + CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "dev") { alsa->device_name = _strdup(arg->Value); @@ -391,16 +385,15 @@ static UINT audin_alsa_parse_addin_args(AudinALSADevice* device, } } CommandLineSwitchEnd(arg) - } - while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); return CHANNEL_RC_OK; } #ifdef BUILTIN_CHANNELS -#define freerdp_audin_client_subsystem_entry alsa_freerdp_audin_client_subsystem_entry +#define freerdp_audin_client_subsystem_entry alsa_freerdp_audin_client_subsystem_entry #else -#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry +#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry #endif /** @@ -408,13 +401,12 @@ static UINT audin_alsa_parse_addin_args(AudinALSADevice* device, * * @return 0 on success, otherwise a Win32 error code */ -UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS - pEntryPoints) +UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints) { ADDIN_ARGV* args; AudinALSADevice* alsa; UINT error; - alsa = (AudinALSADevice*) calloc(1, sizeof(AudinALSADevice)); + alsa = (AudinALSADevice*)calloc(1, sizeof(AudinALSADevice)); if (!alsa) { @@ -433,8 +425,8 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS if ((error = audin_alsa_parse_addin_args(alsa, args))) { - WLog_Print(alsa->log, WLOG_ERROR, "audin_alsa_parse_addin_args failed with errorcode %"PRIu32"!", - error); + WLog_Print(alsa->log, WLOG_ERROR, + "audin_alsa_parse_addin_args failed with errorcode %" PRIu32 "!", error); goto error_out; } @@ -456,10 +448,10 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS alsa->aformat.wFormatTag = WAVE_FORMAT_PCM; alsa->aformat.nSamplesPerSec = 44100; - if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, - (IAudinDevice*) alsa))) + if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*)alsa))) { - WLog_Print(alsa->log, WLOG_ERROR, "RegisterAudinDevice failed with error %"PRIu32"!", error); + WLog_Print(alsa->log, WLOG_ERROR, "RegisterAudinDevice failed with error %" PRIu32 "!", + error); goto error_out; } diff --git a/channels/audin/client/audin_main.c b/channels/audin/client/audin_main.c index b7ce330..26ac483 100644 --- a/channels/audin/client/audin_main.c +++ b/channels/audin/client/audin_main.c @@ -42,13 +42,13 @@ #include "audin_main.h" -#define MSG_SNDIN_VERSION 0x01 -#define MSG_SNDIN_FORMATS 0x02 -#define MSG_SNDIN_OPEN 0x03 -#define MSG_SNDIN_OPEN_REPLY 0x04 +#define MSG_SNDIN_VERSION 0x01 +#define MSG_SNDIN_FORMATS 0x02 +#define MSG_SNDIN_OPEN 0x03 +#define MSG_SNDIN_OPEN_REPLY 0x04 #define MSG_SNDIN_DATA_INCOMING 0x05 -#define MSG_SNDIN_DATA 0x06 -#define MSG_SNDIN_FORMATCHANGE 0x07 +#define MSG_SNDIN_DATA 0x06 +#define MSG_SNDIN_FORMATCHANGE 0x07 typedef struct _AUDIN_LISTENER_CALLBACK AUDIN_LISTENER_CALLBACK; struct _AUDIN_LISTENER_CALLBACK @@ -100,12 +100,14 @@ struct _AUDIN_PLUGIN FREERDP_DSP_CONTEXT* dsp_context; wLog* log; + + IWTSListener* listener; }; static BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args); static UINT audin_channel_write_and_free(AUDIN_CHANNEL_CALLBACK* callback, wStream* out, - BOOL freeStream) + BOOL freeStream) { UINT error; @@ -116,9 +118,8 @@ static UINT audin_channel_write_and_free(AUDIN_CHANNEL_CALLBACK* callback, wStre return ERROR_INTERNAL_ERROR; Stream_SealLength(out); - error = callback->channel->Write(callback->channel, - Stream_Length(out), - Stream_Buffer(out), NULL); + error = + callback->channel->Write(callback->channel, Stream_Length(out), Stream_Buffer(out), NULL); if (freeStream) Stream_Free(out, TRUE); @@ -126,7 +127,6 @@ static UINT audin_channel_write_and_free(AUDIN_CHANNEL_CALLBACK* callback, wStre return error; } - /** * Function description * @@ -142,15 +142,16 @@ static UINT audin_process_version(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* c return ERROR_INVALID_DATA; Stream_Read_UINT32(s, ServerVersion); - WLog_Print(audin->log, WLOG_DEBUG, "ServerVersion=%"PRIu32", ClientVersion=%"PRIu32, ServerVersion, - ClientVersion); + WLog_Print(audin->log, WLOG_DEBUG, "ServerVersion=%" PRIu32 ", ClientVersion=%" PRIu32, + ServerVersion, ClientVersion); /* Do not answer server packet, we do not support the channel version. */ if (ServerVersion != ClientVersion) { WLog_Print(audin->log, WLOG_WARN, - "Incompatible channel version server=%"PRIu32", client supports version=%"PRIu32, ServerVersion, - ClientVersion); + "Incompatible channel version server=%" PRIu32 + ", client supports version=%" PRIu32, + ServerVersion, ClientVersion); return CHANNEL_RC_OK; } @@ -199,11 +200,11 @@ static UINT audin_process_formats(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* c return ERROR_INVALID_DATA; Stream_Read_UINT32(s, NumFormats); - WLog_Print(audin->log, WLOG_DEBUG, "NumFormats %"PRIu32"", NumFormats); + WLog_Print(audin->log, WLOG_DEBUG, "NumFormats %" PRIu32 "", NumFormats); if ((NumFormats < 1) || (NumFormats > 1000)) { - WLog_Print(audin->log, WLOG_ERROR, "bad NumFormats %"PRIu32"", NumFormats); + WLog_Print(audin->log, WLOG_ERROR, "bad NumFormats %" PRIu32 "", NumFormats); return ERROR_INVALID_DATA; } @@ -271,11 +272,11 @@ static UINT audin_process_formats(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* c goto out; } - cbSizeFormatsPacket = (UINT32) Stream_GetPosition(out); + cbSizeFormatsPacket = (UINT32)Stream_GetPosition(out); Stream_SetPosition(out, 0); - Stream_Write_UINT8(out, MSG_SNDIN_FORMATS); /* Header (1 byte) */ + Stream_Write_UINT8(out, MSG_SNDIN_FORMATS); /* Header (1 byte) */ Stream_Write_UINT32(out, callback->formats_count); /* NumFormats (4 bytes) */ - Stream_Write_UINT32(out, cbSizeFormatsPacket); /* cbSizeFormatsPacket (4 bytes) */ + Stream_Write_UINT32(out, cbSizeFormatsPacket); /* cbSizeFormatsPacket (4 bytes) */ Stream_SetPosition(out, cbSizeFormatsPacket); error = audin_channel_write_and_free(callback, out, FALSE); out: @@ -296,7 +297,7 @@ out: * @return 0 on success, otherwise a Win32 error code */ static UINT audin_send_format_change_pdu(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callback, - UINT32 NewFormat) + UINT32 NewFormat) { wStream* out = Stream_New(NULL, 5); @@ -337,13 +338,13 @@ static UINT audin_send_open_reply_pdu(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBAC * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_receive_wave_data(const AUDIO_FORMAT* format, - const BYTE* data, size_t size, void* user_data) +static UINT audin_receive_wave_data(const AUDIO_FORMAT* format, const BYTE* data, size_t size, + void* user_data) { UINT error; BOOL compatible; AUDIN_PLUGIN* audin; - AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) user_data; + AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*)user_data; if (!callback) return CHANNEL_RC_BAD_CHANNEL_HANDLE; @@ -382,7 +383,7 @@ static UINT audin_receive_wave_data(const AUDIO_FORMAT* format, return CHANNEL_RC_OK; audio_format_print(audin->log, WLOG_TRACE, audin->format); - WLog_Print(audin->log, WLOG_TRACE, "[%"PRIdz"/%"PRIdz"]", size, + WLog_Print(audin->log, WLOG_TRACE, "[%" PRIdz "/%" PRIdz "]", size, Stream_GetPosition(audin->data) - 1); if ((error = audin_send_incoming_data_pdu(callback))) @@ -411,12 +412,7 @@ static BOOL audin_open_device(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callb if (!supported) { /* Default sample rates supported by most backends. */ - const UINT32 samplerates[] = { - 96000, - 48000, - 44100, - 22050 - }; + const UINT32 samplerates[] = { 96000, 48000, 44100, 22050 }; BOOL test = FALSE; format.wFormatTag = WAVE_FORMAT_PCM; @@ -425,7 +421,7 @@ static BOOL audin_open_device(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callb if (!test) { size_t x; - for (x=0; xdevice->FormatSupported, audin->device, &format); @@ -437,13 +433,11 @@ static BOOL audin_open_device(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callb return FALSE; } - IFCALLRET(audin->device->SetFormat, error, - audin->device, &format, - audin->FramesPerPacket); + IFCALLRET(audin->device->SetFormat, error, audin->device, &format, audin->FramesPerPacket); if (error != CHANNEL_RC_OK) { - WLog_ERR(TAG, "SetFormat failed with errorcode %"PRIu32"", error); + WLog_ERR(TAG, "SetFormat failed with errorcode %" PRIu32 "", error); return FALSE; } @@ -453,12 +447,11 @@ static BOOL audin_open_device(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callb return FALSE; } - IFCALLRET(audin->device->Open, error, audin->device, - audin_receive_wave_data, callback); + IFCALLRET(audin->device->Open, error, audin->device, audin_receive_wave_data, callback); if (error != CHANNEL_RC_OK) { - WLog_ERR(TAG, "Open failed with errorcode %"PRIu32"", error); + WLog_ERR(TAG, "Open failed with errorcode %" PRIu32 "", error); return FALSE; } @@ -480,13 +473,13 @@ static UINT audin_process_open(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* call Stream_Read_UINT32(s, FramesPerPacket); Stream_Read_UINT32(s, initialFormat); - WLog_Print(audin->log, WLOG_DEBUG, "FramesPerPacket=%"PRIu32" initialFormat=%"PRIu32"", + WLog_Print(audin->log, WLOG_DEBUG, "FramesPerPacket=%" PRIu32 " initialFormat=%" PRIu32 "", FramesPerPacket, initialFormat); audin->FramesPerPacket = FramesPerPacket; if (initialFormat >= callback->formats_count) { - WLog_Print(audin->log, WLOG_ERROR, "invalid format index %"PRIu32" (total %d)", + WLog_Print(audin->log, WLOG_ERROR, "invalid format index %" PRIu32 " (total %d)", initialFormat, callback->formats_count); return ERROR_INVALID_DATA; } @@ -523,12 +516,12 @@ static UINT audin_process_format_change(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLB return ERROR_INVALID_DATA; Stream_Read_UINT32(s, NewFormat); - WLog_Print(audin->log, WLOG_DEBUG, "NewFormat=%"PRIu32"", NewFormat); + WLog_Print(audin->log, WLOG_DEBUG, "NewFormat=%" PRIu32 "", NewFormat); if (NewFormat >= callback->formats_count) { - WLog_Print(audin->log, WLOG_ERROR, "invalid format index %"PRIu32" (total %d)", - NewFormat, callback->formats_count); + WLog_Print(audin->log, WLOG_ERROR, "invalid format index %" PRIu32 " (total %d)", NewFormat, + callback->formats_count); return ERROR_INVALID_DATA; } @@ -540,7 +533,7 @@ static UINT audin_process_format_change(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLB if (error != CHANNEL_RC_OK) { - WLog_ERR(TAG, "Close failed with errorcode %"PRIu32"", error); + WLog_ERR(TAG, "Close failed with errorcode %" PRIu32 "", error); return error; } } @@ -564,12 +557,12 @@ static UINT audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, UINT error; BYTE MessageId; AUDIN_PLUGIN* audin; - AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback; + AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*)pChannelCallback; if (!callback || !data) return ERROR_INVALID_PARAMETER; - audin = (AUDIN_PLUGIN*) callback->plugin; + audin = (AUDIN_PLUGIN*)callback->plugin; if (!audin) return ERROR_INTERNAL_ERROR; @@ -578,7 +571,7 @@ static UINT audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, return ERROR_NO_DATA; Stream_Read_UINT8(data, MessageId); - WLog_Print(audin->log, WLOG_DEBUG, "MessageId=0x%02"PRIx8"", MessageId); + WLog_Print(audin->log, WLOG_DEBUG, "MessageId=0x%02" PRIx8 "", MessageId); switch (MessageId) { @@ -599,7 +592,7 @@ static UINT audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, break; default: - WLog_Print(audin->log, WLOG_ERROR, "unknown MessageId=0x%02"PRIx8"", MessageId); + WLog_Print(audin->log, WLOG_ERROR, "unknown MessageId=0x%02" PRIx8 "", MessageId); error = ERROR_INVALID_DATA; break; } @@ -614,8 +607,8 @@ static UINT audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, */ static UINT audin_on_close(IWTSVirtualChannelCallback* pChannelCallback) { - AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback; - AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) callback->plugin; + AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*)pChannelCallback; + AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*)callback->plugin; UINT error = CHANNEL_RC_OK; WLog_Print(audin->log, WLOG_TRACE, "..."); @@ -624,7 +617,7 @@ static UINT audin_on_close(IWTSVirtualChannelCallback* pChannelCallback) IFCALLRET(audin->device->Close, error, audin->device); if (error != CHANNEL_RC_OK) - WLog_Print(audin->log, WLOG_ERROR, "Close failed with errorcode %"PRIu32"", error); + WLog_Print(audin->log, WLOG_ERROR, "Close failed with errorcode %" PRIu32 "", error); } audin->format = NULL; @@ -639,19 +632,19 @@ static UINT audin_on_close(IWTSVirtualChannelCallback* pChannelCallback) * @return 0 on success, otherwise a Win32 error code */ static UINT audin_on_new_channel_connection(IWTSListenerCallback* pListenerCallback, - IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept, - IWTSVirtualChannelCallback** ppCallback) + IWTSVirtualChannel* pChannel, BYTE* Data, + BOOL* pbAccept, IWTSVirtualChannelCallback** ppCallback) { AUDIN_CHANNEL_CALLBACK* callback; AUDIN_PLUGIN* audin; - AUDIN_LISTENER_CALLBACK* listener_callback = (AUDIN_LISTENER_CALLBACK*) pListenerCallback; + AUDIN_LISTENER_CALLBACK* listener_callback = (AUDIN_LISTENER_CALLBACK*)pListenerCallback; if (!listener_callback || !listener_callback->plugin) return ERROR_INTERNAL_ERROR; - audin = (AUDIN_PLUGIN*) listener_callback->plugin; + audin = (AUDIN_PLUGIN*)listener_callback->plugin; WLog_Print(audin->log, WLOG_TRACE, "..."); - callback = (AUDIN_CHANNEL_CALLBACK*) calloc(1, sizeof(AUDIN_CHANNEL_CALLBACK)); + callback = (AUDIN_CHANNEL_CALLBACK*)calloc(1, sizeof(AUDIN_CHANNEL_CALLBACK)); if (!callback) { @@ -664,7 +657,7 @@ static UINT audin_on_new_channel_connection(IWTSListenerCallback* pListenerCallb callback->plugin = listener_callback->plugin; callback->channel_mgr = listener_callback->channel_mgr; callback->channel = pChannel; - *ppCallback = (IWTSVirtualChannelCallback*) callback; + *ppCallback = (IWTSVirtualChannelCallback*)callback; return CHANNEL_RC_OK; } @@ -675,7 +668,7 @@ static UINT audin_on_new_channel_connection(IWTSListenerCallback* pListenerCallb */ static UINT audin_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr) { - AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin; + AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*)pPlugin; if (!audin) return CHANNEL_RC_BAD_CHANNEL_HANDLE; @@ -684,7 +677,7 @@ static UINT audin_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManag return ERROR_INVALID_PARAMETER; WLog_Print(audin->log, WLOG_TRACE, "..."); - audin->listener_callback = (AUDIN_LISTENER_CALLBACK*) calloc(1, sizeof(AUDIN_LISTENER_CALLBACK)); + audin->listener_callback = (AUDIN_LISTENER_CALLBACK*)calloc(1, sizeof(AUDIN_LISTENER_CALLBACK)); if (!audin->listener_callback) { @@ -696,7 +689,7 @@ static UINT audin_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManag audin->listener_callback->plugin = pPlugin; audin->listener_callback->channel_mgr = pChannelMgr; return pChannelMgr->CreateListener(pChannelMgr, "AUDIO_INPUT", 0, - (IWTSListenerCallback*) audin->listener_callback, NULL); + &audin->listener_callback->iface, &audin->listener); } /** @@ -706,14 +699,21 @@ static UINT audin_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManag */ static UINT audin_plugin_terminated(IWTSPlugin* pPlugin) { - AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin; + AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*)pPlugin; UINT error = CHANNEL_RC_OK; if (!audin) return CHANNEL_RC_BAD_CHANNEL_HANDLE; WLog_Print(audin->log, WLOG_TRACE, "..."); - audio_format_free(audin->fixed_format); + + if (audin->listener_callback) + { + IWTSVirtualChannelManager* mgr = audin->listener_callback->channel_mgr; + if (mgr) + IFCALL(mgr->DestroyListener, mgr, audin->listener); + } + audio_formats_free(audin->fixed_format, 1); if (audin->device) { @@ -721,7 +721,7 @@ static UINT audin_plugin_terminated(IWTSPlugin* pPlugin) if (error != CHANNEL_RC_OK) { - WLog_Print(audin->log, WLOG_ERROR, "Free failed with errorcode %"PRIu32"", error); + WLog_Print(audin->log, WLOG_ERROR, "Free failed with errorcode %" PRIu32 "", error); // dont stop on error } @@ -739,7 +739,7 @@ static UINT audin_plugin_terminated(IWTSPlugin* pPlugin) static UINT audin_plugin_attached(IWTSPlugin* pPlugin) { - AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin; + AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*)pPlugin; UINT error = CHANNEL_RC_OK; if (!audin) @@ -751,7 +751,7 @@ static UINT audin_plugin_attached(IWTSPlugin* pPlugin) static UINT audin_plugin_detached(IWTSPlugin* pPlugin) { - AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin; + AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*)pPlugin; UINT error = CHANNEL_RC_OK; if (!audin) @@ -768,7 +768,7 @@ static UINT audin_plugin_detached(IWTSPlugin* pPlugin) */ static UINT audin_register_device_plugin(IWTSPlugin* pPlugin, IAudinDevice* device) { - AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin; + AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*)pPlugin; if (audin->device) { @@ -791,8 +791,8 @@ static UINT audin_load_device_plugin(AUDIN_PLUGIN* audin, char* name, ADDIN_ARGV PFREERDP_AUDIN_DEVICE_ENTRY entry; FREERDP_AUDIN_DEVICE_ENTRY_POINTS entryPoints; UINT error; - entry = (PFREERDP_AUDIN_DEVICE_ENTRY) freerdp_load_channel_addin_entry("audin", (LPSTR) name, NULL, - 0); + entry = (PFREERDP_AUDIN_DEVICE_ENTRY)freerdp_load_channel_addin_entry("audin", (LPSTR)name, + NULL, 0); if (entry == NULL) { @@ -802,14 +802,14 @@ static UINT audin_load_device_plugin(AUDIN_PLUGIN* audin, char* name, ADDIN_ARGV return ERROR_INVALID_FUNCTION; } - entryPoints.plugin = (IWTSPlugin*) audin; + entryPoints.plugin = (IWTSPlugin*)audin; entryPoints.pRegisterAudinDevice = audin_register_device_plugin; entryPoints.args = args; entryPoints.rdpcontext = audin->rdpcontext; if ((error = entry(&entryPoints))) { - WLog_Print(audin->log, WLOG_ERROR, "%s entry returned error %"PRIu32".", name, error); + WLog_Print(audin->log, WLOG_ERROR, "%s entry returned error %" PRIu32 ".", name, error); return error; } @@ -855,29 +855,28 @@ static UINT audin_set_device_name(AUDIN_PLUGIN* audin, const char* device_name) return CHANNEL_RC_OK; } -static COMMAND_LINE_ARGUMENT_A audin_args[] = -{ - { "sys", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "subsystem" }, - { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "device" }, - { "format", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "format" }, - { "rate", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "rate" }, - { "channel", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "channel" }, - { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } -}; - BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args) { int status; DWORD flags; COMMAND_LINE_ARGUMENT_A* arg; UINT error; + COMMAND_LINE_ARGUMENT_A audin_args[] = { + { "sys", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "subsystem" }, + { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "device" }, + { "format", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "format" }, + { "rate", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "rate" }, + { "channel", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "channel" }, + { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } + }; if (!args || args->argc == 1) return TRUE; - flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; - status = CommandLineParseArgumentsA(args->argc, args->argv, - audin_args, flags, audin, NULL, NULL); + flags = + COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; + status = + CommandLineParseArgumentsA(args->argc, args->argv, audin_args, flags, audin, NULL, NULL); if (status != 0) return FALSE; @@ -890,12 +889,12 @@ BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args) if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) continue; - CommandLineSwitchStart(arg) - CommandLineSwitchCase(arg, "sys") + CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "sys") { if ((error = audin_set_subsystem(audin, arg->Value))) { - WLog_Print(audin->log, WLOG_ERROR, "audin_set_subsystem failed with error %"PRIu32"!", error); + WLog_Print(audin->log, WLOG_ERROR, + "audin_set_subsystem failed with error %" PRIu32 "!", error); return FALSE; } } @@ -903,7 +902,8 @@ BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args) { if ((error = audin_set_device_name(audin, arg->Value))) { - WLog_Print(audin->log, WLOG_ERROR, "audin_set_device_name failed with error %"PRIu32"!", error); + WLog_Print(audin->log, WLOG_ERROR, + "audin_set_device_name failed with error %" PRIu32 "!", error); return FALSE; } } @@ -936,16 +936,15 @@ BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args) { } CommandLineSwitchEnd(arg) - } - while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); return TRUE; } #ifdef BUILTIN_CHANNELS -#define DVCPluginEntry audin_DVCPluginEntry +#define DVCPluginEntry audin_DVCPluginEntry #else -#define DVCPluginEntry FREERDP_API DVCPluginEntry +#define DVCPluginEntry FREERDP_API DVCPluginEntry #endif /** @@ -966,34 +965,34 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) struct SubsystemEntry entries[] = { #if defined(WITH_PULSE) - {"pulse", ""}, + { "pulse", "" }, #endif #if defined(WITH_OSS) - {"oss", "default"}, + { "oss", "default" }, #endif #if defined(WITH_ALSA) - {"alsa", "default"}, + { "alsa", "default" }, #endif #if defined(WITH_OPENSLES) - {"opensles", "default"}, + { "opensles", "default" }, #endif #if defined(WITH_WINMM) - {"winmm", "default"}, + { "winmm", "default" }, #endif #if defined(WITH_MACAUDIO) - {"mac", "default"}, + { "mac", "default" }, #endif - {NULL, NULL} + { NULL, NULL } }; struct SubsystemEntry* entry = &entries[0]; assert(pEntryPoints); assert(pEntryPoints->GetPlugin); - audin = (AUDIN_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "audin"); + audin = (AUDIN_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "audin"); if (audin != NULL) return CHANNEL_RC_ALREADY_INITIALIZED; - audin = (AUDIN_PLUGIN*) calloc(1, sizeof(AUDIN_PLUGIN)); + audin = (AUDIN_PLUGIN*)calloc(1, sizeof(AUDIN_PLUGIN)); if (!audin) { @@ -1024,8 +1023,8 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) audin->iface.Attached = audin_plugin_attached; audin->iface.Detached = audin_plugin_detached; args = pEntryPoints->GetPluginData(pEntryPoints); - audin->rdpcontext = ((freerdp*)((rdpSettings*) pEntryPoints->GetRdpSettings( - pEntryPoints))->instance)->context; + audin->rdpcontext = + ((freerdp*)((rdpSettings*)pEntryPoints->GetRdpSettings(pEntryPoints))->instance)->context; if (args) { @@ -1037,8 +1036,10 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) { if ((error = audin_load_device_plugin(audin, audin->subsystem, args))) { - WLog_Print(audin->log, WLOG_ERROR, "audin_load_device_plugin %s failed with error %"PRIu32"!", - audin->subsystem, error); + WLog_Print( + audin->log, WLOG_ERROR, + "Unable to load microphone redirection subsystem %s because of error %" PRIu32 "", + audin->subsystem, error); goto out; } } @@ -1048,17 +1049,20 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) { if ((error = audin_set_subsystem(audin, entry->subsystem))) { - WLog_Print(audin->log, WLOG_ERROR, "audin_set_subsystem for %s failed with error %"PRIu32"!", + WLog_Print(audin->log, WLOG_ERROR, + "audin_set_subsystem for %s failed with error %" PRIu32 "!", entry->subsystem, error); } else if ((error = audin_set_device_name(audin, entry->device))) { - WLog_Print(audin->log, WLOG_ERROR, "audin_set_device_name for %s failed with error %"PRIu32"!", + WLog_Print(audin->log, WLOG_ERROR, + "audin_set_device_name for %s failed with error %" PRIu32 "!", entry->subsystem, error); } else if ((error = audin_load_device_plugin(audin, audin->subsystem, args))) { - WLog_Print(audin->log, WLOG_ERROR, "audin_load_device_plugin %s failed with error %"PRIu32"!", + WLog_Print(audin->log, WLOG_ERROR, + "audin_load_device_plugin %s failed with error %" PRIu32 "!", entry->subsystem, error); } @@ -1067,13 +1071,19 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) } if (audin->device == NULL) - WLog_Print(audin->log, WLOG_ERROR, "no sound device."); - - error = pEntryPoints->RegisterPlugin(pEntryPoints, "audin", (IWTSPlugin*) audin); -out: + { + /* If we have no audin device do not register plugin but still return OK or the client will + * just disconnect due to a missing microphone. */ + WLog_Print(audin->log, WLOG_ERROR, "No microphone device could be found."); + error = CHANNEL_RC_OK; + goto out; + } - if (error != CHANNEL_RC_OK) - audin_plugin_terminated((IWTSPlugin*)audin); + error = pEntryPoints->RegisterPlugin(pEntryPoints, "audin", (IWTSPlugin*)audin); + if (error == CHANNEL_RC_OK) + return error; +out: + audin_plugin_terminated((IWTSPlugin*)audin); return error; } diff --git a/channels/audin/client/audin_main.h b/channels/audin/client/audin_main.h index 83a75a4..760d3c8 100644 --- a/channels/audin/client/audin_main.h +++ b/channels/audin/client/audin_main.h @@ -33,4 +33,3 @@ #define TAG CHANNELS_TAG("audin.client") #endif /* FREERDP_CHANNEL_AUDIN_CLIENT_MAIN_H */ - diff --git a/channels/audin/client/mac/audin_mac.c b/channels/audin/client/mac/audin_mac.c index 40ba05d..e34b835 100644 --- a/channels/audin/client/mac/audin_mac.c +++ b/channels/audin/client/mac/audin_mac.c @@ -34,7 +34,11 @@ #include #define __COREFOUNDATION_CFPLUGINCOM__ 1 -#define IUNKNOWN_C_GUTS void *_reserved; void* QueryInterface; void* AddRef; void* Release +#define IUNKNOWN_C_GUTS \ + void* _reserved; \ + void* QueryInterface; \ + void* AddRef; \ + void* Release #include #include @@ -46,7 +50,7 @@ #include "audin_main.h" -#define MAC_AUDIO_QUEUE_NUM_BUFFERS 100 +#define MAC_AUDIO_QUEUE_NUM_BUFFERS 100 /* Fix for #4462: Provide type alias if not declared (Mac OS < 10.10) * https://developer.apple.com/documentation/coreaudio/audioformatid @@ -133,8 +137,8 @@ static UINT audin_mac_set_format(IAudinDevice* device, const AUDIO_FORMAT* forma mac->FramesPerPacket = FramesPerPacket; mac->format = *format; WLog_INFO(TAG, "Audio Format %s [channels=%d, samples=%d, bits=%d]", - audio_format_get_tag_string(format->wFormatTag), - format->nChannels, format->nSamplesPerSec, format->wBitsPerSample); + audio_format_get_tag_string(format->wFormatTag), format->nChannels, + format->nSamplesPerSec, format->wBitsPerSample); mac->audioFormat.mBitsPerChannel = format->wBitsPerSample; if (format->wBitsPerSample == 0) @@ -151,11 +155,8 @@ static UINT audin_mac_set_format(IAudinDevice* device, const AUDIO_FORMAT* forma return CHANNEL_RC_OK; } -static void mac_audio_queue_input_cb(void* aqData, - AudioQueueRef inAQ, - AudioQueueBufferRef inBuffer, - const AudioTimeStamp* inStartTime, - UInt32 inNumPackets, +static void mac_audio_queue_input_cb(void* aqData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer, + const AudioTimeStamp* inStartTime, UInt32 inNumPackets, const AudioStreamPacketDescription* inPacketDesc) { AudinMacDevice* mac = (AudinMacDevice*)aqData; @@ -174,7 +175,7 @@ static void mac_audio_queue_input_cb(void* aqData, if (error) { - WLog_ERR(TAG, "mac->receive failed with error %"PRIu32"", error); + WLog_ERR(TAG, "mac->receive failed with error %" PRIu32 "", error); SetLastError(ERROR_INTERNAL_ERROR); } } @@ -196,7 +197,7 @@ static UINT audin_mac_close(IAudinDevice* device) if (devStat != 0) { errCode = GetLastError(); - WLog_ERR(TAG, "AudioQueueStop failed with %s [%"PRIu32"]", + WLog_ERR(TAG, "AudioQueueStop failed with %s [%" PRIu32 "]", winpr_strerror(errCode, errString, sizeof(errString)), errCode); } @@ -210,7 +211,7 @@ static UINT audin_mac_close(IAudinDevice* device) if (devStat != 0) { errCode = GetLastError(); - WLog_ERR(TAG, "AudioQueueDispose failed with %s [%"PRIu32"]", + WLog_ERR(TAG, "AudioQueueDispose failed with %s [%" PRIu32 "]", winpr_strerror(errCode, errString, sizeof(errString)), errCode); } @@ -231,13 +232,13 @@ static UINT audin_mac_open(IAudinDevice* device, AudinReceive receive, void* use size_t index; mac->receive = receive; mac->user_data = user_data; - devStat = AudioQueueNewInput(&(mac->audioFormat), mac_audio_queue_input_cb, - mac, NULL, kCFRunLoopCommonModes, 0, &(mac->audioQueue)); + devStat = AudioQueueNewInput(&(mac->audioFormat), mac_audio_queue_input_cb, mac, NULL, + kCFRunLoopCommonModes, 0, &(mac->audioQueue)); if (devStat != 0) { errCode = GetLastError(); - WLog_ERR(TAG, "AudioQueueNewInput failed with %s [%"PRIu32"]", + WLog_ERR(TAG, "AudioQueueNewInput failed with %s [%" PRIu32 "]", winpr_strerror(errCode, errString, sizeof(errString)), errCode); goto err_out; } @@ -251,20 +252,17 @@ static UINT audin_mac_open(IAudinDevice* device, AudinReceive receive, void* use if (devStat != 0) { errCode = GetLastError(); - WLog_ERR(TAG, "AudioQueueAllocateBuffer failed with %s [%"PRIu32"]", + WLog_ERR(TAG, "AudioQueueAllocateBuffer failed with %s [%" PRIu32 "]", winpr_strerror(errCode, errString, sizeof(errString)), errCode); goto err_out; } - devStat = AudioQueueEnqueueBuffer(mac->audioQueue, - mac->audioBuffers[index], - 0, - NULL); + devStat = AudioQueueEnqueueBuffer(mac->audioQueue, mac->audioBuffers[index], 0, NULL); if (devStat != 0) { errCode = GetLastError(); - WLog_ERR(TAG, "AudioQueueEnqueueBuffer failed with %s [%"PRIu32"]", + WLog_ERR(TAG, "AudioQueueEnqueueBuffer failed with %s [%" PRIu32 "]", winpr_strerror(errCode, errString, sizeof(errString)), errCode); goto err_out; } @@ -275,7 +273,7 @@ static UINT audin_mac_open(IAudinDevice* device, AudinReceive receive, void* use if (devStat != 0) { errCode = GetLastError(); - WLog_ERR(TAG, "AudioQueueStart failed with %s [%"PRIu32"]", + WLog_ERR(TAG, "AudioQueueStart failed with %s [%" PRIu32 "]", winpr_strerror(errCode, errString, sizeof(errString)), errCode); goto err_out; } @@ -304,28 +302,27 @@ static UINT audin_mac_free(IAudinDevice* device) return CHANNEL_RC_OK; } -static COMMAND_LINE_ARGUMENT_A audin_mac_args[] = -{ - { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "audio device name" }, - { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } -}; - static UINT audin_mac_parse_addin_args(AudinMacDevice* device, ADDIN_ARGV* args) { DWORD errCode; char errString[1024]; int status; - char* str_num, *eptr; + char *str_num, *eptr; DWORD flags; COMMAND_LINE_ARGUMENT_A* arg; + COMMAND_LINE_ARGUMENT_A audin_mac_args[] = { { "dev", COMMAND_LINE_VALUE_REQUIRED, "", + NULL, NULL, -1, NULL, "audio device name" }, + { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } }; + AudinMacDevice* mac = (AudinMacDevice*)device; if (args->argc == 1) return CHANNEL_RC_OK; - flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; - status = CommandLineParseArgumentsA(args->argc, args->argv, audin_mac_args, flags, - mac, NULL, NULL); + flags = + COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; + status = + CommandLineParseArgumentsA(args->argc, args->argv, audin_mac_args, flags, mac, NULL, NULL); if (status < 0) return ERROR_INVALID_PARAMETER; @@ -337,8 +334,7 @@ static UINT audin_mac_parse_addin_args(AudinMacDevice* device, ADDIN_ARGV* args) if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) continue; - CommandLineSwitchStart(arg) - CommandLineSwitchCase(arg, "dev") + CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "dev") { str_num = _strdup(arg->Value); @@ -358,16 +354,15 @@ static UINT audin_mac_parse_addin_args(AudinMacDevice* device, ADDIN_ARGV* args) free(str_num); } CommandLineSwitchEnd(arg) - } - while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); return CHANNEL_RC_OK; } #ifdef BUILTIN_CHANNELS -#define freerdp_audin_client_subsystem_entry mac_freerdp_audin_client_subsystem_entry +#define freerdp_audin_client_subsystem_entry mac_freerdp_audin_client_subsystem_entry #else -#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry +#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry #endif UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints) @@ -382,7 +377,7 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn if (!mac) { errCode = GetLastError(); - WLog_ERR(TAG, "calloc failed with %s [%"PRIu32"]", + WLog_ERR(TAG, "calloc failed with %s [%" PRIu32 "]", winpr_strerror(errCode, errString, sizeof(errString)), errCode); return CHANNEL_RC_NO_MEMORY; } @@ -398,13 +393,13 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn if ((error = audin_mac_parse_addin_args(mac, args))) { - WLog_ERR(TAG, "audin_mac_parse_addin_args failed with %"PRIu32"!", error); + WLog_ERR(TAG, "audin_mac_parse_addin_args failed with %" PRIu32 "!", error); goto error_out; } - if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) mac))) + if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*)mac))) { - WLog_ERR(TAG, "RegisterAudinDevice failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "RegisterAudinDevice failed with error %" PRIu32 "!", error); goto error_out; } diff --git a/channels/audin/client/opensles/audin_opensl_es.c b/channels/audin/client/opensles/audin_opensl_es.c index 549edd0..4e3efde 100644 --- a/channels/audin/client/opensles/audin_opensl_es.c +++ b/channels/audin/client/opensles/audin_opensl_es.c @@ -65,7 +65,7 @@ static UINT audin_opensles_close(IAudinDevice* device); static void audin_receive(void* context, const void* data, size_t size) { UINT error; - AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) context; + AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*)context; if (!opensles || !data) { @@ -86,39 +86,32 @@ static void audin_receive(void* context, const void* data, size_t size) */ static UINT audin_opensles_free(IAudinDevice* device) { - AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device; + AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*)device; if (!opensles) return ERROR_INVALID_PARAMETER; - 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; + WLog_Print(opensles->log, WLOG_DEBUG, "device=%p", (void*)device); free(opensles->device_name); free(opensles); return CHANNEL_RC_OK; } -static BOOL audin_opensles_format_supported(IAudinDevice* device, - const AUDIO_FORMAT* format) +static BOOL audin_opensles_format_supported(IAudinDevice* device, const AUDIO_FORMAT* format) { - AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device; + AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*)device; if (!opensles || !format) return FALSE; - WLog_Print(opensles->log, WLOG_DEBUG, "device=%p, format=%p", (void*) opensles, (void*) format); + WLog_Print(opensles->log, WLOG_DEBUG, "device=%p, format=%p", (void*)opensles, (void*)format); assert(format); switch (format->wFormatTag) { case WAVE_FORMAT_PCM: /* PCM */ - if (format->cbSize == 0 && - (format->nSamplesPerSec <= 48000) && + if (format->cbSize == 0 && (format->nSamplesPerSec <= 48000) && (format->wBitsPerSample == 8 || format->wBitsPerSample == 16) && (format->nChannels >= 1 && format->nChannels <= 2)) { @@ -128,9 +121,8 @@ static BOOL audin_opensles_format_supported(IAudinDevice* device, break; default: - WLog_Print(opensles->log, WLOG_DEBUG, "Encoding '%s' [0x%04X"PRIX16"] not supported", - audio_format_get_tag_string(format->wFormatTag), - format->wFormatTag); + WLog_Print(opensles->log, WLOG_DEBUG, "Encoding '%s' [0x%04X" PRIX16 "] not supported", + audio_format_get_tag_string(format->wFormatTag), format->wFormatTag); break; } @@ -142,23 +134,18 @@ static BOOL audin_opensles_format_supported(IAudinDevice* device, * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_opensles_set_format(IAudinDevice* device, - const AUDIO_FORMAT* format, UINT32 FramesPerPacket) +static UINT audin_opensles_set_format(IAudinDevice* device, const AUDIO_FORMAT* format, + UINT32 FramesPerPacket) { - AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device; + AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*)device; if (!opensles || !format) return ERROR_INVALID_PARAMETER; - WLog_Print(opensles->log, WLOG_DEBUG, "device=%p, format=%p, FramesPerPacket=%"PRIu32"", - (void*) device, (void*) format, FramesPerPacket); + WLog_Print(opensles->log, WLOG_DEBUG, "device=%p, format=%p, FramesPerPacket=%" PRIu32 "", + (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) @@ -187,13 +174,13 @@ static UINT audin_opensles_set_format(IAudinDevice* device, break; default: - WLog_Print(opensles->log, WLOG_ERROR, "Encoding '%"PRIu16"' [%04"PRIX16"] not supported", - format->wFormatTag, + WLog_Print(opensles->log, WLOG_ERROR, + "Encoding '%" PRIu16 "' [%04" PRIX16 "] not supported", format->wFormatTag, format->wFormatTag); return ERROR_UNSUPPORTED_TYPE; } - WLog_Print(opensles->log, WLOG_DEBUG, "frames_per_packet=%"PRIu32, + WLog_Print(opensles->log, WLOG_DEBUG, "frames_per_packet=%" PRIu32, opensles->frames_per_packet); return CHANNEL_RC_OK; } @@ -203,27 +190,22 @@ static UINT audin_opensles_set_format(IAudinDevice* device, * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_opensles_open(IAudinDevice* device, AudinReceive receive, - void* user_data) +static UINT audin_opensles_open(IAudinDevice* device, AudinReceive receive, void* user_data) { - AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device; + AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*)device; if (!opensles || !receive || !user_data) return ERROR_INVALID_PARAMETER; - WLog_Print(opensles->log, WLOG_DEBUG, "device=%p, receive=%p, user_data=%p", (void*) device, - (void*) receive, - (void*) user_data); + WLog_Print(opensles->log, WLOG_DEBUG, "device=%p, receive=%p, user_data=%p", (void*)device, + (void*)receive, (void*)user_data); if (opensles->stream) goto error_out; if (!(opensles->stream = android_OpenRecDevice( - opensles, audin_receive, - opensles->format.nSamplesPerSec, - opensles->format.nChannels, - opensles->frames_per_packet, - opensles->format.wBitsPerSample))) + opensles, audin_receive, opensles->format.nSamplesPerSec, opensles->format.nChannels, + opensles->frames_per_packet, opensles->format.wBitsPerSample))) { WLog_Print(opensles->log, WLOG_ERROR, "android_OpenRecDevice failed!"); goto error_out; @@ -244,12 +226,12 @@ error_out: */ UINT audin_opensles_close(IAudinDevice* device) { - AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device; + AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*)device; if (!opensles) return ERROR_INVALID_PARAMETER; - WLog_Print(opensles->log, WLOG_DEBUG, "device=%p", (void*) device); + WLog_Print(opensles->log, WLOG_DEBUG, "device=%p", (void*)device); android_CloseRecDevice(opensles->stream); opensles->receive = NULL; opensles->user_data = NULL; @@ -257,31 +239,28 @@ UINT audin_opensles_close(IAudinDevice* device) return CHANNEL_RC_OK; } -static COMMAND_LINE_ARGUMENT_A audin_opensles_args[] = -{ - { - "dev", COMMAND_LINE_VALUE_REQUIRED, "", - NULL, NULL, -1, NULL, "audio device name" - }, - { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } -}; - /** * Function description * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_opensles_parse_addin_args(AudinOpenSLESDevice* device, - ADDIN_ARGV* args) +static UINT audin_opensles_parse_addin_args(AudinOpenSLESDevice* device, ADDIN_ARGV* args) { UINT status; DWORD flags; COMMAND_LINE_ARGUMENT_A* arg; - AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device; - WLog_Print(opensles->log, WLOG_DEBUG, "device=%p, args=%p", (void*) device, (void*) args); - flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; - status = CommandLineParseArgumentsA(args->argc, args->argv, - audin_opensles_args, flags, opensles, NULL, NULL); + AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*)device; + COMMAND_LINE_ARGUMENT_A audin_opensles_args[] = { + { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, + "audio device name" }, + { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } + }; + + WLog_Print(opensles->log, WLOG_DEBUG, "device=%p, args=%p", (void*)device, (void*)args); + flags = + COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; + status = CommandLineParseArgumentsA(args->argc, args->argv, audin_opensles_args, flags, + opensles, NULL, NULL); if (status < 0) return status; @@ -293,8 +272,7 @@ static UINT audin_opensles_parse_addin_args(AudinOpenSLESDevice* device, if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) continue; - CommandLineSwitchStart(arg) - CommandLineSwitchCase(arg, "dev") + CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "dev") { opensles->device_name = _strdup(arg->Value); @@ -305,18 +283,15 @@ static UINT audin_opensles_parse_addin_args(AudinOpenSLESDevice* device, } } CommandLineSwitchEnd(arg) - } - while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); return CHANNEL_RC_OK; } #ifdef BUILTIN_CHANNELS -#define freerdp_audin_client_subsystem_entry \ - opensles_freerdp_audin_client_subsystem_entry +#define freerdp_audin_client_subsystem_entry opensles_freerdp_audin_client_subsystem_entry #else -#define freerdp_audin_client_subsystem_entry \ - FREERDP_API freerdp_audin_client_subsystem_entry +#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry #endif /** @@ -324,13 +299,12 @@ static UINT audin_opensles_parse_addin_args(AudinOpenSLESDevice* device, * * @return 0 on success, otherwise a Win32 error code */ -UINT freerdp_audin_client_subsystem_entry( - PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints) +UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints) { ADDIN_ARGV* args; AudinOpenSLESDevice* opensles; UINT error; - opensles = (AudinOpenSLESDevice*) calloc(1, sizeof(AudinOpenSLESDevice)); + opensles = (AudinOpenSLESDevice*)calloc(1, sizeof(AudinOpenSLESDevice)); if (!opensles) { @@ -350,13 +324,14 @@ UINT freerdp_audin_client_subsystem_entry( if ((error = audin_opensles_parse_addin_args(opensles, args))) { WLog_Print(opensles->log, WLOG_ERROR, - "audin_opensles_parse_addin_args failed with errorcode %"PRIu32"!", error); + "audin_opensles_parse_addin_args failed with errorcode %" PRIu32 "!", error); goto error_out; } - if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) opensles))) + if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*)opensles))) { - WLog_Print(opensles->log, WLOG_ERROR, "RegisterAudinDevice failed with error %"PRIu32"!", error); + WLog_Print(opensles->log, WLOG_ERROR, "RegisterAudinDevice failed with error %" PRIu32 "!", + error); goto error_out; } diff --git a/channels/audin/client/opensles/opensl_io.c b/channels/audin/client/opensles/opensl_io.c index 5e7fba6..be3e0b4 100644 --- a/channels/audin/client/opensles/opensl_io.c +++ b/channels/audin/client/opensles/opensl_io.c @@ -6,14 +6,14 @@ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * 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. + * Neither the name of the nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -32,7 +32,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "audin_main.h" #include "opensl_io.h" #define CONV16BIT 32768 -#define CONVMYFLT (1./32768.) +#define CONVMYFLT (1. / 32768.) typedef struct { @@ -66,7 +66,6 @@ struct opensl_stream opensl_receive_t receive; }; - static void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void* context); // creates the OpenSL ES audio engine @@ -76,22 +75,24 @@ static SLresult openSLCreateEngine(OPENSL_STREAM* p) // create engine result = slCreateEngine(&(p->engineObject), 0, NULL, 0, NULL, NULL); - if (result != SL_RESULT_SUCCESS) goto engine_end; + if (result != SL_RESULT_SUCCESS) + goto engine_end; // realize the engine result = (*p->engineObject)->Realize(p->engineObject, SL_BOOLEAN_FALSE); - if (result != SL_RESULT_SUCCESS) goto engine_end; + if (result != SL_RESULT_SUCCESS) + goto engine_end; // get the engine interface, which is needed in order to create other objects - result = (*p->engineObject)->GetInterface(p->engineObject, SL_IID_ENGINE, - &(p->engineEngine)); + result = (*p->engineObject)->GetInterface(p->engineObject, SL_IID_ENGINE, &(p->engineEngine)); - if (result != SL_RESULT_SUCCESS) goto engine_end; + if (result != SL_RESULT_SUCCESS) + goto engine_end; // get the volume interface - important, this is optional! - result = (*p->engineObject)->GetInterface(p->engineObject, SL_IID_DEVICEVOLUME, - &(p->deviceVolume)); + result = + (*p->engineObject)->GetInterface(p->engineObject, SL_IID_DEVICEVOLUME, &(p->deviceVolume)); if (result != SL_RESULT_SUCCESS) { @@ -169,10 +170,9 @@ static SLresult openSLRecOpen(OPENSL_STREAM* p) } // configure audio source - SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, - SL_DEFAULTDEVICEID_AUDIOINPUT, NULL - }; - SLDataSource audioSrc = {&loc_dev, NULL}; + SLDataLocator_IODevice loc_dev = { SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, + SL_DEFAULTDEVICEID_AUDIOINPUT, NULL }; + SLDataSource audioSrc = { &loc_dev, NULL }; // configure audio sink int speakers; @@ -181,7 +181,8 @@ static SLresult openSLRecOpen(OPENSL_STREAM* p) else speakers = SL_SPEAKER_FRONT_CENTER; - SLDataLocator_AndroidSimpleBufferQueue loc_bq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2}; + SLDataLocator_AndroidSimpleBufferQueue loc_bq = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, + 2 }; SLDataFormat_PCM format_pcm; format_pcm.formatType = SL_DATAFORMAT_PCM; format_pcm.numChannels = channels; @@ -202,41 +203,46 @@ static SLresult openSLRecOpen(OPENSL_STREAM* p) else assert(0); - SLDataSink audioSnk = {&loc_bq, &format_pcm}; + SLDataSink audioSnk = { &loc_bq, &format_pcm }; // create audio recorder // (requires the RECORD_AUDIO permission) - const SLInterfaceID id[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE}; - const SLboolean req[] = {SL_BOOLEAN_TRUE}; - result = (*p->engineEngine)->CreateAudioRecorder(p->engineEngine, - &(p->recorderObject), &audioSrc, &audioSnk, 1, id, req); + const SLInterfaceID id[] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE }; + const SLboolean req[] = { SL_BOOLEAN_TRUE }; + result = (*p->engineEngine) + ->CreateAudioRecorder(p->engineEngine, &(p->recorderObject), &audioSrc, + &audioSnk, 1, id, req); assert(!result); - if (SL_RESULT_SUCCESS != result) goto end_recopen; + if (SL_RESULT_SUCCESS != result) + goto end_recopen; // realize the audio recorder result = (*p->recorderObject)->Realize(p->recorderObject, SL_BOOLEAN_FALSE); assert(!result); - if (SL_RESULT_SUCCESS != result) goto end_recopen; + if (SL_RESULT_SUCCESS != result) + goto end_recopen; // get the record interface - result = (*p->recorderObject)->GetInterface(p->recorderObject, - SL_IID_RECORD, &(p->recorderRecord)); + result = (*p->recorderObject) + ->GetInterface(p->recorderObject, SL_IID_RECORD, &(p->recorderRecord)); assert(!result); - if (SL_RESULT_SUCCESS != result) goto end_recopen; + if (SL_RESULT_SUCCESS != result) + goto end_recopen; // get the buffer queue interface - result = (*p->recorderObject)->GetInterface(p->recorderObject, - SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - &(p->recorderBufferQueue)); + result = (*p->recorderObject) + ->GetInterface(p->recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, + &(p->recorderBufferQueue)); assert(!result); - if (SL_RESULT_SUCCESS != result) goto end_recopen; + if (SL_RESULT_SUCCESS != result) + goto end_recopen; // register callback on the buffer queue - result = (*p->recorderBufferQueue)->RegisterCallback(p->recorderBufferQueue, - bqRecorderCallback, p); + result = (*p->recorderBufferQueue) + ->RegisterCallback(p->recorderBufferQueue, bqRecorderCallback, p); assert(!result); if (SL_RESULT_SUCCESS != result) @@ -245,7 +251,8 @@ static SLresult openSLRecOpen(OPENSL_STREAM* p) end_recopen: return result; } - else return SL_RESULT_SUCCESS; + else + return SL_RESULT_SUCCESS; } // close the OpenSL IO and destroy the audio engine @@ -299,17 +306,15 @@ static void opensles_queue_element_free(void* obj) } // open the android audio device for input -OPENSL_STREAM* android_OpenRecDevice(void* context, opensl_receive_t receive, - int sr, - int inchannels, - int bufferframes, int bits_per_sample) +OPENSL_STREAM* android_OpenRecDevice(void* context, opensl_receive_t receive, int sr, + int inchannels, int bufferframes, int bits_per_sample) { OPENSL_STREAM* p; if (!context || !receive) return NULL; - p = (OPENSL_STREAM*) calloc(1, sizeof(OPENSL_STREAM)); + p = (OPENSL_STREAM*)calloc(1, sizeof(OPENSL_STREAM)); if (!p) return NULL; @@ -337,12 +342,9 @@ OPENSL_STREAM* android_OpenRecDevice(void* context, opensl_receive_t receive, if (!p->prep || !p->next) goto fail; - (*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue, - p->next->data, p->next->size); - (*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue, - p->prep->data, p->prep->size); - (*p->recorderRecord)->SetRecordState(p->recorderRecord, - SL_RECORDSTATE_RECORDING); + (*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue, p->next->data, p->next->size); + (*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue, p->prep->data, p->prep->size); + (*p->recorderRecord)->SetRecordState(p->recorderRecord, SL_RECORDSTATE_RECORDING); return p; fail: android_CloseRecDevice(p); @@ -364,7 +366,7 @@ void android_CloseRecDevice(OPENSL_STREAM* p) // this callback handler is called every time a buffer finishes recording static void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void* context) { - OPENSL_STREAM* p = (OPENSL_STREAM*) context; + OPENSL_STREAM* p = (OPENSL_STREAM*)context; queue_element* e; if (!p) @@ -382,7 +384,5 @@ static void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void* context) p->next = p->prep; p->prep = e; - (*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue, - e->data, e->size); + (*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue, e->data, e->size); } - diff --git a/channels/audin/client/opensles/opensl_io.h b/channels/audin/client/opensles/opensl_io.h index 6a54b7c..e99522c 100644 --- a/channels/audin/client/opensles/opensl_io.h +++ b/channels/audin/client/opensles/opensl_io.h @@ -6,14 +6,14 @@ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * 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. + * Neither the name of the nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -38,25 +38,25 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -typedef struct opensl_stream OPENSL_STREAM; + typedef struct opensl_stream OPENSL_STREAM; -typedef void (*opensl_receive_t)(void* context, const void* data, size_t size); + typedef void (*opensl_receive_t)(void* context, const void* data, size_t size); -/* -Open the audio device with a given sampling rate (sr), input and output channels and IO buffer size -in frames. Returns a handle to the OpenSL stream -*/ -FREERDP_LOCAL OPENSL_STREAM* android_OpenRecDevice(void* context, - opensl_receive_t receive, int sr, - int inchannels, - int bufferframes, int bits_per_sample); -/* -Close the audio device -*/ -FREERDP_LOCAL void android_CloseRecDevice(OPENSL_STREAM* p); + /* + Open the audio device with a given sampling rate (sr), input and output channels and IO buffer + size in frames. Returns a handle to the OpenSL stream + */ + FREERDP_LOCAL OPENSL_STREAM* android_OpenRecDevice(void* context, opensl_receive_t receive, + int sr, int inchannels, int bufferframes, + int bits_per_sample); + /* + Close the audio device + */ + FREERDP_LOCAL void android_CloseRecDevice(OPENSL_STREAM* p); #ifdef __cplusplus }; diff --git a/channels/audin/client/oss/audin_oss.c b/channels/audin/client/oss/audin_oss.c index e1d73b2..97eb349 100644 --- a/channels/audin/client/oss/audin_oss.c +++ b/channels/audin/client/oss/audin_oss.c @@ -69,11 +69,10 @@ typedef struct _AudinOSSDevice } AudinOSSDevice; #define OSS_LOG_ERR(_text, _error) \ - if (_error != 0) \ + if (_error != 0) \ WLog_ERR(TAG, "%s: %i - %s\n", _text, _error, strerror(_error)); - -static int audin_oss_get_format(const AUDIO_FORMAT* format) +static UINT32 audin_oss_get_format(const AUDIO_FORMAT* format) { switch (format->wFormatTag) { @@ -99,8 +98,7 @@ static int audin_oss_get_format(const AUDIO_FORMAT* format) return 0; } -static BOOL audin_oss_format_supported(IAudinDevice* device, - const AUDIO_FORMAT* format) +static BOOL audin_oss_format_supported(IAudinDevice* device, const AUDIO_FORMAT* format) { if (device == NULL || format == NULL) return FALSE; @@ -108,8 +106,7 @@ static BOOL audin_oss_format_supported(IAudinDevice* device, switch (format->wFormatTag) { case WAVE_FORMAT_PCM: - if (format->cbSize != 0 || - format->nSamplesPerSec > 48000 || + if (format->cbSize != 0 || format->nSamplesPerSec > 48000 || (format->wBitsPerSample != 8 && format->wBitsPerSample != 16) || (format->nChannels != 1 && format->nChannels != 2)) return FALSE; @@ -151,7 +148,7 @@ static DWORD WINAPI audin_oss_thread_func(LPVOID arg) char mixer_name[PATH_MAX] = "/dev/mixer"; int pcm_handle = -1, mixer_handle; BYTE* buffer = NULL; - int tmp; + unsigned long tmp; size_t buffer_size; AudinOSSDevice* oss = (AudinOSSDevice*)arg; UINT error = 0; @@ -233,8 +230,7 @@ static DWORD WINAPI audin_oss_thread_func(LPVOID arg) if (ioctl(pcm_handle, SNDCTL_DSP_SETFRAGMENT, &tmp) == -1) OSS_LOG_ERR("SNDCTL_DSP_SETFRAGMENT failed", errno); - buffer_size = (oss->FramesPerPacket * oss->format.nChannels * - (oss->format.wBitsPerSample / 8)); + buffer_size = (oss->FramesPerPacket * oss->format.nChannels * (oss->format.wBitsPerSample / 8)); buffer = (BYTE*)calloc((buffer_size + sizeof(void*)), sizeof(BYTE)); if (NULL == buffer) @@ -246,42 +242,42 @@ static DWORD WINAPI audin_oss_thread_func(LPVOID arg) while (1) { + SSIZE_T stmp; status = WaitForSingleObject(oss->stopEvent, 0); if (status == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error); goto err_out; } if (status == WAIT_OBJECT_0) break; - tmp = read(pcm_handle, buffer, buffer_size); + stmp = read(pcm_handle, buffer, buffer_size); /* Error happen. */ - if (tmp < 0) + if (stmp < 0) { OSS_LOG_ERR("read() error", errno); continue; } - if (tmp < buffer_size) /* Not enouth data. */ + if ((size_t)stmp < buffer_size) /* Not enouth data. */ continue; if ((error = oss->receive(&oss->format, buffer, buffer_size, oss->user_data))) { - WLog_ERR(TAG, "oss->receive failed with error %"PRIu32"", error); + WLog_ERR(TAG, "oss->receive failed with error %" PRIu32 "", error); break; } } err_out: - if (error && oss->rdpcontext) - setChannelError(oss->rdpcontext, error, - "audin_oss_thread_func reported an error"); + if (error && oss && oss->rdpcontext) + setChannelError(oss->rdpcontext, error, "audin_oss_thread_func reported an error"); if (pcm_handle != -1) { @@ -299,8 +295,7 @@ err_out: * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_oss_open(IAudinDevice* device, AudinReceive receive, - void* user_data) +static UINT audin_oss_open(IAudinDevice* device, AudinReceive receive, void* user_data) { AudinOSSDevice* oss = (AudinOSSDevice*)device; oss->receive = receive; @@ -343,7 +338,7 @@ static UINT audin_oss_close(IAudinDevice* device) if (WaitForSingleObject(oss->thread, INFINITE) == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error); return error; } @@ -366,7 +361,7 @@ static UINT audin_oss_close(IAudinDevice* device) static UINT audin_oss_free(IAudinDevice* device) { AudinOSSDevice* oss = (AudinOSSDevice*)device; - int error; + UINT error; if (device == NULL) return ERROR_INVALID_PARAMETER; @@ -380,12 +375,6 @@ static UINT audin_oss_free(IAudinDevice* device) return CHANNEL_RC_OK; } -static COMMAND_LINE_ARGUMENT_A audin_oss_args[] = -{ - { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "audio device name" }, - { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } -}; - /** * Function description * @@ -394,14 +383,18 @@ static COMMAND_LINE_ARGUMENT_A audin_oss_args[] = static UINT audin_oss_parse_addin_args(AudinOSSDevice* device, ADDIN_ARGV* args) { int status; - char* str_num, *eptr; + char *str_num, *eptr; DWORD flags; COMMAND_LINE_ARGUMENT_A* arg; AudinOSSDevice* oss = (AudinOSSDevice*)device; - flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | - COMMAND_LINE_IGN_UNKNOWN_KEYWORD; - status = CommandLineParseArgumentsA(args->argc, args->argv, - audin_oss_args, flags, oss, NULL, NULL); + COMMAND_LINE_ARGUMENT_A audin_oss_args[] = { { "dev", COMMAND_LINE_VALUE_REQUIRED, "", + NULL, NULL, -1, NULL, "audio device name" }, + { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } }; + + flags = + COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; + status = + CommandLineParseArgumentsA(args->argc, args->argv, audin_oss_args, flags, oss, NULL, NULL); if (status < 0) return ERROR_INVALID_PARAMETER; @@ -414,8 +407,7 @@ static UINT audin_oss_parse_addin_args(AudinOSSDevice* device, ADDIN_ARGV* args) if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) continue; - CommandLineSwitchStart(arg) - CommandLineSwitchCase(arg, "dev") + CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "dev") { str_num = _strdup(arg->Value); @@ -434,7 +426,7 @@ static UINT audin_oss_parse_addin_args(AudinOSSDevice* device, ADDIN_ARGV* args) return CHANNEL_RC_NULL_DATA; } - oss->dev_unit = val; + oss->dev_unit = (INT32)val; } if (oss->dev_unit < 0 || *eptr != '\0') @@ -443,16 +435,15 @@ static UINT audin_oss_parse_addin_args(AudinOSSDevice* device, ADDIN_ARGV* args) free(str_num); } CommandLineSwitchEnd(arg) - } - while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); return CHANNEL_RC_OK; } #ifdef BUILTIN_CHANNELS -#define freerdp_audin_client_subsystem_entry oss_freerdp_audin_client_subsystem_entry +#define freerdp_audin_client_subsystem_entry oss_freerdp_audin_client_subsystem_entry #else -#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry +#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry #endif /** @@ -460,8 +451,7 @@ static UINT audin_oss_parse_addin_args(AudinOSSDevice* device, ADDIN_ARGV* args) * * @return 0 on success, otherwise a Win32 error code */ -UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS - pEntryPoints) +UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints) { ADDIN_ARGV* args; AudinOSSDevice* oss; @@ -485,14 +475,13 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS if ((error = audin_oss_parse_addin_args(oss, args))) { - WLog_ERR(TAG, "audin_oss_parse_addin_args failed with errorcode %"PRIu32"!", error); + WLog_ERR(TAG, "audin_oss_parse_addin_args failed with errorcode %" PRIu32 "!", error); goto error_out; } - if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, - (IAudinDevice*) oss))) + if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*)oss))) { - WLog_ERR(TAG, "RegisterAudinDevice failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "RegisterAudinDevice failed with error %" PRIu32 "!", error); goto error_out; } diff --git a/channels/audin/client/pulse/audin_pulse.c b/channels/audin/client/pulse/audin_pulse.c index d22de87..8a5c3be 100644 --- a/channels/audin/client/pulse/audin_pulse.c +++ b/channels/audin/client/pulse/audin_pulse.c @@ -62,27 +62,67 @@ typedef struct _AudinPulseDevice wLog* log; } AudinPulseDevice; +static const char* pulse_context_state_string(pa_context_state_t state) +{ + switch (state) + { + case PA_CONTEXT_UNCONNECTED: + return "PA_CONTEXT_UNCONNECTED"; + case PA_CONTEXT_CONNECTING: + return "PA_CONTEXT_CONNECTING"; + case PA_CONTEXT_AUTHORIZING: + return "PA_CONTEXT_AUTHORIZING"; + case PA_CONTEXT_SETTING_NAME: + return "PA_CONTEXT_SETTING_NAME"; + case PA_CONTEXT_READY: + return "PA_CONTEXT_READY"; + case PA_CONTEXT_FAILED: + return "PA_CONTEXT_FAILED"; + case PA_CONTEXT_TERMINATED: + return "PA_CONTEXT_TERMINATED"; + default: + return "UNKNOWN"; + } +} + +static const char* pulse_stream_state_string(pa_stream_state_t state) +{ + switch (state) + { + case PA_STREAM_UNCONNECTED: + return "PA_STREAM_UNCONNECTED"; + case PA_STREAM_CREATING: + return "PA_STREAM_CREATING"; + case PA_STREAM_READY: + return "PA_STREAM_READY"; + case PA_STREAM_FAILED: + return "PA_STREAM_FAILED"; + case PA_STREAM_TERMINATED: + return "PA_STREAM_TERMINATED"; + default: + return "UNKNOWN"; + } +} + static void audin_pulse_context_state_callback(pa_context* context, void* userdata) { pa_context_state_t state; - AudinPulseDevice* pulse = (AudinPulseDevice*) userdata; + AudinPulseDevice* pulse = (AudinPulseDevice*)userdata; state = pa_context_get_state(context); + WLog_Print(pulse->log, WLOG_DEBUG, "context state %s", pulse_context_state_string(state)); switch (state) { case PA_CONTEXT_READY: - WLog_Print(pulse->log, WLOG_DEBUG, "PA_CONTEXT_READY"); pa_threaded_mainloop_signal(pulse->mainloop, 0); break; case PA_CONTEXT_FAILED: case PA_CONTEXT_TERMINATED: - WLog_Print(pulse->log, WLOG_DEBUG, "state %d", state); pa_threaded_mainloop_signal(pulse->mainloop, 0); break; default: - WLog_Print(pulse->log, WLOG_DEBUG, "state %d", state); break; } } @@ -95,7 +135,7 @@ static void audin_pulse_context_state_callback(pa_context* context, void* userda static UINT audin_pulse_connect(IAudinDevice* device) { pa_context_state_t state; - AudinPulseDevice* pulse = (AudinPulseDevice*) device; + AudinPulseDevice* pulse = (AudinPulseDevice*)device; if (!pulse->context) return ERROR_INVALID_PARAMETER; @@ -126,8 +166,8 @@ static UINT audin_pulse_connect(IAudinDevice* device) if (!PA_CONTEXT_IS_GOOD(state)) { - WLog_Print(pulse->log, WLOG_ERROR, "bad context state (%d)", - pa_context_errno(pulse->context)); + WLog_Print(pulse->log, WLOG_ERROR, "bad context state (%s: %d)", + pulse_context_state_string(state), pa_context_errno(pulse->context)); pa_context_disconnect(pulse->context); return ERROR_INVALID_STATE; } @@ -136,7 +176,7 @@ static UINT audin_pulse_connect(IAudinDevice* device) } pa_threaded_mainloop_unlock(pulse->mainloop); - WLog_Print(pulse->log, WLOG_DEBUG, "connected"); + WLog_Print(pulse->log, WLOG_DEBUG, "connected"); return CHANNEL_RC_OK; } @@ -147,7 +187,7 @@ static UINT audin_pulse_connect(IAudinDevice* device) */ static UINT audin_pulse_free(IAudinDevice* device) { - AudinPulseDevice* pulse = (AudinPulseDevice*) device; + AudinPulseDevice* pulse = (AudinPulseDevice*)device; if (!pulse) return ERROR_INVALID_PARAMETER; @@ -176,7 +216,7 @@ static UINT audin_pulse_free(IAudinDevice* device) static BOOL audin_pulse_format_supported(IAudinDevice* device, const AUDIO_FORMAT* format) { - AudinPulseDevice* pulse = (AudinPulseDevice*) device; + AudinPulseDevice* pulse = (AudinPulseDevice*)device; if (!pulse || !format) return FALSE; @@ -187,8 +227,7 @@ static BOOL audin_pulse_format_supported(IAudinDevice* device, const AUDIO_FORMA switch (format->wFormatTag) { case WAVE_FORMAT_PCM: - if (format->cbSize == 0 && - (format->nSamplesPerSec <= PA_RATE_MAX) && + if (format->cbSize == 0 && (format->nSamplesPerSec <= PA_RATE_MAX) && (format->wBitsPerSample == 8 || format->wBitsPerSample == 16) && (format->nChannels >= 1 && format->nChannels <= PA_CHANNELS_MAX)) { @@ -197,10 +236,9 @@ static BOOL audin_pulse_format_supported(IAudinDevice* device, const AUDIO_FORMA break; - case WAVE_FORMAT_ALAW: /* A-LAW */ + case WAVE_FORMAT_ALAW: /* A-LAW */ case WAVE_FORMAT_MULAW: /* U-LAW */ - if (format->cbSize == 0 && - (format->nSamplesPerSec <= PA_RATE_MAX) && + if (format->cbSize == 0 && (format->nSamplesPerSec <= PA_RATE_MAX) && (format->wBitsPerSample == 8) && (format->nChannels >= 1 && format->nChannels <= PA_CHANNELS_MAX)) { @@ -225,7 +263,7 @@ static UINT audin_pulse_set_format(IAudinDevice* device, const AUDIO_FORMAT* for UINT32 FramesPerPacket) { pa_sample_spec sample_spec = { 0 }; - AudinPulseDevice* pulse = (AudinPulseDevice*) device; + AudinPulseDevice* pulse = (AudinPulseDevice*)device; if (!pulse || !format) return ERROR_INVALID_PARAMETER; @@ -278,24 +316,22 @@ static UINT audin_pulse_set_format(IAudinDevice* device, const AUDIO_FORMAT* for static void audin_pulse_stream_state_callback(pa_stream* stream, void* userdata) { pa_stream_state_t state; - AudinPulseDevice* pulse = (AudinPulseDevice*) userdata; + AudinPulseDevice* pulse = (AudinPulseDevice*)userdata; state = pa_stream_get_state(stream); + WLog_Print(pulse->log, WLOG_DEBUG, "stream state %s", pulse_stream_state_string(state)); switch (state) { case PA_STREAM_READY: - WLog_Print(pulse->log, WLOG_DEBUG, "PA_STREAM_READY"); pa_threaded_mainloop_signal(pulse->mainloop, 0); break; case PA_STREAM_FAILED: case PA_STREAM_TERMINATED: - WLog_Print(pulse->log, WLOG_DEBUG, "state %d", state); pa_threaded_mainloop_signal(pulse->mainloop, 0); break; default: - WLog_Print(pulse->log, WLOG_DEBUG, "state %d", state); break; } } @@ -303,17 +339,17 @@ static void audin_pulse_stream_state_callback(pa_stream* stream, void* userdata) static void audin_pulse_stream_request_callback(pa_stream* stream, size_t length, void* userdata) { const void* data; - AudinPulseDevice* pulse = (AudinPulseDevice*) userdata; + AudinPulseDevice* pulse = (AudinPulseDevice*)userdata; UINT error = CHANNEL_RC_OK; pa_stream_peek(stream, &data, &length); - error = IFCALLRESULT(CHANNEL_RC_OK, pulse->receive, &pulse->format, data, length, pulse->user_data); + error = + IFCALLRESULT(CHANNEL_RC_OK, pulse->receive, &pulse->format, data, length, pulse->user_data); pa_stream_drop(stream); if (error && pulse->rdpcontext) setChannelError(pulse->rdpcontext, error, "audin_pulse_thread_func reported an error"); } - /** * Function description * @@ -321,7 +357,7 @@ static void audin_pulse_stream_request_callback(pa_stream* stream, size_t length */ static UINT audin_pulse_close(IAudinDevice* device) { - AudinPulseDevice* pulse = (AudinPulseDevice*) device; + AudinPulseDevice* pulse = (AudinPulseDevice*)device; if (!pulse) return ERROR_INVALID_PARAMETER; @@ -349,7 +385,7 @@ static UINT audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* u { pa_stream_state_t state; pa_buffer_attr buffer_attr = { 0 }; - AudinPulseDevice* pulse = (AudinPulseDevice*) device; + AudinPulseDevice* pulse = (AudinPulseDevice*)device; if (!pulse || !receive || !user_data) return ERROR_INVALID_PARAMETER; @@ -363,8 +399,7 @@ static UINT audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* u pulse->receive = receive; pulse->user_data = user_data; pa_threaded_mainloop_lock(pulse->mainloop); - pulse->stream = pa_stream_new(pulse->context, "freerdp_audin", - &pulse->sample_spec, NULL); + pulse->stream = pa_stream_new(pulse->context, "freerdp_audin", &pulse->sample_spec, NULL); if (!pulse->stream) { @@ -375,24 +410,21 @@ static UINT audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* u } pulse->bytes_per_frame = pa_frame_size(&pulse->sample_spec); - pa_stream_set_state_callback(pulse->stream, - audin_pulse_stream_state_callback, pulse); - pa_stream_set_read_callback(pulse->stream, - audin_pulse_stream_request_callback, pulse); - buffer_attr.maxlength = (UINT32) - 1; - buffer_attr.tlength = (UINT32) - 1; - buffer_attr.prebuf = (UINT32) - 1; - buffer_attr.minreq = (UINT32) - 1; + pa_stream_set_state_callback(pulse->stream, audin_pulse_stream_state_callback, pulse); + pa_stream_set_read_callback(pulse->stream, audin_pulse_stream_request_callback, pulse); + buffer_attr.maxlength = (UINT32)-1; + buffer_attr.tlength = (UINT32)-1; + buffer_attr.prebuf = (UINT32)-1; + buffer_attr.minreq = (UINT32)-1; /* 500ms latency */ buffer_attr.fragsize = pulse->bytes_per_frame * pulse->frames_per_packet; if (buffer_attr.fragsize % pulse->format.nBlockAlign) - buffer_attr.fragsize += pulse->format.nBlockAlign - buffer_attr.fragsize % - pulse->format.nBlockAlign; + buffer_attr.fragsize += + pulse->format.nBlockAlign - buffer_attr.fragsize % pulse->format.nBlockAlign; - if (pa_stream_connect_record(pulse->stream, - pulse->device_name, - &buffer_attr, PA_STREAM_ADJUST_LATENCY) < 0) + if (pa_stream_connect_record(pulse->stream, pulse->device_name, &buffer_attr, + PA_STREAM_ADJUST_LATENCY) < 0) { pa_threaded_mainloop_unlock(pulse->mainloop); WLog_Print(pulse->log, WLOG_ERROR, "pa_stream_connect_playback failed (%d)", @@ -410,8 +442,8 @@ static UINT audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* u if (!PA_STREAM_IS_GOOD(state)) { audin_pulse_close(device); - WLog_Print(pulse->log, WLOG_ERROR, "bad stream state (%d)", - pa_context_errno(pulse->context)); + WLog_Print(pulse->log, WLOG_ERROR, "bad stream state (%s: %d)", + pulse_stream_state_string(state), pa_context_errno(pulse->context)); pa_threaded_mainloop_unlock(pulse->mainloop); return pa_context_errno(pulse->context); } @@ -425,12 +457,6 @@ static UINT audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* u return CHANNEL_RC_OK; } -static COMMAND_LINE_ARGUMENT_A audin_pulse_args[] = -{ - { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "audio device name" }, - { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } -}; - /** * Function description * @@ -441,10 +467,15 @@ static UINT audin_pulse_parse_addin_args(AudinPulseDevice* device, ADDIN_ARGV* a int status; DWORD flags; COMMAND_LINE_ARGUMENT_A* arg; - AudinPulseDevice* pulse = (AudinPulseDevice*) device; - flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; - status = CommandLineParseArgumentsA(args->argc, args->argv, audin_pulse_args, flags, - pulse, NULL, NULL); + AudinPulseDevice* pulse = (AudinPulseDevice*)device; + COMMAND_LINE_ARGUMENT_A audin_pulse_args[] = { { "dev", COMMAND_LINE_VALUE_REQUIRED, "", + NULL, NULL, -1, NULL, "audio device name" }, + { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } }; + + flags = + COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; + status = CommandLineParseArgumentsA(args->argc, args->argv, audin_pulse_args, flags, pulse, + NULL, NULL); if (status < 0) return ERROR_INVALID_PARAMETER; @@ -456,8 +487,7 @@ static UINT audin_pulse_parse_addin_args(AudinPulseDevice* device, ADDIN_ARGV* a if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) continue; - CommandLineSwitchStart(arg) - CommandLineSwitchCase(arg, "dev") + CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "dev") { pulse->device_name = _strdup(arg->Value); @@ -468,16 +498,15 @@ static UINT audin_pulse_parse_addin_args(AudinPulseDevice* device, ADDIN_ARGV* a } } CommandLineSwitchEnd(arg) - } - while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); return CHANNEL_RC_OK; } #ifdef BUILTIN_CHANNELS -#define freerdp_audin_client_subsystem_entry pulse_freerdp_audin_client_subsystem_entry +#define freerdp_audin_client_subsystem_entry pulse_freerdp_audin_client_subsystem_entry #else -#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry +#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry #endif /** @@ -490,7 +519,7 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn ADDIN_ARGV* args; AudinPulseDevice* pulse; UINT error; - pulse = (AudinPulseDevice*) calloc(1, sizeof(AudinPulseDevice)); + pulse = (AudinPulseDevice*)calloc(1, sizeof(AudinPulseDevice)); if (!pulse) { @@ -509,8 +538,8 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn if ((error = audin_pulse_parse_addin_args(pulse, args))) { - WLog_Print(pulse->log, WLOG_ERROR, "audin_pulse_parse_addin_args failed with error %"PRIu32"!", - error); + WLog_Print(pulse->log, WLOG_ERROR, + "audin_pulse_parse_addin_args failed with error %" PRIu32 "!", error); goto error_out; } @@ -534,21 +563,21 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn pa_context_set_state_callback(pulse->context, audin_pulse_context_state_callback, pulse); - if ((error = audin_pulse_connect((IAudinDevice*) pulse))) + if ((error = audin_pulse_connect(&pulse->iface))) { WLog_Print(pulse->log, WLOG_ERROR, "audin_pulse_connect failed"); goto error_out; } - if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) pulse))) + if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, &pulse->iface))) { - WLog_Print(pulse->log, WLOG_ERROR, "RegisterAudinDevice failed with error %"PRIu32"!", error); + WLog_Print(pulse->log, WLOG_ERROR, "RegisterAudinDevice failed with error %" PRIu32 "!", + error); goto error_out; } return CHANNEL_RC_OK; error_out: - audin_pulse_free((IAudinDevice*)pulse); + audin_pulse_free(&pulse->iface); return error; } - diff --git a/channels/audin/client/winmm/audin_winmm.c b/channels/audin/client/winmm/audin_winmm.c index 5e21005..bab9361 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 @@ -59,7 +59,7 @@ typedef struct _AudinWinmmDevice static void CALLBACK waveInProc(HWAVEIN hWaveIn, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { - AudinWinmmDevice* winmm = (AudinWinmmDevice*) dwInstance; + AudinWinmmDevice* winmm = (AudinWinmmDevice*)dwInstance; PWAVEHDR pWaveHdr; UINT error = CHANNEL_RC_OK; MMRESULT mmResult; @@ -74,8 +74,8 @@ static void CALLBACK waveInProc(HWAVEIN hWaveIn, UINT uMsg, DWORD_PTR dwInstance if (WHDR_DONE == (WHDR_DONE & pWaveHdr->dwFlags)) { - if (pWaveHdr->dwBytesRecorded - && !(WaitForSingleObject(winmm->stopEvent, 0) == WAIT_OBJECT_0)) + if (pWaveHdr->dwBytesRecorded && + !(WaitForSingleObject(winmm->stopEvent, 0) == WAIT_OBJECT_0)) { AUDIO_FORMAT format; format.cbSize = winmm->pwfx_cur->cbSize; @@ -86,8 +86,8 @@ static void CALLBACK waveInProc(HWAVEIN hWaveIn, UINT uMsg, DWORD_PTR dwInstance format.wBitsPerSample = winmm->pwfx_cur->wBitsPerSample; format.wFormatTag = winmm->pwfx_cur->wFormatTag; - if ((error = winmm->receive(&format, pWaveHdr->lpData, pWaveHdr->dwBytesRecorded, - winmm->user_data))) + if ((error = winmm->receive(&format, pWaveHdr->lpData, + pWaveHdr->dwBytesRecorded, winmm->user_data))) break; mmResult = waveInAddBuffer(hWaveIn, pWaveHdr, sizeof(WAVEHDR)); @@ -112,7 +112,7 @@ static void CALLBACK waveInProc(HWAVEIN hWaveIn, UINT uMsg, DWORD_PTR dwInstance static DWORD WINAPI audin_winmm_thread_func(LPVOID arg) { - AudinWinmmDevice* winmm = (AudinWinmmDevice*) arg; + AudinWinmmDevice* winmm = (AudinWinmmDevice*)arg; char* buffer; int size, i; WAVEHDR waveHdr[4]; @@ -122,7 +122,8 @@ static DWORD WINAPI audin_winmm_thread_func(LPVOID arg) if (!winmm->hWaveIn) { if (MMSYSERR_NOERROR != waveInOpen(&winmm->hWaveIn, WAVE_MAPPER, winmm->pwfx_cur, - (DWORD_PTR)waveInProc, (DWORD_PTR)winmm, CALLBACK_FUNCTION)) + (DWORD_PTR)waveInProc, (DWORD_PTR)winmm, + CALLBACK_FUNCTION)) { if (winmm->rdpcontext) setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, @@ -132,12 +133,14 @@ static DWORD WINAPI audin_winmm_thread_func(LPVOID arg) } } - size = (winmm->pwfx_cur->wBitsPerSample * winmm->pwfx_cur->nChannels * winmm->frames_per_packet + - 7) / 8; + size = + (winmm->pwfx_cur->wBitsPerSample * winmm->pwfx_cur->nChannels * winmm->frames_per_packet + + 7) / + 8; for (i = 0; i < 4; i++) { - buffer = (char*) malloc(size); + buffer = (char*)malloc(size); if (!buffer) return CHANNEL_RC_NO_MEMORY; @@ -149,7 +152,7 @@ static DWORD WINAPI audin_winmm_thread_func(LPVOID arg) if (MMSYSERR_NOERROR != rc) { - WLog_Print(winmm->log, WLOG_DEBUG, "waveInPrepareHeader failed. %"PRIu32"", rc); + WLog_Print(winmm->log, WLOG_DEBUG, "waveInPrepareHeader failed. %" PRIu32 "", rc); if (winmm->rdpcontext) setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, @@ -160,7 +163,7 @@ static DWORD WINAPI audin_winmm_thread_func(LPVOID arg) if (MMSYSERR_NOERROR != rc) { - WLog_Print(winmm->log, WLOG_DEBUG, "waveInAddBuffer failed. %"PRIu32"", rc); + WLog_Print(winmm->log, WLOG_DEBUG, "waveInAddBuffer failed. %" PRIu32 "", rc); if (winmm->rdpcontext) setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, @@ -172,7 +175,7 @@ static DWORD WINAPI audin_winmm_thread_func(LPVOID arg) if (MMSYSERR_NOERROR != rc) { - WLog_Print(winmm->log, WLOG_DEBUG, "waveInStart failed. %"PRIu32"", rc); + WLog_Print(winmm->log, WLOG_DEBUG, "waveInStart failed. %" PRIu32 "", rc); if (winmm->rdpcontext) setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, @@ -194,7 +197,7 @@ static DWORD WINAPI audin_winmm_thread_func(LPVOID arg) if (MMSYSERR_NOERROR != rc) { - WLog_Print(winmm->log, WLOG_DEBUG, "waveInReset failed. %"PRIu32"", rc); + WLog_Print(winmm->log, WLOG_DEBUG, "waveInReset failed. %" PRIu32 "", rc); if (winmm->rdpcontext) setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, @@ -207,7 +210,7 @@ static DWORD WINAPI audin_winmm_thread_func(LPVOID arg) if (MMSYSERR_NOERROR != rc) { - WLog_Print(winmm->log, WLOG_DEBUG, "waveInUnprepareHeader failed. %"PRIu32"", rc); + WLog_Print(winmm->log, WLOG_DEBUG, "waveInUnprepareHeader failed. %" PRIu32 "", rc); if (winmm->rdpcontext) setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, @@ -221,7 +224,7 @@ static DWORD WINAPI audin_winmm_thread_func(LPVOID arg) if (MMSYSERR_NOERROR != rc) { - WLog_Print(winmm->log, WLOG_DEBUG, "waveInClose failed. %"PRIu32"", rc); + WLog_Print(winmm->log, WLOG_DEBUG, "waveInClose failed. %" PRIu32 "", rc); if (winmm->rdpcontext) setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, @@ -240,7 +243,7 @@ static DWORD WINAPI audin_winmm_thread_func(LPVOID arg) static UINT audin_winmm_free(IAudinDevice* device) { UINT32 i; - AudinWinmmDevice* winmm = (AudinWinmmDevice*) device; + AudinWinmmDevice* winmm = (AudinWinmmDevice*)device; if (!winmm) return ERROR_INVALID_PARAMETER; @@ -265,7 +268,7 @@ static UINT audin_winmm_close(IAudinDevice* device) { DWORD status; UINT error = CHANNEL_RC_OK; - AudinWinmmDevice* winmm = (AudinWinmmDevice*) device; + AudinWinmmDevice* winmm = (AudinWinmmDevice*)device; if (!winmm) return ERROR_INVALID_PARAMETER; @@ -276,7 +279,8 @@ static UINT audin_winmm_close(IAudinDevice* device) if (status == WAIT_FAILED) { error = GetLastError(); - WLog_Print(winmm->log, WLOG_ERROR, "WaitForSingleObject failed with error %"PRIu32"!", error); + WLog_Print(winmm->log, WLOG_ERROR, "WaitForSingleObject failed with error %" PRIu32 "!", + error); return error; } @@ -298,7 +302,7 @@ static UINT audin_winmm_set_format(IAudinDevice* device, const AUDIO_FORMAT* for UINT32 FramesPerPacket) { UINT32 i; - AudinWinmmDevice* winmm = (AudinWinmmDevice*) device; + AudinWinmmDevice* winmm = (AudinWinmmDevice*)device; if (!winmm || !format) return ERROR_INVALID_PARAMETER; @@ -307,9 +311,9 @@ static UINT audin_winmm_set_format(IAudinDevice* device, const AUDIO_FORMAT* for for (i = 0; i < winmm->cFormats; i++) { - if (winmm->ppwfx[i]->wFormatTag == format->wFormatTag - && winmm->ppwfx[i]->nChannels == format->nChannels - && winmm->ppwfx[i]->wBitsPerSample == format->wBitsPerSample) + if (winmm->ppwfx[i]->wFormatTag == format->wFormatTag && + winmm->ppwfx[i]->nChannels == format->nChannels && + winmm->ppwfx[i]->wBitsPerSample == format->wBitsPerSample) { winmm->pwfx_cur = winmm->ppwfx[i]; break; @@ -321,7 +325,7 @@ static UINT audin_winmm_set_format(IAudinDevice* device, const AUDIO_FORMAT* for static BOOL audin_winmm_format_supported(IAudinDevice* device, const AUDIO_FORMAT* format) { - AudinWinmmDevice* winmm = (AudinWinmmDevice*) device; + AudinWinmmDevice* winmm = (AudinWinmmDevice*)device; PWAVEFORMATEX pwfx; BYTE* data; @@ -376,7 +380,7 @@ static BOOL audin_winmm_format_supported(IAudinDevice* device, const AUDIO_FORMA */ static UINT audin_winmm_open(IAudinDevice* device, AudinReceive receive, void* user_data) { - AudinWinmmDevice* winmm = (AudinWinmmDevice*) device; + AudinWinmmDevice* winmm = (AudinWinmmDevice*)device; if (!winmm || !receive || !user_data) return ERROR_INVALID_PARAMETER; @@ -390,8 +394,7 @@ static UINT audin_winmm_open(IAudinDevice* device, AudinReceive receive, void* u return ERROR_INTERNAL_ERROR; } - if (!(winmm->thread = CreateThread(NULL, 0, - audin_winmm_thread_func, winmm, 0, NULL))) + if (!(winmm->thread = CreateThread(NULL, 0, audin_winmm_thread_func, winmm, 0, NULL))) { WLog_Print(winmm->log, WLOG_ERROR, "CreateThread failed!"); CloseHandle(winmm->stopEvent); @@ -402,12 +405,6 @@ static UINT audin_winmm_open(IAudinDevice* device, AudinReceive receive, void* u return CHANNEL_RC_OK; } -static COMMAND_LINE_ARGUMENT_A audin_winmm_args[] = -{ - { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "audio device name" }, - { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } -}; - /** * Function description * @@ -418,10 +415,15 @@ static UINT audin_winmm_parse_addin_args(AudinWinmmDevice* device, ADDIN_ARGV* a int status; DWORD flags; COMMAND_LINE_ARGUMENT_A* arg; - AudinWinmmDevice* winmm = (AudinWinmmDevice*) device; - flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; - status = CommandLineParseArgumentsA(args->argc, args->argv, audin_winmm_args, flags, - winmm, NULL, NULL); + AudinWinmmDevice* winmm = (AudinWinmmDevice*)device; + COMMAND_LINE_ARGUMENT_A audin_winmm_args[] = { { "dev", COMMAND_LINE_VALUE_REQUIRED, "", + NULL, NULL, -1, NULL, "audio device name" }, + { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } }; + + flags = + COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; + status = CommandLineParseArgumentsA(args->argc, args->argv, audin_winmm_args, flags, winmm, + NULL, NULL); arg = audin_winmm_args; do @@ -429,8 +431,7 @@ static UINT audin_winmm_parse_addin_args(AudinWinmmDevice* device, ADDIN_ARGV* a if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) continue; - CommandLineSwitchStart(arg) - CommandLineSwitchCase(arg, "dev") + CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "dev") { winmm->device_name = _strdup(arg->Value); @@ -441,16 +442,15 @@ static UINT audin_winmm_parse_addin_args(AudinWinmmDevice* device, ADDIN_ARGV* a } } CommandLineSwitchEnd(arg) - } - while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); return CHANNEL_RC_OK; } #ifdef BUILTIN_CHANNELS -#define freerdp_audin_client_subsystem_entry winmm_freerdp_audin_client_subsystem_entry +#define freerdp_audin_client_subsystem_entry winmm_freerdp_audin_client_subsystem_entry #else -#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry +#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry #endif /** @@ -463,7 +463,14 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn ADDIN_ARGV* args; AudinWinmmDevice* winmm; UINT error; - winmm = (AudinWinmmDevice*) calloc(1, sizeof(AudinWinmmDevice)); + + if (waveInGetNumDevs() == 0) + { + WLog_Print(WLog_Get(TAG), WLOG_ERROR, "No microphone available!"); + return ERROR_DEVICE_NOT_AVAILABLE; + } + + winmm = (AudinWinmmDevice*)calloc(1, sizeof(AudinWinmmDevice)); if (!winmm) { @@ -482,8 +489,8 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn if ((error = audin_winmm_parse_addin_args(winmm, args))) { - WLog_Print(winmm->log, WLOG_ERROR, "audin_winmm_parse_addin_args failed with error %"PRIu32"!", - error); + WLog_Print(winmm->log, WLOG_ERROR, + "audin_winmm_parse_addin_args failed with error %" PRIu32 "!", error); goto error_out; } @@ -509,9 +516,10 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn goto error_out; } - if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) winmm))) + if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*)winmm))) { - WLog_Print(winmm->log, WLOG_ERROR, "RegisterAudinDevice failed with error %"PRIu32"!", error); + WLog_Print(winmm->log, WLOG_ERROR, "RegisterAudinDevice failed with error %" PRIu32 "!", + error); goto error_out; } diff --git a/channels/audin/server/audin.c b/channels/audin/server/audin.c index f521667..aa1979c 100644 --- a/channels/audin/server/audin.c +++ b/channels/audin/server/audin.c @@ -39,13 +39,13 @@ #include #define TAG CHANNELS_TAG("audin.server") -#define MSG_SNDIN_VERSION 0x01 -#define MSG_SNDIN_FORMATS 0x02 -#define MSG_SNDIN_OPEN 0x03 -#define MSG_SNDIN_OPEN_REPLY 0x04 -#define MSG_SNDIN_DATA_INCOMING 0x05 -#define MSG_SNDIN_DATA 0x06 -#define MSG_SNDIN_FORMATCHANGE 0x07 +#define MSG_SNDIN_VERSION 0x01 +#define MSG_SNDIN_FORMATS 0x02 +#define MSG_SNDIN_OPEN 0x03 +#define MSG_SNDIN_OPEN_REPLY 0x04 +#define MSG_SNDIN_DATA_INCOMING 0x05 +#define MSG_SNDIN_DATA 0x06 +#define MSG_SNDIN_FORMATCHANGE 0x07 typedef struct _audin_server { @@ -69,15 +69,13 @@ typedef struct _audin_server * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_server_select_format(audin_server_context* context, - size_t client_format_index) +static UINT audin_server_select_format(audin_server_context* context, size_t client_format_index) { - audin_server* audin = (audin_server*) context; + audin_server* audin = (audin_server*)context; if (client_format_index >= context->num_client_formats) { - WLog_ERR(TAG, - "error in protocol: client_format_index >= context->num_client_formats!"); + WLog_ERR(TAG, "error in protocol: client_format_index >= context->num_client_formats!"); return ERROR_INVALID_DATA; } @@ -109,7 +107,7 @@ static UINT audin_server_send_version(audin_server* audin, wStream* s) Stream_Write_UINT8(s, MSG_SNDIN_VERSION); Stream_Write_UINT32(s, 1); /* Version (4 bytes) */ - if (!WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), + if (!WTSVirtualChannelWrite(audin->audin_channel, (PCHAR)Stream_Buffer(s), Stream_GetPosition(s), &written)) { WLog_ERR(TAG, "WTSVirtualChannelWrite failed!"); @@ -124,14 +122,13 @@ static UINT audin_server_send_version(audin_server* audin, wStream* s) * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_server_recv_version(audin_server* audin, wStream* s, - UINT32 length) +static UINT audin_server_recv_version(audin_server* audin, wStream* s, UINT32 length) { UINT32 Version; if (length < 4) { - WLog_ERR(TAG, "error parsing version info: expected at least 4 bytes, got %"PRIu32"", + WLog_ERR(TAG, "error parsing version info: expected at least 4 bytes, got %" PRIu32 "", length); return ERROR_INVALID_DATA; } @@ -140,7 +137,7 @@ static UINT audin_server_recv_version(audin_server* audin, wStream* s, if (Version < 1) { - WLog_ERR(TAG, "expected Version > 0 but got %"PRIu32"", Version); + WLog_ERR(TAG, "expected Version > 0 but got %" PRIu32 "", Version); return ERROR_INVALID_DATA; } @@ -158,16 +155,15 @@ static UINT audin_server_send_formats(audin_server* audin, wStream* s) ULONG written; Stream_SetPosition(s, 0); Stream_Write_UINT8(s, MSG_SNDIN_FORMATS); - Stream_Write_UINT32(s, - audin->context.num_server_formats); /* NumFormats (4 bytes) */ - Stream_Write_UINT32(s, - 0); /* cbSizeFormatsPacket (4 bytes), client-to-server only */ + Stream_Write_UINT32(s, audin->context.num_server_formats); /* NumFormats (4 bytes) */ + Stream_Write_UINT32(s, 0); /* cbSizeFormatsPacket (4 bytes), client-to-server only */ for (i = 0; i < audin->context.num_server_formats; i++) { AUDIO_FORMAT format = audin->context.server_formats[i]; // TODO: Eliminate this - format.nAvgBytesPerSec = format.nSamplesPerSec * format.nChannels * format.wBitsPerSample / 8; + format.nAvgBytesPerSec = + format.nSamplesPerSec * format.nChannels * format.wBitsPerSample / 8; if (!audio_format_write(s, &format)) { @@ -176,8 +172,10 @@ static UINT audin_server_send_formats(audin_server* audin, wStream* s) } } - return WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), - Stream_GetPosition(s), &written) ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; + return WTSVirtualChannelWrite(audin->audin_channel, (PCHAR)Stream_Buffer(s), + Stream_GetPosition(s), &written) + ? CHANNEL_RC_OK + : ERROR_INTERNAL_ERROR; } /** @@ -185,22 +183,20 @@ static UINT audin_server_send_formats(audin_server* audin, wStream* s) * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_server_recv_formats(audin_server* audin, wStream* s, - UINT32 length) +static UINT audin_server_recv_formats(audin_server* audin, wStream* s, UINT32 length) { size_t i; UINT success = CHANNEL_RC_OK; if (length < 8) { - WLog_ERR(TAG, "error parsing rec formats: expected at least 8 bytes, got %"PRIu32"", + WLog_ERR(TAG, "error parsing rec formats: expected at least 8 bytes, got %" PRIu32 "", length); return ERROR_INVALID_DATA; } - Stream_Read_UINT32(s, - audin->context.num_client_formats); /* NumFormats (4 bytes) */ - Stream_Seek_UINT32(s); /* cbSizeFormatsPacket (4 bytes) */ + Stream_Read_UINT32(s, audin->context.num_client_formats); /* NumFormats (4 bytes) */ + Stream_Seek_UINT32(s); /* cbSizeFormatsPacket (4 bytes) */ length -= 8; if (audin->context.num_client_formats <= 0) @@ -223,7 +219,7 @@ static UINT audin_server_recv_formats(audin_server* audin, wStream* s, { audio_formats_free(audin->context.client_formats, i); audin->context.client_formats = NULL; - WLog_ERR(TAG, "expected length at least 18, but got %"PRIu32"", length); + WLog_ERR(TAG, "expected length at least 18, but got %" PRIu32 "", length); return ERROR_INVALID_DATA; } @@ -233,7 +229,7 @@ static UINT audin_server_recv_formats(audin_server* audin, wStream* s, IFCALLRET(audin->context.Opening, success, &audin->context); if (success) - WLog_ERR(TAG, "context.Opening failed with error %"PRIu32"", success); + WLog_ERR(TAG, "context.Opening failed with error %" PRIu32 "", success); return success; } @@ -257,24 +253,24 @@ static UINT audin_server_send_open(audin_server* audin, wStream* s) audin->opened = TRUE; Stream_SetPosition(s, 0); Stream_Write_UINT8(s, MSG_SNDIN_OPEN); - Stream_Write_UINT32(s, - audin->context.frames_per_packet); /* FramesPerPacket (4 bytes) */ - Stream_Write_UINT32(s, - audin->context.selected_client_format); /* initialFormat (4 bytes) */ + Stream_Write_UINT32(s, audin->context.frames_per_packet); /* FramesPerPacket (4 bytes) */ + Stream_Write_UINT32(s, audin->context.selected_client_format); /* initialFormat (4 bytes) */ /* * [MS-RDPEAI] 3.2.5.1.6 * The second format specify the format that SHOULD be used to capture data from * the actual audio input device. */ - Stream_Write_UINT16(s, 1); /* wFormatTag = PCM */ - Stream_Write_UINT16(s, 2); /* nChannels */ - Stream_Write_UINT32(s, 44100); /* nSamplesPerSec */ + Stream_Write_UINT16(s, 1); /* wFormatTag = PCM */ + Stream_Write_UINT16(s, 2); /* nChannels */ + Stream_Write_UINT32(s, 44100); /* nSamplesPerSec */ Stream_Write_UINT32(s, 44100 * 2 * 2); /* nAvgBytesPerSec */ - Stream_Write_UINT16(s, 4); /* nBlockAlign */ - Stream_Write_UINT16(s, 16); /* wBitsPerSample */ - Stream_Write_UINT16(s, 0); /* cbSize */ - return WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), - Stream_GetPosition(s), &written) ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; + Stream_Write_UINT16(s, 4); /* nBlockAlign */ + Stream_Write_UINT16(s, 16); /* wBitsPerSample */ + Stream_Write_UINT16(s, 0); /* cbSize */ + return WTSVirtualChannelWrite(audin->audin_channel, (PCHAR)Stream_Buffer(s), + Stream_GetPosition(s), &written) + ? CHANNEL_RC_OK + : ERROR_INTERNAL_ERROR; } /** @@ -282,15 +278,14 @@ static UINT audin_server_send_open(audin_server* audin, wStream* s) * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_server_recv_open_reply(audin_server* audin, wStream* s, - UINT32 length) +static UINT audin_server_recv_open_reply(audin_server* audin, wStream* s, UINT32 length) { UINT32 Result; UINT success = CHANNEL_RC_OK; if (length < 4) { - WLog_ERR(TAG, "error parsing version info: expected at least 4 bytes, got %"PRIu32"", + WLog_ERR(TAG, "error parsing version info: expected at least 4 bytes, got %" PRIu32 "", length); return ERROR_INVALID_DATA; } @@ -299,7 +294,7 @@ static UINT audin_server_recv_open_reply(audin_server* audin, wStream* s, IFCALLRET(audin->context.OpenResult, success, &audin->context, Result); if (success) - WLog_ERR(TAG, "context.OpenResult failed with error %"PRIu32"", success); + WLog_ERR(TAG, "context.OpenResult failed with error %" PRIu32 "", success); return success; } @@ -309,8 +304,7 @@ static UINT audin_server_recv_open_reply(audin_server* audin, wStream* s, * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_server_recv_data(audin_server* audin, wStream* s, - UINT32 length) +static UINT audin_server_recv_data(audin_server* audin, wStream* s, UINT32 length) { AUDIO_FORMAT* format; int sbytes_per_sample; @@ -346,7 +340,7 @@ static UINT audin_server_recv_data(audin_server* audin, wStream* s, IFCALLRET(audin->context.ReceiveSamples, success, &audin->context, &dformat, out, frames); if (success) - WLog_ERR(TAG, "context.ReceiveSamples failed with error %"PRIu32"", success); + WLog_ERR(TAG, "context.ReceiveSamples failed with error %" PRIu32 "", success); } else WLog_ERR(TAG, "freerdp_dsp_decode failed!"); @@ -365,7 +359,7 @@ static DWORD WINAPI audin_server_thread_func(LPVOID arg) BOOL ready = FALSE; HANDLE ChannelEvent; DWORD BytesReturned = 0; - audin_server* audin = (audin_server*) arg; + audin_server* audin = (audin_server*)arg; UINT error = CHANNEL_RC_OK; DWORD status; buffer = NULL; @@ -395,26 +389,25 @@ static DWORD WINAPI audin_server_thread_func(LPVOID arg) while (1) { - if ((status = WaitForMultipleObjects(nCount, events, FALSE, - 100)) == WAIT_OBJECT_0) + if ((status = WaitForMultipleObjects(nCount, events, FALSE, 100)) == WAIT_OBJECT_0) goto out; if (status == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"", error); + WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error); goto out; } - if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualChannelReady, - &buffer, &BytesReturned) == FALSE) + if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualChannelReady, &buffer, + &BytesReturned) == FALSE) { WLog_ERR(TAG, "WTSVirtualChannelQuery failed"); error = ERROR_INTERNAL_ERROR; goto out; } - ready = *((BOOL*) buffer); + ready = *((BOOL*)buffer); WTSFreeMemory(buffer); if (ready) @@ -434,21 +427,20 @@ static DWORD WINAPI audin_server_thread_func(LPVOID arg) { if ((error = audin_server_send_version(audin, s))) { - WLog_ERR(TAG, "audin_server_send_version failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "audin_server_send_version failed with error %" PRIu32 "!", error); goto out_capacity; } } while (ready) { - if ((status = WaitForMultipleObjects(nCount, events, FALSE, - INFINITE)) == WAIT_OBJECT_0) + if ((status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE)) == WAIT_OBJECT_0) break; if (status == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"", error); + WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error); goto out; } @@ -467,7 +459,7 @@ static DWORD WINAPI audin_server_thread_func(LPVOID arg) if (!Stream_EnsureRemainingCapacity(s, BytesReturned)) break; - if (WTSVirtualChannelRead(audin->audin_channel, 0, (PCHAR) Stream_Buffer(s), + if (WTSVirtualChannelRead(audin->audin_channel, 0, (PCHAR)Stream_Buffer(s), Stream_Capacity(s), &BytesReturned) == FALSE) { WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); @@ -483,13 +475,15 @@ static DWORD WINAPI audin_server_thread_func(LPVOID arg) case MSG_SNDIN_VERSION: if ((error = audin_server_recv_version(audin, s, BytesReturned))) { - WLog_ERR(TAG, "audin_server_recv_version failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "audin_server_recv_version failed with error %" PRIu32 "!", + error); goto out_capacity; } if ((error = audin_server_send_formats(audin, s))) { - WLog_ERR(TAG, "audin_server_send_formats failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "audin_server_send_formats failed with error %" PRIu32 "!", + error); goto out_capacity; } @@ -498,13 +492,14 @@ static DWORD WINAPI audin_server_thread_func(LPVOID arg) case MSG_SNDIN_FORMATS: if ((error = audin_server_recv_formats(audin, s, BytesReturned))) { - WLog_ERR(TAG, "audin_server_recv_formats failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "audin_server_recv_formats failed with error %" PRIu32 "!", + error); goto out_capacity; } if ((error = audin_server_send_open(audin, s))) { - WLog_ERR(TAG, "audin_server_send_open failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "audin_server_send_open failed with error %" PRIu32 "!", error); goto out_capacity; } @@ -513,7 +508,8 @@ static DWORD WINAPI audin_server_thread_func(LPVOID arg) case MSG_SNDIN_OPEN_REPLY: if ((error = audin_server_recv_open_reply(audin, s, BytesReturned))) { - WLog_ERR(TAG, "audin_server_recv_open_reply failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "audin_server_recv_open_reply failed with error %" PRIu32 "!", + error); goto out_capacity; } @@ -525,7 +521,7 @@ static DWORD WINAPI audin_server_thread_func(LPVOID arg) case MSG_SNDIN_DATA: if ((error = audin_server_recv_data(audin, s, BytesReturned))) { - WLog_ERR(TAG, "audin_server_recv_data failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "audin_server_recv_data failed with error %" PRIu32 "!", error); goto out_capacity; }; @@ -535,7 +531,7 @@ static DWORD WINAPI audin_server_thread_func(LPVOID arg) break; default: - WLog_ERR(TAG, "audin_server_thread_func: unknown MessageId %"PRIu8"", MessageId); + WLog_ERR(TAG, "audin_server_thread_func: unknown MessageId %" PRIu8 "", MessageId); break; } } @@ -556,7 +552,7 @@ out: static BOOL audin_server_open(audin_server_context* context) { - audin_server* audin = (audin_server*) context; + audin_server* audin = (audin_server*)context; if (!audin->thread) { @@ -564,15 +560,15 @@ static BOOL audin_server_open(audin_server_context* context) DWORD BytesReturned = 0; audin->SessionId = WTS_CURRENT_SESSION; - if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, - WTSSessionId, (LPSTR*) &pSessionId, &BytesReturned)) + if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId, + (LPSTR*)&pSessionId, &BytesReturned)) { - audin->SessionId = (DWORD) * pSessionId; + audin->SessionId = (DWORD)*pSessionId; WTSFreeMemory(pSessionId); } - audin->audin_channel = WTSVirtualChannelOpenEx(audin->SessionId, - "AUDIO_INPUT", WTS_CHANNEL_OPTION_DYNAMIC); + audin->audin_channel = + WTSVirtualChannelOpenEx(audin->SessionId, "AUDIO_INPUT", WTS_CHANNEL_OPTION_DYNAMIC); if (!audin->audin_channel) { @@ -586,7 +582,8 @@ static BOOL audin_server_open(audin_server_context* context) return FALSE; } - if (!(audin->thread = CreateThread(NULL, 0, audin_server_thread_func, (void*) audin, 0, NULL))) + if (!(audin->thread = + CreateThread(NULL, 0, audin_server_thread_func, (void*)audin, 0, NULL))) { WLog_ERR(TAG, "CreateThread failed!"); CloseHandle(audin->stopEvent); @@ -603,7 +600,7 @@ static BOOL audin_server_open(audin_server_context* context) static BOOL audin_server_is_open(audin_server_context* context) { - audin_server* audin = (audin_server*) context; + audin_server* audin = (audin_server*)context; if (!audin) return FALSE; @@ -613,7 +610,7 @@ static BOOL audin_server_is_open(audin_server_context* context) static BOOL audin_server_close(audin_server_context* context) { - audin_server* audin = (audin_server*) context; + audin_server* audin = (audin_server*)context; if (audin->thread) { @@ -621,7 +618,7 @@ static BOOL audin_server_close(audin_server_context* context) if (WaitForSingleObject(audin->thread, INFINITE) == WAIT_FAILED) { - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", GetLastError()); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", GetLastError()); return FALSE; } @@ -668,12 +665,12 @@ audin_server_context* audin_server_context_new(HANDLE vcm) return NULL; } - return (audin_server_context*) audin; + return (audin_server_context*)audin; } void audin_server_context_free(audin_server_context* context) { - audin_server* audin = (audin_server*) context; + audin_server* audin = (audin_server*)context; if (!audin) return; diff --git a/channels/client/CMakeLists.txt b/channels/client/CMakeLists.txt index 5f1fb31..eb0c80f 100644 --- a/channels/client/CMakeLists.txt +++ b/channels/client/CMakeLists.txt @@ -33,22 +33,28 @@ set(CLIENT_STATIC_TYPEDEFS "${CLIENT_STATIC_TYPEDEFS}typedef UINT (*static_addin foreach(STATIC_ENTRY ${CHANNEL_STATIC_CLIENT_ENTRIES}) foreach(STATIC_MODULE ${CHANNEL_STATIC_CLIENT_MODULES}) - if(${${STATIC_MODULE}_CLIENT_ENTRY} STREQUAL ${STATIC_ENTRY}) - set(STATIC_MODULE_NAME ${${STATIC_MODULE}_CLIENT_NAME}) - set(STATIC_MODULE_CHANNEL ${${STATIC_MODULE}_CLIENT_CHANNEL}) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${STATIC_MODULE_NAME}) + foreach(ENTRY ${${STATIC_MODULE}_CLIENT_ENTRY}) + if(${ENTRY} STREQUAL ${STATIC_ENTRY}) + set(STATIC_MODULE_NAME ${${STATIC_MODULE}_CLIENT_NAME}) + set(STATIC_MODULE_CHANNEL ${${STATIC_MODULE}_CLIENT_CHANNEL}) + set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${STATIC_MODULE_NAME}) - set(ENTRY_POINT_NAME "${STATIC_MODULE_CHANNEL}_${${STATIC_MODULE}_CLIENT_ENTRY}") - if(${${STATIC_MODULE}_CLIENT_ENTRY} STREQUAL "VirtualChannelEntry") - set(ENTRY_POINT_IMPORT "extern BOOL VCAPITYPE ${ENTRY_POINT_NAME}(PCHANNEL_ENTRY_POINTS);") - elseif(${${STATIC_MODULE}_CLIENT_ENTRY} STREQUAL "VirtualChannelEntryEx") - set(ENTRY_POINT_IMPORT "extern BOOL VCAPITYPE ${ENTRY_POINT_NAME}(PCHANNEL_ENTRY_POINTS,PVOID);") - else() - set(ENTRY_POINT_IMPORT "extern UINT ${ENTRY_POINT_NAME}(void);") + set(ENTRY_POINT_NAME "${STATIC_MODULE_CHANNEL}_${ENTRY}") + if(${ENTRY} STREQUAL "VirtualChannelEntry") + set(ENTRY_POINT_IMPORT "extern BOOL VCAPITYPE ${ENTRY_POINT_NAME}(PCHANNEL_ENTRY_POINTS);") + elseif(${ENTRY} STREQUAL "VirtualChannelEntryEx") + set(ENTRY_POINT_IMPORT "extern BOOL VCAPITYPE ${ENTRY_POINT_NAME}(PCHANNEL_ENTRY_POINTS,PVOID);") + elseif(${ENTRY} MATCHES "DVCPluginEntry$") + set(ENTRY_POINT_IMPORT "extern UINT ${ENTRY_POINT_NAME}(IDRDYNVC_ENTRY_POINTS* pEntryPoints);") + elseif(${ENTRY} MATCHES "DeviceServiceEntry$") + set(ENTRY_POINT_IMPORT "extern UINT ${ENTRY_POINT_NAME}(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints);") + else() + set(ENTRY_POINT_IMPORT "extern UINT ${ENTRY_POINT_NAME}(void);") + endif() + set(${STATIC_ENTRY}_IMPORTS "${${STATIC_ENTRY}_IMPORTS}\n${ENTRY_POINT_IMPORT}") + set(${STATIC_ENTRY}_TABLE "${${STATIC_ENTRY}_TABLE}\n\t{ \"${STATIC_MODULE_CHANNEL}\", (static_entry_fkt)${ENTRY_POINT_NAME} },") endif() - set(${STATIC_ENTRY}_IMPORTS "${${STATIC_ENTRY}_IMPORTS}\n${ENTRY_POINT_IMPORT}") - set(${STATIC_ENTRY}_TABLE "${${STATIC_ENTRY}_TABLE}\n\t{ \"${STATIC_MODULE_CHANNEL}\", (static_entry_fkt)${ENTRY_POINT_NAME} },") - endif() + endforeach() endforeach() endforeach() @@ -91,15 +97,17 @@ foreach(STATIC_MODULE ${CHANNEL_STATIC_CLIENT_MODULES}) set(STATIC_SUBSYSTEM_ENTRY "${STATIC_SUBSYSTEM_NAME}_freerdp_${STATIC_MODULE_CHANNEL}_client_subsystem_entry") endif() set(SUBSYSTEM_TABLE "${SUBSYSTEM_TABLE}\n\t{ \"${STATIC_SUBSYSTEM_NAME}\", \"${STATIC_SUBSYSTEM_TYPE}\", ${STATIC_SUBSYSTEM_ENTRY} },") - set(SUBSYSTEM_IMPORT "extern void ${STATIC_SUBSYSTEM_ENTRY}(void);") + set(SUBSYSTEM_IMPORT "extern UINT ${STATIC_SUBSYSTEM_ENTRY}(void*);") set(CLIENT_STATIC_SUBSYSTEM_IMPORTS "${CLIENT_STATIC_SUBSYSTEM_IMPORTS}\n${SUBSYSTEM_IMPORT}") endforeach() set(SUBSYSTEM_TABLE "${SUBSYSTEM_TABLE}\n\t{ NULL, NULL, NULL }\n};") set(CLIENT_STATIC_SUBSYSTEM_TABLES "${CLIENT_STATIC_SUBSYSTEM_TABLES}\n${SUBSYSTEM_TABLE}") - set(ENTRY_POINT_NAME "${STATIC_MODULE_CHANNEL}_${${STATIC_MODULE}_CLIENT_ENTRY}") - set(CLIENT_STATIC_ADDIN_TABLE "${CLIENT_STATIC_ADDIN_TABLE}\n\t{ \"${STATIC_MODULE_CHANNEL}\", (static_addin_fkt)${ENTRY_POINT_NAME}, ${SUBSYSTEM_TABLE_NAME} },") + foreach(ENTRY ${${STATIC_MODULE}_CLIENT_ENTRY}) + set (ENTRY_POINT_NAME ${STATIC_MODULE_CHANNEL}_${ENTRY}) + set(CLIENT_STATIC_ADDIN_TABLE "${CLIENT_STATIC_ADDIN_TABLE}\n\t{ \"${STATIC_MODULE_CHANNEL}\", \"${ENTRY}\", (static_addin_fkt)${ENTRY_POINT_NAME}, ${SUBSYSTEM_TABLE_NAME} },") + endforeach() endforeach() -set(CLIENT_STATIC_ADDIN_TABLE "${CLIENT_STATIC_ADDIN_TABLE}\n\t{ NULL, NULL, NULL }\n};") +set(CLIENT_STATIC_ADDIN_TABLE "${CLIENT_STATIC_ADDIN_TABLE}\n\t{ NULL, NULL, NULL, NULL }\n};") configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tables.c.in ${CMAKE_CURRENT_BINARY_DIR}/tables.c) diff --git a/channels/client/addin.c b/channels/client/addin.c index 86b9f43..cd6f90e 100644 --- a/channels/client/addin.c +++ b/channels/client/addin.c @@ -43,21 +43,21 @@ extern const STATIC_ENTRY_TABLE CLIENT_STATIC_ENTRY_TABLES[]; -void* freerdp_channels_find_static_entry_in_table(const STATIC_ENTRY_TABLE* table, - const char* identifier) +static void* freerdp_channels_find_static_entry_in_table(const STATIC_ENTRY_TABLE* table, + const char* identifier) { - int index = 0; + size_t index = 0; STATIC_ENTRY* pEntry; - pEntry = (STATIC_ENTRY*) &table->table[index++]; + pEntry = (STATIC_ENTRY*)&table->table[index++]; while (pEntry->entry != NULL) { if (strcmp(pEntry->name, identifier) == 0) { - return (void*) pEntry->entry; + return (void*)pEntry->entry; } - pEntry = (STATIC_ENTRY*) &table->table[index++]; + pEntry = (STATIC_ENTRY*)&table->table[index++]; } return NULL; @@ -65,9 +65,9 @@ void* freerdp_channels_find_static_entry_in_table(const STATIC_ENTRY_TABLE* tabl void* freerdp_channels_client_find_static_entry(const char* name, const char* identifier) { - int index = 0; + size_t index = 0; STATIC_ENTRY_TABLE* pEntry; - pEntry = (STATIC_ENTRY_TABLE*) &CLIENT_STATIC_ENTRY_TABLES[index++]; + pEntry = (STATIC_ENTRY_TABLE*)&CLIENT_STATIC_ENTRY_TABLES[index++]; while (pEntry->table != NULL) { @@ -76,7 +76,7 @@ void* freerdp_channels_client_find_static_entry(const char* name, const char* id return freerdp_channels_find_static_entry_in_table(pEntry, identifier); } - pEntry = (STATIC_ENTRY_TABLE*) &CLIENT_STATIC_ENTRY_TABLES[index++]; + pEntry = (STATIC_ENTRY_TABLE*)&CLIENT_STATIC_ENTRY_TABLES[index++]; } return NULL; @@ -84,15 +84,16 @@ void* freerdp_channels_client_find_static_entry(const char* name, const char* id extern const STATIC_ADDIN_TABLE CLIENT_STATIC_ADDIN_TABLE[]; -FREERDP_ADDIN** freerdp_channels_list_client_static_addins(LPSTR pszName, LPSTR pszSubsystem, - LPSTR pszType, DWORD dwFlags) +static FREERDP_ADDIN** freerdp_channels_list_client_static_addins(LPCSTR pszName, + LPCSTR pszSubsystem, + LPCSTR pszType, DWORD dwFlags) { size_t i, j; DWORD nAddins; FREERDP_ADDIN** ppAddins = NULL; STATIC_SUBSYSTEM_ENTRY* subsystems; nAddins = 0; - ppAddins = (FREERDP_ADDIN**) calloc(128, sizeof(FREERDP_ADDIN*)); + ppAddins = (FREERDP_ADDIN**)calloc(128, sizeof(FREERDP_ADDIN*)); if (!ppAddins) { @@ -104,7 +105,7 @@ FREERDP_ADDIN** freerdp_channels_list_client_static_addins(LPSTR pszName, LPSTR for (i = 0; CLIENT_STATIC_ADDIN_TABLE[i].name != NULL; i++) { - FREERDP_ADDIN* pAddin = (FREERDP_ADDIN*) calloc(1, sizeof(FREERDP_ADDIN)); + FREERDP_ADDIN* pAddin = (FREERDP_ADDIN*)calloc(1, sizeof(FREERDP_ADDIN)); if (!pAddin) { @@ -117,11 +118,11 @@ FREERDP_ADDIN** freerdp_channels_list_client_static_addins(LPSTR pszName, LPSTR pAddin->dwFlags |= FREERDP_ADDIN_STATIC; pAddin->dwFlags |= FREERDP_ADDIN_NAME; ppAddins[nAddins++] = pAddin; - subsystems = (STATIC_SUBSYSTEM_ENTRY*) CLIENT_STATIC_ADDIN_TABLE[i].table; + subsystems = (STATIC_SUBSYSTEM_ENTRY*)CLIENT_STATIC_ADDIN_TABLE[i].table; for (j = 0; subsystems[j].name != NULL; j++) { - pAddin = (FREERDP_ADDIN*) calloc(1, sizeof(FREERDP_ADDIN)); + pAddin = (FREERDP_ADDIN*)calloc(1, sizeof(FREERDP_ADDIN)); if (!pAddin) { @@ -129,7 +130,8 @@ FREERDP_ADDIN** freerdp_channels_list_client_static_addins(LPSTR pszName, LPSTR goto error_out; } - sprintf_s(pAddin->cName, ARRAYSIZE(pAddin->cName), "%s", CLIENT_STATIC_ADDIN_TABLE[i].name); + sprintf_s(pAddin->cName, ARRAYSIZE(pAddin->cName), "%s", + CLIENT_STATIC_ADDIN_TABLE[i].name); sprintf_s(pAddin->cSubsystem, ARRAYSIZE(pAddin->cSubsystem), "%s", subsystems[j].name); pAddin->dwFlags = FREERDP_ADDIN_CLIENT; pAddin->dwFlags |= FREERDP_ADDIN_STATIC; @@ -145,8 +147,8 @@ error_out: return NULL; } -FREERDP_ADDIN** freerdp_channels_list_dynamic_addins(LPSTR pszName, LPSTR pszSubsystem, - LPSTR pszType, DWORD dwFlags) +static FREERDP_ADDIN** freerdp_channels_list_dynamic_addins(LPCSTR pszName, LPCSTR pszSubsystem, + LPCSTR pszType, DWORD dwFlags) { int index; int nDashes; @@ -163,11 +165,11 @@ FREERDP_ADDIN** freerdp_channels_list_dynamic_addins(LPSTR pszName, LPSTR pszSub size_t cchInstallPrefix; FREERDP_ADDIN** ppAddins; WIN32_FIND_DATAA FindData; - cchAddinPath = strlen(pszAddinPath); - cchInstallPrefix = strlen(pszInstallPrefix); + cchAddinPath = strnlen(pszAddinPath, sizeof(FREERDP_ADDIN_PATH)); + cchInstallPrefix = strnlen(pszInstallPrefix, sizeof(FREERDP_INSTALL_PREFIX)); pszExtension = PathGetSharedLibraryExtensionA(0); - cchPattern = 128 + strlen(pszExtension) + 2; - pszPattern = (LPSTR) malloc(cchPattern + 1); + cchPattern = 128 + strnlen(pszExtension, MAX_PATH) + 2; + pszPattern = (LPSTR)malloc(cchPattern + 1); if (!pszPattern) { @@ -177,28 +179,28 @@ FREERDP_ADDIN** freerdp_channels_list_dynamic_addins(LPSTR pszName, LPSTR pszSub if (pszName && pszSubsystem && pszType) { - sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX"%s-client-%s-%s.%s", + sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX "%s-client-%s-%s.%s", pszName, pszSubsystem, pszType, pszExtension); } else if (pszName && pszType) { - sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX"%s-client-?-%s.%s", + sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX "%s-client-?-%s.%s", pszName, pszType, pszExtension); } else if (pszName) { - sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX"%s-client*.%s", - pszName, pszExtension); + sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX "%s-client*.%s", pszName, + pszExtension); } else { - sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX"?-client*.%s", + sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX "?-client*.%s", pszExtension); } - cchPattern = strlen(pszPattern); + cchPattern = strnlen(pszPattern, cchPattern); cchSearchPath = cchInstallPrefix + cchAddinPath + cchPattern + 3; - pszSearchPath = (LPSTR) malloc(cchSearchPath + 1); + pszSearchPath = (LPSTR)malloc(cchSearchPath + 1); if (!pszSearchPath) { @@ -215,7 +217,7 @@ FREERDP_ADDIN** freerdp_channels_list_dynamic_addins(LPSTR pszName, LPSTR pszSub hFind = FindFirstFileA(pszSearchPath, &FindData); free(pszSearchPath); nAddins = 0; - ppAddins = (FREERDP_ADDIN**) calloc(128, sizeof(FREERDP_ADDIN*)); + ppAddins = (FREERDP_ADDIN**)calloc(128, sizeof(FREERDP_ADDIN*)); if (!ppAddins) { @@ -232,7 +234,7 @@ FREERDP_ADDIN** freerdp_channels_list_dynamic_addins(LPSTR pszName, LPSTR pszSub char* p[5]; FREERDP_ADDIN* pAddin; nDashes = 0; - pAddin = (FREERDP_ADDIN*) calloc(1, sizeof(FREERDP_ADDIN)); + pAddin = (FREERDP_ADDIN*)calloc(1, sizeof(FREERDP_ADDIN)); if (!pAddin) { @@ -291,8 +293,7 @@ FREERDP_ADDIN** freerdp_channels_list_dynamic_addins(LPSTR pszName, LPSTR pszSub { free(pAddin); } - } - while (FindNextFileA(hFind, &FindData)); + } while (FindNextFileA(hFind, &FindData)); FindClose(hFind); ppAddins[nAddins] = NULL; @@ -303,8 +304,8 @@ error_out: return NULL; } -FREERDP_ADDIN** freerdp_channels_list_addins(LPSTR pszName, LPSTR pszSubsystem, LPSTR pszType, - DWORD dwFlags) +FREERDP_ADDIN** freerdp_channels_list_addins(LPCSTR pszName, LPCSTR pszSubsystem, LPCSTR pszType, + DWORD dwFlags) { if (dwFlags & FREERDP_ADDIN_STATIC) return freerdp_channels_list_client_static_addins(pszName, pszSubsystem, pszType, dwFlags); @@ -316,7 +317,7 @@ FREERDP_ADDIN** freerdp_channels_list_addins(LPSTR pszName, LPSTR pszSubsystem, void freerdp_channels_addin_list_free(FREERDP_ADDIN** ppAddins) { - int index; + size_t index; if (!ppAddins) return; @@ -329,48 +330,68 @@ void freerdp_channels_addin_list_free(FREERDP_ADDIN** ppAddins) extern const STATIC_ENTRY CLIENT_VirtualChannelEntryEx_TABLE[]; -BOOL freerdp_channels_is_virtual_channel_entry_ex(LPCSTR pszName) +static BOOL freerdp_channels_is_virtual_channel_entry_ex(LPCSTR pszName) { - int i; - STATIC_ENTRY* entry; + size_t i; for (i = 0; CLIENT_VirtualChannelEntryEx_TABLE[i].name != NULL; i++) { - entry = (STATIC_ENTRY*) &CLIENT_VirtualChannelEntryEx_TABLE[i]; + const STATIC_ENTRY* entry = &CLIENT_VirtualChannelEntryEx_TABLE[i]; - if (!strcmp(entry->name, pszName)) + if (!strncmp(entry->name, pszName, MAX_PATH)) return TRUE; } return FALSE; } -PVIRTUALCHANNELENTRY freerdp_channels_load_static_addin_entry(LPCSTR pszName, LPSTR pszSubsystem, - LPSTR pszType, DWORD dwFlags) +PVIRTUALCHANNELENTRY freerdp_channels_load_static_addin_entry(LPCSTR pszName, LPCSTR pszSubsystem, + LPCSTR pszType, DWORD dwFlags) { - int i, j; - STATIC_SUBSYSTEM_ENTRY* subsystems; + const STATIC_ADDIN_TABLE* table = CLIENT_STATIC_ADDIN_TABLE; + const char* type = NULL; - for (i = 0; CLIENT_STATIC_ADDIN_TABLE[i].name != NULL; i++) + if (!pszName) + return NULL; + + if (dwFlags & FREERDP_ADDIN_CHANNEL_DYNAMIC) + type = "DVCPluginEntry"; + else if (dwFlags & FREERDP_ADDIN_CHANNEL_DEVICE) + type = "DeviceServiceEntry"; + else if (dwFlags & FREERDP_ADDIN_CHANNEL_STATIC) + { + if (dwFlags & FREERDP_ADDIN_CHANNEL_ENTRYEX) + type = "VirtualChannelEntryEx"; + else + type = "VirtualChannelEntry"; + } + + for (; table->name != NULL; table++) { - if (strcmp(CLIENT_STATIC_ADDIN_TABLE[i].name, pszName) == 0) + if (strncmp(table->name, pszName, MAX_PATH) == 0) { + if (type && strncmp(table->type, type, MAX_PATH)) + continue; + if (pszSubsystem != NULL) { - subsystems = (STATIC_SUBSYSTEM_ENTRY*) CLIENT_STATIC_ADDIN_TABLE[i].table; + const STATIC_SUBSYSTEM_ENTRY* subsystems = table->table; - for (j = 0; subsystems[j].name != NULL; j++) + for (; subsystems->name != NULL; subsystems++) { - if (strcmp(subsystems[j].name, pszSubsystem) == 0) + /* If the pszSubsystem is an empty string use the default backend. */ + if ((strnlen(pszSubsystem, 1) == + 0) || /* we only want to know if strnlen is > 0 */ + (strncmp(subsystems->name, pszSubsystem, MAX_PATH) == 0)) { if (pszType) { - if (strcmp(subsystems[j].type, pszType) == 0) - return (PVIRTUALCHANNELENTRY) subsystems[j].entry; + if (strncmp(subsystems->type, pszType, MAX_PATH) == 0) + return (PVIRTUALCHANNELENTRY)subsystems->entry; } else { - return (PVIRTUALCHANNELENTRY) subsystems[j].entry; + return (PVIRTUALCHANNELENTRY)subsystems->entry; } } } @@ -383,7 +404,7 @@ PVIRTUALCHANNELENTRY freerdp_channels_load_static_addin_entry(LPCSTR pszName, LP return NULL; } - return (PVIRTUALCHANNELENTRY) CLIENT_STATIC_ADDIN_TABLE[i].entry; + return (PVIRTUALCHANNELENTRY)table->entry; } } } diff --git a/channels/client/addin.h b/channels/client/addin.h index f3ad970..849b11f 100644 --- a/channels/client/addin.h +++ b/channels/client/addin.h @@ -16,5 +16,3 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - - diff --git a/channels/client/tables.c.in b/channels/client/tables.c.in index cc789d8..aafc71d 100644 --- a/channels/client/tables.c.in +++ b/channels/client/tables.c.in @@ -19,6 +19,7 @@ * limitations under the License. */ +#include #include "tables.h" ${CLIENT_STATIC_TYPEDEFS} diff --git a/channels/client/tables.h b/channels/client/tables.h index c84298a..b6b3f9c 100644 --- a/channels/client/tables.h +++ b/channels/client/tables.h @@ -22,7 +22,7 @@ struct _STATIC_ENTRY { const char* name; - UINT(*entry)(); + UINT (*entry)(); }; typedef struct _STATIC_ENTRY STATIC_ENTRY; @@ -37,14 +37,15 @@ struct _STATIC_SUBSYSTEM_ENTRY { const char* name; const char* type; - void (*entry)(void); + UINT (*entry)(); }; typedef struct _STATIC_SUBSYSTEM_ENTRY STATIC_SUBSYSTEM_ENTRY; struct _STATIC_ADDIN_TABLE { const char* name; - UINT(*entry)(); + const char* type; + UINT (*entry)(); const STATIC_SUBSYSTEM_ENTRY* table; }; typedef struct _STATIC_ADDIN_TABLE STATIC_ADDIN_TABLE; diff --git a/channels/cliprdr/client/CMakeLists.txt b/channels/cliprdr/client/CMakeLists.txt index 6081bee..4511e08 100644 --- a/channels/cliprdr/client/CMakeLists.txt +++ b/channels/cliprdr/client/CMakeLists.txt @@ -21,7 +21,10 @@ set(${MODULE_PREFIX}_SRCS cliprdr_format.c cliprdr_format.h cliprdr_main.c - cliprdr_main.h) + cliprdr_main.h + ../cliprdr_common.h + ../cliprdr_common.c + ) add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntryEx") diff --git a/channels/cliprdr/client/cliprdr_format.c b/channels/cliprdr/client/cliprdr_format.c index a97a584..43b967e 100644 --- a/channels/cliprdr/client/cliprdr_format.c +++ b/channels/cliprdr/client/cliprdr_format.c @@ -33,22 +33,17 @@ #include "cliprdr_main.h" #include "cliprdr_format.h" +#include "../cliprdr_common.h" /** * Function description * * @return 0 on success, otherwise a Win32 error code */ -UINT cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags) +UINT cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, + UINT16 msgFlags) { - UINT32 index; - size_t position; - BOOL asciiNames; - int formatNameLength; - char* szFormatName; - WCHAR* wszFormatName; - CLIPRDR_FORMAT* formats = NULL; - CLIPRDR_FORMAT_LIST formatList; + CLIPRDR_FORMAT_LIST formatList = { 0 }; CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); UINT error = CHANNEL_RC_OK; @@ -58,185 +53,24 @@ UINT cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data return ERROR_INTERNAL_ERROR; } - asciiNames = (msgFlags & CB_ASCII_NAMES) ? TRUE : FALSE; - formatList.msgType = CB_FORMAT_LIST; formatList.msgFlags = msgFlags; formatList.dataLen = dataLen; - index = 0; - formatList.numFormats = 0; - position = Stream_GetPosition(s); - - if (!formatList.dataLen) - { - /* empty format list */ - formatList.formats = NULL; - formatList.numFormats = 0; - } - else if (!cliprdr->useLongFormatNames) - { - formatList.numFormats = (dataLen / 36); - - if ((formatList.numFormats * 36) != dataLen) - { - WLog_ERR(TAG, "Invalid short format list length: %"PRIu32"", dataLen); - return ERROR_INTERNAL_ERROR; - } - - if (formatList.numFormats) - formats = (CLIPRDR_FORMAT*) calloc(formatList.numFormats, sizeof(CLIPRDR_FORMAT)); - - if (!formats) - { - WLog_ERR(TAG, "calloc failed!"); - return CHANNEL_RC_NO_MEMORY; - } - - formatList.formats = formats; - - while (dataLen) - { - Stream_Read_UINT32(s, formats[index].formatId); /* formatId (4 bytes) */ - dataLen -= 4; - - formats[index].formatName = NULL; - - /* According to MS-RDPECLIP 2.2.3.1.1.1 formatName is "a 32-byte block containing - * the *null-terminated* name assigned to the Clipboard Format: (32 ASCII 8 characters - * or 16 Unicode characters)" - * However, both Windows RDSH and mstsc violate this specs as seen in the following - * example of a transferred short format name string: [R.i.c.h. .T.e.x.t. .F.o.r.m.a.t.] - * These are 16 unicode charaters - *without* terminating null ! - */ - - if (asciiNames) - { - szFormatName = (char*) Stream_Pointer(s); - - if (szFormatName[0]) - { - /* ensure null termination */ - formats[index].formatName = (char*) malloc(32 + 1); - if (!formats[index].formatName) - { - WLog_ERR(TAG, "malloc failed!"); - error = CHANNEL_RC_NO_MEMORY; - goto error_out; - } - CopyMemory(formats[index].formatName, szFormatName, 32); - formats[index].formatName[32] = '\0'; - } - } - else - { - wszFormatName = (WCHAR*) Stream_Pointer(s); - - if (wszFormatName[0]) - { - /* ConvertFromUnicode always returns a null-terminated - * string on success, even if the source string isn't. - */ - if (ConvertFromUnicode(CP_UTF8, 0, wszFormatName, 16, - &(formats[index].formatName), 0, NULL, NULL) < 1) - { - WLog_ERR(TAG, "failed to convert short clipboard format name"); - error = ERROR_INTERNAL_ERROR; - goto error_out; - } - } - } - - Stream_Seek(s, 32); - dataLen -= 32; - index++; - } - } - else - { - while (dataLen) - { - Stream_Seek(s, 4); /* formatId (4 bytes) */ - dataLen -= 4; - - wszFormatName = (WCHAR*) Stream_Pointer(s); - - if (!wszFormatName[0]) - formatNameLength = 0; - else - formatNameLength = _wcslen(wszFormatName); - - Stream_Seek(s, (formatNameLength + 1) * 2); - dataLen -= ((formatNameLength + 1) * 2); - - formatList.numFormats++; - } - - dataLen = formatList.dataLen; - Stream_SetPosition(s, position); - - if (formatList.numFormats) - formats = (CLIPRDR_FORMAT*) calloc(formatList.numFormats, sizeof(CLIPRDR_FORMAT)); - - if (!formats) - { - WLog_ERR(TAG, "calloc failed!"); - return CHANNEL_RC_NO_MEMORY; - } - - formatList.formats = formats; - - while (dataLen) - { - Stream_Read_UINT32(s, formats[index].formatId); /* formatId (4 bytes) */ - dataLen -= 4; - - formats[index].formatName = NULL; - - wszFormatName = (WCHAR*) Stream_Pointer(s); - - if (!wszFormatName[0]) - formatNameLength = 0; - else - formatNameLength = _wcslen(wszFormatName); + if ((error = cliprdr_read_format_list(s, &formatList, cliprdr->useLongFormatNames))) + goto error_out; - if (formatNameLength) - { - if (ConvertFromUnicode(CP_UTF8, 0, wszFormatName, -1, - &(formats[index].formatName), 0, NULL, NULL) < 1) - { - WLog_ERR(TAG, "failed to convert long clipboard format name"); - error = ERROR_INTERNAL_ERROR; - goto error_out; - } - } - - Stream_Seek(s, (formatNameLength + 1) * 2); - dataLen -= ((formatNameLength + 1) * 2); - - index++; - } - } - - WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatList: numFormats: %"PRIu32"", - formatList.numFormats); + WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatList: numFormats: %" PRIu32 "", + formatList.numFormats); if (context->ServerFormatList) { if ((error = context->ServerFormatList(context, &formatList))) - WLog_ERR(TAG, "ServerFormatList failed with error %"PRIu32"", error); + WLog_ERR(TAG, "ServerFormatList failed with error %" PRIu32 "", error); } error_out: - if (formats) - { - for (index = 0; index < formatList.numFormats; index++) - { - free(formats[index].formatName); - } - - free(formats); - } + cliprdr_free_format_list(&formatList); return error; } @@ -245,9 +79,10 @@ error_out: * * @return 0 on success, otherwise a Win32 error code */ -UINT cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags) +UINT cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, + UINT16 msgFlags) { - CLIPRDR_FORMAT_LIST_RESPONSE formatListResponse; + CLIPRDR_FORMAT_LIST_RESPONSE formatListResponse = { 0 }; CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); UINT error = CHANNEL_RC_OK; @@ -265,7 +100,7 @@ UINT cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, wStream* s, UI IFCALLRET(context->ServerFormatListResponse, error, context, &formatListResponse); if (error) - WLog_ERR(TAG, "ServerFormatListResponse failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "ServerFormatListResponse failed with error %" PRIu32 "!", error); return error; } @@ -275,7 +110,8 @@ UINT cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, wStream* s, UI * * @return 0 on success, otherwise a Win32 error code */ -UINT cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags) +UINT cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, + UINT16 msgFlags) { CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest; CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); @@ -293,12 +129,13 @@ UINT cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UIN formatDataRequest.msgFlags = msgFlags; formatDataRequest.dataLen = dataLen; - Stream_Read_UINT32(s, formatDataRequest.requestedFormatId); /* requestedFormatId (4 bytes) */ - + if ((error = cliprdr_read_format_data_request(s, &formatDataRequest))) + return error; + context->lastRequestedFormatId = formatDataRequest.requestedFormatId; IFCALLRET(context->ServerFormatDataRequest, error, context, &formatDataRequest); if (error) - WLog_ERR(TAG, "ServerFormatDataRequest failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "ServerFormatDataRequest failed with error %" PRIu32 "!", error); return error; } @@ -308,7 +145,8 @@ UINT cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UIN * * @return 0 on success, otherwise a Win32 error code */ -UINT cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags) +UINT cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, + UINT16 msgFlags) { CLIPRDR_FORMAT_DATA_RESPONSE formatDataResponse; CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); @@ -325,14 +163,13 @@ UINT cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UI formatDataResponse.msgType = CB_FORMAT_DATA_RESPONSE; formatDataResponse.msgFlags = msgFlags; formatDataResponse.dataLen = dataLen; - formatDataResponse.requestedFormatData = NULL; - if (dataLen) - formatDataResponse.requestedFormatData = (BYTE*) Stream_Pointer(s); + if ((error = cliprdr_read_format_data_response(s, &formatDataResponse))) + return error; IFCALLRET(context->ServerFormatDataResponse, error, context, &formatDataResponse); if (error) - WLog_ERR(TAG, "ServerFormatDataResponse failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "ServerFormatDataResponse failed with error %" PRIu32 "!", error); return error; } @@ -340,17 +177,17 @@ UINT cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UI static UINT64 filetime_to_uint64(FILETIME value) { UINT64 converted = 0; - converted |= (UINT32) value.dwHighDateTime; + converted |= (UINT32)value.dwHighDateTime; converted <<= 32; - converted |= (UINT32) value.dwLowDateTime; + converted |= (UINT32)value.dwLowDateTime; return converted; } static FILETIME uint64_to_filetime(UINT64 value) { FILETIME converted; - converted.dwLowDateTime = (UINT32) (value >> 0); - converted.dwHighDateTime = (UINT32) (value >> 32); + converted.dwLowDateTime = (UINT32)(value >> 0); + converted.dwHighDateTime = (UINT32)(value >> 32); return converted; } @@ -369,7 +206,7 @@ static FILETIME uint64_to_filetime(UINT64 value) * @returns 0 on success, otherwise a Win32 error code. */ UINT cliprdr_parse_file_list(const BYTE* format_data, UINT32 format_data_length, - FILEDESCRIPTOR** file_descriptor_array, UINT32* file_descriptor_count) + FILEDESCRIPTOR** file_descriptor_array, UINT32* file_descriptor_count) { UINT result = NO_ERROR; UINT32 i; @@ -379,7 +216,7 @@ UINT cliprdr_parse_file_list(const BYTE* format_data, UINT32 format_data_length, if (!format_data || !file_descriptor_array || !file_descriptor_count) return ERROR_BAD_ARGUMENTS; - s = Stream_New((BYTE*) format_data, format_data_length); + s = Stream_New((BYTE*)format_data, format_data_length); if (!s) return ERROR_NOT_ENOUGH_MEMORY; @@ -395,9 +232,8 @@ UINT cliprdr_parse_file_list(const BYTE* format_data, UINT32 format_data_length, if (Stream_GetRemainingLength(s) / CLIPRDR_FILEDESCRIPTOR_SIZE < count) { - WLog_ERR(TAG, "packed file list is too short: expected %"PRIuz", have %"PRIuz, - ((size_t) count) * CLIPRDR_FILEDESCRIPTOR_SIZE, - Stream_GetRemainingLength(s)); + WLog_ERR(TAG, "packed file list is too short: expected %" PRIuz ", have %" PRIuz, + ((size_t)count) * CLIPRDR_FILEDESCRIPTOR_SIZE, Stream_GetRemainingLength(s)); result = ERROR_INCORRECT_SIZE; goto out; @@ -417,21 +253,21 @@ UINT cliprdr_parse_file_list(const BYTE* format_data, UINT32 format_data_length, UINT64 lastWriteTime; FILEDESCRIPTOR* file = &((*file_descriptor_array)[i]); - Stream_Read_UINT32(s, file->dwFlags); /* flags (4 bytes) */ - Stream_Seek(s, 32); /* reserved1 (32 bytes) */ + Stream_Read_UINT32(s, file->dwFlags); /* flags (4 bytes) */ + Stream_Seek(s, 32); /* reserved1 (32 bytes) */ Stream_Read_UINT32(s, file->dwFileAttributes); /* fileAttributes (4 bytes) */ - Stream_Seek(s, 16); /* reserved2 (16 bytes) */ - Stream_Read_UINT64(s, lastWriteTime); /* lastWriteTime (8 bytes) */ + Stream_Seek(s, 16); /* reserved2 (16 bytes) */ + Stream_Read_UINT64(s, lastWriteTime); /* lastWriteTime (8 bytes) */ file->ftLastWriteTime = uint64_to_filetime(lastWriteTime); Stream_Read_UINT32(s, file->nFileSizeHigh); /* fileSizeHigh (4 bytes) */ - Stream_Read_UINT32(s, file->nFileSizeLow); /* fileSizeLow (4 bytes) */ - for (c = 0; c < 260; c++) /* cFileName (520 bytes) */ + Stream_Read_UINT32(s, file->nFileSizeLow); /* fileSizeLow (4 bytes) */ + for (c = 0; c < 260; c++) /* cFileName (520 bytes) */ Stream_Read_UINT16(s, file->cFileName[c]); } if (Stream_GetRemainingLength(s) > 0) - WLog_WARN(TAG, "packed file list has %"PRIuz" excess bytes", - Stream_GetRemainingLength(s)); + WLog_WARN(TAG, "packed file list has %" PRIuz " excess bytes", + Stream_GetRemainingLength(s)); out: Stream_Free(s, FALSE); @@ -453,7 +289,8 @@ out: * @returns 0 on success, otherwise a Win32 error code. */ UINT cliprdr_serialize_file_list(const FILEDESCRIPTOR* file_descriptor_array, - UINT32 file_descriptor_count, BYTE** format_data, UINT32* format_data_length) + UINT32 file_descriptor_count, BYTE** format_data, + UINT32* format_data_length) { UINT result = NO_ERROR; UINT32 i; @@ -488,15 +325,15 @@ UINT cliprdr_serialize_file_list(const FILEDESCRIPTOR* file_descriptor_array, goto error; } - Stream_Write_UINT32(s, file->dwFlags); /* flags (4 bytes) */ - Stream_Zero(s, 32); /* reserved1 (32 bytes) */ + Stream_Write_UINT32(s, file->dwFlags); /* flags (4 bytes) */ + Stream_Zero(s, 32); /* reserved1 (32 bytes) */ Stream_Write_UINT32(s, file->dwFileAttributes); /* fileAttributes (4 bytes) */ - Stream_Zero(s, 16); /* reserved2 (16 bytes) */ + Stream_Zero(s, 16); /* reserved2 (16 bytes) */ lastWriteTime = filetime_to_uint64(file->ftLastWriteTime); - Stream_Write_UINT64(s, lastWriteTime); /* lastWriteTime (8 bytes) */ + Stream_Write_UINT64(s, lastWriteTime); /* lastWriteTime (8 bytes) */ Stream_Write_UINT32(s, file->nFileSizeHigh); /* fileSizeHigh (4 bytes) */ - Stream_Write_UINT32(s, file->nFileSizeLow); /* fileSizeLow (4 bytes) */ - for (c = 0; c < 260; c++) /* cFileName (520 bytes) */ + Stream_Write_UINT32(s, file->nFileSizeLow); /* fileSizeLow (4 bytes) */ + for (c = 0; c < 260; c++) /* cFileName (520 bytes) */ Stream_Write_UINT16(s, file->cFileName[c]); } diff --git a/channels/cliprdr/client/cliprdr_format.h b/channels/cliprdr/client/cliprdr_format.h index dfe6965..a068d6f 100644 --- a/channels/cliprdr/client/cliprdr_format.h +++ b/channels/cliprdr/client/cliprdr_format.h @@ -23,9 +23,13 @@ #ifndef FREERDP_CHANNEL_CLIPRDR_CLIENT_FORMAT_H #define FREERDP_CHANNEL_CLIPRDR_CLIENT_FORMAT_H -UINT cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags); -UINT cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags); -UINT cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags); -UINT cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags); +UINT cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, + UINT16 msgFlags); +UINT cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, + UINT16 msgFlags); +UINT cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, + UINT16 msgFlags); +UINT cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, + UINT16 msgFlags); #endif /* FREERDP_CHANNEL_CLIPRDR_CLIENT_FORMAT_H */ diff --git a/channels/cliprdr/client/cliprdr_main.c b/channels/cliprdr/client/cliprdr_main.c index 8ab0903..b5d119a 100644 --- a/channels/cliprdr/client/cliprdr_main.c +++ b/channels/cliprdr/client/cliprdr_main.c @@ -33,23 +33,21 @@ #include "cliprdr_main.h" #include "cliprdr_format.h" +#include "../cliprdr_common.h" #ifdef WITH_DEBUG_CLIPRDR -static const char* const CB_MSG_TYPE_STRINGS[] = -{ - "", - "CB_MONITOR_READY", - "CB_FORMAT_LIST", - "CB_FORMAT_LIST_RESPONSE", - "CB_FORMAT_DATA_REQUEST", - "CB_FORMAT_DATA_RESPONSE", - "CB_TEMP_DIRECTORY", - "CB_CLIP_CAPS", - "CB_FILECONTENTS_REQUEST", - "CB_FILECONTENTS_RESPONSE", - "CB_LOCK_CLIPDATA", - "CB_UNLOCK_CLIPDATA" -}; +static const char* const CB_MSG_TYPE_STRINGS[] = { "", + "CB_MONITOR_READY", + "CB_FORMAT_LIST", + "CB_FORMAT_LIST_RESPONSE", + "CB_FORMAT_DATA_REQUEST", + "CB_FORMAT_DATA_RESPONSE", + "CB_TEMP_DIRECTORY", + "CB_CLIP_CAPS", + "CB_FILECONTENTS_REQUEST", + "CB_FILECONTENTS_RESPONSE", + "CB_LOCK_CLIPDATA", + "CB_UNLOCK_CLIPDATA" }; #endif CliprdrClientContext* cliprdr_get_client_interface(cliprdrPlugin* cliprdr) @@ -59,29 +57,10 @@ CliprdrClientContext* cliprdr_get_client_interface(cliprdrPlugin* cliprdr) if (!cliprdr) return NULL; - pInterface = (CliprdrClientContext*) cliprdr->channelEntryPoints.pInterface; + pInterface = (CliprdrClientContext*)cliprdr->channelEntryPoints.pInterface; return pInterface; } -static wStream* cliprdr_packet_new(UINT16 msgType, UINT16 msgFlags, - UINT32 dataLen) -{ - wStream* s; - s = Stream_New(NULL, dataLen + 8); - - if (!s) - { - WLog_ERR(TAG, "Stream_New failed!"); - return NULL; - } - - Stream_Write_UINT16(s, msgType); - Stream_Write_UINT16(s, msgFlags); - /* Write actual length after the entire packet has been constructed. */ - Stream_Seek(s, 4); - return s; -} - /** * Function description * @@ -98,7 +77,7 @@ static UINT cliprdr_packet_send(cliprdrPlugin* cliprdr, wStream* s) Stream_Write_UINT32(s, dataLen); Stream_SetPosition(s, pos); #ifdef WITH_DEBUG_CLIPRDR - WLog_DBG(TAG, "Cliprdr Sending (%"PRIu32" bytes)", dataLen + 8); + WLog_DBG(TAG, "Cliprdr Sending (%" PRIu32 " bytes)", dataLen + 8); winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), dataLen + 8); #endif @@ -108,14 +87,17 @@ static UINT cliprdr_packet_send(cliprdrPlugin* cliprdr, wStream* s) } else { - status = cliprdr->channelEntryPoints.pVirtualChannelWriteEx(cliprdr->InitHandle, - cliprdr->OpenHandle, - Stream_Buffer(s), (UINT32) Stream_GetPosition(s), s); + status = cliprdr->channelEntryPoints.pVirtualChannelWriteEx( + cliprdr->InitHandle, cliprdr->OpenHandle, Stream_Buffer(s), + (UINT32)Stream_GetPosition(s), s); } if (status != CHANNEL_RC_OK) - WLog_ERR(TAG, "VirtualChannelWrite failed with %s [%08"PRIX32"]", + { + Stream_Free(s, TRUE); + WLog_ERR(TAG, "VirtualChannelWrite failed with %s [%08" PRIX32 "]", WTSErrorToString(status), status); + } return status; } @@ -123,21 +105,21 @@ static UINT cliprdr_packet_send(cliprdrPlugin* cliprdr, wStream* s) #ifdef WITH_DEBUG_CLIPRDR static void cliprdr_print_general_capability_flags(UINT32 flags) { - WLog_INFO(TAG, "generalFlags (0x%08"PRIX32") {", flags); + WLog_INFO(TAG, "generalFlags (0x%08" PRIX32 ") {", flags); if (flags & CB_USE_LONG_FORMAT_NAMES) - WLog_INFO(TAG, "\tCB_USE_LONG_FORMAT_NAMES"); + WLog_INFO(TAG, "\tCB_USE_LONG_FORMAT_NAMES"); if (flags & CB_STREAM_FILECLIP_ENABLED) - WLog_INFO(TAG, "\tCB_STREAM_FILECLIP_ENABLED"); + WLog_INFO(TAG, "\tCB_STREAM_FILECLIP_ENABLED"); if (flags & CB_FILECLIP_NO_FILE_PATHS) - WLog_INFO(TAG, "\tCB_FILECLIP_NO_FILE_PATHS"); + WLog_INFO(TAG, "\tCB_FILECLIP_NO_FILE_PATHS"); if (flags & CB_CAN_LOCK_CLIPDATA) - WLog_INFO(TAG, "\tCB_CAN_LOCK_CLIPDATA"); + WLog_INFO(TAG, "\tCB_CAN_LOCK_CLIPDATA"); - WLog_INFO(TAG, "}"); + WLog_INFO(TAG, "}"); } #endif @@ -146,8 +128,7 @@ static void cliprdr_print_general_capability_flags(UINT32 flags) * * @return 0 on success, otherwise a Win32 error code */ -static UINT cliprdr_process_general_capability(cliprdrPlugin* cliprdr, - wStream* s) +static UINT cliprdr_process_general_capability(cliprdrPlugin* cliprdr, wStream* s) { UINT32 version; UINT32 generalFlags; @@ -165,28 +146,17 @@ static UINT cliprdr_process_general_capability(cliprdrPlugin* cliprdr, if (Stream_GetRemainingLength(s) < 8) return ERROR_INVALID_DATA; - Stream_Read_UINT32(s, version); /* version (4 bytes) */ + Stream_Read_UINT32(s, version); /* version (4 bytes) */ Stream_Read_UINT32(s, generalFlags); /* generalFlags (4 bytes) */ - DEBUG_CLIPRDR("Version: %"PRIu32"", version); + DEBUG_CLIPRDR("Version: %" PRIu32 "", version); #ifdef WITH_DEBUG_CLIPRDR cliprdr_print_general_capability_flags(generalFlags); #endif - if (cliprdr->useLongFormatNames) - cliprdr->useLongFormatNames = (generalFlags & CB_USE_LONG_FORMAT_NAMES) ? TRUE : - FALSE; - - if (cliprdr->streamFileClipEnabled) - cliprdr->streamFileClipEnabled = (generalFlags & CB_STREAM_FILECLIP_ENABLED) ? - TRUE : FALSE; - - if (cliprdr->fileClipNoFilePaths) - cliprdr->fileClipNoFilePaths = (generalFlags & CB_FILECLIP_NO_FILE_PATHS) ? - TRUE : FALSE; - - if (cliprdr->canLockClipData) - cliprdr->canLockClipData = (generalFlags & CB_CAN_LOCK_CLIPDATA) ? TRUE : FALSE; - + cliprdr->useLongFormatNames = (generalFlags & CB_USE_LONG_FORMAT_NAMES); + cliprdr->streamFileClipEnabled = (generalFlags & CB_STREAM_FILECLIP_ENABLED); + cliprdr->fileClipNoFilePaths = (generalFlags & CB_FILECLIP_NO_FILE_PATHS); + cliprdr->canLockClipData = (generalFlags & CB_CAN_LOCK_CLIPDATA); cliprdr->capabilitiesReceived = TRUE; if (!context->custom) @@ -195,9 +165,9 @@ static UINT cliprdr_process_general_capability(cliprdrPlugin* cliprdr, return ERROR_INTERNAL_ERROR; } + capabilities.msgType = CB_CLIP_CAPS; capabilities.cCapabilitiesSets = 1; - capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*) & - (generalCapabilitySet); + capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*)&(generalCapabilitySet); generalCapabilitySet.capabilitySetType = CB_CAPSTYPE_GENERAL; generalCapabilitySet.capabilitySetLength = 12; generalCapabilitySet.version = version; @@ -205,7 +175,7 @@ static UINT cliprdr_process_general_capability(cliprdrPlugin* cliprdr, IFCALLRET(context->ServerCapabilities, error, context, &capabilities); if (error) - WLog_ERR(TAG, "ServerCapabilities failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "ServerCapabilities failed with error %" PRIu32 "!", error); return error; } @@ -215,8 +185,8 @@ 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) +static UINT cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, wStream* s, UINT32 length, + UINT16 flags) { UINT16 index; UINT16 lengthCapability; @@ -228,7 +198,7 @@ static UINT cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, wStream* s, return ERROR_INVALID_DATA; Stream_Read_UINT16(s, cCapabilitiesSets); /* cCapabilitiesSets (2 bytes) */ - Stream_Seek_UINT16(s); /* pad1 (2 bytes) */ + Stream_Seek_UINT16(s); /* pad1 (2 bytes) */ WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerCapabilities"); for (index = 0; index < cCapabilitiesSets; index++) @@ -237,9 +207,9 @@ static UINT cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, wStream* s, return ERROR_INVALID_DATA; Stream_Read_UINT16(s, capabilitySetType); /* capabilitySetType (2 bytes) */ - Stream_Read_UINT16(s, lengthCapability); /* lengthCapability (2 bytes) */ + Stream_Read_UINT16(s, lengthCapability); /* lengthCapability (2 bytes) */ - if (lengthCapability < 4 || Stream_GetRemainingLength(s) < lengthCapability - 4) + if ((lengthCapability < 4) || (Stream_GetRemainingLength(s) < (lengthCapability - 4U))) return ERROR_INVALID_DATA; switch (capabilitySetType) @@ -247,7 +217,8 @@ static UINT cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, wStream* s, case CB_CAPSTYPE_GENERAL: if ((error = cliprdr_process_general_capability(cliprdr, s))) { - WLog_ERR(TAG, "cliprdr_process_general_capability failed with error %"PRIu32"!", + WLog_ERR(TAG, + "cliprdr_process_general_capability failed with error %" PRIu32 "!", error); return error; } @@ -255,9 +226,8 @@ static UINT cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, wStream* s, break; default: - WLog_ERR(TAG, "unknown cliprdr capability set: %"PRIu16"", capabilitySetType); + WLog_ERR(TAG, "unknown cliprdr capability set: %" PRIu16 "", capabilitySetType); return CHANNEL_RC_BAD_PROC; - break; } } @@ -269,8 +239,8 @@ 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) +static UINT cliprdr_process_monitor_ready(cliprdrPlugin* cliprdr, wStream* s, UINT32 length, + UINT16 flags) { CLIPRDR_MONITOR_READY monitorReady; CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); @@ -286,11 +256,11 @@ static UINT cliprdr_process_monitor_ready(cliprdrPlugin* cliprdr, wStream* s, if (!cliprdr->capabilitiesReceived) { /** - * The clipboard capabilities pdu from server to client is optional, - * but a server using it must send it before sending the monitor ready pdu. - * When the server capabilities pdu is not used, default capabilities - * corresponding to a generalFlags field set to zero are assumed. - */ + * The clipboard capabilities pdu from server to client is optional, + * but a server using it must send it before sending the monitor ready pdu. + * When the server capabilities pdu is not used, default capabilities + * corresponding to a generalFlags field set to zero are assumed. + */ cliprdr->useLongFormatNames = FALSE; cliprdr->streamFileClipEnabled = FALSE; cliprdr->fileClipNoFilePaths = TRUE; @@ -303,7 +273,7 @@ static UINT cliprdr_process_monitor_ready(cliprdrPlugin* cliprdr, wStream* s, IFCALLRET(context->MonitorReady, error, context, &monitorReady); if (error) - WLog_ERR(TAG, "MonitorReady failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "MonitorReady failed with error %" PRIu32 "!", error); return error; } @@ -313,8 +283,8 @@ static UINT cliprdr_process_monitor_ready(cliprdrPlugin* cliprdr, wStream* s, * * @return 0 on success, otherwise a Win32 error code */ -static UINT cliprdr_process_filecontents_request(cliprdrPlugin* cliprdr, - wStream* s, UINT32 length, UINT16 flags) +static UINT cliprdr_process_filecontents_request(cliprdrPlugin* cliprdr, wStream* s, UINT32 length, + UINT16 flags) { CLIPRDR_FILE_CONTENTS_REQUEST request; CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); @@ -327,33 +297,17 @@ static UINT cliprdr_process_filecontents_request(cliprdrPlugin* cliprdr, return ERROR_INTERNAL_ERROR; } - if (Stream_GetRemainingLength(s) < 24) - { - WLog_ERR(TAG, "not enough remaining data"); - return ERROR_INVALID_DATA; - } - request.msgType = CB_FILECONTENTS_REQUEST; request.msgFlags = flags; request.dataLen = length; - request.haveClipDataId = FALSE; - Stream_Read_UINT32(s, request.streamId); /* streamId (4 bytes) */ - Stream_Read_UINT32(s, request.listIndex); /* listIndex (4 bytes) */ - Stream_Read_UINT32(s, request.dwFlags); /* dwFlags (4 bytes) */ - Stream_Read_UINT32(s, request.nPositionLow); /* nPositionLow (4 bytes) */ - Stream_Read_UINT32(s, request.nPositionHigh); /* nPositionHigh (4 bytes) */ - Stream_Read_UINT32(s, request.cbRequested); /* cbRequested (4 bytes) */ - - if (Stream_GetRemainingLength(s) >= 4) - { - Stream_Read_UINT32(s, request.clipDataId); /* clipDataId (4 bytes) */ - request.haveClipDataId = TRUE; - } + + if ((error = cliprdr_read_file_contents_request(s, &request))) + return error; IFCALLRET(context->ServerFileContentsRequest, error, context, &request); if (error) - WLog_ERR(TAG, "ServerFileContentsRequest failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "ServerFileContentsRequest failed with error %" PRIu32 "!", error); return error; } @@ -363,8 +317,8 @@ static UINT cliprdr_process_filecontents_request(cliprdrPlugin* cliprdr, * * @return 0 on success, otherwise a Win32 error code */ -static UINT cliprdr_process_filecontents_response(cliprdrPlugin* cliprdr, - wStream* s, UINT32 length, UINT16 flags) +static UINT cliprdr_process_filecontents_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 length, + UINT16 flags) { CLIPRDR_FILE_CONTENTS_RESPONSE response; CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); @@ -377,22 +331,17 @@ static UINT cliprdr_process_filecontents_response(cliprdrPlugin* cliprdr, return ERROR_INTERNAL_ERROR; } - if (Stream_GetRemainingLength(s) < 4) - { - WLog_ERR(TAG, "not enough remaining data"); - return ERROR_INVALID_DATA; - } - response.msgType = CB_FILECONTENTS_RESPONSE; response.msgFlags = flags; response.dataLen = length; - Stream_Read_UINT32(s, response.streamId); /* streamId (4 bytes) */ - response.cbRequested = length - 4; - response.requestedData = Stream_Pointer(s); /* requestedFileContentsData */ + + if ((error = cliprdr_read_file_contents_response(s, &response))) + return error; + IFCALLRET(context->ServerFileContentsResponse, error, context, &response); if (error) - WLog_ERR(TAG, "ServerFileContentsResponse failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "ServerFileContentsResponse failed with error %" PRIu32 "!", error); return error; } @@ -402,8 +351,8 @@ static UINT cliprdr_process_filecontents_response(cliprdrPlugin* cliprdr, * * @return 0 on success, otherwise a Win32 error code */ -static UINT cliprdr_process_lock_clipdata(cliprdrPlugin* cliprdr, wStream* s, - UINT32 length, UINT16 flags) +static UINT cliprdr_process_lock_clipdata(cliprdrPlugin* cliprdr, wStream* s, UINT32 length, + UINT16 flags) { CLIPRDR_LOCK_CLIPBOARD_DATA lockClipboardData; CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); @@ -429,7 +378,7 @@ static UINT cliprdr_process_lock_clipdata(cliprdrPlugin* cliprdr, wStream* s, IFCALLRET(context->ServerLockClipboardData, error, context, &lockClipboardData); if (error) - WLog_ERR(TAG, "ServerLockClipboardData failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "ServerLockClipboardData failed with error %" PRIu32 "!", error); return error; } @@ -439,8 +388,8 @@ static UINT cliprdr_process_lock_clipdata(cliprdrPlugin* cliprdr, wStream* s, * * @return 0 on success, otherwise a Win32 error code */ -static UINT cliprdr_process_unlock_clipdata(cliprdrPlugin* cliprdr, wStream* s, - UINT32 length, UINT16 flags) +static UINT cliprdr_process_unlock_clipdata(cliprdrPlugin* cliprdr, wStream* s, UINT32 length, + UINT16 flags) { CLIPRDR_UNLOCK_CLIPBOARD_DATA unlockClipboardData; CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); @@ -453,21 +402,17 @@ static UINT cliprdr_process_unlock_clipdata(cliprdrPlugin* cliprdr, wStream* s, return ERROR_INTERNAL_ERROR; } - if (Stream_GetRemainingLength(s) < 4) - { - WLog_ERR(TAG, "not enough remaining data"); - return ERROR_INVALID_DATA; - } + if ((error = cliprdr_read_unlock_clipdata(s, &unlockClipboardData))) + return error; unlockClipboardData.msgType = CB_UNLOCK_CLIPDATA; unlockClipboardData.msgFlags = flags; unlockClipboardData.dataLen = length; - Stream_Read_UINT32(s, unlockClipboardData.clipDataId); /* clipDataId (4 bytes) */ - IFCALLRET(context->ServerUnlockClipboardData, error, context, - &unlockClipboardData); + + IFCALLRET(context->ServerUnlockClipboardData, error, context, &unlockClipboardData); if (error) - WLog_ERR(TAG, "ServerUnlockClipboardData failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "ServerUnlockClipboardData failed with error %" PRIu32 "!", error); return error; } @@ -487,15 +432,15 @@ static UINT cliprdr_order_recv(cliprdrPlugin* cliprdr, wStream* s) if (Stream_GetRemainingLength(s) < 8) return ERROR_INVALID_DATA; - Stream_Read_UINT16(s, msgType); /* msgType (2 bytes) */ + Stream_Read_UINT16(s, msgType); /* msgType (2 bytes) */ Stream_Read_UINT16(s, msgFlags); /* msgFlags (2 bytes) */ - Stream_Read_UINT32(s, dataLen); /* dataLen (4 bytes) */ + Stream_Read_UINT32(s, dataLen); /* dataLen (4 bytes) */ if (Stream_GetRemainingLength(s) < dataLen) return ERROR_INVALID_DATA; #ifdef WITH_DEBUG_CLIPRDR - WLog_DBG(TAG, "msgType: %s (%"PRIu16"), msgFlags: %"PRIu16" dataLen: %"PRIu32"", + WLog_DBG(TAG, "msgType: %s (%" PRIu16 "), msgFlags: %" PRIu16 " dataLen: %" PRIu32 "", CB_MSG_TYPE_STRINGS[msgType], msgType, msgFlags, dataLen); winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), dataLen + 8); #endif @@ -504,72 +449,76 @@ static UINT cliprdr_order_recv(cliprdrPlugin* cliprdr, wStream* s) { case CB_CLIP_CAPS: if ((error = cliprdr_process_clip_caps(cliprdr, s, dataLen, msgFlags))) - WLog_ERR(TAG, "cliprdr_process_clip_caps failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "cliprdr_process_clip_caps failed with error %" PRIu32 "!", error); break; case CB_MONITOR_READY: if ((error = cliprdr_process_monitor_ready(cliprdr, s, dataLen, msgFlags))) - WLog_ERR(TAG, "cliprdr_process_monitor_ready failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "cliprdr_process_monitor_ready failed with error %" PRIu32 "!", + error); break; case CB_FORMAT_LIST: if ((error = cliprdr_process_format_list(cliprdr, s, dataLen, msgFlags))) - WLog_ERR(TAG, "cliprdr_process_format_list failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "cliprdr_process_format_list failed with error %" PRIu32 "!", error); break; case CB_FORMAT_LIST_RESPONSE: if ((error = cliprdr_process_format_list_response(cliprdr, s, dataLen, msgFlags))) - WLog_ERR(TAG, "cliprdr_process_format_list_response failed with error %"PRIu32"!", + WLog_ERR(TAG, "cliprdr_process_format_list_response failed with error %" PRIu32 "!", error); break; case CB_FORMAT_DATA_REQUEST: if ((error = cliprdr_process_format_data_request(cliprdr, s, dataLen, msgFlags))) - WLog_ERR(TAG, "cliprdr_process_format_data_request failed with error %"PRIu32"!", + WLog_ERR(TAG, "cliprdr_process_format_data_request failed with error %" PRIu32 "!", error); break; case CB_FORMAT_DATA_RESPONSE: if ((error = cliprdr_process_format_data_response(cliprdr, s, dataLen, msgFlags))) - WLog_ERR(TAG, "cliprdr_process_format_data_response failed with error %"PRIu32"!", + WLog_ERR(TAG, "cliprdr_process_format_data_response failed with error %" PRIu32 "!", error); break; case CB_FILECONTENTS_REQUEST: if ((error = cliprdr_process_filecontents_request(cliprdr, s, dataLen, msgFlags))) - WLog_ERR(TAG, "cliprdr_process_filecontents_request failed with error %"PRIu32"!", + WLog_ERR(TAG, "cliprdr_process_filecontents_request failed with error %" PRIu32 "!", error); break; case CB_FILECONTENTS_RESPONSE: if ((error = cliprdr_process_filecontents_response(cliprdr, s, dataLen, msgFlags))) - WLog_ERR(TAG, "cliprdr_process_filecontents_response failed with error %"PRIu32"!", + WLog_ERR(TAG, + "cliprdr_process_filecontents_response failed with error %" PRIu32 "!", error); break; case CB_LOCK_CLIPDATA: if ((error = cliprdr_process_lock_clipdata(cliprdr, s, dataLen, msgFlags))) - WLog_ERR(TAG, "cliprdr_process_lock_clipdata failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "cliprdr_process_lock_clipdata failed with error %" PRIu32 "!", + error); break; case CB_UNLOCK_CLIPDATA: if ((error = cliprdr_process_unlock_clipdata(cliprdr, s, dataLen, msgFlags))) - WLog_ERR(TAG, "cliprdr_process_lock_clipdata failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "cliprdr_process_lock_clipdata failed with error %" PRIu32 "!", + error); break; default: error = CHANNEL_RC_BAD_PROC; - WLog_ERR(TAG, "unknown msgType %"PRIu16"", msgType); + WLog_ERR(TAG, "unknown msgType %" PRIu16 "", msgType); break; } @@ -587,11 +536,13 @@ 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; - cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle; + UINT32 flags; + const CLIPRDR_GENERAL_CAPABILITY_SET* generalCapabilitySet; + cliprdrPlugin* cliprdr = (cliprdrPlugin*)context->handle; + s = cliprdr_packet_new(CB_CLIP_CAPS, 0, 4 + CB_CAPSTYPE_GENERAL_LEN); if (!s) @@ -602,11 +553,31 @@ 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; - Stream_Write_UINT16(s, generalCapabilitySet->capabilitySetType); /* capabilitySetType */ + 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 */ - Stream_Write_UINT32(s, generalCapabilitySet->generalFlags); /* generalFlags */ + Stream_Write_UINT32(s, generalCapabilitySet->version); /* version */ + flags = generalCapabilitySet->generalFlags; + + /* Client capabilities are sent in response to server capabilities. + * -> Do not request features the server does not support. + * -> Update clipboard context feature state to what was agreed upon. + */ + if (!cliprdr->useLongFormatNames) + flags &= ~CB_USE_LONG_FORMAT_NAMES; + if (!cliprdr->streamFileClipEnabled) + flags &= ~CB_STREAM_FILECLIP_ENABLED; + if (!cliprdr->fileClipNoFilePaths) + flags &= ~CB_FILECLIP_NO_FILE_PATHS; + if (!cliprdr->canLockClipData) + flags &= CB_CAN_LOCK_CLIPDATA; + + cliprdr->useLongFormatNames = flags & CB_USE_LONG_FORMAT_NAMES; + cliprdr->streamFileClipEnabled = flags & CB_STREAM_FILECLIP_ENABLED; + cliprdr->fileClipNoFilePaths = flags & CB_FILECLIP_NO_FILE_PATHS; + cliprdr->canLockClipData = flags & CB_CAN_LOCK_CLIPDATA; + + Stream_Write_UINT32(s, flags); /* generalFlags */ WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientCapabilities"); return cliprdr_packet_send(cliprdr, s); } @@ -617,13 +588,13 @@ 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; WCHAR* wszTempDir = NULL; - cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle; - s = cliprdr_packet_new(CB_TEMP_DIRECTORY, 0, 520 * 2); + cliprdrPlugin* cliprdr = (cliprdrPlugin*)context->handle; + s = cliprdr_packet_new(CB_TEMP_DIRECTORY, 0, 260 * sizeof(WCHAR)); if (!s) { @@ -636,14 +607,15 @@ static UINT cliprdr_temp_directory(CliprdrClientContext* context, if (length < 0) return ERROR_INTERNAL_ERROR; - if (length > 520) - length = 520; + /* Path must be 260 UTF16 characters with '\0' termination. + * ensure this here */ + if (length >= 260) + length = 259; - Stream_Write(s, wszTempDir, length * 2); - Stream_Zero(s, (520 - length) * 2); + Stream_Write_UTF16_String(s, wszTempDir, length); + Stream_Zero(s, 520 - (length * sizeof(WCHAR))); free(wszTempDir); - WLog_Print(cliprdr->log, WLOG_DEBUG, "TempDirectory: %s", - tempDirectory->szTempDir); + WLog_Print(cliprdr->log, WLOG_DEBUG, "TempDirectory: %s", tempDirectory->szTempDir); return cliprdr_packet_send(cliprdr, s); } @@ -653,114 +625,19 @@ 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; - int cchWideChar; - LPWSTR lpWideCharStr; - int formatNameSize; - int formatNameLength; - char* szFormatName; - WCHAR* wszFormatName; - BOOL asciiNames = FALSE; - CLIPRDR_FORMAT* format; - cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle; - - if (!cliprdr->useLongFormatNames) - { - length = formatList->numFormats * 36; - s = cliprdr_packet_new(CB_FORMAT_LIST, 0, length); + cliprdrPlugin* cliprdr = (cliprdrPlugin*)context->handle; - if (!s) - { - WLog_ERR(TAG, "cliprdr_packet_new failed!"); - return ERROR_INTERNAL_ERROR; - } - - for (index = 0; index < formatList->numFormats; index++) - { - format = (CLIPRDR_FORMAT*) & (formatList->formats[index]); - Stream_Write_UINT32(s, format->formatId); /* formatId (4 bytes) */ - formatNameSize = 0; - formatNameLength = 0; - szFormatName = format->formatName; - - if (asciiNames) - { - if (szFormatName) - formatNameLength = strlen(szFormatName); - - if (formatNameLength > 31) - formatNameLength = 31; - - Stream_Write(s, szFormatName, formatNameLength); - Stream_Zero(s, 32 - formatNameLength); - } - else - { - wszFormatName = NULL; - - if (szFormatName) - formatNameSize = ConvertToUnicode(CP_UTF8, 0, szFormatName, -1, &wszFormatName, - 0); - - if (formatNameSize > 15) - formatNameSize = 15; - - if (wszFormatName) - Stream_Write(s, wszFormatName, formatNameSize * 2); - - Stream_Zero(s, 32 - (formatNameSize * 2)); - free(wszFormatName); - } - } - } - else + s = cliprdr_packet_format_list_new(formatList, cliprdr->useLongFormatNames); + if (!s) { - for (index = 0; index < formatList->numFormats; index++) - { - format = (CLIPRDR_FORMAT*) & (formatList->formats[index]); - length += 4; - formatNameSize = 2; - - if (format->formatName) - formatNameSize = MultiByteToWideChar(CP_UTF8, 0, format->formatName, -1, NULL, - 0) * 2; - - length += formatNameSize; - } - - s = cliprdr_packet_new(CB_FORMAT_LIST, 0, length); - - if (!s) - { - WLog_ERR(TAG, "cliprdr_packet_new failed!"); - return ERROR_INTERNAL_ERROR; - } - - for (index = 0; index < formatList->numFormats; index++) - { - format = (CLIPRDR_FORMAT*) & (formatList->formats[index]); - Stream_Write_UINT32(s, format->formatId); /* formatId (4 bytes) */ - - if (format->formatName) - { - lpWideCharStr = (LPWSTR) Stream_Pointer(s); - cchWideChar = (Stream_Capacity(s) - Stream_GetPosition(s)) / 2; - formatNameSize = MultiByteToWideChar(CP_UTF8, 0, - format->formatName, -1, lpWideCharStr, cchWideChar) * 2; - Stream_Seek(s, formatNameSize); - } - else - { - Stream_Write_UINT16(s, 0); - } - } + WLog_ERR(TAG, "cliprdr_packet_format_list_new failed!"); + return ERROR_INTERNAL_ERROR; } - WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientFormatList: numFormats: %"PRIu32"", + WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientFormatList: numFormats: %" PRIu32 "", formatList->numFormats); return cliprdr_packet_send(cliprdr, s); } @@ -770,15 +647,13 @@ 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) +static UINT +cliprdr_client_format_list_response(CliprdrClientContext* context, + 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); + cliprdrPlugin* cliprdr = (cliprdrPlugin*)context->handle; + s = cliprdr_packet_new(CB_FORMAT_LIST_RESPONSE, formatListResponse->msgFlags, 0); if (!s) { @@ -796,11 +671,11 @@ 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; - s = cliprdr_packet_new(CB_LOCK_CLIPDATA, 0, 4); + cliprdrPlugin* cliprdr = (cliprdrPlugin*)context->handle; + s = cliprdr_packet_lock_clipdata_new(lockClipboardData); if (!s) { @@ -808,9 +683,7 @@ static UINT cliprdr_client_lock_clipboard_data(CliprdrClientContext* context, return ERROR_INTERNAL_ERROR; } - Stream_Write_UINT32(s, lockClipboardData->clipDataId); /* clipDataId (4 bytes) */ - WLog_Print(cliprdr->log, WLOG_DEBUG, - "ClientLockClipboardData: clipDataId: 0x%08"PRIX32"", + WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientLockClipboardData: clipDataId: 0x%08" PRIX32 "", lockClipboardData->clipDataId); return cliprdr_packet_send(cliprdr, s); } @@ -820,12 +693,13 @@ 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) +static UINT +cliprdr_client_unlock_clipboard_data(CliprdrClientContext* context, + const CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData) { wStream* s; - cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle; - s = cliprdr_packet_new(CB_UNLOCK_CLIPDATA, 0, 4); + cliprdrPlugin* cliprdr = (cliprdrPlugin*)context->handle; + s = cliprdr_packet_unlock_clipdata_new(unlockClipboardData); if (!s) { @@ -833,9 +707,7 @@ static UINT cliprdr_client_unlock_clipboard_data(CliprdrClientContext* context, return ERROR_INTERNAL_ERROR; } - Stream_Write_UINT32(s, unlockClipboardData->clipDataId); /* clipDataId (4 bytes) */ - WLog_Print(cliprdr->log, WLOG_DEBUG, - "ClientUnlockClipboardData: clipDataId: 0x%08"PRIX32"", + WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientUnlockClipboardData: clipDataId: 0x%08" PRIX32 "", unlockClipboardData->clipDataId); return cliprdr_packet_send(cliprdr, s); } @@ -846,15 +718,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); + cliprdrPlugin* cliprdr = (cliprdrPlugin*)context->handle; + + s = cliprdr_packet_new(CB_FORMAT_DATA_REQUEST, 0, 4); if (!s) { @@ -872,14 +741,15 @@ 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) +static UINT +cliprdr_client_format_data_response(CliprdrClientContext* context, + 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, - formatDataResponse->msgFlags, formatDataResponse->dataLen); + cliprdrPlugin* cliprdr = (cliprdrPlugin*)context->handle; + + s = cliprdr_packet_new(CB_FORMAT_DATA_RESPONSE, formatDataResponse->msgFlags, + formatDataResponse->dataLen); if (!s) { @@ -887,8 +757,7 @@ static UINT cliprdr_client_format_data_response(CliprdrClientContext* context, return ERROR_INTERNAL_ERROR; } - Stream_Write(s, formatDataResponse->requestedFormatData, - formatDataResponse->dataLen); + Stream_Write(s, formatDataResponse->requestedFormatData, formatDataResponse->dataLen); WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientFormatDataResponse"); return cliprdr_packet_send(cliprdr, s); } @@ -898,31 +767,22 @@ 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) +static UINT +cliprdr_client_file_contents_request(CliprdrClientContext* context, + const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) { wStream* s; - cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle; - s = cliprdr_packet_new(CB_FILECONTENTS_REQUEST, 0, 28); + cliprdrPlugin* cliprdr = (cliprdrPlugin*)context->handle; + + s = cliprdr_packet_file_contents_request_new(fileContentsRequest); if (!s) { - WLog_ERR(TAG, "cliprdr_packet_new failed!"); + WLog_ERR(TAG, "cliprdr_packet_file_contents_request_new failed!"); return ERROR_INTERNAL_ERROR; } - Stream_Write_UINT32(s, fileContentsRequest->streamId); /* streamId (4 bytes) */ - Stream_Write_UINT32(s, fileContentsRequest->listIndex); /* listIndex (4 bytes) */ - Stream_Write_UINT32(s, fileContentsRequest->dwFlags); /* dwFlags (4 bytes) */ - Stream_Write_UINT32(s, fileContentsRequest->nPositionLow); /* nPositionLow (4 bytes) */ - Stream_Write_UINT32(s, fileContentsRequest->nPositionHigh); /* nPositionHigh (4 bytes) */ - Stream_Write_UINT32(s, fileContentsRequest->cbRequested); /* cbRequested (4 bytes) */ - - if (fileContentsRequest->haveClipDataId) - Stream_Write_UINT32(s, fileContentsRequest->clipDataId); /* clipDataId (4 bytes) */ - - WLog_Print(cliprdr->log, WLOG_DEBUG, - "ClientFileContentsRequest: streamId: 0x%08"PRIX32"", + WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientFileContentsRequest: streamId: 0x%08" PRIX32 "", fileContentsRequest->streamId); return cliprdr_packet_send(cliprdr, s); } @@ -932,13 +792,13 @@ 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) +static UINT +cliprdr_client_file_contents_response(CliprdrClientContext* context, + const CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse) { wStream* s; - cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle; - s = cliprdr_packet_new(CB_FILECONTENTS_RESPONSE, fileContentsResponse->msgFlags, - 4 + fileContentsResponse->cbRequested); + cliprdrPlugin* cliprdr = (cliprdrPlugin*)context->handle; + s = cliprdr_packet_file_contents_response_new(fileContentsResponse); if (!s) { @@ -946,16 +806,7 @@ static UINT cliprdr_client_file_contents_response(CliprdrClientContext* context, return ERROR_INTERNAL_ERROR; } - Stream_Write_UINT32(s, fileContentsResponse->streamId); /* streamId (4 bytes) */ - /** - * requestedFileContentsData: - * FILECONTENTS_SIZE: file size as UINT64 - * FILECONTENTS_RANGE: file data from requested range - */ - Stream_Write(s, fileContentsResponse->requestedData, - fileContentsResponse->cbRequested); - WLog_Print(cliprdr->log, WLOG_DEBUG, - "ClientFileContentsResponse: streamId: 0x%08"PRIX32"", + WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientFileContentsResponse: streamId: 0x%08" PRIX32 "", fileContentsResponse->streamId); return cliprdr_packet_send(cliprdr, s); } @@ -965,8 +816,9 @@ static UINT cliprdr_client_file_contents_response(CliprdrClientContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT cliprdr_virtual_channel_event_data_received(cliprdrPlugin* cliprdr, - void* pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) +static UINT cliprdr_virtual_channel_event_data_received(cliprdrPlugin* cliprdr, void* pData, + UINT32 dataLength, UINT32 totalLength, + UINT32 dataFlags) { wStream* data_in; @@ -989,7 +841,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; @@ -1010,7 +862,7 @@ static UINT cliprdr_virtual_channel_event_data_received(cliprdrPlugin* cliprdr, Stream_SealLength(data_in); Stream_SetPosition(data_in, 0); - if (!MessageQueue_Post(cliprdr->queue, NULL, 0, (void*) data_in, NULL)) + if (!MessageQueue_Post(cliprdr->queue, NULL, 0, (void*)data_in, NULL)) { WLog_ERR(TAG, "MessageQueue_Post failed!"); return ERROR_INTERNAL_ERROR; @@ -1021,35 +873,40 @@ static UINT cliprdr_virtual_channel_event_data_received(cliprdrPlugin* cliprdr, } static VOID VCAPITYPE cliprdr_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle, - UINT event, - LPVOID pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) + UINT event, LPVOID pData, + UINT32 dataLength, UINT32 totalLength, + UINT32 dataFlags) { UINT error = CHANNEL_RC_OK; - cliprdrPlugin* cliprdr = (cliprdrPlugin*) lpUserParam; - - if (!cliprdr || (cliprdr->OpenHandle != openHandle)) - { - WLog_ERR(TAG, "error no match"); - return; - } + cliprdrPlugin* cliprdr = (cliprdrPlugin*)lpUserParam; switch (event) { case CHANNEL_EVENT_DATA_RECEIVED: + if (!cliprdr || (cliprdr->OpenHandle != openHandle)) + { + WLog_ERR(TAG, "error no match"); + return; + } if ((error = cliprdr_virtual_channel_event_data_received(cliprdr, pData, dataLength, - totalLength, dataFlags))) - WLog_ERR(TAG, "failed with error %"PRIu32"", error); + totalLength, dataFlags))) + WLog_ERR(TAG, "failed with error %" PRIu32 "", error); break; + case CHANNEL_EVENT_WRITE_CANCELLED: case CHANNEL_EVENT_WRITE_COMPLETE: - break; + { + wStream* s = (wStream*)pData; + Stream_Free(s, TRUE); + } + break; case CHANNEL_EVENT_USER: break; } - if (error && cliprdr->context->rdpcontext) + if (error && cliprdr && cliprdr->context->rdpcontext) setChannelError(cliprdr->context->rdpcontext, error, "cliprdr_virtual_channel_open_event_ex reported an error"); } @@ -1058,7 +915,7 @@ static DWORD WINAPI cliprdr_virtual_channel_client_thread(LPVOID arg) { wStream* data; wMessage message; - cliprdrPlugin* cliprdr = (cliprdrPlugin*) arg; + cliprdrPlugin* cliprdr = (cliprdrPlugin*)arg; UINT error = CHANNEL_RC_OK; while (1) @@ -1082,11 +939,11 @@ static DWORD WINAPI cliprdr_virtual_channel_client_thread(LPVOID arg) if (message.id == 0) { - data = (wStream*) message.wParam; + data = (wStream*)message.wParam; if ((error = cliprdr_order_recv(cliprdr, data))) { - WLog_ERR(TAG, "cliprdr_order_recv failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "cliprdr_order_recv failed with error %" PRIu32 "!", error); break; } } @@ -1100,27 +957,40 @@ 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 * * @return 0 on success, otherwise a Win32 error code */ -static UINT cliprdr_virtual_channel_event_connected(cliprdrPlugin* cliprdr, - LPVOID pData, UINT32 dataLength) +static UINT cliprdr_virtual_channel_event_connected(cliprdrPlugin* cliprdr, LPVOID pData, + UINT32 dataLength) { UINT32 status; - status = cliprdr->channelEntryPoints.pVirtualChannelOpenEx(cliprdr->InitHandle, - &cliprdr->OpenHandle, cliprdr->channelDef.name, - cliprdr_virtual_channel_open_event_ex); + wObject obj = { 0 }; + status = cliprdr->channelEntryPoints.pVirtualChannelOpenEx( + cliprdr->InitHandle, &cliprdr->OpenHandle, cliprdr->channelDef.name, + cliprdr_virtual_channel_open_event_ex); if (status != CHANNEL_RC_OK) { - WLog_ERR(TAG, "pVirtualChannelOpen failed with %s [%08"PRIX32"]", + WLog_ERR(TAG, "pVirtualChannelOpen failed with %s [%08" PRIX32 "]", WTSErrorToString(status), status); return status; } - cliprdr->queue = MessageQueue_New(NULL); + obj.fnObjectFree = cliprdr_free_msg; + cliprdr->queue = MessageQueue_New(&obj); if (!cliprdr->queue) { @@ -1129,8 +999,7 @@ static UINT cliprdr_virtual_channel_event_connected(cliprdrPlugin* cliprdr, } if (!(cliprdr->thread = CreateThread(NULL, 0, cliprdr_virtual_channel_client_thread, - (void*) cliprdr, - 0, NULL))) + (void*)cliprdr, 0, NULL))) { WLog_ERR(TAG, "CreateThread failed!"); MessageQueue_Free(cliprdr->queue); @@ -1153,22 +1022,23 @@ static UINT cliprdr_virtual_channel_event_disconnected(cliprdrPlugin* cliprdr) if (cliprdr->OpenHandle == 0) return CHANNEL_RC_OK; - if (MessageQueue_PostQuit(cliprdr->queue, 0) - && (WaitForSingleObject(cliprdr->thread, INFINITE) == WAIT_FAILED)) + if (MessageQueue_PostQuit(cliprdr->queue, 0) && + (WaitForSingleObject(cliprdr->thread, INFINITE) == WAIT_FAILED)) { rc = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", rc); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", rc); return rc; } MessageQueue_Free(cliprdr->queue); CloseHandle(cliprdr->thread); - rc = cliprdr->channelEntryPoints.pVirtualChannelCloseEx(cliprdr->InitHandle, cliprdr->OpenHandle); + rc = cliprdr->channelEntryPoints.pVirtualChannelCloseEx(cliprdr->InitHandle, + cliprdr->OpenHandle); if (CHANNEL_RC_OK != rc) { - WLog_ERR(TAG, "pVirtualChannelClose failed with %s [%08"PRIX32"]", - WTSErrorToString(rc), rc); + WLog_ERR(TAG, "pVirtualChannelClose failed with %s [%08" PRIX32 "]", WTSErrorToString(rc), + rc); return rc; } @@ -1197,10 +1067,11 @@ static UINT cliprdr_virtual_channel_event_terminated(cliprdrPlugin* cliprdr) } static VOID VCAPITYPE cliprdr_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle, - UINT event, LPVOID pData, UINT dataLength) + UINT event, LPVOID pData, + UINT dataLength) { UINT error = CHANNEL_RC_OK; - cliprdrPlugin* cliprdr = (cliprdrPlugin*) lpUserParam; + cliprdrPlugin* cliprdr = (cliprdrPlugin*)lpUserParam; if (!cliprdr || (cliprdr->InitHandle != pInitHandle)) { @@ -1212,7 +1083,8 @@ static VOID VCAPITYPE cliprdr_virtual_channel_init_event_ex(LPVOID lpUserParam, { case CHANNEL_EVENT_CONNECTED: if ((error = cliprdr_virtual_channel_event_connected(cliprdr, pData, dataLength))) - WLog_ERR(TAG, "cliprdr_virtual_channel_event_connected failed with error %"PRIu32"!", + WLog_ERR(TAG, + "cliprdr_virtual_channel_event_connected failed with error %" PRIu32 "!", error); break; @@ -1220,13 +1092,16 @@ static VOID VCAPITYPE cliprdr_virtual_channel_init_event_ex(LPVOID lpUserParam, case CHANNEL_EVENT_DISCONNECTED: if ((error = cliprdr_virtual_channel_event_disconnected(cliprdr))) WLog_ERR(TAG, - "cliprdr_virtual_channel_event_disconnected failed with error %"PRIu32"!", error); + "cliprdr_virtual_channel_event_disconnected failed with error %" PRIu32 + "!", + error); break; case CHANNEL_EVENT_TERMINATED: if ((error = cliprdr_virtual_channel_event_terminated(cliprdr))) - WLog_ERR(TAG, "cliprdr_virtual_channel_event_terminated failed with error %"PRIu32"!", + WLog_ERR(TAG, + "cliprdr_virtual_channel_event_terminated failed with error %" PRIu32 "!", error); break; @@ -1238,7 +1113,7 @@ static VOID VCAPITYPE cliprdr_virtual_channel_init_event_ex(LPVOID lpUserParam, } /* cliprdr is always built-in */ -#define VirtualChannelEntryEx cliprdr_VirtualChannelEntryEx +#define VirtualChannelEntryEx cliprdr_VirtualChannelEntryEx BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID pInitHandle) { @@ -1246,7 +1121,7 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p cliprdrPlugin* cliprdr; CliprdrClientContext* context = NULL; CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx; - cliprdr = (cliprdrPlugin*) calloc(1, sizeof(cliprdrPlugin)); + cliprdr = (cliprdrPlugin*)calloc(1, sizeof(cliprdrPlugin)); if (!cliprdr) { @@ -1254,18 +1129,15 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p return FALSE; } - cliprdr->channelDef.options = - CHANNEL_OPTION_INITIALIZED | - CHANNEL_OPTION_ENCRYPT_RDP | - CHANNEL_OPTION_COMPRESS_RDP | - CHANNEL_OPTION_SHOW_PROTOCOL; + cliprdr->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP | + CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL; sprintf_s(cliprdr->channelDef.name, ARRAYSIZE(cliprdr->channelDef.name), "cliprdr"); - pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*) pEntryPoints; + pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints; if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) && (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER)) { - context = (CliprdrClientContext*) calloc(1, sizeof(CliprdrClientContext)); + context = (CliprdrClientContext*)calloc(1, sizeof(CliprdrClientContext)); if (!context) { @@ -1274,7 +1146,7 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p return FALSE; } - context->handle = (void*) cliprdr; + context->handle = (void*)cliprdr; context->custom = NULL; context->ClientCapabilities = cliprdr_client_capabilities; context->TempDirectory = cliprdr_temp_directory; @@ -1291,22 +1163,18 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p } cliprdr->log = WLog_Get("com.freerdp.channels.cliprdr.client"); - cliprdr->useLongFormatNames = TRUE; - cliprdr->streamFileClipEnabled = FALSE; - cliprdr->fileClipNoFilePaths = TRUE; - cliprdr->canLockClipData = FALSE; WLog_Print(cliprdr->log, WLOG_DEBUG, "VirtualChannelEntryEx"); CopyMemory(&(cliprdr->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)); cliprdr->InitHandle = pInitHandle; - rc = cliprdr->channelEntryPoints.pVirtualChannelInitEx(cliprdr, context, pInitHandle, - &cliprdr->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, - cliprdr_virtual_channel_init_event_ex); + rc = cliprdr->channelEntryPoints.pVirtualChannelInitEx( + cliprdr, context, pInitHandle, &cliprdr->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, + cliprdr_virtual_channel_init_event_ex); if (CHANNEL_RC_OK != rc) { - WLog_ERR(TAG, "pVirtualChannelInit failed with %s [%08"PRIX32"]", - WTSErrorToString(rc), rc); + WLog_ERR(TAG, "pVirtualChannelInit failed with %s [%08" PRIX32 "]", WTSErrorToString(rc), + rc); free(cliprdr->context); free(cliprdr); return FALSE; diff --git a/channels/cliprdr/client/cliprdr_main.h b/channels/cliprdr/client/cliprdr_main.h index 25bad18..a233407 100644 --- a/channels/cliprdr/client/cliprdr_main.h +++ b/channels/cliprdr/client/cliprdr_main.h @@ -57,7 +57,10 @@ CliprdrClientContext* cliprdr_get_client_interface(cliprdrPlugin* cliprdr); #ifdef WITH_DEBUG_CLIPRDR #define DEBUG_CLIPRDR(...) WLog_DBG(TAG, __VA_ARGS__) #else -#define DEBUG_CLIPRDR(...) do { } while (0) +#define DEBUG_CLIPRDR(...) \ + do \ + { \ + } while (0) #endif #endif /* FREERDP_CHANNEL_CLIPRDR_CLIENT_MAIN_H */ diff --git a/channels/cliprdr/cliprdr_common.c b/channels/cliprdr/cliprdr_common.c new file mode 100644 index 0000000..c0fae6e --- /dev/null +++ b/channels/cliprdr/cliprdr_common.c @@ -0,0 +1,578 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Cliprdr common + * + * Copyright 2013 Marc-Andre Moreau + * Copyright 2015 Thincast Technologies GmbH + * Copyright 2015 DI (FH) Martin Haimberger + * Copyright 2019 Kobi Mizrachi + * + * 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 + +#define TAG CHANNELS_TAG("cliprdr.common") + +#include "cliprdr_common.h" + +static BOOL cliprdr_validate_file_contents_request(const CLIPRDR_FILE_CONTENTS_REQUEST* request) +{ + /* + * [MS-RDPECLIP] 2.2.5.3 File Contents Request PDU (CLIPRDR_FILECONTENTS_REQUEST). + * + * A request for the size of the file identified by the lindex field. The size MUST be + * returned as a 64-bit, unsigned integer. The cbRequested field MUST be set to + * 0x00000008 and both the nPositionLow and nPositionHigh fields MUST be + * set to 0x00000000. + */ + + if (request->dwFlags & FILECONTENTS_SIZE) + { + if (request->cbRequested != sizeof(UINT64)) + { + WLog_ERR(TAG, "[%s]: cbRequested must be %" PRIu32 ", got %" PRIu32 "", __FUNCTION__, + sizeof(UINT64), request->cbRequested); + return FALSE; + } + + if (request->nPositionHigh != 0 || request->nPositionLow != 0) + { + WLog_ERR(TAG, "[%s]: nPositionHigh and nPositionLow must be set to 0", __FUNCTION__); + return FALSE; + } + } + + return TRUE; +} + +wStream* cliprdr_packet_new(UINT16 msgType, UINT16 msgFlags, UINT32 dataLen) +{ + wStream* s; + s = Stream_New(NULL, dataLen + 8); + + if (!s) + { + WLog_ERR(TAG, "Stream_New failed!"); + return NULL; + } + + Stream_Write_UINT16(s, msgType); + Stream_Write_UINT16(s, msgFlags); + /* Write actual length after the entire packet has been constructed. */ + Stream_Seek(s, 4); + return s; +} + +static void cliprdr_write_file_contents_request(wStream* s, + const CLIPRDR_FILE_CONTENTS_REQUEST* request) +{ + Stream_Write_UINT32(s, request->streamId); /* streamId (4 bytes) */ + Stream_Write_UINT32(s, request->listIndex); /* listIndex (4 bytes) */ + Stream_Write_UINT32(s, request->dwFlags); /* dwFlags (4 bytes) */ + Stream_Write_UINT32(s, request->nPositionLow); /* nPositionLow (4 bytes) */ + Stream_Write_UINT32(s, request->nPositionHigh); /* nPositionHigh (4 bytes) */ + Stream_Write_UINT32(s, request->cbRequested); /* cbRequested (4 bytes) */ + + if (request->haveClipDataId) + Stream_Write_UINT32(s, request->clipDataId); /* clipDataId (4 bytes) */ +} + +static INLINE void cliprdr_write_lock_unlock_clipdata(wStream* s, UINT32 clipDataId) +{ + Stream_Write_UINT32(s, clipDataId); +} + +static void cliprdr_write_lock_clipdata(wStream* s, + const CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData) +{ + cliprdr_write_lock_unlock_clipdata(s, lockClipboardData->clipDataId); +} + +static void cliprdr_write_unlock_clipdata(wStream* s, + const CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData) +{ + cliprdr_write_lock_unlock_clipdata(s, unlockClipboardData->clipDataId); +} + +static void cliprdr_write_file_contents_response(wStream* s, + const CLIPRDR_FILE_CONTENTS_RESPONSE* response) +{ + Stream_Write_UINT32(s, response->streamId); /* streamId (4 bytes) */ + Stream_Write(s, response->requestedData, response->cbRequested); +} + +wStream* cliprdr_packet_lock_clipdata_new(const CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData) +{ + wStream* s; + + if (!lockClipboardData) + return NULL; + + s = cliprdr_packet_new(CB_LOCK_CLIPDATA, 0, 4); + + if (!s) + return NULL; + + cliprdr_write_lock_clipdata(s, lockClipboardData); + return s; +} + +wStream* +cliprdr_packet_unlock_clipdata_new(const CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData) +{ + wStream* s; + + if (!unlockClipboardData) + return NULL; + + s = cliprdr_packet_new(CB_LOCK_CLIPDATA, 0, 4); + + if (!s) + return NULL; + + cliprdr_write_unlock_clipdata(s, unlockClipboardData); + return s; +} + +wStream* cliprdr_packet_file_contents_request_new(const CLIPRDR_FILE_CONTENTS_REQUEST* request) +{ + wStream* s; + + if (!request) + return NULL; + + s = cliprdr_packet_new(CB_FILECONTENTS_REQUEST, 0, 28); + + if (!s) + return NULL; + + cliprdr_write_file_contents_request(s, request); + return s; +} + +wStream* cliprdr_packet_file_contents_response_new(const CLIPRDR_FILE_CONTENTS_RESPONSE* response) +{ + wStream* s; + + if (!response) + return NULL; + + s = cliprdr_packet_new(CB_FILECONTENTS_RESPONSE, response->msgFlags, 4 + response->cbRequested); + + if (!s) + return NULL; + + cliprdr_write_file_contents_response(s, response); + return s; +} + +wStream* cliprdr_packet_format_list_new(const CLIPRDR_FORMAT_LIST* formatList, + BOOL useLongFormatNames) +{ + wStream* s; + UINT32 index; + int cchWideChar; + LPWSTR lpWideCharStr; + int formatNameSize; + char* szFormatName; + WCHAR* wszFormatName; + BOOL asciiNames = FALSE; + CLIPRDR_FORMAT* format; + + if (formatList->msgType != CB_FORMAT_LIST) + WLog_WARN(TAG, "[%s] called with invalid type %08" PRIx32, __FUNCTION__, + formatList->msgType); + + if (!useLongFormatNames) + { + UINT32 length = formatList->numFormats * 36; + s = cliprdr_packet_new(CB_FORMAT_LIST, 0, length); + + if (!s) + { + WLog_ERR(TAG, "cliprdr_packet_new failed!"); + return NULL; + } + + for (index = 0; index < formatList->numFormats; index++) + { + size_t formatNameLength = 0; + format = (CLIPRDR_FORMAT*)&(formatList->formats[index]); + Stream_Write_UINT32(s, format->formatId); /* formatId (4 bytes) */ + formatNameSize = 0; + + szFormatName = format->formatName; + + if (asciiNames) + { + if (szFormatName) + formatNameLength = strnlen(szFormatName, 32); + + if (formatNameLength > 31) + formatNameLength = 31; + + Stream_Write(s, szFormatName, formatNameLength); + Stream_Zero(s, 32 - formatNameLength); + } + else + { + wszFormatName = NULL; + + if (szFormatName) + formatNameSize = + ConvertToUnicode(CP_UTF8, 0, szFormatName, -1, &wszFormatName, 0); + + if (formatNameSize < 0) + return NULL; + + if (formatNameSize > 15) + formatNameSize = 15; + + /* size in bytes instead of wchar */ + formatNameSize *= 2; + + if (wszFormatName) + Stream_Write(s, wszFormatName, (size_t)formatNameSize); + + Stream_Zero(s, (size_t)(32 - formatNameSize)); + free(wszFormatName); + } + } + } + else + { + UINT32 length = 0; + for (index = 0; index < formatList->numFormats; index++) + { + format = (CLIPRDR_FORMAT*)&(formatList->formats[index]); + length += 4; + formatNameSize = 2; + + if (format->formatName) + formatNameSize = + MultiByteToWideChar(CP_UTF8, 0, format->formatName, -1, NULL, 0) * 2; + + if (formatNameSize < 0) + return NULL; + + length += (UINT32)formatNameSize; + } + + s = cliprdr_packet_new(CB_FORMAT_LIST, 0, length); + + if (!s) + { + WLog_ERR(TAG, "cliprdr_packet_new failed!"); + return NULL; + } + + for (index = 0; index < formatList->numFormats; index++) + { + format = (CLIPRDR_FORMAT*)&(formatList->formats[index]); + Stream_Write_UINT32(s, format->formatId); /* formatId (4 bytes) */ + + if (format->formatName) + { + const size_t cap = Stream_Capacity(s); + const size_t pos = Stream_GetPosition(s); + const size_t rem = cap - pos; + if ((cap < pos) || ((rem / 2) > INT_MAX)) + return NULL; + + lpWideCharStr = (LPWSTR)Stream_Pointer(s); + cchWideChar = (int)(rem / 2); + formatNameSize = MultiByteToWideChar(CP_UTF8, 0, format->formatName, -1, + lpWideCharStr, cchWideChar) * + 2; + if (formatNameSize < 0) + return NULL; + Stream_Seek(s, (size_t)formatNameSize); + } + else + { + Stream_Write_UINT16(s, 0); + } + } + } + + return s; +} +UINT cliprdr_read_unlock_clipdata(wStream* s, CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData) +{ + if (Stream_GetRemainingLength(s) < 4) + { + WLog_ERR(TAG, "not enough remaining data"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT32(s, unlockClipboardData->clipDataId); /* clipDataId (4 bytes) */ + return CHANNEL_RC_OK; +} + +UINT cliprdr_read_format_data_request(wStream* s, CLIPRDR_FORMAT_DATA_REQUEST* request) +{ + if (Stream_GetRemainingLength(s) < 4) + { + WLog_ERR(TAG, "not enough data in stream!"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT32(s, request->requestedFormatId); /* requestedFormatId (4 bytes) */ + return CHANNEL_RC_OK; +} + +UINT cliprdr_read_format_data_response(wStream* s, CLIPRDR_FORMAT_DATA_RESPONSE* response) +{ + response->requestedFormatData = NULL; + + if (Stream_GetRemainingLength(s) < response->dataLen) + { + WLog_ERR(TAG, "not enough data in stream!"); + return ERROR_INVALID_DATA; + } + + if (response->dataLen) + response->requestedFormatData = Stream_Pointer(s); + + return CHANNEL_RC_OK; +} + +UINT cliprdr_read_file_contents_request(wStream* s, CLIPRDR_FILE_CONTENTS_REQUEST* request) +{ + if (Stream_GetRemainingLength(s) < 24) + { + WLog_ERR(TAG, "not enough remaining data"); + return ERROR_INVALID_DATA; + } + + request->haveClipDataId = FALSE; + Stream_Read_UINT32(s, request->streamId); /* streamId (4 bytes) */ + Stream_Read_UINT32(s, request->listIndex); /* listIndex (4 bytes) */ + Stream_Read_UINT32(s, request->dwFlags); /* dwFlags (4 bytes) */ + Stream_Read_UINT32(s, request->nPositionLow); /* nPositionLow (4 bytes) */ + Stream_Read_UINT32(s, request->nPositionHigh); /* nPositionHigh (4 bytes) */ + Stream_Read_UINT32(s, request->cbRequested); /* cbRequested (4 bytes) */ + + if (Stream_GetRemainingLength(s) >= 4) + { + Stream_Read_UINT32(s, request->clipDataId); /* clipDataId (4 bytes) */ + request->haveClipDataId = TRUE; + } + + if (!cliprdr_validate_file_contents_request(request)) + return ERROR_BAD_ARGUMENTS; + + return CHANNEL_RC_OK; +} + +UINT cliprdr_read_file_contents_response(wStream* s, CLIPRDR_FILE_CONTENTS_RESPONSE* response) +{ + if (Stream_GetRemainingLength(s) < 4) + { + WLog_ERR(TAG, "not enough remaining data"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT32(s, response->streamId); /* streamId (4 bytes) */ + response->requestedData = Stream_Pointer(s); /* requestedFileContentsData */ + response->cbRequested = response->dataLen - 4; + return CHANNEL_RC_OK; +} + +UINT cliprdr_read_format_list(wStream* s, CLIPRDR_FORMAT_LIST* formatList, BOOL useLongFormatNames) +{ + UINT32 index; + BOOL asciiNames; + int formatNameLength; + char* szFormatName; + WCHAR* wszFormatName; + wStream sub1, sub2; + CLIPRDR_FORMAT* formats = NULL; + UINT error = ERROR_INTERNAL_ERROR; + + asciiNames = (formatList->msgFlags & CB_ASCII_NAMES) ? TRUE : FALSE; + + index = 0; + /* empty format list */ + formatList->formats = NULL; + formatList->numFormats = 0; + + Stream_StaticInit(&sub1, Stream_Pointer(s), formatList->dataLen); + if (!Stream_SafeSeek(s, formatList->dataLen)) + return ERROR_INVALID_DATA; + + if (!formatList->dataLen) + { + } + else if (!useLongFormatNames) + { + const size_t cap = Stream_Capacity(&sub1); + formatList->numFormats = (cap / 36); + + if ((formatList->numFormats * 36) != cap) + { + WLog_ERR(TAG, "Invalid short format list length: %" PRIuz "", cap); + return ERROR_INTERNAL_ERROR; + } + + if (formatList->numFormats) + formats = (CLIPRDR_FORMAT*)calloc(formatList->numFormats, sizeof(CLIPRDR_FORMAT)); + + if (!formats) + { + WLog_ERR(TAG, "calloc failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + formatList->formats = formats; + + while (Stream_GetRemainingLength(&sub1) >= 4) + { + Stream_Read_UINT32(&sub1, formats[index].formatId); /* formatId (4 bytes) */ + + formats[index].formatName = NULL; + + /* According to MS-RDPECLIP 2.2.3.1.1.1 formatName is "a 32-byte block containing + * the *null-terminated* name assigned to the Clipboard Format: (32 ASCII 8 characters + * or 16 Unicode characters)" + * However, both Windows RDSH and mstsc violate this specs as seen in the following + * example of a transferred short format name string: [R.i.c.h. .T.e.x.t. .F.o.r.m.a.t.] + * These are 16 unicode charaters - *without* terminating null ! + */ + + szFormatName = (char*)Stream_Pointer(&sub1); + wszFormatName = (WCHAR*)Stream_Pointer(&sub1); + if (!Stream_SafeSeek(&sub1, 32)) + goto error_out; + if (asciiNames) + { + if (szFormatName[0]) + { + /* ensure null termination */ + formats[index].formatName = (char*)malloc(32 + 1); + if (!formats[index].formatName) + { + WLog_ERR(TAG, "malloc failed!"); + error = CHANNEL_RC_NO_MEMORY; + goto error_out; + } + CopyMemory(formats[index].formatName, szFormatName, 32); + formats[index].formatName[32] = '\0'; + } + } + else + { + if (wszFormatName[0]) + { + /* ConvertFromUnicode always returns a null-terminated + * string on success, even if the source string isn't. + */ + if (ConvertFromUnicode(CP_UTF8, 0, wszFormatName, 16, + &(formats[index].formatName), 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert short clipboard format name"); + error = ERROR_INTERNAL_ERROR; + goto error_out; + } + } + } + + index++; + } + } + else + { + sub2 = sub1; + while (Stream_GetRemainingLength(&sub1) > 0) + { + size_t rest; + if (!Stream_SafeSeek(&sub1, 4)) /* formatId (4 bytes) */ + goto error_out; + + wszFormatName = (WCHAR*)Stream_Pointer(&sub1); + rest = Stream_GetRemainingLength(&sub1); + formatNameLength = _wcsnlen(wszFormatName, rest / sizeof(WCHAR)); + + if (!Stream_SafeSeek(&sub1, (formatNameLength + 1) * sizeof(WCHAR))) + goto error_out; + formatList->numFormats++; + } + + if (formatList->numFormats) + formats = (CLIPRDR_FORMAT*)calloc(formatList->numFormats, sizeof(CLIPRDR_FORMAT)); + + if (!formats) + { + WLog_ERR(TAG, "calloc failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + formatList->formats = formats; + + while (Stream_GetRemainingLength(&sub2) >= 4) + { + size_t rest; + Stream_Read_UINT32(&sub2, formats[index].formatId); /* formatId (4 bytes) */ + + formats[index].formatName = NULL; + + wszFormatName = (WCHAR*)Stream_Pointer(&sub2); + rest = Stream_GetRemainingLength(&sub2); + formatNameLength = _wcsnlen(wszFormatName, rest / sizeof(WCHAR)); + if (!Stream_SafeSeek(&sub2, (formatNameLength + 1) * sizeof(WCHAR))) + goto error_out; + + if (formatNameLength) + { + if (ConvertFromUnicode(CP_UTF8, 0, wszFormatName, formatNameLength, + &(formats[index].formatName), 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert long clipboard format name"); + error = ERROR_INTERNAL_ERROR; + goto error_out; + } + } + + index++; + } + } + + return CHANNEL_RC_OK; + +error_out: + cliprdr_free_format_list(formatList); + return error; +} + +void cliprdr_free_format_list(CLIPRDR_FORMAT_LIST* formatList) +{ + UINT index = 0; + + if (formatList == NULL) + return; + + if (formatList->formats) + { + for (index = 0; index < formatList->numFormats; index++) + { + free(formatList->formats[index].formatName); + } + + free(formatList->formats); + formatList->formats = NULL; + formatList->numFormats = 0; + } +} diff --git a/channels/cliprdr/cliprdr_common.h b/channels/cliprdr/cliprdr_common.h new file mode 100644 index 0000000..b5d36b9 --- /dev/null +++ b/channels/cliprdr/cliprdr_common.h @@ -0,0 +1,61 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Cliprdr common + * + * Copyright 2013 Marc-Andre Moreau + * Copyright 2015 Thincast Technologies GmbH + * Copyright 2015 DI (FH) Martin Haimberger + * Copyright 2019 Kobi Mizrachi + * + * 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_CHANNEL_RDPECLIP_COMMON_H +#define FREERDP_CHANNEL_RDPECLIP_COMMON_H + +#include +#include + +#include +#include + +FREERDP_LOCAL wStream* cliprdr_packet_new(UINT16 msgType, UINT16 msgFlags, UINT32 dataLen); +FREERDP_LOCAL wStream* +cliprdr_packet_lock_clipdata_new(const CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData); +FREERDP_LOCAL wStream* +cliprdr_packet_unlock_clipdata_new(const CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData); +FREERDP_LOCAL wStream* +cliprdr_packet_file_contents_request_new(const CLIPRDR_FILE_CONTENTS_REQUEST* request); +FREERDP_LOCAL wStream* +cliprdr_packet_file_contents_response_new(const CLIPRDR_FILE_CONTENTS_RESPONSE* response); +FREERDP_LOCAL wStream* cliprdr_packet_format_list_new(const CLIPRDR_FORMAT_LIST* formatList, + BOOL useLongFormatNames); + +FREERDP_LOCAL UINT cliprdr_read_lock_clipdata(wStream* s, + CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData); +FREERDP_LOCAL UINT cliprdr_read_unlock_clipdata(wStream* s, + CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData); +FREERDP_LOCAL UINT cliprdr_read_format_data_request(wStream* s, + CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest); +FREERDP_LOCAL UINT cliprdr_read_format_data_response(wStream* s, + CLIPRDR_FORMAT_DATA_RESPONSE* response); +FREERDP_LOCAL UINT +cliprdr_read_file_contents_request(wStream* s, CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest); +FREERDP_LOCAL UINT cliprdr_read_file_contents_response(wStream* s, + CLIPRDR_FILE_CONTENTS_RESPONSE* response); +FREERDP_LOCAL UINT cliprdr_read_format_list(wStream* s, CLIPRDR_FORMAT_LIST* formatList, + BOOL useLongFormatNames); + +FREERDP_LOCAL void cliprdr_free_format_list(CLIPRDR_FORMAT_LIST* formatList); + +#endif /* FREERDP_CHANNEL_RDPECLIP_COMMON_H */ diff --git a/channels/cliprdr/server/CMakeLists.txt b/channels/cliprdr/server/CMakeLists.txt index 911c7a4..32ffbaa 100644 --- a/channels/cliprdr/server/CMakeLists.txt +++ b/channels/cliprdr/server/CMakeLists.txt @@ -19,7 +19,10 @@ define_channel_server("cliprdr") set(${MODULE_PREFIX}_SRCS cliprdr_main.c - cliprdr_main.h) + cliprdr_main.h + ../cliprdr_common.h + ../cliprdr_common.c + ) add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry") diff --git a/channels/cliprdr/server/cliprdr_main.c b/channels/cliprdr/server/cliprdr_main.c index 118c2b0..da4ab0b 100644 --- a/channels/cliprdr/server/cliprdr_main.c +++ b/channels/cliprdr/server/cliprdr_main.c @@ -29,6 +29,7 @@ #include #include "cliprdr_main.h" +#include "../cliprdr_common.h" /** * Initialization Sequence\n @@ -50,60 +51,62 @@ * | |\n * |-------------------------------------------------------------------------|\n _ * |-------------------------------Format List PDU-------------------------->|\n | - * |<--------------------------Format List Response PDU----------------------|\n _| Copy Sequence + * |<--------------------------Format List Response PDU----------------------|\n _| Copy + * Sequence * |<---------------------Lock Clipboard Data PDU (Optional)-----------------|\n * |-------------------------------------------------------------------------|\n * |-------------------------------------------------------------------------|\n _ - * |<--------------------------Format Data Request PDU-----------------------|\n | Paste Sequence Palette, - * |---------------------------Format Data Response PDU--------------------->|\n _| Metafile, File List Data + * |<--------------------------Format Data Request PDU-----------------------|\n | Paste + * Sequence Palette, + * |---------------------------Format Data Response PDU--------------------->|\n _| Metafile, + * File List Data * |-------------------------------------------------------------------------|\n * |-------------------------------------------------------------------------|\n _ - * |<------------------------Format Contents Request PDU---------------------|\n | Paste Sequence - * |-------------------------Format Contents Response PDU------------------->|\n _| File Stream Data + * |<------------------------Format Contents Request PDU---------------------|\n | Paste + * Sequence + * |-------------------------Format Contents Response PDU------------------->|\n _| File + * Stream Data * |<---------------------Lock Clipboard Data PDU (Optional)-----------------|\n * |-------------------------------------------------------------------------|\n * */ -wStream* cliprdr_server_packet_new(UINT16 msgType, UINT16 msgFlags, - UINT32 dataLen) -{ - wStream* s; - s = Stream_New(NULL, dataLen + 8); - - if (!s) - { - WLog_ERR(TAG, "Stream_New failed!"); - return NULL; - } - - Stream_Write_UINT16(s, msgType); - Stream_Write_UINT16(s, msgFlags); - /* Write actual length after the entire packet has been constructed. */ - Stream_Seek(s, 4); - return s; -} - /** * Function description * * @return 0 on success, otherwise a Win32 error code */ -UINT cliprdr_server_packet_send(CliprdrServerPrivate* cliprdr, wStream* s) +static UINT cliprdr_server_packet_send(CliprdrServerPrivate* cliprdr, wStream* s) { - size_t pos; + UINT rc; + size_t pos, size; BOOL status; UINT32 dataLen; UINT32 written; pos = Stream_GetPosition(s); - dataLen = pos - 8; + if ((pos < 8) || (pos > UINT32_MAX)) + { + rc = ERROR_NO_DATA; + goto fail; + } + + dataLen = (UINT32)(pos - 8); Stream_SetPosition(s, 4); Stream_Write_UINT32(s, dataLen); Stream_SetPosition(s, pos); - status = WTSVirtualChannelWrite(cliprdr->ChannelHandle, - (PCHAR) Stream_Buffer(s), Stream_Length(s), &written); + size = Stream_Length(s); + if (size > UINT32_MAX) + { + rc = ERROR_INVALID_DATA; + goto fail; + } + + status = WTSVirtualChannelWrite(cliprdr->ChannelHandle, (PCHAR)Stream_Buffer(s), (UINT32)size, + &written); + rc = status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; +fail: Stream_Free(s, TRUE); - return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; + return rc; } /** @@ -112,32 +115,66 @@ UINT cliprdr_server_packet_send(CliprdrServerPrivate* cliprdr, wStream* s) * @return 0 on success, otherwise a Win32 error code */ static UINT cliprdr_server_capabilities(CliprdrServerContext* context, - CLIPRDR_CAPABILITIES* capabilities) + const CLIPRDR_CAPABILITIES* capabilities) { + size_t offset = 0; + UINT32 x; wStream* s; - CLIPRDR_GENERAL_CAPABILITY_SET* generalCapabilitySet; - CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*) context->handle; - capabilities->msgType = CB_CLIP_CAPS; - capabilities->msgFlags = 0; - s = cliprdr_server_packet_new(CB_CLIP_CAPS, 0, 4 + CB_CAPSTYPE_GENERAL_LEN); + CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*)context->handle; + + if (capabilities->msgType != CB_CLIP_CAPS) + WLog_WARN(TAG, "[%s] called with invalid type %08" PRIx32, __FUNCTION__, + capabilities->msgType); + + if (capabilities->cCapabilitiesSets > UINT16_MAX) + { + WLog_ERR(TAG, "Invalid number of capability sets in clipboard caps"); + return ERROR_INVALID_PARAMETER; + } + + s = cliprdr_packet_new(CB_CLIP_CAPS, 0, 4 + CB_CAPSTYPE_GENERAL_LEN); if (!s) { - WLog_ERR(TAG, "cliprdr_server_packet_new failed!"); + WLog_ERR(TAG, "cliprdr_packet_new failed!"); return ERROR_INTERNAL_ERROR; } - Stream_Write_UINT16(s, 1); /* cCapabilitiesSets (2 bytes) */ - Stream_Write_UINT16(s, 0); /* pad1 (2 bytes) */ - generalCapabilitySet = (CLIPRDR_GENERAL_CAPABILITY_SET*) - capabilities->capabilitySets; - Stream_Write_UINT16(s, - generalCapabilitySet->capabilitySetType); /* capabilitySetType (2 bytes) */ Stream_Write_UINT16(s, - generalCapabilitySet->capabilitySetLength); /* lengthCapability (2 bytes) */ - Stream_Write_UINT32(s, generalCapabilitySet->version); /* version (4 bytes) */ - Stream_Write_UINT32(s, - generalCapabilitySet->generalFlags); /* generalFlags (4 bytes) */ + (UINT16)capabilities->cCapabilitiesSets); /* cCapabilitiesSets (2 bytes) */ + Stream_Write_UINT16(s, 0); /* pad1 (2 bytes) */ + for (x = 0; x < capabilities->cCapabilitiesSets; x++) + { + const CLIPRDR_CAPABILITY_SET* cap = + (const CLIPRDR_CAPABILITY_SET*)(((const BYTE*)capabilities->capabilitySets) + offset); + offset += cap->capabilitySetLength; + + switch (cap->capabilitySetType) + { + case CB_CAPSTYPE_GENERAL: + { + const CLIPRDR_GENERAL_CAPABILITY_SET* generalCapabilitySet = + (const CLIPRDR_GENERAL_CAPABILITY_SET*)cap; + Stream_Write_UINT16( + s, generalCapabilitySet->capabilitySetType); /* capabilitySetType (2 bytes) */ + Stream_Write_UINT16( + s, generalCapabilitySet->capabilitySetLength); /* lengthCapability (2 bytes) */ + Stream_Write_UINT32(s, generalCapabilitySet->version); /* version (4 bytes) */ + Stream_Write_UINT32( + s, generalCapabilitySet->generalFlags); /* generalFlags (4 bytes) */ + } + break; + + default: + WLog_WARN(TAG, "Unknown capability set type %08" PRIx16, cap->capabilitySetType); + if (!Stream_SafeSeek(s, cap->capabilitySetLength)) + { + WLog_ERR(TAG, "%s: short stream", __FUNCTION__); + return ERROR_NO_DATA; + } + break; + } + } WLog_DBG(TAG, "ServerCapabilities"); return cliprdr_server_packet_send(cliprdr, s); } @@ -148,19 +185,20 @@ static UINT cliprdr_server_capabilities(CliprdrServerContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT cliprdr_server_monitor_ready(CliprdrServerContext* context, - CLIPRDR_MONITOR_READY* monitorReady) + const CLIPRDR_MONITOR_READY* monitorReady) { wStream* s; - CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*) context->handle; - monitorReady->msgType = CB_MONITOR_READY; - monitorReady->msgFlags = 0; - monitorReady->dataLen = 0; - s = cliprdr_server_packet_new(monitorReady->msgType, - monitorReady->msgFlags, monitorReady->dataLen); + CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*)context->handle; + + if (monitorReady->msgType != CB_MONITOR_READY) + WLog_WARN(TAG, "[%s] called with invalid type %08" PRIx32, __FUNCTION__, + monitorReady->msgType); + + s = cliprdr_packet_new(CB_MONITOR_READY, monitorReady->msgFlags, monitorReady->dataLen); if (!s) { - WLog_ERR(TAG, "cliprdr_server_packet_new failed!"); + WLog_ERR(TAG, "cliprdr_packet_new failed!"); return ERROR_INTERNAL_ERROR; } @@ -174,115 +212,19 @@ static UINT cliprdr_server_monitor_ready(CliprdrServerContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT cliprdr_server_format_list(CliprdrServerContext* context, - CLIPRDR_FORMAT_LIST* formatList) + const CLIPRDR_FORMAT_LIST* formatList) { wStream* s; - UINT32 index; - int length = 0; - int cchWideChar; - LPWSTR lpWideCharStr; - int formatNameSize; - int formatNameLength; - char* szFormatName; - WCHAR* wszFormatName; - BOOL asciiNames = FALSE; - CLIPRDR_FORMAT* format; - CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*) context->handle; - - if (!context->useLongFormatNames) - { - length = formatList->numFormats * 36; - s = cliprdr_server_packet_new(CB_FORMAT_LIST, 0, length); - - if (!s) - { - WLog_ERR(TAG, "cliprdr_server_packet_new failed!"); - return ERROR_INTERNAL_ERROR; - } - - for (index = 0; index < formatList->numFormats; index++) - { - format = (CLIPRDR_FORMAT*) & (formatList->formats[index]); - Stream_Write_UINT32(s, format->formatId); /* formatId (4 bytes) */ - formatNameSize = 0; - formatNameLength = 0; - szFormatName = format->formatName; - - if (asciiNames) - { - if (szFormatName) - formatNameLength = strlen(szFormatName); - - if (formatNameLength > 31) - formatNameLength = 31; - - Stream_Write(s, szFormatName, formatNameLength); - Stream_Zero(s, 32 - formatNameLength); - } - else - { - wszFormatName = NULL; - - if (szFormatName) - formatNameSize = ConvertToUnicode(CP_UTF8, 0, szFormatName, -1, &wszFormatName, - 0); - - if (formatNameSize > 15) - formatNameSize = 15; - - if (wszFormatName) - Stream_Write(s, wszFormatName, formatNameSize * 2); + CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*)context->handle; - Stream_Zero(s, 32 - (formatNameSize * 2)); - free(wszFormatName); - } - } - } - else + s = cliprdr_packet_format_list_new(formatList, context->useLongFormatNames); + if (!s) { - for (index = 0; index < formatList->numFormats; index++) - { - format = (CLIPRDR_FORMAT*) & (formatList->formats[index]); - length += 4; - formatNameSize = 2; - - if (format->formatName) - formatNameSize = MultiByteToWideChar(CP_UTF8, 0, format->formatName, -1, NULL, - 0) * 2; - - length += formatNameSize; - } - - s = cliprdr_server_packet_new(CB_FORMAT_LIST, 0, length); - - if (!s) - { - WLog_ERR(TAG, "cliprdr_server_packet_new failed!"); - return ERROR_INTERNAL_ERROR; - } - - for (index = 0; index < formatList->numFormats; index++) - { - format = (CLIPRDR_FORMAT*) & (formatList->formats[index]); - Stream_Write_UINT32(s, format->formatId); /* formatId (4 bytes) */ - - if (format->formatName) - { - lpWideCharStr = (LPWSTR) Stream_Pointer(s); - cchWideChar = (Stream_Capacity(s) - Stream_GetPosition(s)) / 2; - formatNameSize = MultiByteToWideChar(CP_UTF8, 0, - format->formatName, -1, lpWideCharStr, cchWideChar) * 2; - Stream_Seek(s, formatNameSize); - } - else - { - Stream_Write_UINT16(s, 0); - } - } + WLog_ERR(TAG, "cliprdr_packet_format_list_new failed!"); + return ERROR_INTERNAL_ERROR; } - WLog_DBG(TAG, "ServerFormatList: numFormats: %"PRIu32"", - formatList->numFormats); + WLog_DBG(TAG, "ServerFormatList: numFormats: %" PRIu32 "", formatList->numFormats); return cliprdr_server_packet_send(cliprdr, s); } @@ -291,19 +233,22 @@ static UINT cliprdr_server_format_list(CliprdrServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT cliprdr_server_format_list_response(CliprdrServerContext* context, - CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse) +static UINT +cliprdr_server_format_list_response(CliprdrServerContext* context, + const CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse) { wStream* s; - CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*) context->handle; - formatListResponse->msgType = CB_FORMAT_LIST_RESPONSE; - formatListResponse->dataLen = 0; - s = cliprdr_server_packet_new(formatListResponse->msgType, - formatListResponse->msgFlags, formatListResponse->dataLen); + CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*)context->handle; + if (formatListResponse->msgType != CB_FORMAT_LIST_RESPONSE) + WLog_WARN(TAG, "[%s] called with invalid type %08" PRIx32, __FUNCTION__, + formatListResponse->msgType); + + s = cliprdr_packet_new(CB_FORMAT_LIST_RESPONSE, formatListResponse->msgFlags, + formatListResponse->dataLen); if (!s) { - WLog_ERR(TAG, "cliprdr_server_packet_new failed!"); + WLog_ERR(TAG, "cliprdr_packet_new failed!"); return ERROR_INTERNAL_ERROR; } @@ -317,21 +262,22 @@ static UINT cliprdr_server_format_list_response(CliprdrServerContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT cliprdr_server_lock_clipboard_data(CliprdrServerContext* context, - CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData) + const CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData) { wStream* s; - CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*) context->handle; - s = cliprdr_server_packet_new(CB_LOCK_CLIPDATA, 0, 4); + CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*)context->handle; + if (lockClipboardData->msgType != CB_LOCK_CLIPDATA) + WLog_WARN(TAG, "[%s] called with invalid type %08" PRIx32, __FUNCTION__, + lockClipboardData->msgType); + s = cliprdr_packet_lock_clipdata_new(lockClipboardData); if (!s) { - WLog_ERR(TAG, "cliprdr_server_packet_new failed!"); + WLog_ERR(TAG, "cliprdr_packet_lock_clipdata_new failed!"); return ERROR_INTERNAL_ERROR; } - Stream_Write_UINT32(s, - lockClipboardData->clipDataId); /* clipDataId (4 bytes) */ - WLog_DBG(TAG, "ServerLockClipboardData: clipDataId: 0x%08"PRIX32"", + WLog_DBG(TAG, "ServerLockClipboardData: clipDataId: 0x%08" PRIX32 "", lockClipboardData->clipDataId); return cliprdr_server_packet_send(cliprdr, s); } @@ -341,22 +287,25 @@ static UINT cliprdr_server_lock_clipboard_data(CliprdrServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT cliprdr_server_unlock_clipboard_data(CliprdrServerContext* context, - CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData) +static UINT +cliprdr_server_unlock_clipboard_data(CliprdrServerContext* context, + const CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData) { wStream* s; - CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*) context->handle; - s = cliprdr_server_packet_new(CB_UNLOCK_CLIPDATA, 0, 4); + CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*)context->handle; + if (unlockClipboardData->msgType != CB_UNLOCK_CLIPDATA) + WLog_WARN(TAG, "[%s] called with invalid type %08" PRIx32, __FUNCTION__, + unlockClipboardData->msgType); + + s = cliprdr_packet_unlock_clipdata_new(unlockClipboardData); if (!s) { - WLog_ERR(TAG, "cliprdr_server_packet_new failed!"); + WLog_ERR(TAG, "cliprdr_packet_unlock_clipdata_new failed!"); return ERROR_INTERNAL_ERROR; } - Stream_Write_UINT32(s, - unlockClipboardData->clipDataId); /* clipDataId (4 bytes) */ - WLog_DBG(TAG, "ServerUnlockClipboardData: clipDataId: 0x%08"PRIX32"", + WLog_DBG(TAG, "ServerUnlockClipboardData: clipDataId: 0x%08" PRIX32 "", unlockClipboardData->clipDataId); return cliprdr_server_packet_send(cliprdr, s); } @@ -367,24 +316,24 @@ static UINT cliprdr_server_unlock_clipboard_data(CliprdrServerContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT cliprdr_server_format_data_request(CliprdrServerContext* context, - CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest) + const CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest) { wStream* s; - CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*) context->handle; - formatDataRequest->msgType = CB_FORMAT_DATA_REQUEST; - formatDataRequest->msgFlags = 0; - formatDataRequest->dataLen = 4; - s = cliprdr_server_packet_new(formatDataRequest->msgType, - formatDataRequest->msgFlags, formatDataRequest->dataLen); + CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*)context->handle; + if (formatDataRequest->msgType != CB_FORMAT_DATA_REQUEST) + WLog_WARN(TAG, "[%s] called with invalid type %08" PRIx32, __FUNCTION__, + formatDataRequest->msgType); + + s = cliprdr_packet_new(CB_FORMAT_DATA_REQUEST, formatDataRequest->msgFlags, + formatDataRequest->dataLen); if (!s) { - WLog_ERR(TAG, "cliprdr_server_packet_new failed!"); + WLog_ERR(TAG, "cliprdr_packet_new failed!"); return ERROR_INTERNAL_ERROR; } - Stream_Write_UINT32(s, - formatDataRequest->requestedFormatId); /* requestedFormatId (4 bytes) */ + Stream_Write_UINT32(s, formatDataRequest->requestedFormatId); /* requestedFormatId (4 bytes) */ WLog_DBG(TAG, "ClientFormatDataRequest"); return cliprdr_server_packet_send(cliprdr, s); } @@ -394,23 +343,27 @@ static UINT cliprdr_server_format_data_request(CliprdrServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT cliprdr_server_format_data_response(CliprdrServerContext* context, - CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse) +static UINT +cliprdr_server_format_data_response(CliprdrServerContext* context, + const CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse) { wStream* s; - CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*) context->handle; - formatDataResponse->msgType = CB_FORMAT_DATA_RESPONSE; - s = cliprdr_server_packet_new(formatDataResponse->msgType, - formatDataResponse->msgFlags, formatDataResponse->dataLen); + CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*)context->handle; + + if (formatDataResponse->msgType != CB_FORMAT_DATA_RESPONSE) + WLog_WARN(TAG, "[%s] called with invalid type %08" PRIx32, __FUNCTION__, + formatDataResponse->msgType); + + s = cliprdr_packet_new(CB_FORMAT_DATA_RESPONSE, formatDataResponse->msgFlags, + formatDataResponse->dataLen); if (!s) { - WLog_ERR(TAG, "cliprdr_server_packet_new failed!"); + WLog_ERR(TAG, "cliprdr_packet_new failed!"); return ERROR_INTERNAL_ERROR; } - Stream_Write(s, formatDataResponse->requestedFormatData, - formatDataResponse->dataLen); + Stream_Write(s, formatDataResponse->requestedFormatData, formatDataResponse->dataLen); WLog_DBG(TAG, "ServerFormatDataResponse"); return cliprdr_server_packet_send(cliprdr, s); } @@ -420,32 +373,25 @@ static UINT cliprdr_server_format_data_response(CliprdrServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT cliprdr_server_file_contents_request(CliprdrServerContext* context, - CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) +static UINT +cliprdr_server_file_contents_request(CliprdrServerContext* context, + const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) { wStream* s; - CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*) context->handle; - s = cliprdr_server_packet_new(CB_FILECONTENTS_REQUEST, 0, 28); + CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*)context->handle; + + if (fileContentsRequest->msgType != CB_FILECONTENTS_REQUEST) + WLog_WARN(TAG, "[%s] called with invalid type %08" PRIx32, __FUNCTION__, + fileContentsRequest->msgType); + s = cliprdr_packet_file_contents_request_new(fileContentsRequest); if (!s) { - WLog_ERR(TAG, "cliprdr_server_packet_new failed!"); + WLog_ERR(TAG, "cliprdr_packet_file_contents_request_new failed!"); return ERROR_INTERNAL_ERROR; } - Stream_Write_UINT32(s, fileContentsRequest->streamId); /* streamId (4 bytes) */ - Stream_Write_UINT32(s, - fileContentsRequest->listIndex); /* listIndex (4 bytes) */ - Stream_Write_UINT32(s, fileContentsRequest->dwFlags); /* dwFlags (4 bytes) */ - Stream_Write_UINT32(s, - fileContentsRequest->nPositionLow); /* nPositionLow (4 bytes) */ - Stream_Write_UINT32(s, - fileContentsRequest->nPositionHigh); /* nPositionHigh (4 bytes) */ - Stream_Write_UINT32(s, - fileContentsRequest->cbRequested); /* cbRequested (4 bytes) */ - Stream_Write_UINT32(s, - fileContentsRequest->clipDataId); /* clipDataId (4 bytes) */ - WLog_DBG(TAG, "ServerFileContentsRequest: streamId: 0x%08"PRIX32"", + WLog_DBG(TAG, "ServerFileContentsRequest: streamId: 0x%08" PRIX32 "", fileContentsRequest->streamId); return cliprdr_server_packet_send(cliprdr, s); } @@ -455,34 +401,25 @@ static UINT cliprdr_server_file_contents_request(CliprdrServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT cliprdr_server_file_contents_response(CliprdrServerContext* context, - CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse) +static UINT +cliprdr_server_file_contents_response(CliprdrServerContext* context, + const CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse) { wStream* s; - CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*) context->handle; + CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*)context->handle; - if (fileContentsResponse->dwFlags & FILECONTENTS_SIZE) - fileContentsResponse->cbRequested = sizeof(UINT64); - - s = cliprdr_server_packet_new(CB_FILECONTENTS_RESPONSE, - fileContentsResponse->msgFlags, - 4 + fileContentsResponse->cbRequested); + if (fileContentsResponse->msgType != CB_FILECONTENTS_RESPONSE) + WLog_WARN(TAG, "[%s] called with invalid type %08" PRIx32, __FUNCTION__, + fileContentsResponse->msgType); + s = cliprdr_packet_file_contents_response_new(fileContentsResponse); if (!s) { - WLog_ERR(TAG, "cliprdr_server_packet_new failed!"); + WLog_ERR(TAG, "cliprdr_packet_file_contents_response_new failed!"); return ERROR_INTERNAL_ERROR; } - Stream_Write_UINT32(s, fileContentsResponse->streamId); /* streamId (4 bytes) */ - /** - * requestedFileContentsData: - * FILECONTENTS_SIZE: file size as UINT64 - * FILECONTENTS_RANGE: file data from requested range - */ - Stream_Write(s, fileContentsResponse->requestedData, - fileContentsResponse->cbRequested); - WLog_DBG(TAG, "ServerFileContentsResponse: streamId: 0x%08"PRIX32"", + WLog_DBG(TAG, "ServerFileContentsResponse: streamId: 0x%08" PRIX32 "", fileContentsResponse->streamId); return cliprdr_server_packet_send(cliprdr, s); } @@ -492,28 +429,29 @@ static UINT cliprdr_server_file_contents_response(CliprdrServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT cliprdr_server_receive_general_capability(CliprdrServerContext* - context, wStream* s) +static UINT cliprdr_server_receive_general_capability(CliprdrServerContext* context, wStream* s, + CLIPRDR_GENERAL_CAPABILITY_SET* cap_set) { - UINT32 version; - UINT32 generalFlags; - Stream_Read_UINT32(s, version); /* version (4 bytes) */ - Stream_Read_UINT32(s, generalFlags); /* generalFlags (4 bytes) */ + if (Stream_GetRemainingLength(s) < 8) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, cap_set->version); /* version (4 bytes) */ + Stream_Read_UINT32(s, cap_set->generalFlags); /* generalFlags (4 bytes) */ if (context->useLongFormatNames) - context->useLongFormatNames = (generalFlags & CB_USE_LONG_FORMAT_NAMES) ? TRUE : - FALSE; + context->useLongFormatNames = + (cap_set->generalFlags & CB_USE_LONG_FORMAT_NAMES) ? TRUE : FALSE; if (context->streamFileClipEnabled) - context->streamFileClipEnabled = (generalFlags & CB_STREAM_FILECLIP_ENABLED) ? - TRUE : FALSE; + context->streamFileClipEnabled = + (cap_set->generalFlags & CB_STREAM_FILECLIP_ENABLED) ? TRUE : FALSE; if (context->fileClipNoFilePaths) - context->fileClipNoFilePaths = (generalFlags & CB_FILECLIP_NO_FILE_PATHS) ? - TRUE : FALSE; + context->fileClipNoFilePaths = + (cap_set->generalFlags & CB_FILECLIP_NO_FILE_PATHS) ? TRUE : FALSE; if (context->canLockClipData) - context->canLockClipData = (generalFlags & CB_CAN_LOCK_CLIPDATA) ? TRUE : FALSE; + context->canLockClipData = (cap_set->generalFlags & CB_CAN_LOCK_CLIPDATA) ? TRUE : FALSE; return CHANNEL_RC_OK; } @@ -523,43 +461,80 @@ static UINT cliprdr_server_receive_general_capability(CliprdrServerContext* * * @return 0 on success, otherwise a Win32 error code */ -static UINT cliprdr_server_receive_capabilities(CliprdrServerContext* context, - wStream* s, CLIPRDR_HEADER* header) +static UINT cliprdr_server_receive_capabilities(CliprdrServerContext* context, wStream* s, + const CLIPRDR_HEADER* header) { UINT16 index; - UINT16 cCapabilitiesSets; UINT16 capabilitySetType; - UINT16 lengthCapability; - UINT error; + UINT16 capabilitySetLength; + UINT error = ERROR_INVALID_DATA; + size_t cap_sets_size = 0; + CLIPRDR_CAPABILITIES capabilities = { 0 }; + CLIPRDR_CAPABILITY_SET* capSet; + + WINPR_UNUSED(header); + + WLog_DBG(TAG, "CliprdrClientCapabilities"); - Stream_Read_UINT16(s, cCapabilitiesSets); /* cCapabilitiesSets (2 bytes) */ - Stream_Seek_UINT16(s); /* pad1 (2 bytes) */ + if (Stream_GetRemainingLength(s) < 4) + return ERROR_INVALID_DATA; - for (index = 0; index < cCapabilitiesSets; index++) + Stream_Read_UINT16(s, capabilities.cCapabilitiesSets); /* cCapabilitiesSets (2 bytes) */ + Stream_Seek_UINT16(s); /* pad1 (2 bytes) */ + + for (index = 0; index < capabilities.cCapabilitiesSets; index++) { - Stream_Read_UINT16(s, capabilitySetType); /* capabilitySetType (2 bytes) */ - Stream_Read_UINT16(s, lengthCapability); /* lengthCapability (2 bytes) */ + void* tmp = NULL; + if (Stream_GetRemainingLength(s) < 4) + goto out; + Stream_Read_UINT16(s, capabilitySetType); /* capabilitySetType (2 bytes) */ + Stream_Read_UINT16(s, capabilitySetLength); /* capabilitySetLength (2 bytes) */ + + cap_sets_size += capabilitySetLength; + + if (cap_sets_size > 0) + tmp = realloc(capabilities.capabilitySets, cap_sets_size); + if (tmp == NULL) + { + WLog_ERR(TAG, "capabilities.capabilitySets realloc failed!"); + free(capabilities.capabilitySets); + return CHANNEL_RC_NO_MEMORY; + } - switch (capabilitySetType) + capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*)tmp; + + capSet = &(capabilities.capabilitySets[index]); + + capSet->capabilitySetType = capabilitySetType; + capSet->capabilitySetLength = capabilitySetLength; + + switch (capSet->capabilitySetType) { case CB_CAPSTYPE_GENERAL: - if ((error = cliprdr_server_receive_general_capability(context, s))) + error = cliprdr_server_receive_general_capability( + context, s, (CLIPRDR_GENERAL_CAPABILITY_SET*)capSet); + if (error) { - WLog_ERR(TAG, "cliprdr_server_receive_general_capability failed with error %"PRIu32"", + WLog_ERR(TAG, + "cliprdr_server_receive_general_capability failed with error %" PRIu32 + "", error); - return error; + goto out; } - break; default: - WLog_ERR(TAG, "unknown cliprdr capability set: %"PRIu16"", capabilitySetType); - return ERROR_INVALID_DATA; - break; + WLog_ERR(TAG, "unknown cliprdr capability set: %" PRIu16 "", + capSet->capabilitySetType); + goto out; } } - return CHANNEL_RC_OK; + error = CHANNEL_RC_OK; + IFCALLRET(context->ClientCapabilities, error, context, &capabilities); +out: + free(capabilities.capabilitySets); + return error; } /** @@ -567,45 +542,46 @@ static UINT cliprdr_server_receive_capabilities(CliprdrServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT cliprdr_server_receive_temporary_directory(CliprdrServerContext* - context, wStream* s, CLIPRDR_HEADER* header) +static UINT cliprdr_server_receive_temporary_directory(CliprdrServerContext* context, wStream* s, + const CLIPRDR_HEADER* header) { - int length; + size_t length; WCHAR* wszTempDir; CLIPRDR_TEMP_DIRECTORY tempDirectory; - CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*) context->handle; + CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*)context->handle; size_t slength; UINT error = CHANNEL_RC_OK; - if ((slength = Stream_GetRemainingLength(s)) < 520) + WINPR_UNUSED(header); + if ((slength = Stream_GetRemainingLength(s)) < 260 * sizeof(WCHAR)) { - WLog_ERR(TAG, - "Stream_GetRemainingLength returned %"PRIuz" but should at least be 520", slength); + WLog_ERR(TAG, "Stream_GetRemainingLength returned %" PRIuz " but should at least be 520", + slength); return CHANNEL_RC_NO_MEMORY; } - wszTempDir = (WCHAR*) Stream_Pointer(s); + wszTempDir = (WCHAR*)Stream_Pointer(s); - if (wszTempDir[260] != 0) + if (wszTempDir[259] != 0) { - WLog_ERR(TAG, "wszTempDir[260] was not 0"); + WLog_ERR(TAG, "wszTempDir[259] was not 0"); return ERROR_INVALID_DATA; } free(cliprdr->temporaryDirectory); cliprdr->temporaryDirectory = NULL; - if (ConvertFromUnicode(CP_UTF8, 0, wszTempDir, -1, - &(cliprdr->temporaryDirectory), 0, NULL, NULL) < 1) + if (ConvertFromUnicode(CP_UTF8, 0, wszTempDir, -1, &(cliprdr->temporaryDirectory), 0, NULL, + NULL) < 1) { WLog_ERR(TAG, "failed to convert temporary directory name"); return ERROR_INVALID_DATA; } - length = strlen(cliprdr->temporaryDirectory); + length = strnlen(cliprdr->temporaryDirectory, 260); - if (length > 519) - length = 519; + if (length >= 260) + length = 259; CopyMemory(tempDirectory.szTempDir, cliprdr->temporaryDirectory, length); tempDirectory.szTempDir[length] = '\0'; @@ -613,7 +589,7 @@ static UINT cliprdr_server_receive_temporary_directory(CliprdrServerContext* IFCALLRET(context->TempDirectory, error, context, &tempDirectory); if (error) - WLog_ERR(TAG, "TempDirectory failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "TempDirectory failed with error %" PRIu32 "!", error); return error; } @@ -623,183 +599,27 @@ static UINT cliprdr_server_receive_temporary_directory(CliprdrServerContext* * * @return 0 on success, otherwise a Win32 error code */ -static UINT cliprdr_server_receive_format_list(CliprdrServerContext* context, - wStream* s, CLIPRDR_HEADER* header) +static UINT cliprdr_server_receive_format_list(CliprdrServerContext* context, wStream* s, + const CLIPRDR_HEADER* header) { - UINT32 index; - UINT32 dataLen; - size_t position; - BOOL asciiNames; - int formatNameLength; - char* szFormatName; - WCHAR* wszFormatName; - CLIPRDR_FORMAT* formats = NULL; CLIPRDR_FORMAT_LIST formatList; UINT error = CHANNEL_RC_OK; - dataLen = header->dataLen; - asciiNames = (header->msgFlags & CB_ASCII_NAMES) ? TRUE : FALSE; + formatList.msgType = CB_FORMAT_LIST; formatList.msgFlags = header->msgFlags; formatList.dataLen = header->dataLen; - index = 0; - formatList.numFormats = 0; - position = Stream_GetPosition(s); - if (!header->dataLen) - { - /* empty format list */ - formatList.formats = NULL; - formatList.numFormats = 0; - } - else if (!context->useLongFormatNames) - { - formatList.numFormats = (dataLen / 36); - - if ((formatList.numFormats * 36) != dataLen) - { - WLog_ERR(TAG, "Invalid short format list length: %"PRIu32"", dataLen); - return ERROR_INVALID_PARAMETER; - } - - if (formatList.numFormats) - formats = (CLIPRDR_FORMAT*) calloc(formatList.numFormats, - sizeof(CLIPRDR_FORMAT)); - - if (!formats) - { - WLog_ERR(TAG, "calloc failed!"); - return CHANNEL_RC_NO_MEMORY; - } - - formatList.formats = formats; - - while (dataLen) - { - Stream_Read_UINT32(s, formats[index].formatId); /* formatId (4 bytes) */ - dataLen -= 4; - formats[index].formatName = NULL; - - /* According to MS-RDPECLIP 2.2.3.1.1.1 formatName is "a 32-byte block containing - * the *null-terminated* name assigned to the Clipboard Format: (32 ASCII 8 characters - * or 16 Unicode characters)" - * However, both Windows RDSH and mstsc violate this specs as seen in the following - * example of a transferred short format name string: [R.i.c.h. .T.e.x.t. .F.o.r.m.a.t.] - * These are 16 unicode charaters - *without* terminating null ! - */ - - if (asciiNames) - { - szFormatName = (char*) Stream_Pointer(s); - - if (szFormatName[0]) - { - /* ensure null termination */ - formats[index].formatName = (char*) malloc(32 + 1); - CopyMemory(formats[index].formatName, szFormatName, 32); - formats[index].formatName[32] = '\0'; - } - } - else - { - wszFormatName = (WCHAR*) Stream_Pointer(s); - - if (wszFormatName[0]) - { - /* ConvertFromUnicode always returns a null-terminated - * string on success, even if the source string isn't. - */ - if (ConvertFromUnicode(CP_UTF8, 0, wszFormatName, 16, - &(formats[index].formatName), 0, NULL, NULL) < 1) - { - WLog_ERR(TAG, "failed to convert short clipboard format name"); - error = ERROR_INVALID_DATA; - goto out; - } - } - } - - Stream_Seek(s, 32); - dataLen -= 32; - index++; - } - } - else - { - while (dataLen) - { - Stream_Seek(s, 4); /* formatId (4 bytes) */ - dataLen -= 4; - wszFormatName = (WCHAR*) Stream_Pointer(s); - - if (!wszFormatName[0]) - formatNameLength = 0; - else - formatNameLength = _wcslen(wszFormatName); - - Stream_Seek(s, (formatNameLength + 1) * 2); - dataLen -= ((formatNameLength + 1) * 2); - formatList.numFormats++; - } - - dataLen = formatList.dataLen; - Stream_SetPosition(s, position); - - if (formatList.numFormats) - formats = (CLIPRDR_FORMAT*) calloc(formatList.numFormats, - sizeof(CLIPRDR_FORMAT)); - - if (!formats) - { - WLog_ERR(TAG, "calloc failed!"); - return CHANNEL_RC_NO_MEMORY; - } - - formatList.formats = formats; - - while (dataLen) - { - Stream_Read_UINT32(s, formats[index].formatId); /* formatId (4 bytes) */ - dataLen -= 4; - formats[index].formatName = NULL; - wszFormatName = (WCHAR*) Stream_Pointer(s); - - if (!wszFormatName[0]) - formatNameLength = 0; - else - formatNameLength = _wcslen(wszFormatName); - - if (formatNameLength) - { - if (ConvertFromUnicode(CP_UTF8, 0, wszFormatName, -1, - &(formats[index].formatName), 0, NULL, NULL) < 1) - { - WLog_ERR(TAG, "failed to convert long clipboard format name"); - error = ERROR_INVALID_DATA; - goto out; - } - } - - Stream_Seek(s, (formatNameLength + 1) * 2); - dataLen -= ((formatNameLength + 1) * 2); - index++; - } - } + if ((error = cliprdr_read_format_list(s, &formatList, context->useLongFormatNames))) + goto out; - WLog_DBG(TAG, "ClientFormatList: numFormats: %"PRIu32"", - formatList.numFormats); + WLog_DBG(TAG, "ClientFormatList: numFormats: %" PRIu32 "", formatList.numFormats); IFCALLRET(context->ClientFormatList, error, context, &formatList); if (error) - WLog_ERR(TAG, "ClientFormatList failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "ClientFormatList failed with error %" PRIu32 "!", error); out: - - for (index = 0; index < formatList.numFormats; index++) - { - free(formatList.formats[index].formatName); - } - - free(formatList.formats); + cliprdr_free_format_list(&formatList); return error; } @@ -808,20 +628,21 @@ out: * * @return 0 on success, otherwise a Win32 error code */ -static UINT cliprdr_server_receive_format_list_response( - CliprdrServerContext* context, wStream* s, CLIPRDR_HEADER* header) +static UINT cliprdr_server_receive_format_list_response(CliprdrServerContext* context, wStream* s, + const CLIPRDR_HEADER* header) { CLIPRDR_FORMAT_LIST_RESPONSE formatListResponse; UINT error = CHANNEL_RC_OK; + + WINPR_UNUSED(s); WLog_DBG(TAG, "CliprdrClientFormatListResponse"); formatListResponse.msgType = CB_FORMAT_LIST_RESPONSE; formatListResponse.msgFlags = header->msgFlags; formatListResponse.dataLen = header->dataLen; - IFCALLRET(context->ClientFormatListResponse, error, context, - &formatListResponse); + IFCALLRET(context->ClientFormatListResponse, error, context, &formatListResponse); if (error) - WLog_ERR(TAG, "ClientFormatListResponse failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "ClientFormatListResponse failed with error %" PRIu32 "!", error); return error; } @@ -831,8 +652,8 @@ static UINT cliprdr_server_receive_format_list_response( * * @return 0 on success, otherwise a Win32 error code */ -static UINT cliprdr_server_receive_lock_clipdata(CliprdrServerContext* context, - wStream* s, CLIPRDR_HEADER* header) +static UINT cliprdr_server_receive_lock_clipdata(CliprdrServerContext* context, wStream* s, + const CLIPRDR_HEADER* header) { CLIPRDR_LOCK_CLIPBOARD_DATA lockClipboardData; UINT error = CHANNEL_RC_OK; @@ -851,7 +672,7 @@ static UINT cliprdr_server_receive_lock_clipdata(CliprdrServerContext* context, IFCALLRET(context->ClientLockClipboardData, error, context, &lockClipboardData); if (error) - WLog_ERR(TAG, "ClientLockClipboardData failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "ClientLockClipboardData failed with error %" PRIu32 "!", error); return error; } @@ -861,29 +682,24 @@ static UINT cliprdr_server_receive_lock_clipdata(CliprdrServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT cliprdr_server_receive_unlock_clipdata(CliprdrServerContext* - context, wStream* s, CLIPRDR_HEADER* header) +static UINT cliprdr_server_receive_unlock_clipdata(CliprdrServerContext* context, wStream* s, + const CLIPRDR_HEADER* header) { CLIPRDR_UNLOCK_CLIPBOARD_DATA unlockClipboardData; UINT error = CHANNEL_RC_OK; WLog_DBG(TAG, "CliprdrClientUnlockClipData"); + unlockClipboardData.msgType = CB_UNLOCK_CLIPDATA; unlockClipboardData.msgFlags = header->msgFlags; unlockClipboardData.dataLen = header->dataLen; - if (Stream_GetRemainingLength(s) < 4) - { - WLog_ERR(TAG, "not enough data in stream!"); - return ERROR_INVALID_DATA; - } + if ((error = cliprdr_read_unlock_clipdata(s, &unlockClipboardData))) + return error; - Stream_Read_UINT32(s, - unlockClipboardData.clipDataId); /* clipDataId (4 bytes) */ - IFCALLRET(context->ClientUnlockClipboardData, error, context, - &unlockClipboardData); + IFCALLRET(context->ClientUnlockClipboardData, error, context, &unlockClipboardData); if (error) - WLog_ERR(TAG, "ClientUnlockClipboardData failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "ClientUnlockClipboardData failed with error %" PRIu32 "!", error); return error; } @@ -893,8 +709,8 @@ static UINT cliprdr_server_receive_unlock_clipdata(CliprdrServerContext* * * @return 0 on success, otherwise a Win32 error code */ -static UINT cliprdr_server_receive_format_data_request(CliprdrServerContext* - context, wStream* s, CLIPRDR_HEADER* header) +static UINT cliprdr_server_receive_format_data_request(CliprdrServerContext* context, wStream* s, + const CLIPRDR_HEADER* header) { CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest; UINT error = CHANNEL_RC_OK; @@ -903,18 +719,14 @@ static UINT cliprdr_server_receive_format_data_request(CliprdrServerContext* formatDataRequest.msgFlags = header->msgFlags; formatDataRequest.dataLen = header->dataLen; - if (Stream_GetRemainingLength(s) < 4) - { - WLog_ERR(TAG, "not enough data in stream!"); - return ERROR_INVALID_DATA; - } + if ((error = cliprdr_read_format_data_request(s, &formatDataRequest))) + return error; - Stream_Read_UINT32(s, - formatDataRequest.requestedFormatId); /* requestedFormatId (4 bytes) */ + context->lastRequestedFormatId = formatDataRequest.requestedFormatId; IFCALLRET(context->ClientFormatDataRequest, error, context, &formatDataRequest); if (error) - WLog_ERR(TAG, "ClientFormatDataRequest failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "ClientFormatDataRequest failed with error %" PRIu32 "!", error); return error; } @@ -924,36 +736,25 @@ static UINT cliprdr_server_receive_format_data_request(CliprdrServerContext* * * @return 0 on success, otherwise a Win32 error code */ -static UINT cliprdr_server_receive_format_data_response( - CliprdrServerContext* context, wStream* s, CLIPRDR_HEADER* header) +static UINT cliprdr_server_receive_format_data_response(CliprdrServerContext* context, wStream* s, + const CLIPRDR_HEADER* header) { CLIPRDR_FORMAT_DATA_RESPONSE formatDataResponse; UINT error = CHANNEL_RC_OK; + WLog_DBG(TAG, "CliprdrClientFormatDataResponse"); formatDataResponse.msgType = CB_FORMAT_DATA_RESPONSE; formatDataResponse.msgFlags = header->msgFlags; formatDataResponse.dataLen = header->dataLen; - formatDataResponse.requestedFormatData = NULL; - - if (Stream_GetRemainingLength(s) < header->dataLen) - { - WLog_ERR(TAG, "not enough data in stream!"); - return ERROR_INVALID_DATA; - } - if (header->dataLen) - { - formatDataResponse.requestedFormatData = (BYTE*) malloc(header->dataLen); - Stream_Read(s, formatDataResponse.requestedFormatData, header->dataLen); - } + if ((error = cliprdr_read_format_data_response(s, &formatDataResponse))) + return error; - IFCALLRET(context->ClientFormatDataResponse, error, context, - &formatDataResponse); + IFCALLRET(context->ClientFormatDataResponse, error, context, &formatDataResponse); if (error) - WLog_ERR(TAG, "ClientFormatDataResponse failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "ClientFormatDataResponse failed with error %" PRIu32 "!", error); - free(formatDataResponse.requestedFormatData); return error; } @@ -962,8 +763,8 @@ static UINT cliprdr_server_receive_format_data_response( * * @return 0 on success, otherwise a Win32 error code */ -static UINT cliprdr_server_receive_filecontents_request( - CliprdrServerContext* context, wStream* s, CLIPRDR_HEADER* header) +static UINT cliprdr_server_receive_filecontents_request(CliprdrServerContext* context, wStream* s, + const CLIPRDR_HEADER* header) { CLIPRDR_FILE_CONTENTS_REQUEST request; UINT error = CHANNEL_RC_OK; @@ -972,28 +773,13 @@ static UINT cliprdr_server_receive_filecontents_request( request.msgFlags = header->msgFlags; request.dataLen = header->dataLen; - if (Stream_GetRemainingLength(s) < 24) - { - WLog_ERR(TAG, "not enough data in stream!"); - return ERROR_INVALID_DATA; - } - - Stream_Read_UINT32(s, request.streamId); /* streamId (4 bytes) */ - Stream_Read_UINT32(s, request.listIndex); /* listIndex (4 bytes) */ - Stream_Read_UINT32(s, request.dwFlags); /* dwFlags (4 bytes) */ - Stream_Read_UINT32(s, request.nPositionLow); /* nPositionLow (4 bytes) */ - Stream_Read_UINT32(s, request.nPositionHigh); /* nPositionHigh (4 bytes) */ - Stream_Read_UINT32(s, request.cbRequested); /* cbRequested (4 bytes) */ - - if (Stream_GetRemainingLength(s) < 4) /* clipDataId (4 bytes) optional */ - request.clipDataId = 0; - else - Stream_Read_UINT32(s, request.clipDataId); + if ((error = cliprdr_read_file_contents_request(s, &request))) + return error; IFCALLRET(context->ClientFileContentsRequest, error, context, &request); if (error) - WLog_ERR(TAG, "ClientFileContentsRequest failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "ClientFileContentsRequest failed with error %" PRIu32 "!", error); return error; } @@ -1003,29 +789,24 @@ static UINT cliprdr_server_receive_filecontents_request( * * @return 0 on success, otherwise a Win32 error code */ -static UINT cliprdr_server_receive_filecontents_response( - CliprdrServerContext* context, wStream* s, CLIPRDR_HEADER* header) +static UINT cliprdr_server_receive_filecontents_response(CliprdrServerContext* context, wStream* s, + const CLIPRDR_HEADER* header) { CLIPRDR_FILE_CONTENTS_RESPONSE response; UINT error = CHANNEL_RC_OK; WLog_DBG(TAG, "CliprdrClientFileContentsResponse"); + response.msgType = CB_FILECONTENTS_RESPONSE; response.msgFlags = header->msgFlags; response.dataLen = header->dataLen; - if (Stream_GetRemainingLength(s) < 4) - { - WLog_ERR(TAG, "not enough data in stream!"); - return ERROR_INVALID_DATA; - } + if ((error = cliprdr_read_file_contents_response(s, &response))) + return error; - Stream_Read_UINT32(s, response.streamId); /* streamId (4 bytes) */ - response.cbRequested = header->dataLen - 4; - response.requestedData = Stream_Pointer(s); /* requestedFileContentsData */ IFCALLRET(context->ClientFileContentsResponse, error, context, &response); if (error) - WLog_ERR(TAG, "ClientFileContentsResponse failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "ClientFileContentsResponse failed with error %" PRIu32 "!", error); return error; } @@ -1035,19 +816,20 @@ static UINT cliprdr_server_receive_filecontents_response( * * @return 0 on success, otherwise a Win32 error code */ -static UINT cliprdr_server_receive_pdu(CliprdrServerContext* context, - wStream* s, CLIPRDR_HEADER* header) +static UINT cliprdr_server_receive_pdu(CliprdrServerContext* context, wStream* s, + const CLIPRDR_HEADER* header) { UINT error; WLog_DBG(TAG, - "CliprdrServerReceivePdu: msgType: %"PRIu16" msgFlags: 0x%04"PRIX16" dataLen: %"PRIu32"", + "CliprdrServerReceivePdu: msgType: %" PRIu16 " msgFlags: 0x%04" PRIX16 + " dataLen: %" PRIu32 "", header->msgType, header->msgFlags, header->dataLen); switch (header->msgType) { case CB_CLIP_CAPS: if ((error = cliprdr_server_receive_capabilities(context, s, header))) - WLog_ERR(TAG, "cliprdr_server_receive_capabilities failed with error %"PRIu32"!", + WLog_ERR(TAG, "cliprdr_server_receive_capabilities failed with error %" PRIu32 "!", error); break; @@ -1055,13 +837,15 @@ static UINT cliprdr_server_receive_pdu(CliprdrServerContext* context, case CB_TEMP_DIRECTORY: if ((error = cliprdr_server_receive_temporary_directory(context, s, header))) WLog_ERR(TAG, - "cliprdr_server_receive_temporary_directory failed with error %"PRIu32"!", error); + "cliprdr_server_receive_temporary_directory failed with error %" PRIu32 + "!", + error); break; case CB_FORMAT_LIST: if ((error = cliprdr_server_receive_format_list(context, s, header))) - WLog_ERR(TAG, "cliprdr_server_receive_format_list failed with error %"PRIu32"!", + WLog_ERR(TAG, "cliprdr_server_receive_format_list failed with error %" PRIu32 "!", error); break; @@ -1069,20 +853,23 @@ static UINT cliprdr_server_receive_pdu(CliprdrServerContext* context, case CB_FORMAT_LIST_RESPONSE: if ((error = cliprdr_server_receive_format_list_response(context, s, header))) WLog_ERR(TAG, - "cliprdr_server_receive_format_list_response failed with error %"PRIu32"!", error); + "cliprdr_server_receive_format_list_response failed with error %" PRIu32 + "!", + error); break; case CB_LOCK_CLIPDATA: if ((error = cliprdr_server_receive_lock_clipdata(context, s, header))) - WLog_ERR(TAG, "cliprdr_server_receive_lock_clipdata failed with error %"PRIu32"!", + WLog_ERR(TAG, "cliprdr_server_receive_lock_clipdata failed with error %" PRIu32 "!", error); break; case CB_UNLOCK_CLIPDATA: if ((error = cliprdr_server_receive_unlock_clipdata(context, s, header))) - WLog_ERR(TAG, "cliprdr_server_receive_unlock_clipdata failed with error %"PRIu32"!", + WLog_ERR(TAG, + "cliprdr_server_receive_unlock_clipdata failed with error %" PRIu32 "!", error); break; @@ -1090,34 +877,42 @@ static UINT cliprdr_server_receive_pdu(CliprdrServerContext* context, case CB_FORMAT_DATA_REQUEST: if ((error = cliprdr_server_receive_format_data_request(context, s, header))) WLog_ERR(TAG, - "cliprdr_server_receive_format_data_request failed with error %"PRIu32"!", error); + "cliprdr_server_receive_format_data_request failed with error %" PRIu32 + "!", + error); break; case CB_FORMAT_DATA_RESPONSE: if ((error = cliprdr_server_receive_format_data_response(context, s, header))) WLog_ERR(TAG, - "cliprdr_server_receive_format_data_response failed with error %"PRIu32"!", error); + "cliprdr_server_receive_format_data_response failed with error %" PRIu32 + "!", + error); break; case CB_FILECONTENTS_REQUEST: if ((error = cliprdr_server_receive_filecontents_request(context, s, header))) WLog_ERR(TAG, - "cliprdr_server_receive_filecontents_request failed with error %"PRIu32"!", error); + "cliprdr_server_receive_filecontents_request failed with error %" PRIu32 + "!", + error); break; case CB_FILECONTENTS_RESPONSE: if ((error = cliprdr_server_receive_filecontents_response(context, s, header))) WLog_ERR(TAG, - "cliprdr_server_receive_filecontents_response failed with error %"PRIu32"!", error); + "cliprdr_server_receive_filecontents_response failed with error %" PRIu32 + "!", + error); break; default: error = ERROR_INVALID_DATA; - WLog_DBG(TAG, "Unexpected clipboard PDU type: %"PRIu16"", header->msgType); + WLog_ERR(TAG, "Unexpected clipboard PDU type: %" PRIu16 "", header->msgType); break; } @@ -1132,13 +927,14 @@ static UINT cliprdr_server_receive_pdu(CliprdrServerContext* context, static UINT cliprdr_server_init(CliprdrServerContext* context) { UINT32 generalFlags; - CLIPRDR_CAPABILITIES capabilities; - CLIPRDR_MONITOR_READY monitorReady; CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet; UINT error; - ZeroMemory(&capabilities, sizeof(capabilities)); - ZeroMemory(&monitorReady, sizeof(monitorReady)); + CLIPRDR_MONITOR_READY monitorReady = { 0 }; + CLIPRDR_CAPABILITIES capabilities = { 0 }; + generalFlags = 0; + monitorReady.msgType = CB_MONITOR_READY; + capabilities.msgType = CB_CLIP_CAPS; if (context->useLongFormatNames) generalFlags |= CB_USE_LONG_FORMAT_NAMES; @@ -1156,7 +952,7 @@ static UINT cliprdr_server_init(CliprdrServerContext* context) capabilities.msgFlags = 0; capabilities.dataLen = 4 + CB_CAPSTYPE_GENERAL_LEN; capabilities.cCapabilitiesSets = 1; - capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*) &generalCapabilitySet; + capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*)&generalCapabilitySet; generalCapabilitySet.capabilitySetType = CB_CAPSTYPE_GENERAL; generalCapabilitySet.capabilitySetLength = CB_CAPSTYPE_GENERAL_LEN; generalCapabilitySet.version = CB_CAPS_VERSION_2; @@ -1164,13 +960,13 @@ static UINT cliprdr_server_init(CliprdrServerContext* context) if ((error = context->ServerCapabilities(context, &capabilities))) { - WLog_ERR(TAG, "ServerCapabilities failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "ServerCapabilities failed with error %" PRIu32 "!", error); return error; } if ((error = context->MonitorReady(context, &monitorReady))) { - WLog_ERR(TAG, "MonitorReady failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "MonitorReady failed with error %" PRIu32 "!", error); return error; } @@ -1182,14 +978,14 @@ static UINT cliprdr_server_init(CliprdrServerContext* context) * * @return 0 on success, otherwise a Win32 error code */ -UINT cliprdr_server_read(CliprdrServerContext* context) +static UINT cliprdr_server_read(CliprdrServerContext* context) { wStream* s; size_t position; DWORD BytesToRead; DWORD BytesReturned; CLIPRDR_HEADER header; - CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*) context->handle; + CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*)context->handle; UINT error; DWORD status; s = cliprdr->s; @@ -1197,21 +993,21 @@ UINT cliprdr_server_read(CliprdrServerContext* context) if (Stream_GetPosition(s) < CLIPRDR_HEADER_LENGTH) { BytesReturned = 0; - BytesToRead = CLIPRDR_HEADER_LENGTH - Stream_GetPosition(s); + BytesToRead = (UINT32)(CLIPRDR_HEADER_LENGTH - Stream_GetPosition(s)); status = WaitForSingleObject(cliprdr->ChannelEvent, 0); if (status == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error); return error; } if (status == WAIT_TIMEOUT) return CHANNEL_RC_OK; - if (!WTSVirtualChannelRead(cliprdr->ChannelHandle, 0, - (PCHAR) Stream_Pointer(s), BytesToRead, &BytesReturned)) + if (!WTSVirtualChannelRead(cliprdr->ChannelHandle, 0, (PCHAR)Stream_Pointer(s), BytesToRead, + &BytesReturned)) { WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); return ERROR_INTERNAL_ERROR; @@ -1224,9 +1020,9 @@ UINT cliprdr_server_read(CliprdrServerContext* context) { position = Stream_GetPosition(s); Stream_SetPosition(s, 0); - Stream_Read_UINT16(s, header.msgType); /* msgType (2 bytes) */ + Stream_Read_UINT16(s, header.msgType); /* msgType (2 bytes) */ Stream_Read_UINT16(s, header.msgFlags); /* msgFlags (2 bytes) */ - Stream_Read_UINT32(s, header.dataLen); /* dataLen (4 bytes) */ + Stream_Read_UINT32(s, header.dataLen); /* dataLen (4 bytes) */ if (!Stream_EnsureCapacity(s, (header.dataLen + CLIPRDR_HEADER_LENGTH))) { @@ -1239,21 +1035,22 @@ UINT cliprdr_server_read(CliprdrServerContext* context) if (Stream_GetPosition(s) < (header.dataLen + CLIPRDR_HEADER_LENGTH)) { BytesReturned = 0; - BytesToRead = (header.dataLen + CLIPRDR_HEADER_LENGTH) - Stream_GetPosition(s); + BytesToRead = + (UINT32)((header.dataLen + CLIPRDR_HEADER_LENGTH) - Stream_GetPosition(s)); status = WaitForSingleObject(cliprdr->ChannelEvent, 0); if (status == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error); return error; } if (status == WAIT_TIMEOUT) return CHANNEL_RC_OK; - if (!WTSVirtualChannelRead(cliprdr->ChannelHandle, 0, - (PCHAR) Stream_Pointer(s), BytesToRead, &BytesReturned)) + if (!WTSVirtualChannelRead(cliprdr->ChannelHandle, 0, (PCHAR)Stream_Pointer(s), + BytesToRead, &BytesReturned)) { WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); return ERROR_INTERNAL_ERROR; @@ -1270,7 +1067,8 @@ UINT cliprdr_server_read(CliprdrServerContext* context) if ((error = cliprdr_server_receive_pdu(context, s, &header))) { - WLog_ERR(TAG, "cliprdr_server_receive_pdu failed with error code %"PRIu32"!", error); + WLog_ERR(TAG, "cliprdr_server_receive_pdu failed with error code %" PRIu32 "!", + error); return error; } @@ -1281,7 +1079,7 @@ UINT cliprdr_server_read(CliprdrServerContext* context) if (status == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error); return error; } @@ -1291,8 +1089,8 @@ UINT cliprdr_server_read(CliprdrServerContext* context) BytesReturned = 0; BytesToRead = 4; - if (!WTSVirtualChannelRead(cliprdr->ChannelHandle, 0, - (PCHAR) Stream_Pointer(s), BytesToRead, &BytesReturned)) + if (!WTSVirtualChannelRead(cliprdr->ChannelHandle, 0, (PCHAR)Stream_Pointer(s), + BytesToRead, &BytesReturned)) { WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); return ERROR_INTERNAL_ERROR; @@ -1300,7 +1098,7 @@ UINT cliprdr_server_read(CliprdrServerContext* context) if (BytesReturned == 4) { - Stream_Read_UINT16(s, header.msgType); /* msgType (2 bytes) */ + Stream_Read_UINT16(s, header.msgType); /* msgType (2 bytes) */ Stream_Read_UINT16(s, header.msgFlags); /* msgFlags (2 bytes) */ if (!header.msgType) @@ -1325,19 +1123,22 @@ static DWORD WINAPI cliprdr_server_thread(LPVOID arg) DWORD nCount; HANDLE events[8]; HANDLE ChannelEvent; - CliprdrServerContext* context = (CliprdrServerContext*) arg; - CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*) context->handle; - UINT error; + CliprdrServerContext* context = (CliprdrServerContext*)arg; + CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*)context->handle; + UINT error = CHANNEL_RC_OK; ChannelEvent = context->GetEventHandle(context); nCount = 0; events[nCount++] = cliprdr->StopEvent; events[nCount++] = ChannelEvent; - if ((error = cliprdr_server_init(context))) + if (context->autoInitializationSequence) { - WLog_ERR(TAG, "cliprdr_server_init failed with error %"PRIu32"!", error); - goto out; + if ((error = cliprdr_server_init(context))) + { + WLog_ERR(TAG, "cliprdr_server_init failed with error %" PRIu32 "!", error); + goto out; + } } while (1) @@ -1347,7 +1148,7 @@ static DWORD WINAPI cliprdr_server_thread(LPVOID arg) if (status == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"", error); + WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error); goto out; } @@ -1356,7 +1157,7 @@ static DWORD WINAPI cliprdr_server_thread(LPVOID arg) if (status == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error); goto out; } @@ -1368,7 +1169,7 @@ static DWORD WINAPI cliprdr_server_thread(LPVOID arg) if (status == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error); goto out; } @@ -1376,7 +1177,7 @@ static DWORD WINAPI cliprdr_server_thread(LPVOID arg) { if ((error = context->CheckEventHandle(context))) { - WLog_ERR(TAG, "CheckEventHandle failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "CheckEventHandle failed with error %" PRIu32 "!", error); break; } } @@ -1385,8 +1186,7 @@ static DWORD WINAPI cliprdr_server_thread(LPVOID arg) out: if (error && context->rdpcontext) - setChannelError(context->rdpcontext, error, - "cliprdr_server_thread reported an error"); + setChannelError(context->rdpcontext, error, "cliprdr_server_thread reported an error"); ExitThread(error); return error; @@ -1401,9 +1201,8 @@ static UINT cliprdr_server_open(CliprdrServerContext* context) { void* buffer = NULL; DWORD BytesReturned = 0; - CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*) context->handle; - cliprdr->ChannelHandle = WTSVirtualChannelOpen(cliprdr->vcm, - WTS_CURRENT_SESSION, "cliprdr"); + CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*)context->handle; + cliprdr->ChannelHandle = WTSVirtualChannelOpen(cliprdr->vcm, WTS_CURRENT_SESSION, "cliprdr"); if (!cliprdr->ChannelHandle) { @@ -1413,8 +1212,8 @@ static UINT cliprdr_server_open(CliprdrServerContext* context) cliprdr->ChannelEvent = NULL; - if (WTSVirtualChannelQuery(cliprdr->ChannelHandle, WTSVirtualEventHandle, - &buffer, &BytesReturned)) + if (WTSVirtualChannelQuery(cliprdr->ChannelHandle, WTSVirtualEventHandle, &buffer, + &BytesReturned)) { if (BytesReturned != sizeof(HANDLE)) { @@ -1442,7 +1241,7 @@ static UINT cliprdr_server_open(CliprdrServerContext* context) */ static UINT cliprdr_server_close(CliprdrServerContext* context) { - CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*) context->handle; + CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*)context->handle; if (cliprdr->ChannelHandle) { @@ -1460,7 +1259,7 @@ static UINT cliprdr_server_close(CliprdrServerContext* context) */ static UINT cliprdr_server_start(CliprdrServerContext* context) { - CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*) context->handle; + CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*)context->handle; UINT error; if (!cliprdr->ChannelHandle) @@ -1478,7 +1277,7 @@ static UINT cliprdr_server_start(CliprdrServerContext* context) return ERROR_INTERNAL_ERROR; } - if (!(cliprdr->Thread = CreateThread(NULL, 0, cliprdr_server_thread, (void*) context, 0, NULL))) + if (!(cliprdr->Thread = CreateThread(NULL, 0, cliprdr_server_thread, (void*)context, 0, NULL))) { WLog_ERR(TAG, "CreateThread failed!"); CloseHandle(cliprdr->StopEvent); @@ -1497,7 +1296,7 @@ static UINT cliprdr_server_start(CliprdrServerContext* context) static UINT cliprdr_server_stop(CliprdrServerContext* context) { UINT error = CHANNEL_RC_OK; - CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*) context->handle; + CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*)context->handle; if (cliprdr->StopEvent) { @@ -1506,7 +1305,7 @@ static UINT cliprdr_server_stop(CliprdrServerContext* context) if (WaitForSingleObject(cliprdr->Thread, INFINITE) == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error); return error; } @@ -1522,7 +1321,7 @@ static UINT cliprdr_server_stop(CliprdrServerContext* context) static HANDLE cliprdr_server_get_event_handle(CliprdrServerContext* context) { - CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*) context->handle; + CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*)context->handle; return cliprdr->ChannelEvent; } @@ -1540,10 +1339,11 @@ CliprdrServerContext* cliprdr_server_context_new(HANDLE vcm) { CliprdrServerContext* context; CliprdrServerPrivate* cliprdr; - context = (CliprdrServerContext*) calloc(1, sizeof(CliprdrServerContext)); + context = (CliprdrServerContext*)calloc(1, sizeof(CliprdrServerContext)); if (context) { + context->autoInitializationSequence = TRUE; context->Open = cliprdr_server_open; context->Close = cliprdr_server_close; context->Start = cliprdr_server_start; @@ -1560,8 +1360,7 @@ CliprdrServerContext* cliprdr_server_context_new(HANDLE vcm) context->ServerFormatDataResponse = cliprdr_server_format_data_response; context->ServerFileContentsRequest = cliprdr_server_file_contents_request; context->ServerFileContentsResponse = cliprdr_server_file_contents_response; - cliprdr = context->handle = (CliprdrServerPrivate*) calloc(1, - sizeof(CliprdrServerPrivate)); + cliprdr = context->handle = (CliprdrServerPrivate*)calloc(1, sizeof(CliprdrServerPrivate)); if (cliprdr) { @@ -1594,7 +1393,7 @@ void cliprdr_server_context_free(CliprdrServerContext* context) if (!context) return; - cliprdr = (CliprdrServerPrivate*) context->handle; + cliprdr = (CliprdrServerPrivate*)context->handle; if (cliprdr) { diff --git a/channels/cliprdr/server/cliprdr_main.h b/channels/cliprdr/server/cliprdr_main.h index 248f341..fce0ddb 100644 --- a/channels/cliprdr/server/cliprdr_main.h +++ b/channels/cliprdr/server/cliprdr_main.h @@ -30,7 +30,7 @@ #define TAG CHANNELS_TAG("cliprdr.server") -#define CLIPRDR_HEADER_LENGTH 8 +#define CLIPRDR_HEADER_LENGTH 8 struct _cliprdr_server_private { diff --git a/channels/disp/CMakeLists.txt b/channels/disp/CMakeLists.txt index 541892d..44afe99 100644 --- a/channels/disp/CMakeLists.txt +++ b/channels/disp/CMakeLists.txt @@ -20,3 +20,7 @@ define_channel("disp") 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/disp/client/CMakeLists.txt b/channels/disp/client/CMakeLists.txt index 1ec2c6f..6376f6e 100644 --- a/channels/disp/client/CMakeLists.txt +++ b/channels/disp/client/CMakeLists.txt @@ -19,7 +19,9 @@ define_channel_client("disp") set(${MODULE_PREFIX}_SRCS disp_main.c - disp_main.h) + disp_main.h + ../disp_common.c + ../disp_common.h) include_directories(..) diff --git a/channels/disp/client/disp_main.c b/channels/disp/client/disp_main.c index 0555317..fa92c25 100644 --- a/channels/disp/client/disp_main.c +++ b/channels/disp/client/disp_main.c @@ -40,6 +40,7 @@ #include #include "disp_main.h" +#include "../disp_common.h" struct _DISP_CHANNEL_CALLBACK { @@ -79,41 +80,42 @@ typedef struct _DISP_PLUGIN DISP_PLUGIN; * * @return 0 on success, otherwise a Win32 error code */ -UINT disp_send_display_control_monitor_layout_pdu(DISP_CHANNEL_CALLBACK* callback, UINT32 NumMonitors, DISPLAY_CONTROL_MONITOR_LAYOUT* Monitors) +static UINT disp_send_display_control_monitor_layout_pdu(DISP_CHANNEL_CALLBACK* callback, + UINT32 NumMonitors, + DISPLAY_CONTROL_MONITOR_LAYOUT* Monitors) { UINT status; wStream* s; - UINT32 type; UINT32 index; - UINT32 length; DISP_PLUGIN* disp; UINT32 MonitorLayoutSize; + DISPLAY_CONTROL_HEADER header; + disp = (DISP_PLUGIN*)callback->plugin; + MonitorLayoutSize = DISPLAY_CONTROL_MONITOR_LAYOUT_SIZE; + header.length = 8 + 8 + (NumMonitors * MonitorLayoutSize); + header.type = DISPLAY_CONTROL_PDU_TYPE_MONITOR_LAYOUT; - disp = (DISP_PLUGIN*) callback->plugin; + s = Stream_New(NULL, header.length); - MonitorLayoutSize = 40; - - length = 8 + 8 + (NumMonitors * MonitorLayoutSize); - - type = DISPLAY_CONTROL_PDU_TYPE_MONITOR_LAYOUT; - - s = Stream_New(NULL, length); - if(!s) + if (!s) { WLog_ERR(TAG, "Stream_New failed!"); return CHANNEL_RC_NO_MEMORY; } - Stream_Write_UINT32(s, type); /* Type (4 bytes) */ - Stream_Write_UINT32(s, length); /* Length (4 bytes) */ + if ((status = disp_write_header(s, &header))) + { + WLog_ERR(TAG, "Failed to write header with error %" PRIu32 "!", status); + goto out; + } if (NumMonitors > disp->MaxNumMonitors) NumMonitors = disp->MaxNumMonitors; Stream_Write_UINT32(s, MonitorLayoutSize); /* MonitorLayoutSize (4 bytes) */ - Stream_Write_UINT32(s, NumMonitors); /* NumMonitors (4 bytes) */ - - WLog_DBG(TAG, "disp_send_display_control_monitor_layout_pdu: NumMonitors=%"PRIu32"", NumMonitors); + Stream_Write_UINT32(s, NumMonitors); /* NumMonitors (4 bytes) */ + WLog_DBG(TAG, "disp_send_display_control_monitor_layout_pdu: NumMonitors=%" PRIu32 "", + NumMonitors); for (index = 0; index < NumMonitors; index++) { @@ -134,30 +136,34 @@ UINT disp_send_display_control_monitor_layout_pdu(DISP_CHANNEL_CALLBACK* callbac if (Monitors[index].Height > 8192) Monitors[index].Height = 8192; - Stream_Write_UINT32(s, Monitors[index].Flags); /* Flags (4 bytes) */ - Stream_Write_UINT32(s, Monitors[index].Left); /* Left (4 bytes) */ - Stream_Write_UINT32(s, Monitors[index].Top); /* Top (4 bytes) */ - Stream_Write_UINT32(s, Monitors[index].Width); /* Width (4 bytes) */ - Stream_Write_UINT32(s, Monitors[index].Height); /* Height (4 bytes) */ - Stream_Write_UINT32(s, Monitors[index].PhysicalWidth); /* PhysicalWidth (4 bytes) */ + Stream_Write_UINT32(s, Monitors[index].Flags); /* Flags (4 bytes) */ + Stream_Write_UINT32(s, Monitors[index].Left); /* Left (4 bytes) */ + Stream_Write_UINT32(s, Monitors[index].Top); /* Top (4 bytes) */ + Stream_Write_UINT32(s, Monitors[index].Width); /* Width (4 bytes) */ + Stream_Write_UINT32(s, Monitors[index].Height); /* Height (4 bytes) */ + Stream_Write_UINT32(s, Monitors[index].PhysicalWidth); /* PhysicalWidth (4 bytes) */ Stream_Write_UINT32(s, Monitors[index].PhysicalHeight); /* PhysicalHeight (4 bytes) */ - Stream_Write_UINT32(s, Monitors[index].Orientation); /* Orientation (4 bytes) */ - Stream_Write_UINT32(s, Monitors[index].DesktopScaleFactor); /* DesktopScaleFactor (4 bytes) */ + Stream_Write_UINT32(s, Monitors[index].Orientation); /* Orientation (4 bytes) */ + Stream_Write_UINT32(s, + Monitors[index].DesktopScaleFactor); /* DesktopScaleFactor (4 bytes) */ Stream_Write_UINT32(s, Monitors[index].DeviceScaleFactor); /* DeviceScaleFactor (4 bytes) */ - - WLog_DBG(TAG, "\t%d : Flags: 0x%08"PRIX32" Left/Top: (%"PRId32",%"PRId32") W/H=%"PRIu32"x%"PRIu32")", index, - Monitors[index].Flags, Monitors[index].Left, Monitors[index].Top, Monitors[index].Width, - Monitors[index].Height); - WLog_DBG(TAG, "\t PhysicalWidth: %"PRIu32" PhysicalHeight: %"PRIu32" Orientation: %"PRIu32"", - Monitors[index].PhysicalWidth, Monitors[index].PhysicalHeight, Monitors[index].Orientation); + WLog_DBG(TAG, + "\t%d : Flags: 0x%08" PRIX32 " Left/Top: (%" PRId32 ",%" PRId32 ") W/H=%" PRIu32 + "x%" PRIu32 ")", + index, Monitors[index].Flags, Monitors[index].Left, Monitors[index].Top, + Monitors[index].Width, Monitors[index].Height); + WLog_DBG(TAG, + "\t PhysicalWidth: %" PRIu32 " PhysicalHeight: %" PRIu32 " Orientation: %" PRIu32 + "", + Monitors[index].PhysicalWidth, Monitors[index].PhysicalHeight, + Monitors[index].Orientation); } +out: Stream_SealLength(s); - - status = callback->channel->Write(callback->channel, (UINT32) Stream_Length(s), Stream_Buffer(s), NULL); - + status = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s), + NULL); Stream_Free(s, TRUE); - return status; } @@ -166,14 +172,13 @@ UINT disp_send_display_control_monitor_layout_pdu(DISP_CHANNEL_CALLBACK* callbac * * @return 0 on success, otherwise a Win32 error code */ -UINT disp_recv_display_control_caps_pdu(DISP_CHANNEL_CALLBACK* callback, wStream* s) +static UINT disp_recv_display_control_caps_pdu(DISP_CHANNEL_CALLBACK* callback, wStream* s) { DISP_PLUGIN* disp; - DispClientContext *context; + DispClientContext* context; UINT ret = CHANNEL_RC_OK; - - disp = (DISP_PLUGIN*) callback->plugin; - context = (DispClientContext *)disp->iface.pInterface; + disp = (DISP_PLUGIN*)callback->plugin; + context = (DispClientContext*)disp->iface.pInterface; if (Stream_GetRemainingLength(s) < 12) { @@ -181,12 +186,13 @@ UINT disp_recv_display_control_caps_pdu(DISP_CHANNEL_CALLBACK* callback, wStream return ERROR_INVALID_DATA; } - Stream_Read_UINT32(s, disp->MaxNumMonitors); /* MaxNumMonitors (4 bytes) */ + Stream_Read_UINT32(s, disp->MaxNumMonitors); /* MaxNumMonitors (4 bytes) */ Stream_Read_UINT32(s, disp->MaxMonitorAreaFactorA); /* MaxMonitorAreaFactorA (4 bytes) */ Stream_Read_UINT32(s, disp->MaxMonitorAreaFactorB); /* MaxMonitorAreaFactorB (4 bytes) */ if (context->DisplayControlCaps) - ret = context->DisplayControlCaps(context, disp->MaxNumMonitors, disp->MaxMonitorAreaFactorA, disp->MaxMonitorAreaFactorB); + ret = context->DisplayControlCaps(context, disp->MaxNumMonitors, + disp->MaxMonitorAreaFactorA, disp->MaxMonitorAreaFactorB); return ret; } @@ -196,10 +202,10 @@ UINT disp_recv_display_control_caps_pdu(DISP_CHANNEL_CALLBACK* callback, wStream * * @return 0 on success, otherwise a Win32 error code */ -UINT disp_recv_pdu(DISP_CHANNEL_CALLBACK* callback, wStream* s) +static UINT disp_recv_pdu(DISP_CHANNEL_CALLBACK* callback, wStream* s) { - UINT32 type; - UINT32 length; + UINT32 error; + DISPLAY_CONTROL_HEADER header; if (Stream_GetRemainingLength(s) < 8) { @@ -207,18 +213,25 @@ UINT disp_recv_pdu(DISP_CHANNEL_CALLBACK* callback, wStream* s) return ERROR_INVALID_DATA; } - Stream_Read_UINT32(s, type); /* Type (4 bytes) */ - Stream_Read_UINT32(s, length); /* Length (4 bytes) */ + if ((error = disp_read_header(s, &header))) + { + WLog_ERR(TAG, "disp_read_header failed with error %" PRIu32 "!", error); + return error; + } - //WLog_ERR(TAG, "Type: %"PRIu32" Length: %"PRIu32"", type, length); + if (!Stream_EnsureRemainingCapacity(s, header.length)) + { + WLog_ERR(TAG, "not enough remaining data"); + return ERROR_INVALID_DATA; + } - switch (type) + switch (header.type) { case DISPLAY_CONTROL_PDU_TYPE_CAPS: return disp_recv_display_control_caps_pdu(callback, s); default: - WLog_ERR(TAG, "Type %"PRIu32" not recognized!", type); + WLog_ERR(TAG, "Type %" PRIu32 " not recognized!", header.type); return ERROR_INTERNAL_ERROR; } } @@ -228,10 +241,9 @@ UINT disp_recv_pdu(DISP_CHANNEL_CALLBACK* callback, wStream* s) * * @return 0 on success, otherwise a Win32 error code */ -static UINT disp_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *data) +static UINT disp_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data) { - DISP_CHANNEL_CALLBACK* callback = (DISP_CHANNEL_CALLBACK*) pChannelCallback; - + DISP_CHANNEL_CALLBACK* callback = (DISP_CHANNEL_CALLBACK*)pChannelCallback; return disp_recv_pdu(callback, data); } @@ -252,13 +264,12 @@ static UINT disp_on_close(IWTSVirtualChannelCallback* pChannelCallback) * @return 0 on success, otherwise a Win32 error code */ static UINT disp_on_new_channel_connection(IWTSListenerCallback* pListenerCallback, - IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept, - IWTSVirtualChannelCallback** ppCallback) + IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept, + IWTSVirtualChannelCallback** ppCallback) { DISP_CHANNEL_CALLBACK* callback; - DISP_LISTENER_CALLBACK* listener_callback = (DISP_LISTENER_CALLBACK*) pListenerCallback; - - callback = (DISP_CHANNEL_CALLBACK*) calloc(1, sizeof(DISP_CHANNEL_CALLBACK)); + DISP_LISTENER_CALLBACK* listener_callback = (DISP_LISTENER_CALLBACK*)pListenerCallback; + callback = (DISP_CHANNEL_CALLBACK*)calloc(1, sizeof(DISP_CHANNEL_CALLBACK)); if (!callback) { @@ -272,9 +283,7 @@ static UINT disp_on_new_channel_connection(IWTSListenerCallback* pListenerCallba callback->channel_mgr = listener_callback->channel_mgr; callback->channel = pChannel; listener_callback->channel_callback = callback; - - *ppCallback = (IWTSVirtualChannelCallback*) callback; - + *ppCallback = (IWTSVirtualChannelCallback*)callback; return CHANNEL_RC_OK; } @@ -286,9 +295,8 @@ static UINT disp_on_new_channel_connection(IWTSListenerCallback* pListenerCallba static UINT disp_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr) { UINT status; - DISP_PLUGIN* disp = (DISP_PLUGIN*) pPlugin; - - disp->listener_callback = (DISP_LISTENER_CALLBACK*) calloc(1, sizeof(DISP_LISTENER_CALLBACK)); + DISP_PLUGIN* disp = (DISP_PLUGIN*)pPlugin; + disp->listener_callback = (DISP_LISTENER_CALLBACK*)calloc(1, sizeof(DISP_LISTENER_CALLBACK)); if (!disp->listener_callback) { @@ -299,12 +307,9 @@ static UINT disp_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManage disp->listener_callback->iface.OnNewChannelConnection = disp_on_new_channel_connection; disp->listener_callback->plugin = pPlugin; disp->listener_callback->channel_mgr = pChannelMgr; - status = pChannelMgr->CreateListener(pChannelMgr, DISP_DVC_CHANNEL_NAME, 0, - (IWTSListenerCallback*) disp->listener_callback, &(disp->listener)); - + &disp->listener_callback->iface, &(disp->listener)); disp->listener->pInterface = disp->iface.pInterface; - return status; } @@ -315,7 +320,15 @@ static UINT disp_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManage */ static UINT disp_plugin_terminated(IWTSPlugin* pPlugin) { - DISP_PLUGIN* disp = (DISP_PLUGIN*) pPlugin; + DISP_PLUGIN* disp = (DISP_PLUGIN*)pPlugin; + + if (disp && disp->listener_callback) + { + IWTSVirtualChannelManager* mgr = disp->listener_callback->channel_mgr; + if (mgr) + IFCALL(mgr->DestroyListener, mgr, disp->listener); + } + free(disp->listener_callback); free(disp->iface.pInterface); free(pPlugin); @@ -331,18 +344,18 @@ static UINT disp_plugin_terminated(IWTSPlugin* pPlugin) * * @return 0 on success, otherwise a Win32 error code */ -UINT disp_send_monitor_layout(DispClientContext* context, UINT32 NumMonitors, DISPLAY_CONTROL_MONITOR_LAYOUT* Monitors) +static UINT disp_send_monitor_layout(DispClientContext* context, UINT32 NumMonitors, + DISPLAY_CONTROL_MONITOR_LAYOUT* Monitors) { - DISP_PLUGIN* disp = (DISP_PLUGIN*) context->handle; + DISP_PLUGIN* disp = (DISP_PLUGIN*)context->handle; DISP_CHANNEL_CALLBACK* callback = disp->listener_callback->channel_callback; - return disp_send_display_control_monitor_layout_pdu(callback, NumMonitors, Monitors); } #ifdef BUILTIN_CHANNELS -#define DVCPluginEntry disp_DVCPluginEntry +#define DVCPluginEntry disp_DVCPluginEntry #else -#define DVCPluginEntry FREERDP_API DVCPluginEntry +#define DVCPluginEntry FREERDP_API DVCPluginEntry #endif /** @@ -355,11 +368,12 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) UINT error = CHANNEL_RC_OK; DISP_PLUGIN* disp; DispClientContext* context; + disp = (DISP_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "disp"); - disp = (DISP_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "disp"); if (!disp) { - disp = (DISP_PLUGIN*) calloc(1, sizeof(DISP_PLUGIN)); + disp = (DISP_PLUGIN*)calloc(1, sizeof(DISP_PLUGIN)); + if (!disp) { WLog_ERR(TAG, "calloc failed!"); @@ -373,8 +387,8 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) disp->MaxNumMonitors = 16; disp->MaxMonitorAreaFactorA = 8192; disp->MaxMonitorAreaFactorB = 8192; + context = (DispClientContext*)calloc(1, sizeof(DispClientContext)); - context = (DispClientContext*) calloc(1, sizeof(DispClientContext)); if (!context) { WLog_ERR(TAG, "calloc failed!"); @@ -382,12 +396,10 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) return CHANNEL_RC_NO_MEMORY; } - context->handle = (void*) disp; + context->handle = (void*)disp; context->SendMonitorLayout = disp_send_monitor_layout; - - disp->iface.pInterface = (void*) context; - - error = pEntryPoints->RegisterPlugin(pEntryPoints, "disp", (IWTSPlugin*) disp); + disp->iface.pInterface = (void*)context; + error = pEntryPoints->RegisterPlugin(pEntryPoints, "disp", (IWTSPlugin*)disp); } else { diff --git a/channels/disp/client/disp_main.h b/channels/disp/client/disp_main.h index c2aabae..45a4830 100644 --- a/channels/disp/client/disp_main.h +++ b/channels/disp/client/disp_main.h @@ -33,10 +33,6 @@ #include -#define DISPLAY_CONTROL_PDU_TYPE_CAPS 0x00000005 -#define DISPLAY_CONTROL_PDU_TYPE_MONITOR_LAYOUT 0x00000002 - #define TAG CHANNELS_TAG("disp.client") #endif /* FREERDP_CHANNEL_DISP_CLIENT_MAIN_H */ - diff --git a/channels/disp/disp_common.c b/channels/disp/disp_common.c new file mode 100644 index 0000000..f4313d1 --- /dev/null +++ b/channels/disp/disp_common.c @@ -0,0 +1,60 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * RDPEDISP Virtual Channel Extension + * + * Copyright 2019 Kobi Mizrachi + * + * 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 + +#define TAG CHANNELS_TAG("disp.common") + +#include "disp_common.h" + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +UINT disp_read_header(wStream* s, DISPLAY_CONTROL_HEADER* header) +{ + if (Stream_GetRemainingLength(s) < 8) + { + WLog_ERR(TAG, "header parsing failed: not enough data!"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT32(s, header->type); + Stream_Read_UINT32(s, header->length); + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +UINT disp_write_header(wStream* s, const DISPLAY_CONTROL_HEADER* header) +{ + Stream_Write_UINT32(s, header->type); + Stream_Write_UINT32(s, header->length); + return CHANNEL_RC_OK; +} diff --git a/channels/disp/disp_common.h b/channels/disp/disp_common.h new file mode 100644 index 0000000..386b8b3 --- /dev/null +++ b/channels/disp/disp_common.h @@ -0,0 +1,32 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * RDPEDISP Virtual Channel Extension + * + * Copyright 2019 Kobi Mizrachi + * + * 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_CHANNEL_DISP_COMMON_H +#define FREERDP_CHANNEL_DISP_COMMON_H + +#include +#include + +#include +#include + +FREERDP_LOCAL UINT disp_read_header(wStream* s, DISPLAY_CONTROL_HEADER* header); +FREERDP_LOCAL UINT disp_write_header(wStream* s, const DISPLAY_CONTROL_HEADER* header); + +#endif /* FREERDP_CHANNEL_DISP_COMMON_H */ diff --git a/channels/disp/server/CMakeLists.txt b/channels/disp/server/CMakeLists.txt new file mode 100644 index 0000000..dddc15b --- /dev/null +++ b/channels/disp/server/CMakeLists.txt @@ -0,0 +1,32 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2019 Kobi Mizrachi +# +# 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("disp") + +set(${MODULE_PREFIX}_SRCS + disp_main.c + disp_main.h + ../disp_common.c + ../disp_common.h + ) + +include_directories(..) + +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/disp/server/disp_main.c b/channels/disp/server/disp_main.c new file mode 100644 index 0000000..5340165 --- /dev/null +++ b/channels/disp/server/disp_main.c @@ -0,0 +1,581 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * RDPEDISP Virtual Channel Extension + * + * Copyright 2019 Kobi Mizrachi + * + * 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 "disp_main.h" +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include "../disp_common.h" + +#define TAG CHANNELS_TAG("rdpedisp.server") + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ + +static wStream* disp_server_single_packet_new(UINT32 type, UINT32 length) +{ + UINT error; + DISPLAY_CONTROL_HEADER header; + wStream* s = Stream_New(NULL, DISPLAY_CONTROL_HEADER_LENGTH + length); + + if (!s) + { + WLog_ERR(TAG, "Stream_New failed!"); + goto error; + } + + header.type = type; + header.length = length; + + if ((error = disp_write_header(s, &header))) + { + WLog_ERR(TAG, "Failed to write header with error %" PRIu32 "!", error); + goto error; + } + + return s; +error: + Stream_Free(s, TRUE); + return NULL; +} + +static BOOL disp_server_is_monitor_layout_valid(DISPLAY_CONTROL_MONITOR_LAYOUT* monitor) +{ + if (monitor->Width < DISPLAY_CONTROL_MIN_MONITOR_WIDTH || + monitor->Width > DISPLAY_CONTROL_MAX_MONITOR_WIDTH) + { + WLog_WARN(TAG, "Received invalid value for monitor->Width: %" PRIu32 "", monitor->Width); + return FALSE; + } + + if (monitor->Height < DISPLAY_CONTROL_MIN_MONITOR_HEIGHT || + monitor->Height > DISPLAY_CONTROL_MAX_MONITOR_HEIGHT) + { + WLog_WARN(TAG, "Received invalid value for monitor->Height: %" PRIu32 "", monitor->Width); + return FALSE; + } + + if (monitor->PhysicalWidth < DISPLAY_CONTROL_MIN_PHYSICAL_MONITOR_WIDTH || + monitor->PhysicalWidth > DISPLAY_CONTROL_MAX_PHYSICAL_MONITOR_WIDTH) + { + WLog_WARN(TAG, "Received invalid value for monitor->PhysicalWidth: %" PRIu32 "", + monitor->PhysicalWidth); + return FALSE; + } + + if (monitor->PhysicalHeight < DISPLAY_CONTROL_MIN_PHYSICAL_MONITOR_HEIGHT || + monitor->PhysicalHeight > DISPLAY_CONTROL_MAX_PHYSICAL_MONITOR_HEIGHT) + { + WLog_WARN(TAG, "Received invalid value for monitor->Height: %" PRIu32 "", + monitor->PhysicalHeight); + return FALSE; + } + + switch (monitor->Orientation) + { + case ORIENTATION_LANDSCAPE: + case ORIENTATION_PORTRAIT: + case ORIENTATION_LANDSCAPE_FLIPPED: + case ORIENTATION_PORTRAIT_FLIPPED: + break; + + default: + WLog_WARN(TAG, "Received incorrect value for monitor->Orientation: %" PRIu32 "", + monitor->Orientation); + return FALSE; + } + + return TRUE; +} + +static UINT disp_recv_display_control_monitor_layout_pdu(wStream* s, DispServerContext* context) +{ + UINT32 error = CHANNEL_RC_OK; + UINT32 index; + DISPLAY_CONTROL_MONITOR_LAYOUT_PDU pdu; + DISPLAY_CONTROL_MONITOR_LAYOUT* monitor; + + if (Stream_GetRemainingLength(s) < 8) + { + WLog_ERR(TAG, "not enough data!"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT32(s, pdu.MonitorLayoutSize); /* MonitorLayoutSize (4 bytes) */ + + if (pdu.MonitorLayoutSize != DISPLAY_CONTROL_MONITOR_LAYOUT_SIZE) + { + WLog_ERR(TAG, "MonitorLayoutSize is set to %" PRIu32 ". expected %" PRIu32 "", + pdu.MonitorLayoutSize, DISPLAY_CONTROL_MONITOR_LAYOUT_SIZE); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT32(s, pdu.NumMonitors); /* NumMonitors (4 bytes) */ + + if (pdu.NumMonitors > context->MaxNumMonitors) + { + WLog_ERR(TAG, "NumMonitors (%" PRIu32 ")> server MaxNumMonitors (%" PRIu32 ")", + pdu.NumMonitors, context->MaxNumMonitors); + return ERROR_INVALID_DATA; + } + + if (Stream_GetRemainingLength(s) < DISPLAY_CONTROL_MONITOR_LAYOUT_SIZE * pdu.NumMonitors) + { + WLog_ERR(TAG, "not enough data!"); + return ERROR_INVALID_DATA; + } + + pdu.Monitors = (DISPLAY_CONTROL_MONITOR_LAYOUT*)calloc(pdu.NumMonitors, + sizeof(DISPLAY_CONTROL_MONITOR_LAYOUT)); + + if (!pdu.Monitors) + { + WLog_ERR(TAG, "disp_recv_display_control_monitor_layout_pdu(): calloc failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + WLog_DBG(TAG, "disp_recv_display_control_monitor_layout_pdu: NumMonitors=%" PRIu32 "", + pdu.NumMonitors); + + for (index = 0; index < pdu.NumMonitors; index++) + { + monitor = &(pdu.Monitors[index]); + Stream_Read_UINT32(s, monitor->Flags); /* Flags (4 bytes) */ + Stream_Read_UINT32(s, monitor->Left); /* Left (4 bytes) */ + Stream_Read_UINT32(s, monitor->Top); /* Top (4 bytes) */ + Stream_Read_UINT32(s, monitor->Width); /* Width (4 bytes) */ + Stream_Read_UINT32(s, monitor->Height); /* Height (4 bytes) */ + Stream_Read_UINT32(s, monitor->PhysicalWidth); /* PhysicalWidth (4 bytes) */ + Stream_Read_UINT32(s, monitor->PhysicalHeight); /* PhysicalHeight (4 bytes) */ + Stream_Read_UINT32(s, monitor->Orientation); /* Orientation (4 bytes) */ + Stream_Read_UINT32(s, monitor->DesktopScaleFactor); /* DesktopScaleFactor (4 bytes) */ + Stream_Read_UINT32(s, monitor->DeviceScaleFactor); /* DeviceScaleFactor (4 bytes) */ + WLog_DBG(TAG, + "\t%d : Flags: 0x%08" PRIX32 " Left/Top: (%" PRId32 ",%" PRId32 ") W/H=%" PRIu32 + "x%" PRIu32 ")", + index, monitor->Flags, monitor->Left, monitor->Top, monitor->Width, + monitor->Height); + WLog_DBG(TAG, + "\t PhysicalWidth: %" PRIu32 " PhysicalHeight: %" PRIu32 " Orientation: %" PRIu32 + "", + monitor->PhysicalWidth, monitor->PhysicalHeight, monitor->Orientation); + + if (!disp_server_is_monitor_layout_valid(monitor)) + { + error = ERROR_INVALID_DATA; + goto out; + } + } + + if (context) + IFCALLRET(context->DispMonitorLayout, error, context, &pdu); + +out: + free(pdu.Monitors); + return error; +} + +static UINT disp_server_receive_pdu(DispServerContext* context, wStream* s) +{ + UINT error = CHANNEL_RC_OK; + size_t beg, end; + DISPLAY_CONTROL_HEADER header; + beg = Stream_GetPosition(s); + + if ((error = disp_read_header(s, &header))) + { + WLog_ERR(TAG, "disp_read_header failed with error %" PRIu32 "!", error); + return error; + } + + switch (header.type) + { + case DISPLAY_CONTROL_PDU_TYPE_MONITOR_LAYOUT: + if ((error = disp_recv_display_control_monitor_layout_pdu(s, context))) + WLog_ERR(TAG, + "disp_recv_display_control_monitor_layout_pdu " + "failed with error %" PRIu32 "!", + error); + + break; + + default: + error = CHANNEL_RC_BAD_PROC; + WLog_WARN(TAG, "Received unknown PDU type: %" PRIu32 "", header.type); + break; + } + + end = Stream_GetPosition(s); + + if (end != (beg + header.length)) + { + WLog_ERR(TAG, "Unexpected DISP pdu end: Actual: %d, Expected: %" PRIu32 "", end, + (beg + header.length)); + Stream_SetPosition(s, (beg + header.length)); + } + + return error; +} + +static UINT disp_server_handle_messages(DispServerContext* context) +{ + DWORD BytesReturned; + void* buffer; + UINT ret = CHANNEL_RC_OK; + DispServerPrivate* priv = context->priv; + wStream* s = priv->input_stream; + + /* Check whether the dynamic channel is ready */ + if (!priv->isReady) + { + if (WTSVirtualChannelQuery(priv->disp_channel, WTSVirtualChannelReady, &buffer, + &BytesReturned) == FALSE) + { + if (GetLastError() == ERROR_NO_DATA) + return ERROR_NO_DATA; + + WLog_ERR(TAG, "WTSVirtualChannelQuery failed"); + return ERROR_INTERNAL_ERROR; + } + + priv->isReady = *((BOOL*)buffer); + WTSFreeMemory(buffer); + } + + /* Consume channel event only after the disp dynamic channel is ready */ + Stream_SetPosition(s, 0); + + if (!WTSVirtualChannelRead(priv->disp_channel, 0, NULL, 0, &BytesReturned)) + { + if (GetLastError() == ERROR_NO_DATA) + return ERROR_NO_DATA; + + WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); + return ERROR_INTERNAL_ERROR; + } + + if (BytesReturned < 1) + return CHANNEL_RC_OK; + + if (!Stream_EnsureRemainingCapacity(s, BytesReturned)) + { + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + if (WTSVirtualChannelRead(priv->disp_channel, 0, (PCHAR)Stream_Buffer(s), Stream_Capacity(s), + &BytesReturned) == FALSE) + { + WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); + return ERROR_INTERNAL_ERROR; + } + + Stream_SetLength(s, BytesReturned); + Stream_SetPosition(s, 0); + + while (Stream_GetPosition(s) < Stream_Length(s)) + { + if ((ret = disp_server_receive_pdu(context, s))) + { + WLog_ERR(TAG, + "disp_server_receive_pdu " + "failed with error %" PRIu32 "!", + ret); + return ret; + } + } + + return ret; +} + +static DWORD WINAPI disp_server_thread_func(LPVOID arg) +{ + DispServerContext* context = (DispServerContext*)arg; + DispServerPrivate* priv = context->priv; + DWORD status; + DWORD nCount; + HANDLE events[8]; + UINT error = CHANNEL_RC_OK; + nCount = 0; + events[nCount++] = priv->stopEvent; + events[nCount++] = priv->channelEvent; + + /* Main virtual channel loop. RDPEDISP do not need version negotiation */ + while (TRUE) + { + status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); + + if (status == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error); + break; + } + + /* Stop Event */ + if (status == WAIT_OBJECT_0) + break; + + if ((error = disp_server_handle_messages(context))) + { + WLog_ERR(TAG, "disp_server_handle_messages failed with error %" PRIu32 "", error); + break; + } + } + + ExitThread(error); + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT disp_server_open(DispServerContext* context) +{ + UINT rc = ERROR_INTERNAL_ERROR; + DispServerPrivate* priv = context->priv; + DWORD BytesReturned = 0; + PULONG pSessionId = NULL; + void* buffer; + buffer = NULL; + priv->SessionId = WTS_CURRENT_SESSION; + + if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId, + (LPSTR*)&pSessionId, &BytesReturned) == FALSE) + { + WLog_ERR(TAG, "WTSQuerySessionInformationA failed!"); + rc = ERROR_INTERNAL_ERROR; + goto out_close; + } + + priv->SessionId = (DWORD)*pSessionId; + WTSFreeMemory(pSessionId); + priv->disp_channel = (HANDLE)WTSVirtualChannelOpenEx(priv->SessionId, DISP_DVC_CHANNEL_NAME, + WTS_CHANNEL_OPTION_DYNAMIC); + + if (!priv->disp_channel) + { + WLog_ERR(TAG, "WTSVirtualChannelOpenEx failed!"); + rc = GetLastError(); + goto out_close; + } + + /* Query for channel event handle */ + if (!WTSVirtualChannelQuery(priv->disp_channel, WTSVirtualEventHandle, &buffer, + &BytesReturned) || + (BytesReturned != sizeof(HANDLE))) + { + WLog_ERR(TAG, + "WTSVirtualChannelQuery failed " + "or invalid returned size(%" PRIu32 ")", + BytesReturned); + + if (buffer) + WTSFreeMemory(buffer); + + rc = ERROR_INTERNAL_ERROR; + goto out_close; + } + + CopyMemory(&priv->channelEvent, buffer, sizeof(HANDLE)); + WTSFreeMemory(buffer); + + if (priv->thread == NULL) + { + if (!(priv->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) + { + WLog_ERR(TAG, "CreateEvent failed!"); + rc = ERROR_INTERNAL_ERROR; + } + + if (!(priv->thread = + CreateThread(NULL, 0, disp_server_thread_func, (void*)context, 0, NULL))) + { + WLog_ERR(TAG, "CreateEvent failed!"); + CloseHandle(priv->stopEvent); + priv->stopEvent = NULL; + rc = ERROR_INTERNAL_ERROR; + } + } + + return CHANNEL_RC_OK; +out_close: + WTSVirtualChannelClose(priv->disp_channel); + priv->disp_channel = NULL; + priv->channelEvent = NULL; + return rc; +} + +static UINT disp_server_packet_send(DispServerContext* context, wStream* s) +{ + UINT ret; + ULONG written; + + if (!WTSVirtualChannelWrite(context->priv->disp_channel, (PCHAR)Stream_Buffer(s), + Stream_GetPosition(s), &written)) + { + WLog_ERR(TAG, "WTSVirtualChannelWrite failed!"); + ret = ERROR_INTERNAL_ERROR; + goto out; + } + + if (written < Stream_GetPosition(s)) + { + WLog_WARN(TAG, "Unexpected bytes written: %" PRIu32 "/%" PRIuz "", written, + Stream_GetPosition(s)); + } + + ret = CHANNEL_RC_OK; +out: + Stream_Free(s, TRUE); + return ret; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT disp_server_send_caps_pdu(DispServerContext* context) +{ + wStream* s = disp_server_single_packet_new(DISPLAY_CONTROL_PDU_TYPE_CAPS, 12); + + if (!s) + { + WLog_ERR(TAG, "disp_server_single_packet_new failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + Stream_Write_UINT32(s, context->MaxNumMonitors); /* MaxNumMonitors (4 bytes) */ + Stream_Write_UINT32(s, context->MaxMonitorAreaFactorA); /* MaxMonitorAreaFactorA (4 bytes) */ + Stream_Write_UINT32(s, context->MaxMonitorAreaFactorB); /* MaxMonitorAreaFactorB (4 bytes) */ + return disp_server_packet_send(context, s); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT disp_server_close(DispServerContext* context) +{ + UINT error = CHANNEL_RC_OK; + DispServerPrivate* priv = context->priv; + + if (priv->thread) + { + SetEvent(priv->stopEvent); + + if (WaitForSingleObject(priv->thread, INFINITE) == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error); + return error; + } + + CloseHandle(priv->thread); + CloseHandle(priv->stopEvent); + priv->thread = NULL; + priv->stopEvent = NULL; + } + + if (priv->disp_channel) + { + WTSVirtualChannelClose(priv->disp_channel); + priv->disp_channel = NULL; + } + + return error; +} + +DispServerContext* disp_server_context_new(HANDLE vcm) +{ + DispServerContext* context; + DispServerPrivate* priv; + context = (DispServerContext*)calloc(1, sizeof(DispServerContext)); + + if (!context) + { + WLog_ERR(TAG, "disp_server_context_new(): calloc DispServerContext failed!"); + goto out_free; + } + + priv = context->priv = (DispServerPrivate*)calloc(1, sizeof(DispServerPrivate)); + + if (!context->priv) + { + WLog_ERR(TAG, "disp_server_context_new(): calloc DispServerPrivate failed!"); + goto out_free; + } + + priv->input_stream = Stream_New(NULL, 4); + + if (!priv->input_stream) + { + WLog_ERR(TAG, "Stream_New failed!"); + goto out_free_priv; + } + + context->vcm = vcm; + context->Open = disp_server_open; + context->Close = disp_server_close; + context->DisplayControlCaps = disp_server_send_caps_pdu; + priv->isReady = FALSE; + return context; +out_free_priv: + free(context->priv); +out_free: + free(context); + return NULL; +} + +void disp_server_context_free(DispServerContext* context) +{ + if (!context) + return; + + disp_server_close(context); + + if (context->priv) + { + Stream_Free(context->priv->input_stream, TRUE); + free(context->priv); + } + + free(context); +} diff --git a/channels/disp/server/disp_main.h b/channels/disp/server/disp_main.h new file mode 100644 index 0000000..c47462b --- /dev/null +++ b/channels/disp/server/disp_main.h @@ -0,0 +1,37 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * RDPEDISP Virtual Channel Extension + * + * Copyright 2019 Kobi Mizrachi + * + * 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_CHANNEL_DISP_SERVER_MAIN_H +#define FREERDP_CHANNEL_DISP_SERVER_MAIN_H + +#include + +struct _disp_server_private +{ + BOOL isReady; + wStream* input_stream; + HANDLE channelEvent; + HANDLE thread; + HANDLE stopEvent; + DWORD SessionId; + + void* disp_channel; +}; + +#endif /* FREERDP_CHANNEL_DISP_SERVER_MAIN_H */ diff --git a/channels/drdynvc/client/drdynvc_main.c b/channels/drdynvc/client/drdynvc_main.c index f27381b..507305f 100644 --- a/channels/drdynvc/client/drdynvc_main.c +++ b/channels/drdynvc/client/drdynvc_main.c @@ -30,18 +30,28 @@ #define TAG CHANNELS_TAG("drdynvc.client") +static void dvcman_free(drdynvcPlugin* drdynvc, IWTSVirtualChannelManager* pChannelMgr); static void dvcman_channel_free(void* channel); -static UINT drdynvc_write_data(drdynvcPlugin* drdynvc, UINT32 ChannelId, - const BYTE* data, UINT32 dataSize); +static UINT drdynvc_write_data(drdynvcPlugin* drdynvc, UINT32 ChannelId, const BYTE* data, + UINT32 dataSize); +static UINT drdynvc_send(drdynvcPlugin* drdynvc, wStream* s); + +static void dvcman_wtslistener_free(DVCMAN_LISTENER* listener) +{ + if (listener) + free(listener->channel_name); + + free(listener); +} /** * Function description * * @return 0 on success, otherwise a Win32 error code */ -static UINT dvcman_get_configuration(IWTSListener* pListener, - void** ppPropertyBag) +static UINT dvcman_get_configuration(IWTSListener* pListener, void** ppPropertyBag) { + WINPR_UNUSED(pListener); *ppPropertyBag = NULL; return ERROR_INTERNAL_ERROR; } @@ -53,48 +63,59 @@ static UINT dvcman_get_configuration(IWTSListener* pListener, */ static UINT dvcman_create_listener(IWTSVirtualChannelManager* pChannelMgr, const char* pszChannelName, ULONG ulFlags, - IWTSListenerCallback* pListenerCallback, IWTSListener** ppListener) + IWTSListenerCallback* pListenerCallback, + IWTSListener** ppListener) { - DVCMAN* dvcman = (DVCMAN*) pChannelMgr; + DVCMAN* dvcman = (DVCMAN*)pChannelMgr; DVCMAN_LISTENER* listener; - if (dvcman->num_listeners < MAX_PLUGINS) + WLog_DBG(TAG, "create_listener: %d.%s.", ArrayList_Count(dvcman->listeners) + 1, + pszChannelName); + listener = (DVCMAN_LISTENER*)calloc(1, sizeof(DVCMAN_LISTENER)); + + if (!listener) { - WLog_DBG(TAG, "create_listener: %d.%s.", dvcman->num_listeners, pszChannelName); - listener = (DVCMAN_LISTENER*) calloc(1, sizeof(DVCMAN_LISTENER)); + WLog_ERR(TAG, "calloc failed!"); + return CHANNEL_RC_NO_MEMORY; + } - if (!listener) - { - WLog_ERR(TAG, "calloc failed!"); - return CHANNEL_RC_NO_MEMORY; - } + listener->iface.GetConfiguration = dvcman_get_configuration; + listener->iface.pInterface = NULL; + listener->dvcman = dvcman; + listener->channel_name = _strdup(pszChannelName); - listener->iface.GetConfiguration = dvcman_get_configuration; - listener->iface.pInterface = NULL; - listener->dvcman = dvcman; - listener->channel_name = _strdup(pszChannelName); + if (!listener->channel_name) + { + WLog_ERR(TAG, "_strdup failed!"); + dvcman_wtslistener_free(listener); + return CHANNEL_RC_NO_MEMORY; + } - if (!listener->channel_name) - { - WLog_ERR(TAG, "_strdup failed!"); - free(listener); - return CHANNEL_RC_NO_MEMORY; - } + listener->flags = ulFlags; + listener->listener_callback = pListenerCallback; - listener->flags = ulFlags; - listener->listener_callback = pListenerCallback; + if (ppListener) + *ppListener = (IWTSListener*)listener; - if (ppListener) - *ppListener = (IWTSListener*) listener; + if (ArrayList_Add(dvcman->listeners, listener) < 0) + return ERROR_INTERNAL_ERROR; + return CHANNEL_RC_OK; +} - dvcman->listeners[dvcman->num_listeners++] = (IWTSListener*) listener; - return CHANNEL_RC_OK; - } - else +static UINT dvcman_destroy_listener(IWTSVirtualChannelManager* pChannelMgr, IWTSListener* pListener) +{ + DVCMAN_LISTENER* listener = (DVCMAN_LISTENER*)pListener; + + WINPR_UNUSED(pChannelMgr); + + if (listener) { - WLog_ERR(TAG, "create_listener: Maximum DVC listener number reached."); - return ERROR_INTERNAL_ERROR; + DVCMAN* dvcman = listener->dvcman; + if (dvcman) + ArrayList_Remove(dvcman->listeners, listener); } + + return CHANNEL_RC_OK; } /** @@ -102,122 +123,154 @@ static UINT dvcman_create_listener(IWTSVirtualChannelManager* pChannelMgr, * * @return 0 on success, otherwise a Win32 error code */ -static UINT dvcman_register_plugin(IDRDYNVC_ENTRY_POINTS* pEntryPoints, - const char* name, IWTSPlugin* pPlugin) +static UINT dvcman_register_plugin(IDRDYNVC_ENTRY_POINTS* pEntryPoints, const char* name, + IWTSPlugin* pPlugin) { - DVCMAN* dvcman = ((DVCMAN_ENTRY_POINTS*) pEntryPoints)->dvcman; + DVCMAN* dvcman = ((DVCMAN_ENTRY_POINTS*)pEntryPoints)->dvcman; - if (dvcman->num_plugins < MAX_PLUGINS) - { - dvcman->plugin_names[dvcman->num_plugins] = name; - dvcman->plugins[dvcman->num_plugins++] = pPlugin; - WLog_DBG(TAG, "register_plugin: num_plugins %d", dvcman->num_plugins); - return CHANNEL_RC_OK; - } - else - { - WLog_ERR(TAG, "register_plugin: Maximum DVC plugin number %u reached.", - MAX_PLUGINS); + if (ArrayList_Add(dvcman->plugin_names, _strdup(name)) < 0) return ERROR_INTERNAL_ERROR; - } + if (ArrayList_Add(dvcman->plugins, pPlugin) < 0) + return ERROR_INTERNAL_ERROR; + + WLog_DBG(TAG, "register_plugin: num_plugins %d", ArrayList_Count(dvcman->plugins)); + return CHANNEL_RC_OK; } -static IWTSPlugin* dvcman_get_plugin(IDRDYNVC_ENTRY_POINTS* pEntryPoints, - const char* name) +static IWTSPlugin* dvcman_get_plugin(IDRDYNVC_ENTRY_POINTS* pEntryPoints, const char* name) { - int i; - DVCMAN* dvcman = ((DVCMAN_ENTRY_POINTS*) pEntryPoints)->dvcman; + IWTSPlugin* plugin = NULL; + size_t i, nc, pc; + DVCMAN* dvcman = ((DVCMAN_ENTRY_POINTS*)pEntryPoints)->dvcman; + if (!dvcman || !pEntryPoints || !name) + return NULL; + + nc = ArrayList_Count(dvcman->plugin_names); + pc = ArrayList_Count(dvcman->plugins); + if (nc != pc) + return NULL; - for (i = 0; i < dvcman->num_plugins; i++) + ArrayList_Lock(dvcman->plugin_names); + ArrayList_Lock(dvcman->plugins); + for (i = 0; i < pc; i++) { - if (dvcman->plugin_names[i] == name || - strcmp(dvcman->plugin_names[i], name) == 0) + const char* cur = ArrayList_GetItem(dvcman->plugin_names, i); + if (strcmp(cur, name) == 0) { - return dvcman->plugins[i]; + plugin = ArrayList_GetItem(dvcman->plugins, i); + break; } } - - return NULL; + ArrayList_Unlock(dvcman->plugin_names); + ArrayList_Unlock(dvcman->plugins); + return plugin; } static ADDIN_ARGV* dvcman_get_plugin_data(IDRDYNVC_ENTRY_POINTS* pEntryPoints) { - return ((DVCMAN_ENTRY_POINTS*) pEntryPoints)->args; + return ((DVCMAN_ENTRY_POINTS*)pEntryPoints)->args; } static void* dvcman_get_rdp_settings(IDRDYNVC_ENTRY_POINTS* pEntryPoints) { - return (void*)((DVCMAN_ENTRY_POINTS*) pEntryPoints)->settings; + return (void*)((DVCMAN_ENTRY_POINTS*)pEntryPoints)->settings; } static UINT32 dvcman_get_channel_id(IWTSVirtualChannel* channel) { - return ((DVCMAN_CHANNEL*) channel)->channel_id; + DVCMAN_CHANNEL* dvc = (DVCMAN_CHANNEL*)channel; + return dvc->channel_id; +} + +static const char* dvcman_get_channel_name(IWTSVirtualChannel* channel) +{ + DVCMAN_CHANNEL* dvc = (DVCMAN_CHANNEL*)channel; + return dvc->channel_name; } -static IWTSVirtualChannel* dvcman_find_channel_by_id(IWTSVirtualChannelManager* - pChannelMgr, - UINT32 ChannelId) +static IWTSVirtualChannel* dvcman_find_channel_by_id(IWTSVirtualChannelManager* pChannelMgr, + UINT32 ChannelId) { int index; - BOOL found = FALSE; - DVCMAN_CHANNEL* channel; - DVCMAN* dvcman = (DVCMAN*) pChannelMgr; + IWTSVirtualChannel* channel = NULL; + DVCMAN* dvcman = (DVCMAN*)pChannelMgr; ArrayList_Lock(dvcman->channels); - index = 0; - channel = (DVCMAN_CHANNEL*) ArrayList_GetItem(dvcman->channels, index++); - - while (channel) + for (index = 0; index < ArrayList_Count(dvcman->channels); index++) { - if (channel->channel_id == ChannelId) + DVCMAN_CHANNEL* cur = (DVCMAN_CHANNEL*)ArrayList_GetItem(dvcman->channels, index); + if (cur->channel_id == ChannelId) { - found = TRUE; + channel = &cur->iface; break; } - - channel = (DVCMAN_CHANNEL*) ArrayList_GetItem(dvcman->channels, index++); } ArrayList_Unlock(dvcman->channels); - return (found) ? ((IWTSVirtualChannel*) channel) : NULL; + return channel; +} + +static void dvcman_plugin_terminate(void* plugin) +{ + IWTSPlugin* pPlugin = plugin; + + UINT error = IFCALLRESULT(CHANNEL_RC_OK, pPlugin->Terminated, pPlugin); + if (error != CHANNEL_RC_OK) + WLog_ERR(TAG, "Terminated failed with error %" PRIu32 "!", error); } +static void wts_listener_free(void* arg) +{ + DVCMAN_LISTENER* listener = (DVCMAN_LISTENER*)arg; + dvcman_wtslistener_free(listener); +} static IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin) { + wObject* obj; DVCMAN* dvcman; - dvcman = (DVCMAN*) calloc(1, sizeof(DVCMAN)); + dvcman = (DVCMAN*)calloc(1, sizeof(DVCMAN)); if (!dvcman) - { - WLog_Print(plugin->log, WLOG_ERROR, "calloc failed!"); return NULL; - } dvcman->iface.CreateListener = dvcman_create_listener; + dvcman->iface.DestroyListener = dvcman_destroy_listener; dvcman->iface.FindChannelById = dvcman_find_channel_by_id; dvcman->iface.GetChannelId = dvcman_get_channel_id; + dvcman->iface.GetChannelName = dvcman_get_channel_name; dvcman->drdynvc = plugin; dvcman->channels = ArrayList_New(TRUE); if (!dvcman->channels) - { - WLog_Print(plugin->log, WLOG_ERROR, "ArrayList_New failed!"); - free(dvcman); - return NULL; - } + goto fail; - dvcman->channels->object.fnObjectFree = dvcman_channel_free; - dvcman->pool = StreamPool_New(TRUE, 10); + obj = ArrayList_Object(dvcman->channels); + obj->fnObjectFree = dvcman_channel_free; + dvcman->pool = StreamPool_New(TRUE, 10); if (!dvcman->pool) - { - WLog_Print(plugin->log, WLOG_ERROR, "StreamPool_New failed!"); - ArrayList_Free(dvcman->channels); - free(dvcman); - return NULL; - } - - return (IWTSVirtualChannelManager*) dvcman; + goto fail; + + dvcman->listeners = ArrayList_New(TRUE); + if (!dvcman->listeners) + goto fail; + obj = ArrayList_Object(dvcman->listeners); + obj->fnObjectFree = wts_listener_free; + + dvcman->plugin_names = ArrayList_New(TRUE); + if (!dvcman->plugin_names) + goto fail; + obj = ArrayList_Object(dvcman->plugin_names); + obj->fnObjectFree = free; + + dvcman->plugins = ArrayList_New(TRUE); + if (!dvcman->plugins) + goto fail; + obj = ArrayList_Object(dvcman->plugins); + obj->fnObjectFree = dvcman_plugin_terminate; + return &dvcman->iface; +fail: + dvcman_free(plugin, &dvcman->iface); + return NULL; } /** @@ -225,17 +278,14 @@ static IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin) * * @return 0 on success, otherwise a Win32 error code */ -static UINT dvcman_load_addin(drdynvcPlugin* drdynvc, - IWTSVirtualChannelManager* pChannelMgr, - ADDIN_ARGV* args, - rdpSettings* settings) +static UINT dvcman_load_addin(drdynvcPlugin* drdynvc, IWTSVirtualChannelManager* pChannelMgr, + ADDIN_ARGV* args, rdpSettings* settings) { DVCMAN_ENTRY_POINTS entryPoints; PDVC_PLUGIN_ENTRY pDVCPluginEntry = NULL; WLog_Print(drdynvc->log, WLOG_INFO, "Loading Dynamic Virtual Channel %s", args->argv[0]); - pDVCPluginEntry = (PDVC_PLUGIN_ENTRY) freerdp_load_channel_addin_entry( - args->argv[0], - NULL, NULL, FREERDP_ADDIN_CHANNEL_DYNAMIC); + pDVCPluginEntry = (PDVC_PLUGIN_ENTRY)freerdp_load_channel_addin_entry( + args->argv[0], NULL, NULL, FREERDP_ADDIN_CHANNEL_DYNAMIC); if (pDVCPluginEntry) { @@ -243,75 +293,66 @@ static UINT dvcman_load_addin(drdynvcPlugin* drdynvc, entryPoints.iface.GetPlugin = dvcman_get_plugin; entryPoints.iface.GetPluginData = dvcman_get_plugin_data; entryPoints.iface.GetRdpSettings = dvcman_get_rdp_settings; - entryPoints.dvcman = (DVCMAN*) pChannelMgr; + entryPoints.dvcman = (DVCMAN*)pChannelMgr; entryPoints.args = args; entryPoints.settings = settings; - return pDVCPluginEntry((IDRDYNVC_ENTRY_POINTS*) &entryPoints); + return pDVCPluginEntry(&entryPoints.iface); } return ERROR_INVALID_FUNCTION; } static DVCMAN_CHANNEL* dvcman_channel_new(drdynvcPlugin* drdynvc, - IWTSVirtualChannelManager* pChannelMgr, - UINT32 ChannelId, const char* ChannelName) + IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, + const char* ChannelName) { DVCMAN_CHANNEL* channel; if (dvcman_find_channel_by_id(pChannelMgr, ChannelId)) { - WLog_Print(drdynvc->log, WLOG_ERROR, "Protocol error: Duplicated ChannelId %"PRIu32" (%s)!", - ChannelId, + WLog_Print(drdynvc->log, WLOG_ERROR, + "Protocol error: Duplicated ChannelId %" PRIu32 " (%s)!", ChannelId, ChannelName); return NULL; } - channel = (DVCMAN_CHANNEL*) calloc(1, sizeof(DVCMAN_CHANNEL)); + channel = (DVCMAN_CHANNEL*)calloc(1, sizeof(DVCMAN_CHANNEL)); if (!channel) - { - WLog_Print(drdynvc->log, WLOG_ERROR, "calloc failed!"); - return NULL; - } + goto fail; - channel->dvcman = (DVCMAN*) pChannelMgr; + channel->dvcman = (DVCMAN*)pChannelMgr; channel->channel_id = ChannelId; channel->channel_name = _strdup(ChannelName); if (!channel->channel_name) - { - WLog_Print(drdynvc->log, WLOG_ERROR, "_strdup failed!"); - free(channel); - return NULL; - } + goto fail; if (!InitializeCriticalSectionEx(&(channel->lock), 0, 0)) - { - WLog_Print(drdynvc->log, WLOG_ERROR, "InitializeCriticalSectionEx failed!"); - free(channel->channel_name); - free(channel); - return NULL; - } + goto fail; return channel; +fail: + dvcman_channel_free(channel); + return NULL; } static void dvcman_channel_free(void* arg) { - DVCMAN_CHANNEL* channel = (DVCMAN_CHANNEL*) arg; + DVCMAN_CHANNEL* channel = (DVCMAN_CHANNEL*)arg; UINT error = CHANNEL_RC_OK; if (channel) { if (channel->channel_callback) { - IFCALL(channel->channel_callback->OnClose, - channel->channel_callback); + IFCALL(channel->channel_callback->OnClose, channel->channel_callback); + channel->channel_callback = NULL; } if (channel->status == CHANNEL_RC_OK) { - IWTSVirtualChannel* ichannel = (IWTSVirtualChannel*) channel; + IWTSVirtualChannel* ichannel = (IWTSVirtualChannel*)channel; if (channel->dvcman && channel->dvcman->drdynvc) { @@ -319,8 +360,7 @@ static void dvcman_channel_free(void* arg) if (context) { - IFCALLRET(context->OnChannelDisconnected, error, - context, channel->channel_name, + IFCALLRET(context->OnChannelDisconnected, error, context, channel->channel_name, channel->pInterface); } } @@ -328,7 +368,7 @@ static void dvcman_channel_free(void* arg) error = IFCALLRESULT(CHANNEL_RC_OK, ichannel->Close, ichannel); if (error != CHANNEL_RC_OK) - WLog_ERR(TAG, "Close failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "Close failed with error %" PRIu32 "!", error); } if (channel->dvc_data) @@ -341,34 +381,29 @@ static void dvcman_channel_free(void* arg) free(channel); } -static void dvcman_free(drdynvcPlugin* drdynvc, IWTSVirtualChannelManager* pChannelMgr) +static void dvcman_clear(drdynvcPlugin* drdynvc, IWTSVirtualChannelManager* pChannelMgr) { - int i; - IWTSPlugin* pPlugin; - DVCMAN_LISTENER* listener; - DVCMAN* dvcman = (DVCMAN*) pChannelMgr; - UINT error; - ArrayList_Free(dvcman->channels); + DVCMAN* dvcman = (DVCMAN*)pChannelMgr; - for (i = 0; i < dvcman->num_listeners; i++) - { - listener = (DVCMAN_LISTENER*) dvcman->listeners[i]; - free(listener->channel_name); - free(listener); - } + WINPR_UNUSED(drdynvc); - dvcman->num_listeners = 0; + ArrayList_Clear(dvcman->plugins); + ArrayList_Clear(dvcman->channels); + ArrayList_Clear(dvcman->plugin_names); + ArrayList_Clear(dvcman->listeners); +} - for (i = 0; i < dvcman->num_plugins; i++) - { - pPlugin = dvcman->plugins[i]; +static void dvcman_free(drdynvcPlugin* drdynvc, IWTSVirtualChannelManager* pChannelMgr) +{ + DVCMAN* dvcman = (DVCMAN*)pChannelMgr; - if (pPlugin->Terminated) - if ((error = pPlugin->Terminated(pPlugin))) - WLog_Print(drdynvc->log, WLOG_ERROR, "Terminated failed with error %"PRIu32"!", error); - } + WINPR_UNUSED(drdynvc); + + ArrayList_Free(dvcman->plugins); + ArrayList_Free(dvcman->channels); + ArrayList_Free(dvcman->plugin_names); + ArrayList_Free(dvcman->listeners); - dvcman->num_plugins = 0; StreamPool_Free(dvcman->pool); free(dvcman); } @@ -380,24 +415,27 @@ static void dvcman_free(drdynvcPlugin* drdynvc, IWTSVirtualChannelManager* pChan */ static UINT dvcman_init(drdynvcPlugin* drdynvc, IWTSVirtualChannelManager* pChannelMgr) { - int i; - IWTSPlugin* pPlugin; - DVCMAN* dvcman = (DVCMAN*) pChannelMgr; - UINT error; + size_t i; + DVCMAN* dvcman = (DVCMAN*)pChannelMgr; + UINT error = CHANNEL_RC_OK; - for (i = 0; i < dvcman->num_plugins; i++) + ArrayList_Lock(dvcman->plugins); + for (i = 0; i < ArrayList_Count(dvcman->plugins); i++) { - pPlugin = dvcman->plugins[i]; + IWTSPlugin* pPlugin = ArrayList_GetItem(dvcman->plugins, i); - if (pPlugin->Initialize) - if ((error = pPlugin->Initialize(pPlugin, pChannelMgr))) - { - WLog_Print(drdynvc->log, WLOG_ERROR, "Initialize failed with error %"PRIu32"!", error); - return error; - } + error = IFCALLRESULT(CHANNEL_RC_OK, pPlugin->Initialize, pPlugin, pChannelMgr); + if (error != CHANNEL_RC_OK) + { + WLog_Print(drdynvc->log, WLOG_ERROR, "Initialize failed with error %" PRIu32 "!", + error); + goto fail; + } } - return CHANNEL_RC_OK; +fail: + ArrayList_Unlock(dvcman->plugins); + return error; } /** @@ -405,18 +443,18 @@ static UINT dvcman_init(drdynvcPlugin* drdynvc, IWTSVirtualChannelManager* pChan * * @return 0 on success, otherwise a Win32 error code */ -static UINT dvcman_write_channel(IWTSVirtualChannel* pChannel, ULONG cbSize, - const BYTE* pBuffer, void* pReserved) +static UINT dvcman_write_channel(IWTSVirtualChannel* pChannel, ULONG cbSize, const BYTE* pBuffer, + void* pReserved) { UINT status; - DVCMAN_CHANNEL* channel = (DVCMAN_CHANNEL*) pChannel; + DVCMAN_CHANNEL* channel = (DVCMAN_CHANNEL*)pChannel; + WINPR_UNUSED(pReserved); if (!channel || !channel->dvcman) return CHANNEL_RC_BAD_CHANNEL; EnterCriticalSection(&(channel->lock)); - status = drdynvc_write_data(channel->dvcman->drdynvc, - channel->channel_id, pBuffer, cbSize); + status = drdynvc_write_data(channel->dvcman->drdynvc, channel->channel_id, pBuffer, cbSize); LeaveCriticalSection(&(channel->lock)); return status; } @@ -428,12 +466,12 @@ static UINT dvcman_write_channel(IWTSVirtualChannel* pChannel, ULONG cbSize, */ static UINT dvcman_close_channel_iface(IWTSVirtualChannel* pChannel) { - DVCMAN_CHANNEL* channel = (DVCMAN_CHANNEL*) pChannel; + DVCMAN_CHANNEL* channel = (DVCMAN_CHANNEL*)pChannel; if (!channel) return CHANNEL_RC_BAD_CHANNEL; - WLog_DBG(TAG, "close_channel_iface: id=%"PRIu32"", channel->channel_id); + WLog_DBG(TAG, "close_channel_iface: id=%" PRIu32 "", channel->channel_id); return CHANNEL_RC_OK; } @@ -442,17 +480,14 @@ static UINT dvcman_close_channel_iface(IWTSVirtualChannel* pChannel) * * @return 0 on success, otherwise a Win32 error code */ -static UINT dvcman_create_channel(drdynvcPlugin* drdynvc, - IWTSVirtualChannelManager* pChannelMgr, +static UINT dvcman_create_channel(drdynvcPlugin* drdynvc, IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, const char* ChannelName) { - int i; + size_t i; BOOL bAccept; - DVCMAN_LISTENER* listener; DVCMAN_CHANNEL* channel; DrdynvcClientContext* context; - IWTSVirtualChannelCallback* pCallback; - DVCMAN* dvcman = (DVCMAN*) pChannelMgr; + DVCMAN* dvcman = (DVCMAN*)pChannelMgr; UINT error; if (!(channel = dvcman_channel_new(drdynvc, pChannelMgr, ChannelId, ChannelName))) @@ -462,25 +497,27 @@ static UINT dvcman_create_channel(drdynvcPlugin* drdynvc, } channel->status = ERROR_NOT_CONNECTED; - ArrayList_Add(dvcman->channels, channel); + if (ArrayList_Add(dvcman->channels, channel) < 0) + return ERROR_INTERNAL_ERROR; - for (i = 0; i < dvcman->num_listeners; i++) + ArrayList_Lock(dvcman->listeners); + for (i = 0; i < ArrayList_Count(dvcman->listeners); i++) { - listener = (DVCMAN_LISTENER*) dvcman->listeners[i]; + DVCMAN_LISTENER* listener = (DVCMAN_LISTENER*)ArrayList_GetItem(dvcman->listeners, i); if (strcmp(listener->channel_name, ChannelName) == 0) { + IWTSVirtualChannelCallback* pCallback = NULL; channel->iface.Write = dvcman_write_channel; channel->iface.Close = dvcman_close_channel_iface; bAccept = TRUE; - pCallback = NULL; if ((error = listener->listener_callback->OnNewChannelConnection( - listener->listener_callback, - (IWTSVirtualChannel*) channel, NULL, &bAccept, &pCallback)) == CHANNEL_RC_OK - && bAccept) + listener->listener_callback, &channel->iface, NULL, &bAccept, &pCallback)) == + CHANNEL_RC_OK && + bAccept) { - WLog_Print(drdynvc->log, WLOG_DEBUG, "listener %s created new channel %"PRIu32"", + WLog_Print(drdynvc->log, WLOG_DEBUG, "listener %s created new channel %" PRIu32 "", listener->channel_name, channel->channel_id); channel->status = CHANNEL_RC_OK; channel->channel_callback = pCallback; @@ -490,28 +527,34 @@ static UINT dvcman_create_channel(drdynvcPlugin* drdynvc, listener->iface.pInterface); if (error) - WLog_Print(drdynvc->log, WLOG_ERROR, "context.OnChannelConnected failed with error %"PRIu32"", - error); + WLog_Print(drdynvc->log, WLOG_ERROR, + "context.OnChannelConnected failed with error %" PRIu32 "", error); - return error; + goto fail; } else { if (error) { - WLog_Print(drdynvc->log, WLOG_ERROR, "OnNewChannelConnection failed with error %"PRIu32"!", error); - return error; + WLog_Print(drdynvc->log, WLOG_ERROR, + "OnNewChannelConnection failed with error %" PRIu32 "!", error); + goto fail; } else { - WLog_Print(drdynvc->log, WLOG_ERROR, "OnNewChannelConnection returned with bAccept FALSE!"); - return ERROR_INTERNAL_ERROR; + WLog_Print(drdynvc->log, WLOG_ERROR, + "OnNewChannelConnection returned with bAccept FALSE!"); + error = ERROR_INTERNAL_ERROR; + goto fail; } } } } + error = ERROR_INTERNAL_ERROR; +fail: + ArrayList_Unlock(dvcman->listeners); - return ERROR_INTERNAL_ERROR; + return error; } /** @@ -519,18 +562,17 @@ static UINT dvcman_create_channel(drdynvcPlugin* drdynvc, * * @return 0 on success, otherwise a Win32 error code */ -static UINT dvcman_open_channel(drdynvcPlugin* drdynvc, - IWTSVirtualChannelManager* pChannelMgr, +static UINT dvcman_open_channel(drdynvcPlugin* drdynvc, IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId) { DVCMAN_CHANNEL* channel; IWTSVirtualChannelCallback* pCallback; UINT error; - channel = (DVCMAN_CHANNEL*) dvcman_find_channel_by_id(pChannelMgr, ChannelId); + channel = (DVCMAN_CHANNEL*)dvcman_find_channel_by_id(pChannelMgr, ChannelId); if (!channel) { - WLog_Print(drdynvc->log, WLOG_ERROR, "ChannelId %"PRIu32" not found!", ChannelId); + WLog_Print(drdynvc->log, WLOG_ERROR, "ChannelId %" PRIu32 " not found!", ChannelId); return ERROR_INTERNAL_ERROR; } @@ -538,13 +580,18 @@ static UINT dvcman_open_channel(drdynvcPlugin* drdynvc, { pCallback = channel->channel_callback; - if ((pCallback->OnOpen) && (error = pCallback->OnOpen(pCallback))) + if (pCallback->OnOpen) { - WLog_Print(drdynvc->log, WLOG_ERROR, "OnOpen failed with error %"PRIu32"!", error); - return error; + error = pCallback->OnOpen(pCallback); + if (error) + { + WLog_Print(drdynvc->log, WLOG_ERROR, "OnOpen failed with error %" PRIu32 "!", + error); + return error; + } } - WLog_Print(drdynvc->log, WLOG_DEBUG, "open_channel: ChannelId %"PRIu32"", ChannelId); + WLog_Print(drdynvc->log, WLOG_DEBUG, "open_channel: ChannelId %" PRIu32 "", ChannelId); } return CHANNEL_RC_OK; @@ -555,24 +602,41 @@ static UINT dvcman_open_channel(drdynvcPlugin* drdynvc, * * @return 0 on success, otherwise a Win32 error code */ -static UINT dvcman_close_channel(IWTSVirtualChannelManager* pChannelMgr, - UINT32 ChannelId) +static UINT dvcman_close_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, + BOOL bSendClosePDU) { DVCMAN_CHANNEL* channel; UINT error = CHANNEL_RC_OK; - DVCMAN* dvcman = (DVCMAN*) pChannelMgr; - channel = (DVCMAN_CHANNEL*) dvcman_find_channel_by_id(pChannelMgr, ChannelId); + DVCMAN* dvcman = (DVCMAN*)pChannelMgr; + drdynvcPlugin* drdynvc = dvcman->drdynvc; + channel = (DVCMAN_CHANNEL*)dvcman_find_channel_by_id(pChannelMgr, ChannelId); if (!channel) { - //WLog_Print(drdynvc->log, WLOG_ERROR, "ChannelId %"PRIu32" not found!", ChannelId); + // WLog_Print(drdynvc->log, WLOG_ERROR, "ChannelId %"PRIu32" not found!", ChannelId); /** - * Windows 8 / Windows Server 2012 send close requests for channels that failed to be created. - * Do not warn, simply return success here. + * Windows 8 / Windows Server 2012 send close requests for channels that failed to be + * created. Do not warn, simply return success here. */ return CHANNEL_RC_OK; } + if (drdynvc && bSendClosePDU) + { + wStream* s = StreamPool_Take(dvcman->pool, 5); + if (!s) + { + WLog_Print(drdynvc->log, WLOG_ERROR, "StreamPool_Take failed!"); + error = CHANNEL_RC_NO_MEMORY; + } + else + { + Stream_Write_UINT8(s, (CLOSE_REQUEST_PDU << 4) | 0x02); + Stream_Write_UINT32(s, ChannelId); + error = drdynvc_send(drdynvc, s); + } + } + ArrayList_Remove(dvcman->channels, channel); return error; } @@ -583,19 +647,20 @@ static UINT dvcman_close_channel(IWTSVirtualChannelManager* pChannelMgr, * @return 0 on success, otherwise a Win32 error code */ static UINT dvcman_receive_channel_data_first(drdynvcPlugin* drdynvc, - IWTSVirtualChannelManager* pChannelMgr, - UINT32 ChannelId, UINT32 length) + IWTSVirtualChannelManager* pChannelMgr, + UINT32 ChannelId, UINT32 length) { DVCMAN_CHANNEL* channel; - channel = (DVCMAN_CHANNEL*) dvcman_find_channel_by_id(pChannelMgr, ChannelId); + channel = (DVCMAN_CHANNEL*)dvcman_find_channel_by_id(pChannelMgr, ChannelId); if (!channel) { /** - * Windows Server 2012 R2 can send some messages over Microsoft::Windows::RDS::Geometry::v08.01 - * even if the dynamic virtual channel wasn't registered on our side. Ignoring it works. + * Windows Server 2012 R2 can send some messages over + * Microsoft::Windows::RDS::Geometry::v08.01 even if the dynamic virtual channel wasn't + * registered on our side. Ignoring it works. */ - WLog_Print(drdynvc->log, WLOG_ERROR, "ChannelId %"PRIu32" not found!", ChannelId); + WLog_Print(drdynvc->log, WLOG_ERROR, "ChannelId %" PRIu32 " not found!", ChannelId); return CHANNEL_RC_OK; } @@ -620,26 +685,26 @@ static UINT dvcman_receive_channel_data_first(drdynvcPlugin* drdynvc, * @return 0 on success, otherwise a Win32 error code */ static UINT dvcman_receive_channel_data(drdynvcPlugin* drdynvc, - IWTSVirtualChannelManager* pChannelMgr, - UINT32 ChannelId, wStream* data) + IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, + wStream* data) { UINT status = CHANNEL_RC_OK; DVCMAN_CHANNEL* channel; size_t dataSize = Stream_GetRemainingLength(data); - channel = (DVCMAN_CHANNEL*) dvcman_find_channel_by_id(pChannelMgr, ChannelId); + channel = (DVCMAN_CHANNEL*)dvcman_find_channel_by_id(pChannelMgr, ChannelId); if (!channel) { /* Windows 8.1 tries to open channels not created. - * Ignore cases like this. */ - WLog_Print(drdynvc->log, WLOG_ERROR, "ChannelId %"PRIu32" not found!", ChannelId); + * Ignore cases like this. */ + WLog_Print(drdynvc->log, WLOG_ERROR, "ChannelId %" PRIu32 " not found!", ChannelId); return CHANNEL_RC_OK; } if (channel->dvc_data) { /* Fragmented data */ - if (Stream_GetPosition(channel->dvc_data) + dataSize > Stream_Capacity(channel->dvc_data)) + if (Stream_GetPosition(channel->dvc_data) + dataSize > channel->dvc_data_length) { WLog_Print(drdynvc->log, WLOG_ERROR, "data exceeding declared length!"); Stream_Release(channel->dvc_data); @@ -654,33 +719,32 @@ static UINT dvcman_receive_channel_data(drdynvcPlugin* drdynvc, Stream_SealLength(channel->dvc_data); Stream_SetPosition(channel->dvc_data, 0); status = channel->channel_callback->OnDataReceived(channel->channel_callback, - channel->dvc_data); + channel->dvc_data); Stream_Release(channel->dvc_data); channel->dvc_data = NULL; } } else { - status = channel->channel_callback->OnDataReceived(channel->channel_callback, - data); + status = channel->channel_callback->OnDataReceived(channel->channel_callback, data); } return status; } -static UINT drdynvc_write_variable_uint(wStream* s, UINT32 val) +static UINT8 drdynvc_write_variable_uint(wStream* s, UINT32 val) { - UINT cb; + UINT8 cb; if (val <= 0xFF) { cb = 0; - Stream_Write_UINT8(s, val); + Stream_Write_UINT8(s, (UINT8)val); } else if (val <= 0xFFFF) { cb = 1; - Stream_Write_UINT16(s, val); + Stream_Write_UINT16(s, (UINT16)val); } else { @@ -704,8 +768,9 @@ static UINT drdynvc_send(drdynvcPlugin* drdynvc, wStream* s) status = CHANNEL_RC_BAD_CHANNEL_HANDLE; else { - status = drdynvc->channelEntryPoints.pVirtualChannelWriteEx(drdynvc->InitHandle, - drdynvc->OpenHandle, Stream_Buffer(s), (UINT32) Stream_GetPosition(s), s); + status = drdynvc->channelEntryPoints.pVirtualChannelWriteEx( + drdynvc->InitHandle, drdynvc->OpenHandle, Stream_Buffer(s), + (UINT32)Stream_GetPosition(s), s); } switch (status) @@ -714,19 +779,19 @@ static UINT drdynvc_send(drdynvcPlugin* drdynvc, wStream* s) return CHANNEL_RC_OK; case CHANNEL_RC_NOT_CONNECTED: - Stream_Free(s, TRUE); + Stream_Release(s); return CHANNEL_RC_OK; case CHANNEL_RC_BAD_CHANNEL_HANDLE: - Stream_Free(s, TRUE); + Stream_Release(s); WLog_ERR(TAG, "VirtualChannelWriteEx failed with CHANNEL_RC_BAD_CHANNEL_HANDLE"); return status; default: - Stream_Free(s, TRUE); - WLog_Print(drdynvc->log, WLOG_ERROR, "VirtualChannelWriteEx failed with %s [%08"PRIX32"]", - WTSErrorToString(status), - status); + Stream_Release(s); + WLog_Print(drdynvc->log, WLOG_ERROR, + "VirtualChannelWriteEx failed with %s [%08" PRIX32 "]", + WTSErrorToString(status), status); return status; } } @@ -736,26 +801,29 @@ static UINT drdynvc_send(drdynvcPlugin* drdynvc, wStream* s) * * @return 0 on success, otherwise a Win32 error code */ -static UINT drdynvc_write_data(drdynvcPlugin* drdynvc, UINT32 ChannelId, - const BYTE* data, UINT32 dataSize) +static UINT drdynvc_write_data(drdynvcPlugin* drdynvc, UINT32 ChannelId, const BYTE* data, + UINT32 dataSize) { wStream* data_out; size_t pos; - UINT32 cbChId; - UINT32 cbLen; + UINT8 cbChId; + UINT8 cbLen; unsigned long chunkLength; - UINT status; + UINT status = CHANNEL_RC_BAD_INIT_HANDLE; + DVCMAN* dvcman; if (!drdynvc) return CHANNEL_RC_BAD_CHANNEL_HANDLE; - WLog_Print(drdynvc->log, WLOG_DEBUG, "write_data: ChannelId=%"PRIu32" size=%"PRIu32"", ChannelId, - dataSize); - data_out = Stream_New(NULL, CHANNEL_CHUNK_LENGTH); + dvcman = (DVCMAN*)drdynvc->channel_mgr; + + WLog_Print(drdynvc->log, WLOG_DEBUG, "write_data: ChannelId=%" PRIu32 " size=%" PRIu32 "", + ChannelId, dataSize); + data_out = StreamPool_Take(dvcman->pool, CHANNEL_CHUNK_LENGTH); if (!data_out) { - WLog_Print(drdynvc->log, WLOG_ERROR, "Stream_New failed!"); + WLog_Print(drdynvc->log, WLOG_ERROR, "StreamPool_Take failed!"); return CHANNEL_RC_NO_MEMORY; } @@ -765,15 +833,13 @@ static UINT drdynvc_write_data(drdynvcPlugin* drdynvc, UINT32 ChannelId, if (dataSize == 0) { - Stream_SetPosition(data_out, 0); - Stream_Write_UINT8(data_out, 0x40 | cbChId); - Stream_SetPosition(data_out, pos); - status = drdynvc_send(drdynvc, data_out); + dvcman_close_channel(drdynvc->channel_mgr, ChannelId, TRUE); + Stream_Release(data_out); } else if (dataSize <= CHANNEL_CHUNK_LENGTH - pos) { Stream_SetPosition(data_out, 0); - Stream_Write_UINT8(data_out, 0x30 | cbChId); + Stream_Write_UINT8(data_out, (DATA_PDU << 4) | cbChId); Stream_SetPosition(data_out, pos); Stream_Write(data_out, data, dataSize); status = drdynvc_send(drdynvc, data_out); @@ -784,7 +850,7 @@ static UINT drdynvc_write_data(drdynvcPlugin* drdynvc, UINT32 ChannelId, cbLen = drdynvc_write_variable_uint(data_out, dataSize); pos = Stream_GetPosition(data_out); Stream_SetPosition(data_out, 0); - Stream_Write_UINT8(data_out, 0x20 | cbChId | (cbLen << 2)); + Stream_Write_UINT8(data_out, (DATA_FIRST_PDU << 4) | cbChId | (cbLen << 2)); Stream_SetPosition(data_out, pos); chunkLength = CHANNEL_CHUNK_LENGTH - pos; Stream_Write(data_out, data, chunkLength); @@ -794,11 +860,11 @@ static UINT drdynvc_write_data(drdynvcPlugin* drdynvc, UINT32 ChannelId, while (status == CHANNEL_RC_OK && dataSize > 0) { - data_out = Stream_New(NULL, CHANNEL_CHUNK_LENGTH); + data_out = StreamPool_Take(dvcman->pool, CHANNEL_CHUNK_LENGTH); if (!data_out) { - WLog_Print(drdynvc->log, WLOG_ERROR, "Stream_New failed!"); + WLog_Print(drdynvc->log, WLOG_ERROR, "StreamPool_Take failed!"); return CHANNEL_RC_NO_MEMORY; } @@ -806,7 +872,7 @@ static UINT drdynvc_write_data(drdynvcPlugin* drdynvc, UINT32 ChannelId, cbChId = drdynvc_write_variable_uint(data_out, ChannelId); pos = Stream_GetPosition(data_out); Stream_SetPosition(data_out, 0); - Stream_Write_UINT8(data_out, 0x30 | cbChId); + Stream_Write_UINT8(data_out, (DATA_PDU << 4) | cbChId); Stream_SetPosition(data_out, pos); chunkLength = dataSize; @@ -822,7 +888,7 @@ static UINT drdynvc_write_data(drdynvcPlugin* drdynvc, UINT32 ChannelId, if (status != CHANNEL_RC_OK) { - WLog_Print(drdynvc->log, WLOG_ERROR, "VirtualChannelWriteEx failed with %s [%08"PRIX32"]", + WLog_Print(drdynvc->log, WLOG_ERROR, "VirtualChannelWriteEx failed with %s [%08" PRIX32 "]", WTSErrorToString(status), status); return status; } @@ -839,12 +905,14 @@ static UINT drdynvc_send_capability_response(drdynvcPlugin* drdynvc) { UINT status; wStream* s; + DVCMAN* dvcman; if (!drdynvc) return CHANNEL_RC_BAD_CHANNEL_HANDLE; + dvcman = (DVCMAN*)drdynvc->channel_mgr; WLog_Print(drdynvc->log, WLOG_TRACE, "capability_response"); - s = Stream_New(NULL, 4); + s = StreamPool_Take(dvcman->pool, 4); if (!s) { @@ -852,14 +920,13 @@ static UINT drdynvc_send_capability_response(drdynvcPlugin* drdynvc) return CHANNEL_RC_NO_MEMORY; } - Stream_Write_UINT16(s, - 0x0050); /* Cmd+Sp+cbChId+Pad. Note: MSTSC sends 0x005c */ + Stream_Write_UINT16(s, 0x0050); /* Cmd+Sp+cbChId+Pad. Note: MSTSC sends 0x005c */ Stream_Write_UINT16(s, drdynvc->version); status = drdynvc_send(drdynvc, s); if (status != CHANNEL_RC_OK) { - WLog_Print(drdynvc->log, WLOG_ERROR, "VirtualChannelWriteEx failed with %s [%08"PRIX32"]", + WLog_Print(drdynvc->log, WLOG_ERROR, "VirtualChannelWriteEx failed with %s [%08" PRIX32 "]", WTSErrorToString(status), status); } @@ -871,8 +938,8 @@ static UINT drdynvc_send_capability_response(drdynvcPlugin* drdynvc) * * @return 0 on success, otherwise a Win32 error code */ -static UINT drdynvc_process_capability_request(drdynvcPlugin* drdynvc, int Sp, - int cbChId, wStream* s) +static UINT drdynvc_process_capability_request(drdynvcPlugin* drdynvc, int Sp, int cbChId, + wStream* s) { UINT status; @@ -947,8 +1014,7 @@ static UINT32 drdynvc_read_variable_uint(wStream* s, int cbLen) * * @return 0 on success, otherwise a Win32 error code */ -static UINT drdynvc_process_create_request(drdynvcPlugin* drdynvc, int Sp, - int cbChId, wStream* s) +static UINT drdynvc_process_create_request(drdynvcPlugin* drdynvc, int Sp, int cbChId, wStream* s) { size_t pos; UINT status; @@ -957,10 +1023,13 @@ static UINT drdynvc_process_create_request(drdynvcPlugin* drdynvc, int Sp, UINT channel_status; char* name; size_t length; + DVCMAN* dvcman; + WINPR_UNUSED(Sp); if (!drdynvc) return CHANNEL_RC_BAD_CHANNEL_HANDLE; + dvcman = (DVCMAN*)drdynvc->channel_mgr; if (drdynvc->state == DRDYNVC_STATE_CAPABILITIES) { /** @@ -990,18 +1059,18 @@ static UINT drdynvc_process_create_request(drdynvcPlugin* drdynvc, int Sp, if (strnlen(name, length) >= length) return ERROR_INVALID_DATA; - WLog_Print(drdynvc->log, WLOG_DEBUG, "process_create_request: ChannelId=%"PRIu32" ChannelName=%s", - ChannelId, name); + WLog_Print(drdynvc->log, WLOG_DEBUG, + "process_create_request: ChannelId=%" PRIu32 " ChannelName=%s", ChannelId, name); channel_status = dvcman_create_channel(drdynvc, drdynvc->channel_mgr, ChannelId, name); - data_out = Stream_New(NULL, pos + 4); + data_out = StreamPool_Take(dvcman->pool, pos + 4); if (!data_out) { - WLog_Print(drdynvc->log, WLOG_ERROR, "Stream_New failed!"); + WLog_Print(drdynvc->log, WLOG_ERROR, "StreamPool_Take failed!"); return CHANNEL_RC_NO_MEMORY; } - Stream_Write_UINT8(data_out, 0x10 | cbChId); + Stream_Write_UINT8(data_out, (CREATE_REQUEST_PDU << 4) | cbChId); Stream_SetPosition(s, 1); Stream_Copy(s, data_out, pos - 1); @@ -1020,7 +1089,7 @@ static UINT drdynvc_process_create_request(drdynvcPlugin* drdynvc, int Sp, if (status != CHANNEL_RC_OK) { - WLog_Print(drdynvc->log, WLOG_ERROR, "VirtualChannelWriteEx failed with %s [%08"PRIX32"]", + WLog_Print(drdynvc->log, WLOG_ERROR, "VirtualChannelWriteEx failed with %s [%08" PRIX32 "]", WTSErrorToString(status), status); return status; } @@ -1029,14 +1098,16 @@ static UINT drdynvc_process_create_request(drdynvcPlugin* drdynvc, int Sp, { if ((status = dvcman_open_channel(drdynvc, drdynvc->channel_mgr, ChannelId))) { - WLog_Print(drdynvc->log, WLOG_ERROR, "dvcman_open_channel failed with error %"PRIu32"!", status); + WLog_Print(drdynvc->log, WLOG_ERROR, + "dvcman_open_channel failed with error %" PRIu32 "!", status); return status; } } else { - if ((status = dvcman_close_channel(drdynvc->channel_mgr, ChannelId))) - WLog_Print(drdynvc->log, WLOG_ERROR, "dvcman_close_channel failed with error %"PRIu32"!", status); + if ((status = dvcman_close_channel(drdynvc->channel_mgr, ChannelId, FALSE))) + WLog_Print(drdynvc->log, WLOG_ERROR, + "dvcman_close_channel failed with error %" PRIu32 "!", status); } return status; @@ -1047,8 +1118,7 @@ static UINT drdynvc_process_create_request(drdynvcPlugin* drdynvc, int Sp, * * @return 0 on success, otherwise a Win32 error code */ -static UINT drdynvc_process_data_first(drdynvcPlugin* drdynvc, int Sp, - int cbChId, wStream* s) +static UINT drdynvc_process_data_first(drdynvcPlugin* drdynvc, int Sp, int cbChId, wStream* s) { UINT status; UINT32 Length; @@ -1060,15 +1130,17 @@ static UINT drdynvc_process_data_first(drdynvcPlugin* drdynvc, int Sp, ChannelId = drdynvc_read_variable_uint(s, cbChId); Length = drdynvc_read_variable_uint(s, Sp); WLog_Print(drdynvc->log, WLOG_DEBUG, - "process_data_first: Sp=%d cbChId=%d, ChannelId=%"PRIu32" Length=%"PRIu32"", Sp, + "process_data_first: Sp=%d cbChId=%d, ChannelId=%" PRIu32 " Length=%" PRIu32 "", Sp, cbChId, ChannelId, Length); - status = dvcman_receive_channel_data_first(drdynvc, drdynvc->channel_mgr, ChannelId, - Length); + status = dvcman_receive_channel_data_first(drdynvc, drdynvc->channel_mgr, ChannelId, Length); - if (status) - return status; + if (status == CHANNEL_RC_OK) + status = dvcman_receive_channel_data(drdynvc, drdynvc->channel_mgr, ChannelId, s); - return dvcman_receive_channel_data(drdynvc, drdynvc->channel_mgr, ChannelId, s); + if (status != CHANNEL_RC_OK) + status = dvcman_close_channel(drdynvc->channel_mgr, ChannelId, TRUE); + + return status; } /** @@ -1076,19 +1148,23 @@ static UINT drdynvc_process_data_first(drdynvcPlugin* drdynvc, int Sp, * * @return 0 on success, otherwise a Win32 error code */ -static UINT drdynvc_process_data(drdynvcPlugin* drdynvc, int Sp, int cbChId, - wStream* s) +static UINT drdynvc_process_data(drdynvcPlugin* drdynvc, int Sp, int cbChId, wStream* s) { UINT32 ChannelId; + UINT status; if (Stream_GetRemainingLength(s) < drdynvc_cblen_to_bytes(cbChId)) return ERROR_INVALID_DATA; ChannelId = drdynvc_read_variable_uint(s, cbChId); - WLog_Print(drdynvc->log, WLOG_TRACE, "process_data: Sp=%d cbChId=%d, ChannelId=%"PRIu32"", Sp, - cbChId, - ChannelId); - return dvcman_receive_channel_data(drdynvc, drdynvc->channel_mgr, ChannelId, s); + WLog_Print(drdynvc->log, WLOG_TRACE, "process_data: Sp=%d cbChId=%d, ChannelId=%" PRIu32 "", Sp, + cbChId, ChannelId); + status = dvcman_receive_channel_data(drdynvc, drdynvc->channel_mgr, ChannelId, s); + + if (status != CHANNEL_RC_OK) + status = dvcman_close_channel(drdynvc->channel_mgr, ChannelId, TRUE); + + return status; } /** @@ -1096,44 +1172,22 @@ static UINT drdynvc_process_data(drdynvcPlugin* drdynvc, int Sp, int cbChId, * * @return 0 on success, otherwise a Win32 error code */ -static UINT drdynvc_process_close_request(drdynvcPlugin* drdynvc, int Sp, - int cbChId, wStream* s) +static UINT drdynvc_process_close_request(drdynvcPlugin* drdynvc, int Sp, int cbChId, wStream* s) { - int value; UINT error; UINT32 ChannelId; - wStream* data_out; if (Stream_GetRemainingLength(s) < drdynvc_cblen_to_bytes(cbChId)) return ERROR_INVALID_DATA; ChannelId = drdynvc_read_variable_uint(s, cbChId); - WLog_Print(drdynvc->log, WLOG_DEBUG, "process_close_request: Sp=%d cbChId=%d, ChannelId=%"PRIu32"", - Sp, - cbChId, ChannelId); - - if ((error = dvcman_close_channel(drdynvc->channel_mgr, ChannelId))) - { - WLog_Print(drdynvc->log, WLOG_ERROR, "dvcman_close_channel failed with error %"PRIu32"!", error); - return error; - } - - data_out = Stream_New(NULL, 4); - - if (!data_out) - { - WLog_Print(drdynvc->log, WLOG_ERROR, "Stream_New failed!"); - return CHANNEL_RC_NO_MEMORY; - } - - value = (CLOSE_REQUEST_PDU << 4) | (cbChId & 0x03); - Stream_Write_UINT8(data_out, value); - drdynvc_write_variable_uint(data_out, ChannelId); - error = drdynvc_send(drdynvc, data_out); + WLog_Print(drdynvc->log, WLOG_DEBUG, + "process_close_request: Sp=%d cbChId=%d, ChannelId=%" PRIu32 "", Sp, cbChId, + ChannelId); - if (error) - WLog_Print(drdynvc->log, WLOG_ERROR, "VirtualChannelWriteEx failed with %s [%08"PRIX32"]", - WTSErrorToString(error), error); + if ((error = dvcman_close_channel(drdynvc->channel_mgr, ChannelId, TRUE))) + WLog_Print(drdynvc->log, WLOG_ERROR, "dvcman_close_channel failed with error %" PRIu32 "!", + error); return error; } @@ -1187,8 +1241,9 @@ static UINT drdynvc_order_recv(drdynvcPlugin* drdynvc, wStream* s) * * @return 0 on success, otherwise a Win32 error code */ -static UINT drdynvc_virtual_channel_event_data_received(drdynvcPlugin* drdynvc, - void* pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) +static UINT drdynvc_virtual_channel_event_data_received(drdynvcPlugin* drdynvc, void* pData, + UINT32 dataLength, UINT32 totalLength, + UINT32 dataFlags) { wStream* data_in; @@ -1199,22 +1254,23 @@ static UINT drdynvc_virtual_channel_event_data_received(drdynvcPlugin* drdynvc, if (dataFlags & CHANNEL_FLAG_FIRST) { + DVCMAN* mgr = (DVCMAN*)drdynvc->channel_mgr; if (drdynvc->data_in) - Stream_Free(drdynvc->data_in, TRUE); + Stream_Release(drdynvc->data_in); - drdynvc->data_in = Stream_New(NULL, totalLength); + drdynvc->data_in = StreamPool_Take(mgr->pool, totalLength); } if (!(data_in = drdynvc->data_in)) { - WLog_Print(drdynvc->log, WLOG_ERROR, "Stream_New failed!"); + WLog_Print(drdynvc->log, WLOG_ERROR, "StreamPool_Take failed!"); return CHANNEL_RC_NO_MEMORY; } if (!Stream_EnsureRemainingCapacity(data_in, dataLength)) { WLog_Print(drdynvc->log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!"); - Stream_Free(drdynvc->data_in, TRUE); + Stream_Release(drdynvc->data_in); drdynvc->data_in = NULL; return ERROR_INTERNAL_ERROR; } @@ -1223,7 +1279,9 @@ static UINT drdynvc_virtual_channel_event_data_received(drdynvcPlugin* drdynvc, if (dataFlags & CHANNEL_FLAG_LAST) { - if (Stream_Capacity(data_in) != Stream_GetPosition(data_in)) + const size_t cap = Stream_Capacity(data_in); + const size_t pos = Stream_GetPosition(data_in); + if (cap < pos) { WLog_Print(drdynvc->log, WLOG_ERROR, "drdynvc_plugin_process_received: read error"); return ERROR_INVALID_DATA; @@ -1233,7 +1291,7 @@ static UINT drdynvc_virtual_channel_event_data_received(drdynvcPlugin* drdynvc, Stream_SealLength(data_in); Stream_SetPosition(data_in, 0); - if (!MessageQueue_Post(drdynvc->queue, NULL, 0, (void*) data_in, NULL)) + if (!MessageQueue_Post(drdynvc->queue, NULL, 0, (void*)data_in, NULL)) { WLog_Print(drdynvc->log, WLOG_ERROR, "MessageQueue_Post failed!"); return ERROR_INTERNAL_ERROR; @@ -1244,36 +1302,45 @@ static UINT drdynvc_virtual_channel_event_data_received(drdynvcPlugin* drdynvc, } static void VCAPITYPE drdynvc_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle, - UINT event, LPVOID pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) + UINT event, LPVOID pData, + UINT32 dataLength, UINT32 totalLength, + UINT32 dataFlags) { UINT error = CHANNEL_RC_OK; - drdynvcPlugin* drdynvc = (drdynvcPlugin*) lpUserParam; - - if (!drdynvc || (drdynvc->OpenHandle != openHandle)) - { - WLog_ERR(TAG, "drdynvc_virtual_channel_open_event: error no match"); - return; - } + drdynvcPlugin* drdynvc = (drdynvcPlugin*)lpUserParam; switch (event) { case CHANNEL_EVENT_DATA_RECEIVED: - if ((error = drdynvc_virtual_channel_event_data_received(drdynvc, pData, dataLength, totalLength, - dataFlags))) + if (!drdynvc || (drdynvc->OpenHandle != openHandle)) + { + WLog_ERR(TAG, "drdynvc_virtual_channel_open_event: error no match"); + return; + } + if ((error = drdynvc_virtual_channel_event_data_received(drdynvc, pData, dataLength, + totalLength, dataFlags))) WLog_Print(drdynvc->log, WLOG_ERROR, - "drdynvc_virtual_channel_event_data_received failed with error %"PRIu32"", error); + "drdynvc_virtual_channel_event_data_received failed with error %" PRIu32 + "", + error); break; + case CHANNEL_EVENT_WRITE_CANCELLED: case CHANNEL_EVENT_WRITE_COMPLETE: - break; + { + wStream* s = (wStream*)pData; + Stream_Release(s); + } + break; case CHANNEL_EVENT_USER: break; } - if (error && drdynvc->rdpcontext) - setChannelError(drdynvc->rdpcontext, error, "drdynvc_virtual_channel_open_event reported an error"); + if (error && drdynvc && drdynvc->rdpcontext) + setChannelError(drdynvc->rdpcontext, error, + "drdynvc_virtual_channel_open_event reported an error"); } static DWORD WINAPI drdynvc_virtual_channel_client_thread(LPVOID arg) @@ -1281,11 +1348,11 @@ static DWORD WINAPI drdynvc_virtual_channel_client_thread(LPVOID arg) wStream* data; wMessage message; UINT error = CHANNEL_RC_OK; - drdynvcPlugin* drdynvc = (drdynvcPlugin*) arg; + drdynvcPlugin* drdynvc = (drdynvcPlugin*)arg; if (!drdynvc) { - ExitThread((DWORD) CHANNEL_RC_BAD_CHANNEL_HANDLE); + ExitThread((DWORD)CHANNEL_RC_BAD_CHANNEL_HANDLE); return CHANNEL_RC_BAD_CHANNEL_HANDLE; } @@ -1310,31 +1377,30 @@ static DWORD WINAPI drdynvc_virtual_channel_client_thread(LPVOID arg) if (message.id == 0) { - data = (wStream*) message.wParam; + data = (wStream*)message.wParam; if ((error = drdynvc_order_recv(drdynvc, data))) { - Stream_Free(data, TRUE); - WLog_Print(drdynvc->log, WLOG_ERROR, "drdynvc_order_recv failed with error %"PRIu32"!", error); - break; + WLog_Print(drdynvc->log, WLOG_WARN, + "drdynvc_order_recv failed with error %" PRIu32 "!", error); } - Stream_Free(data, TRUE); + Stream_Release(data); } } { /* Disconnect remaining dynamic channels that the server did not. - * This is required to properly shut down channels by calling the appropriate - * event handlers. */ + * This is required to properly shut down channels by calling the appropriate + * event handlers. */ DVCMAN* drdynvcMgr = (DVCMAN*)drdynvc->channel_mgr; while (ArrayList_Count(drdynvcMgr->channels) > 0) { - IWTSVirtualChannel* channel = (IWTSVirtualChannel*) - ArrayList_GetItem(drdynvcMgr->channels, 0); + IWTSVirtualChannel* channel = + (IWTSVirtualChannel*)ArrayList_GetItem(drdynvcMgr->channels, 0); const UINT32 ChannelId = drdynvc->channel_mgr->GetChannelId(channel); - dvcman_close_channel(drdynvc->channel_mgr, ChannelId); + dvcman_close_channel(drdynvc->channel_mgr, ChannelId, FALSE); } } @@ -1342,7 +1408,7 @@ static DWORD WINAPI drdynvc_virtual_channel_client_thread(LPVOID arg) setChannelError(drdynvc->rdpcontext, error, "drdynvc_virtual_channel_client_thread reported an error"); - ExitThread((DWORD) error); + ExitThread((DWORD)error); return error; } @@ -1357,35 +1423,18 @@ static void drdynvc_queue_object_free(void* obj) s = (wStream*)msg->wParam; if (s) - Stream_Free(s, TRUE); + Stream_Release(s); } -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT drdynvc_virtual_channel_event_connected(drdynvcPlugin* drdynvc, LPVOID pData, - UINT32 dataLength) +static UINT drdynvc_virtual_channel_event_initialized(drdynvcPlugin* drdynvc, LPVOID pData, + UINT32 dataLength) { - UINT error; - UINT32 status; - UINT32 index; - ADDIN_ARGV* args; - rdpSettings* settings; + UINT error = CHANNEL_RC_OK; + WINPR_UNUSED(pData); + WINPR_UNUSED(dataLength); if (!drdynvc) - return CHANNEL_RC_BAD_CHANNEL_HANDLE; - - status = drdynvc->channelEntryPoints.pVirtualChannelOpenEx(drdynvc->InitHandle, - &drdynvc->OpenHandle, drdynvc->channelDef.name, drdynvc_virtual_channel_open_event_ex); - - if (status != CHANNEL_RC_OK) - { - WLog_Print(drdynvc->log, WLOG_ERROR, "pVirtualChannelOpen failed with %s [%08"PRIX32"]", - WTSErrorToString(status), status); - return status; - } + goto error; drdynvc->queue = MessageQueue_New(NULL); @@ -1406,7 +1455,43 @@ static UINT drdynvc_virtual_channel_event_connected(drdynvcPlugin* drdynvc, LPVO goto error; } - settings = (rdpSettings*) drdynvc->channelEntryPoints.pExtendedData; + return CHANNEL_RC_OK; +error: + return ERROR_INTERNAL_ERROR; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT drdynvc_virtual_channel_event_connected(drdynvcPlugin* drdynvc, LPVOID pData, + UINT32 dataLength) +{ + UINT error; + UINT32 status; + UINT32 index; + ADDIN_ARGV* args; + rdpSettings* settings; + + WINPR_UNUSED(pData); + WINPR_UNUSED(dataLength); + + if (!drdynvc) + return CHANNEL_RC_BAD_CHANNEL_HANDLE; + + status = drdynvc->channelEntryPoints.pVirtualChannelOpenEx( + drdynvc->InitHandle, &drdynvc->OpenHandle, drdynvc->channelDef.name, + drdynvc_virtual_channel_open_event_ex); + + if (status != CHANNEL_RC_OK) + { + WLog_Print(drdynvc->log, WLOG_ERROR, "pVirtualChannelOpen failed with %s [%08" PRIX32 "]", + WTSErrorToString(status), status); + return status; + } + + settings = (rdpSettings*)drdynvc->channelEntryPoints.pExtendedData; for (index = 0; index < settings->DynamicChannelCount; index++) { @@ -1419,15 +1504,14 @@ static UINT drdynvc_virtual_channel_event_connected(drdynvcPlugin* drdynvc, LPVO if ((error = dvcman_init(drdynvc, drdynvc->channel_mgr))) { - WLog_Print(drdynvc->log, WLOG_ERROR, "dvcman_init failed with error %"PRIu32"!", error); + WLog_Print(drdynvc->log, WLOG_ERROR, "dvcman_init failed with error %" PRIu32 "!", error); goto error; } drdynvc->state = DRDYNVC_STATE_CAPABILITIES; if (!(drdynvc->thread = CreateThread(NULL, 0, drdynvc_virtual_channel_client_thread, - (void*) drdynvc, - 0, NULL))) + (void*)drdynvc, 0, NULL))) { error = ERROR_INTERNAL_ERROR; WLog_Print(drdynvc->log, WLOG_ERROR, "CreateThread failed!"); @@ -1447,53 +1531,50 @@ 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(); - WLog_Print(drdynvc->log, WLOG_ERROR, "MessageQueue_PostQuit failed with error %"PRIu32"", status); + WLog_Print(drdynvc->log, WLOG_ERROR, "MessageQueue_PostQuit failed with error %" PRIu32 "", + status); return status; } if (WaitForSingleObject(drdynvc->thread, INFINITE) != WAIT_OBJECT_0) { status = GetLastError(); - WLog_Print(drdynvc->log, WLOG_ERROR, "WaitForSingleObject failed with error %"PRIu32"", status); + WLog_Print(drdynvc->log, WLOG_ERROR, "WaitForSingleObject failed with error %" PRIu32 "", + status); return status; } - MessageQueue_Free(drdynvc->queue); CloseHandle(drdynvc->thread); - drdynvc->queue = NULL; drdynvc->thread = NULL; + status = drdynvc->channelEntryPoints.pVirtualChannelCloseEx(drdynvc->InitHandle, - drdynvc->OpenHandle); + drdynvc->OpenHandle); if (status != CHANNEL_RC_OK) { - WLog_Print(drdynvc->log, WLOG_ERROR, "pVirtualChannelClose failed with %s [%08"PRIX32"]", + WLog_Print(drdynvc->log, WLOG_ERROR, "pVirtualChannelClose failed with %s [%08" PRIX32 "]", WTSErrorToString(status), status); } + dvcman_clear(drdynvc, drdynvc->channel_mgr); + MessageQueue_Clear(drdynvc->queue); drdynvc->OpenHandle = 0; if (drdynvc->data_in) { - Stream_Free(drdynvc->data_in, TRUE); + Stream_Release(drdynvc->data_in); drdynvc->data_in = NULL; } - if (drdynvc->channel_mgr) - { - dvcman_free(drdynvc, drdynvc->channel_mgr); - drdynvc->channel_mgr = NULL; - } - return status; } @@ -1507,6 +1588,15 @@ static UINT drdynvc_virtual_channel_event_terminated(drdynvcPlugin* drdynvc) if (!drdynvc) return CHANNEL_RC_BAD_CHANNEL_HANDLE; + MessageQueue_Free(drdynvc->queue); + drdynvc->queue = NULL; + + if (drdynvc->channel_mgr) + { + dvcman_free(drdynvc, drdynvc->channel_mgr); + drdynvc->channel_mgr = NULL; + } + drdynvc->InitHandle = 0; free(drdynvc->context); free(drdynvc); @@ -1515,67 +1605,75 @@ static UINT drdynvc_virtual_channel_event_terminated(drdynvcPlugin* drdynvc) static UINT drdynvc_virtual_channel_event_attached(drdynvcPlugin* drdynvc) { - int i; + UINT error = CHANNEL_RC_OK; + size_t i; DVCMAN* dvcman; if (!drdynvc) return CHANNEL_RC_BAD_CHANNEL_HANDLE; - dvcman = (DVCMAN*) drdynvc->channel_mgr; + dvcman = (DVCMAN*)drdynvc->channel_mgr; if (!dvcman) return CHANNEL_RC_BAD_CHANNEL_HANDLE; - for (i = 0; i < dvcman->num_plugins; i++) + ArrayList_Lock(dvcman->plugins); + for (i = 0; i < ArrayList_Count(dvcman->plugins); i++) { - UINT error; - IWTSPlugin* pPlugin = dvcman->plugins[i]; + IWTSPlugin* pPlugin = ArrayList_GetItem(dvcman->plugins, i); - if (pPlugin->Attached) - if ((error = pPlugin->Attached(pPlugin))) - { - WLog_Print(drdynvc->log, WLOG_ERROR, "Attach failed with error %"PRIu32"!", error); - return error; - } + error = IFCALLRESULT(CHANNEL_RC_OK, pPlugin->Attached, pPlugin); + if (error != CHANNEL_RC_OK) + { + WLog_Print(drdynvc->log, WLOG_ERROR, "Attach failed with error %" PRIu32 "!", error); + goto fail; + } } - return CHANNEL_RC_OK; +fail: + ArrayList_Unlock(dvcman->plugins); + return error; } static UINT drdynvc_virtual_channel_event_detached(drdynvcPlugin* drdynvc) { - int i; + UINT error = CHANNEL_RC_OK; + size_t i; DVCMAN* dvcman; if (!drdynvc) return CHANNEL_RC_BAD_CHANNEL_HANDLE; - dvcman = (DVCMAN*) drdynvc->channel_mgr; + dvcman = (DVCMAN*)drdynvc->channel_mgr; if (!dvcman) return CHANNEL_RC_BAD_CHANNEL_HANDLE; - for (i = 0; i < dvcman->num_plugins; i++) + ArrayList_Lock(dvcman->plugins); + for (i = 0; i < ArrayList_Count(dvcman->plugins); i++) { - UINT error; - IWTSPlugin* pPlugin = dvcman->plugins[i]; + IWTSPlugin* pPlugin = ArrayList_GetItem(dvcman->plugins, i); - if (pPlugin->Detached) - if ((error = pPlugin->Detached(pPlugin))) - { - WLog_Print(drdynvc->log, WLOG_ERROR, "Detach failed with error %"PRIu32"!", error); - return error; - } + error = IFCALLRESULT(CHANNEL_RC_OK, pPlugin->Detached, pPlugin); + if (error != CHANNEL_RC_OK) + { + WLog_Print(drdynvc->log, WLOG_ERROR, "Detach failed with error %" PRIu32 "!", error); + goto fail; + } } - return CHANNEL_RC_OK; +fail: + ArrayList_Unlock(dvcman->plugins); + + return error; } static VOID VCAPITYPE drdynvc_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle, - UINT event, LPVOID pData, UINT dataLength) + UINT event, LPVOID pData, + UINT dataLength) { UINT error = CHANNEL_RC_OK; - drdynvcPlugin* drdynvc = (drdynvcPlugin*) lpUserParam; + drdynvcPlugin* drdynvc = (drdynvcPlugin*)lpUserParam; if (!drdynvc || (drdynvc->InitHandle != pInitHandle)) { @@ -1585,38 +1683,47 @@ static VOID VCAPITYPE drdynvc_virtual_channel_init_event_ex(LPVOID lpUserParam, switch (event) { + case CHANNEL_EVENT_INITIALIZED: + error = drdynvc_virtual_channel_event_initialized(drdynvc, pData, dataLength); + break; case CHANNEL_EVENT_CONNECTED: if ((error = drdynvc_virtual_channel_event_connected(drdynvc, pData, dataLength))) WLog_Print(drdynvc->log, WLOG_ERROR, - "drdynvc_virtual_channel_event_connected failed with error %"PRIu32"", error); + "drdynvc_virtual_channel_event_connected failed with error %" PRIu32 "", + error); break; case CHANNEL_EVENT_DISCONNECTED: - if ((error = drdynvc_virtual_channel_event_disconnected(drdynvc))) + if ((error = drdynvc_virtual_channel_event_disconnected(drdynvc))) WLog_Print(drdynvc->log, WLOG_ERROR, - "drdynvc_virtual_channel_event_disconnected failed with error %"PRIu32"", error); + "drdynvc_virtual_channel_event_disconnected failed with error %" PRIu32 + "", + error); break; case CHANNEL_EVENT_TERMINATED: - if ((error = drdynvc_virtual_channel_event_terminated(drdynvc))) + if ((error = drdynvc_virtual_channel_event_terminated(drdynvc))) WLog_Print(drdynvc->log, WLOG_ERROR, - "drdynvc_virtual_channel_event_terminated failed with error %"PRIu32"", error); + "drdynvc_virtual_channel_event_terminated failed with error %" PRIu32 "", + error); break; case CHANNEL_EVENT_ATTACHED: - if ((error = drdynvc_virtual_channel_event_attached(drdynvc))) + if ((error = drdynvc_virtual_channel_event_attached(drdynvc))) WLog_Print(drdynvc->log, WLOG_ERROR, - "drdynvc_virtual_channel_event_attached failed with error %"PRIu32"", error); + "drdynvc_virtual_channel_event_attached failed with error %" PRIu32 "", + error); break; case CHANNEL_EVENT_DETACHED: - if ((error = drdynvc_virtual_channel_event_detached(drdynvc))) + if ((error = drdynvc_virtual_channel_event_detached(drdynvc))) WLog_Print(drdynvc->log, WLOG_ERROR, - "drdynvc_virtual_channel_event_detached failed with error %"PRIu32"", error); + "drdynvc_virtual_channel_event_detached failed with error %" PRIu32 "", + error); break; @@ -1635,12 +1742,12 @@ static VOID VCAPITYPE drdynvc_virtual_channel_init_event_ex(LPVOID lpUserParam, static int drdynvc_get_version(DrdynvcClientContext* context) { - drdynvcPlugin* drdynvc = (drdynvcPlugin*) context->handle; + drdynvcPlugin* drdynvc = (drdynvcPlugin*)context->handle; return drdynvc->version; } /* drdynvc is always built-in */ -#define VirtualChannelEntryEx drdynvc_VirtualChannelEntryEx +#define VirtualChannelEntryEx drdynvc_VirtualChannelEntryEx BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS_EX pEntryPoints, PVOID pInitHandle) { @@ -1648,7 +1755,7 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS_EX pEntryPoints, PVOI drdynvcPlugin* drdynvc; DrdynvcClientContext* context = NULL; CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx; - drdynvc = (drdynvcPlugin*) calloc(1, sizeof(drdynvcPlugin)); + drdynvc = (drdynvcPlugin*)calloc(1, sizeof(drdynvcPlugin)); if (!drdynvc) { @@ -1657,17 +1764,15 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS_EX pEntryPoints, PVOI } drdynvc->channelDef.options = - CHANNEL_OPTION_INITIALIZED | - CHANNEL_OPTION_ENCRYPT_RDP | - CHANNEL_OPTION_COMPRESS_RDP; + CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_COMPRESS_RDP; sprintf_s(drdynvc->channelDef.name, ARRAYSIZE(drdynvc->channelDef.name), "drdynvc"); drdynvc->state = DRDYNVC_STATE_INITIAL; - pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*) pEntryPoints; + pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints; if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) && (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER)) { - context = (DrdynvcClientContext*) calloc(1, sizeof(DrdynvcClientContext)); + context = (DrdynvcClientContext*)calloc(1, sizeof(DrdynvcClientContext)); if (!context) { @@ -1676,7 +1781,7 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS_EX pEntryPoints, PVOI return FALSE; } - context->handle = (void*) drdynvc; + context->handle = (void*)drdynvc; context->custom = NULL; drdynvc->context = context; context->GetVersion = drdynvc_get_version; @@ -1685,14 +1790,16 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS_EX pEntryPoints, PVOI drdynvc->log = WLog_Get(TAG); WLog_Print(drdynvc->log, WLOG_DEBUG, "VirtualChannelEntryEx"); - CopyMemory(&(drdynvc->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)); + CopyMemory(&(drdynvc->channelEntryPoints), pEntryPoints, + sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)); drdynvc->InitHandle = pInitHandle; - rc = drdynvc->channelEntryPoints.pVirtualChannelInitEx(drdynvc, context, pInitHandle, - &drdynvc->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, drdynvc_virtual_channel_init_event_ex); + rc = drdynvc->channelEntryPoints.pVirtualChannelInitEx( + drdynvc, context, pInitHandle, &drdynvc->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, + drdynvc_virtual_channel_init_event_ex); if (CHANNEL_RC_OK != rc) { - WLog_Print(drdynvc->log, WLOG_ERROR, "pVirtualChannelInit failed with %s [%08"PRIX32"]", + WLog_Print(drdynvc->log, WLOG_ERROR, "pVirtualChannelInit failed with %s [%08" PRIX32 "]", WTSErrorToString(rc), rc); free(drdynvc->context); free(drdynvc); @@ -1702,4 +1809,3 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS_EX pEntryPoints, PVOI drdynvc->channelEntryPoints.pInterface = context; return TRUE; } - diff --git a/channels/drdynvc/client/drdynvc_main.h b/channels/drdynvc/client/drdynvc_main.h index 1d83582..646c8fd 100644 --- a/channels/drdynvc/client/drdynvc_main.h +++ b/channels/drdynvc/client/drdynvc_main.h @@ -37,21 +37,16 @@ typedef struct drdynvc_plugin drdynvcPlugin; -#define MAX_PLUGINS 32 - struct _DVCMAN { IWTSVirtualChannelManager iface; drdynvcPlugin* drdynvc; - int num_plugins; - const char* plugin_names[MAX_PLUGINS]; - IWTSPlugin* plugins[MAX_PLUGINS]; - - int num_listeners; - IWTSListener* listeners[MAX_PLUGINS]; + wArrayList* plugin_names; + wArrayList* plugins; + wArrayList* listeners; wArrayList* channels; wStreamPool* pool; }; @@ -106,11 +101,11 @@ enum _DRDYNVC_STATE }; typedef enum _DRDYNVC_STATE DRDYNVC_STATE; -#define CREATE_REQUEST_PDU 0x01 -#define DATA_FIRST_PDU 0x02 -#define DATA_PDU 0x03 -#define CLOSE_REQUEST_PDU 0x04 -#define CAPABILITY_REQUEST_PDU 0x05 +#define CREATE_REQUEST_PDU 0x01 +#define DATA_FIRST_PDU 0x02 +#define DATA_PDU 0x03 +#define CLOSE_REQUEST_PDU 0x04 +#define CAPABILITY_REQUEST_PDU 0x05 struct drdynvc_plugin { @@ -127,7 +122,7 @@ struct drdynvc_plugin DRDYNVC_STATE state; DrdynvcClientContext* context; - int version; + UINT16 version; int PriorityCharge0; int PriorityCharge1; int PriorityCharge2; diff --git a/channels/drdynvc/server/drdynvc_main.c b/channels/drdynvc/server/drdynvc_main.c index b963970..66440b2 100644 --- a/channels/drdynvc/server/drdynvc_main.c +++ b/channels/drdynvc/server/drdynvc_main.c @@ -32,7 +32,6 @@ #define TAG CHANNELS_TAG("drdynvc.server") - static DWORD WINAPI drdynvc_server_thread(LPVOID arg) { #if 0 @@ -121,8 +120,8 @@ static DWORD WINAPI drdynvc_server_thread(LPVOID arg) */ static UINT drdynvc_server_start(DrdynvcServerContext* context) { - context->priv->ChannelHandle = WTSVirtualChannelOpen(context->vcm, - WTS_CURRENT_SESSION, "drdynvc"); + context->priv->ChannelHandle = + WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "drdynvc"); if (!context->priv->ChannelHandle) { @@ -136,7 +135,8 @@ static UINT drdynvc_server_start(DrdynvcServerContext* context) return ERROR_INTERNAL_ERROR; } - if (!(context->priv->Thread = CreateThread(NULL, 0, drdynvc_server_thread, (void*) context, 0, NULL))) + if (!(context->priv->Thread = + CreateThread(NULL, 0, drdynvc_server_thread, (void*)context, 0, NULL))) { WLog_ERR(TAG, "CreateThread failed!"); CloseHandle(context->priv->StopEvent); @@ -160,7 +160,7 @@ static UINT drdynvc_server_stop(DrdynvcServerContext* context) if (WaitForSingleObject(context->priv->Thread, INFINITE) == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error); return error; } @@ -171,14 +171,14 @@ static UINT drdynvc_server_stop(DrdynvcServerContext* context) DrdynvcServerContext* drdynvc_server_context_new(HANDLE vcm) { DrdynvcServerContext* context; - context = (DrdynvcServerContext*) calloc(1, sizeof(DrdynvcServerContext)); + context = (DrdynvcServerContext*)calloc(1, sizeof(DrdynvcServerContext)); if (context) { context->vcm = vcm; context->Start = drdynvc_server_start; context->Stop = drdynvc_server_stop; - context->priv = (DrdynvcServerPrivate*) calloc(1, sizeof(DrdynvcServerPrivate)); + context->priv = (DrdynvcServerPrivate*)calloc(1, sizeof(DrdynvcServerPrivate)); if (!context->priv) { diff --git a/channels/drive/client/drive_file.c b/channels/drive/client/drive_file.c index f816695..3054385 100644 --- a/channels/drive/client/drive_file.c +++ b/channels/drive/client/drive_file.c @@ -46,16 +46,25 @@ #include "drive_file.h" #ifdef WITH_DEBUG_RDPDR -#define DEBUG_WSTR(msg, wstr) do { LPSTR lpstr; ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &lpstr, 0, NULL, NULL); WLog_DBG(TAG, msg, lpstr); free(lpstr); } while (0) +#define DEBUG_WSTR(msg, wstr) \ + do \ + { \ + LPSTR lpstr; \ + ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &lpstr, 0, NULL, NULL); \ + WLog_DBG(TAG, msg, lpstr); \ + free(lpstr); \ + } while (0) #else -#define DEBUG_WSTR(msg, wstr) do { } while (0) +#define DEBUG_WSTR(msg, wstr) \ + do \ + { \ + } while (0) #endif 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,12 +89,12 @@ 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) + if (!base_path || (!path && (PathLength > 0))) return NULL; base_path_length = _wcslen(base_path) * 2; @@ -98,7 +107,8 @@ static WCHAR* drive_file_combine_fullpath(const WCHAR* base_path, const WCHAR* p } CopyMemory(fullpath, base_path, base_path_length); - CopyMemory((char*)fullpath + base_path_length, path, PathLength); + if (path) + CopyMemory((char*)fullpath + base_path_length, path, PathLength); drive_file_fix_path(fullpath); return fullpath; } @@ -107,11 +117,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,10 +149,10 @@ 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'.')) + if ((len == 1 && findFileData.cFileName[0] == L'.') || + (len == 2 && findFileData.cFileName[0] == L'.' && findFileData.cFileName[1] == L'.')) { continue; } @@ -164,8 +173,7 @@ static BOOL drive_file_remove_dir(const WCHAR* path) if (!ret) break; - } - while (ret && FindNextFileW(dir, &findFileData) != 0); + } while (ret && FindNextFileW(dir, &findFileData) != 0); FindClose(dir); @@ -240,7 +248,8 @@ static BOOL drive_file_init(DRIVE_FILE* file) if (file->is_dir) { /* Should only create the directory if the disposition allows for it */ - if ((file->CreateDisposition == FILE_OPEN_IF) || (file->CreateDisposition == FILE_CREATE)) + if ((file->CreateDisposition == FILE_OPEN_IF) || + (file->CreateDisposition == FILE_CREATE)) { if (CreateDirectoryW(file->fullpath, NULL) != 0) { @@ -257,27 +266,33 @@ static BOOL drive_file_init(DRIVE_FILE* file) { switch (file->CreateDisposition) { - case FILE_SUPERSEDE: /* If the file already exists, replace it with the given file. If it does not, create the given file. */ + case FILE_SUPERSEDE: /* If the file already exists, replace it with the given file. If + it does not, create the given file. */ CreateDisposition = CREATE_ALWAYS; break; - case FILE_OPEN: /* If the file already exists, open it instead of creating a new file. If it does not, fail the request and do not create a new file. */ + case FILE_OPEN: /* If the file already exists, open it instead of creating a new file. + If it does not, fail the request and do not create a new file. */ CreateDisposition = OPEN_EXISTING; break; - case FILE_CREATE: /* If the file already exists, fail the request and do not create or open the given file. If it does not, create the given file. */ + case FILE_CREATE: /* If the file already exists, fail the request and do not create or + open the given file. If it does not, create the given file. */ CreateDisposition = CREATE_NEW; break; - case FILE_OPEN_IF: /* If the file already exists, open it. If it does not, create the given file. */ + case FILE_OPEN_IF: /* If the file already exists, open it. If it does not, create the + given file. */ CreateDisposition = OPEN_ALWAYS; break; - case FILE_OVERWRITE: /* If the file already exists, open it and overwrite it. If it does not, fail the request. */ + case FILE_OVERWRITE: /* If the file already exists, open it and overwrite it. If it does + not, fail the request. */ CreateDisposition = TRUNCATE_EXISTING; break; - case FILE_OVERWRITE_IF: /* If the file already exists, open it and overwrite it. If it does not, create the given file. */ + case FILE_OVERWRITE_IF: /* If the file already exists, open it and overwrite it. If it + does not, create the given file. */ CreateDisposition = CREATE_ALWAYS; break; @@ -288,11 +303,11 @@ static BOOL drive_file_init(DRIVE_FILE* file) #ifndef WIN32 file->SharedAccess = 0; #endif - file->file_handle = CreateFileW(file->fullpath, file->DesiredAccess, - file->SharedAccess, NULL, CreateDisposition, - file->FileAttributes, NULL); + file->file_handle = CreateFileW(file->fullpath, file->DesiredAccess, file->SharedAccess, + NULL, CreateDisposition, file->FileAttributes, NULL); } +#ifdef WIN32 if (file->file_handle == INVALID_HANDLE_VALUE) { /* Get the error message, if any. */ @@ -300,31 +315,34 @@ static BOOL drive_file_init(DRIVE_FILE* file) if (errorMessageID != 0) { -#ifdef WIN32 LPSTR messageBuffer = NULL; - size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL); + size_t size = + FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR)&messageBuffer, 0, NULL); WLog_ERR(TAG, "Error in drive_file_init: %s %s", messageBuffer, file->fullpath); /* Free the buffer. */ LocalFree(messageBuffer); -#endif + /* restore original error code */ + SetLastError(errorMessageID); } } +#endif return file->file_handle != INVALID_HANDLE_VALUE; } DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 PathLength, UINT32 id, - UINT32 DesiredAccess, UINT32 CreateDisposition, - UINT32 CreateOptions, UINT32 FileAttributes, UINT32 SharedAccess) + UINT32 DesiredAccess, UINT32 CreateDisposition, UINT32 CreateOptions, + UINT32 FileAttributes, UINT32 SharedAccess) { DRIVE_FILE* file; - if (!base_path || !path) + if (!base_path || (!path && (PathLength > 0))) return NULL; - file = (DRIVE_FILE*) calloc(1, sizeof(DRIVE_FILE)); + file = (DRIVE_FILE*)calloc(1, sizeof(DRIVE_FILE)); if (!file) { @@ -335,7 +353,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; @@ -345,7 +363,9 @@ DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 Pat if (!drive_file_init(file)) { + DWORD lastError = GetLastError(); drive_file_free(file); + SetLastError(lastError); return NULL; } @@ -397,7 +417,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); } @@ -460,15 +483,23 @@ BOOL drive_file_query_information(DRIVE_FILE* file, UINT32 FsInformationClass, w goto out_fail; Stream_Write_UINT32(output, 36); /* Length */ - Stream_Write_UINT32(output, fileAttributes.ftCreationTime.dwLowDateTime); /* CreationTime */ - Stream_Write_UINT32(output, fileAttributes.ftCreationTime.dwHighDateTime); /* CreationTime */ - Stream_Write_UINT32(output, fileAttributes.ftLastAccessTime.dwLowDateTime); /* LastAccessTime */ - Stream_Write_UINT32(output, fileAttributes.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */ - Stream_Write_UINT32(output, fileAttributes.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */ - Stream_Write_UINT32(output, fileAttributes.ftLastWriteTime.dwHighDateTime); /* LastWriteTime */ - Stream_Write_UINT32(output, fileAttributes.ftLastWriteTime.dwLowDateTime); /* ChangeTime */ - Stream_Write_UINT32(output, fileAttributes.ftLastWriteTime.dwHighDateTime); /* ChangeTime */ - Stream_Write_UINT32(output, fileAttributes.dwFileAttributes); /* FileAttributes */ + Stream_Write_UINT32(output, + fileAttributes.ftCreationTime.dwLowDateTime); /* CreationTime */ + Stream_Write_UINT32(output, + fileAttributes.ftCreationTime.dwHighDateTime); /* CreationTime */ + Stream_Write_UINT32(output, + fileAttributes.ftLastAccessTime.dwLowDateTime); /* LastAccessTime */ + Stream_Write_UINT32( + output, fileAttributes.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */ + Stream_Write_UINT32(output, + fileAttributes.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */ + Stream_Write_UINT32(output, + fileAttributes.ftLastWriteTime.dwHighDateTime); /* LastWriteTime */ + Stream_Write_UINT32(output, + fileAttributes.ftLastWriteTime.dwLowDateTime); /* ChangeTime */ + Stream_Write_UINT32(output, + fileAttributes.ftLastWriteTime.dwHighDateTime); /* ChangeTime */ + Stream_Write_UINT32(output, fileAttributes.dwFileAttributes); /* FileAttributes */ /* Reserved(4), MUST NOT be added! */ break; @@ -478,15 +509,16 @@ BOOL drive_file_query_information(DRIVE_FILE* file, UINT32 FsInformationClass, w if (!Stream_EnsureRemainingCapacity(output, 4 + 22)) goto out_fail; - Stream_Write_UINT32(output, 22); /* Length */ - Stream_Write_UINT32(output, fileAttributes.nFileSizeLow); /* AllocationSize */ + Stream_Write_UINT32(output, 22); /* Length */ + Stream_Write_UINT32(output, fileAttributes.nFileSizeLow); /* AllocationSize */ Stream_Write_UINT32(output, fileAttributes.nFileSizeHigh); /* AllocationSize */ - Stream_Write_UINT32(output, fileAttributes.nFileSizeLow); /* EndOfFile */ + Stream_Write_UINT32(output, fileAttributes.nFileSizeLow); /* EndOfFile */ Stream_Write_UINT32(output, fileAttributes.nFileSizeHigh); /* EndOfFile */ - Stream_Write_UINT32(output, 0); /* NumberOfLinks */ - Stream_Write_UINT8(output, file->delete_pending ? 1 : 0); /* DeletePending */ - Stream_Write_UINT8(output, fileAttributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? TRUE : - FALSE); /* Directory */ + Stream_Write_UINT32(output, 0); /* NumberOfLinks */ + Stream_Write_UINT8(output, file->delete_pending ? 1 : 0); /* DeletePending */ + Stream_Write_UINT8(output, fileAttributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY + ? TRUE + : FALSE); /* Directory */ /* Reserved(2), MUST NOT be added! */ break; @@ -496,9 +528,9 @@ BOOL drive_file_query_information(DRIVE_FILE* file, UINT32 FsInformationClass, w if (!Stream_EnsureRemainingCapacity(output, 4 + 8)) goto out_fail; - Stream_Write_UINT32(output, 8); /* Length */ + Stream_Write_UINT32(output, 8); /* Length */ Stream_Write_UINT32(output, fileAttributes.dwFileAttributes); /* FileAttributes */ - Stream_Write_UINT32(output, 0); /* ReparseTag */ + Stream_Write_UINT32(output, 0); /* ReparseTag */ break; default: @@ -555,47 +587,49 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN if (file->file_handle == INVALID_HANDLE_VALUE) { - WLog_ERR(TAG, "Unable to set file time %s (%"PRId32")", file->fullpath, GetLastError()); + WLog_ERR(TAG, "Unable to set file time %s (%" PRId32 ")", file->fullpath, + GetLastError()); return FALSE; } if (liCreationTime.QuadPart != 0) { - ftCreationTime.dwHighDateTime = liCreationTime.HighPart; - ftCreationTime.dwLowDateTime = liCreationTime.LowPart; + ftCreationTime.dwHighDateTime = liCreationTime.u.HighPart; + ftCreationTime.dwLowDateTime = liCreationTime.u.LowPart; pftCreationTime = &ftCreationTime; } if (liLastAccessTime.QuadPart != 0) { - ftLastAccessTime.dwHighDateTime = liLastAccessTime.HighPart; - ftLastAccessTime.dwLowDateTime = liLastAccessTime.LowPart; + ftLastAccessTime.dwHighDateTime = liLastAccessTime.u.HighPart; + ftLastAccessTime.dwLowDateTime = liLastAccessTime.u.LowPart; pftLastAccessTime = &ftLastAccessTime; } if (liLastWriteTime.QuadPart != 0) { - ftLastWriteTime.dwHighDateTime = liLastWriteTime.HighPart; - ftLastWriteTime.dwLowDateTime = liLastWriteTime.LowPart; + ftLastWriteTime.dwHighDateTime = liLastWriteTime.u.HighPart; + ftLastWriteTime.dwLowDateTime = liLastWriteTime.u.LowPart; pftLastWriteTime = &ftLastWriteTime; } if (liChangeTime.QuadPart != 0 && liChangeTime.QuadPart > liLastWriteTime.QuadPart) { - ftLastWriteTime.dwHighDateTime = liChangeTime.HighPart; - ftLastWriteTime.dwLowDateTime = liChangeTime.LowPart; + ftLastWriteTime.dwHighDateTime = liChangeTime.u.HighPart; + ftLastWriteTime.dwLowDateTime = liChangeTime.u.LowPart; pftLastWriteTime = &ftLastWriteTime; } DEBUG_WSTR("SetFileTime %s", file->fullpath); - if (!SetFileTime(file->file_handle, pftCreationTime, pftLastAccessTime, pftLastWriteTime)) + SetFileAttributesW(file->fullpath, FileAttributes); + if (!SetFileTime(file->file_handle, pftCreationTime, pftLastAccessTime, + pftLastWriteTime)) { WLog_ERR(TAG, "Unable to set file time to %s", file->fullpath); return FALSE; } - SetFileAttributesW(file->fullpath, FileAttributes); break; case FileEndOfFileInformation: @@ -610,14 +644,17 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN if (file->file_handle == INVALID_HANDLE_VALUE) { - WLog_ERR(TAG, "Unable to truncate %s to %"PRId64" (%"PRId32")", file->fullpath, size, - GetLastError()); + WLog_ERR(TAG, "Unable to truncate %s to %" PRId64 " (%" PRId32 ")", file->fullpath, + size, GetLastError()); 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()); + WLog_ERR(TAG, "Unable to truncate %s to %d (%" PRId32 ")", file->fullpath, size, + GetLastError()); return FALSE; } @@ -625,7 +662,8 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN if (SetEndOfFile(file->file_handle) == 0) { - WLog_ERR(TAG, "Unable to truncate %s to %d (%"PRId32")", file->fullpath, size, GetLastError()); + WLog_ERR(TAG, "Unable to truncate %s to %d (%" PRId32 ")", file->fullpath, size, + GetLastError()); return FALSE; } @@ -696,7 +734,8 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN DEBUG_WSTR("MoveFileExW %s", file->fullpath); if (MoveFileExW(file->fullpath, fullpath, - MOVEFILE_COPY_ALLOWED | (ReplaceIfExists ? MOVEFILE_REPLACE_EXISTING : 0))) + MOVEFILE_COPY_ALLOWED | + (ReplaceIfExists ? MOVEFILE_REPLACE_EXISTING : 0))) { if (!drive_file_set_fullpath(file, fullpath)) return FALSE; @@ -755,23 +794,34 @@ 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 */ - Stream_Write_UINT32(output, 0); /* NextEntryOffset */ - Stream_Write_UINT32(output, 0); /* FileIndex */ - Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwLowDateTime); /* CreationTime */ - 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.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */ - Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */ - 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 */ + 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 */ + 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.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */ + Stream_Write_UINT32(output, + file->find_data.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */ + 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(output, file->find_data.cFileName, length); break; @@ -781,24 +831,35 @@ 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 */ - 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.ftLastAccessTime.dwLowDateTime); /* LastAccessTime */ - Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwHighDateTime); /* LastWriteTime */ - 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.dwLowDateTime); /* 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 */ + 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.dwLowDateTime); /* CreationTime */ + 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.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */ + Stream_Write_UINT32(output, + file->find_data.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */ + 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, 0); /* EaSize */ + Stream_Write_UINT32(output, (UINT32)length); /* FileNameLength */ + Stream_Write_UINT32(output, 0); /* EaSize */ Stream_Write(output, file->find_data.cFileName, length); break; @@ -808,25 +869,36 @@ 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 */ - Stream_Write_UINT32(output, 0); /* NextEntryOffset */ - Stream_Write_UINT32(output, 0); /* FileIndex */ - Stream_Write_UINT32(output, file->find_data.ftCreationTime.dwLowDateTime); /* CreationTime */ - 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.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */ - Stream_Write_UINT32(output, file->find_data.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */ - 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 */ + 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 */ + 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.ftLastAccessTime.dwHighDateTime); /* LastAccessTime */ + Stream_Write_UINT32(output, + file->find_data.ftLastWriteTime.dwLowDateTime); /* LastWriteTime */ + 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, 0); /* EaSize */ - Stream_Write_UINT8(output, 0); /* ShortNameLength */ + 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! */ Stream_Zero(output, 24); /* ShortName */ Stream_Write(output, file->find_data.cFileName, length); @@ -838,14 +910,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 */ - Stream_Write_UINT32(output, 0); /* NextEntryOffset */ - Stream_Write_UINT32(output, 0); /* FileIndex */ - Stream_Write_UINT32(output, length); /* FileNameLength */ + 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, (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; } @@ -853,6 +929,6 @@ BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYT return TRUE; out_fail: Stream_Write_UINT32(output, 0); /* Length */ - Stream_Write_UINT8(output, 0); /* Padding */ + Stream_Write_UINT8(output, 0); /* Padding */ return FALSE; } diff --git a/channels/drive/client/drive_file.h b/channels/drive/client/drive_file.h index b928187..ed789d6 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; @@ -52,8 +52,8 @@ struct _DRIVE_FILE }; DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 PathLength, UINT32 id, - UINT32 DesiredAccess, UINT32 CreateDisposition, - UINT32 CreateOptions, UINT32 FileAttributes, UINT32 SharedAccess); + UINT32 DesiredAccess, UINT32 CreateDisposition, UINT32 CreateOptions, + UINT32 FileAttributes, UINT32 SharedAccess); BOOL drive_file_free(DRIVE_FILE* file); BOOL drive_file_open(DRIVE_FILE* file); diff --git a/channels/drive/client/drive_main.c b/channels/drive/client/drive_main.c index df361c0..1b54225 100644 --- a/channels/drive/client/drive_main.c +++ b/channels/drive/client/drive_main.c @@ -102,7 +102,7 @@ static DWORD drive_map_windows_err(DWORD fs_errno) case ERROR_FILE_EXISTS: case ERROR_ALREADY_EXISTS: - rc = STATUS_OBJECT_NAME_COLLISION; + rc = STATUS_OBJECT_NAME_COLLISION; break; case ERROR_INVALID_NAME: @@ -127,7 +127,7 @@ static DWORD drive_map_windows_err(DWORD fs_errno) default: rc = STATUS_UNSUCCESSFUL; - WLog_ERR(TAG, "Error code not found: %"PRIu32"", fs_errno); + WLog_ERR(TAG, "Error code not found: %" PRIu32 "", fs_errno); break; } @@ -137,12 +137,12 @@ static DWORD drive_map_windows_err(DWORD fs_errno) static DRIVE_FILE* drive_get_file_by_id(DRIVE_DEVICE* drive, UINT32 id) { DRIVE_FILE* file = NULL; - void* key = (void*)(size_t) id; + void* key = (void*)(size_t)id; if (!drive) return NULL; - file = (DRIVE_FILE*) ListDictionary_GetItemValue(drive->files, key); + file = (DRIVE_FILE*)ListDictionary_GetItemValue(drive->files, key); return file; } @@ -182,7 +182,7 @@ static UINT drive_process_irp_create(DRIVE_DEVICE* drive, IRP* irp) if (Stream_GetRemainingLength(irp->input) < PathLength) return ERROR_INVALID_DATA; - path = (WCHAR*) Stream_Pointer(irp->input); + path = (const WCHAR*)Stream_Pointer(irp->input); FileId = irp->devman->id_sequence++; file = drive_file_new(drive->path, path, PathLength, FileId, DesiredAccess, CreateDisposition, CreateOptions, FileAttributes, SharedAccess); @@ -195,7 +195,7 @@ static UINT drive_process_irp_create(DRIVE_DEVICE* drive, IRP* irp) } else { - void* key = (void*)(size_t) file->id; + void* key = (void*)(size_t)file->id; if (!ListDictionary_Add(drive->files, key, file)) { @@ -245,7 +245,7 @@ static UINT drive_process_irp_close(DRIVE_DEVICE* drive, IRP* irp) return ERROR_INVALID_PARAMETER; file = drive_get_file_by_id(drive, irp->FileId); - key = (void*)(size_t) irp->FileId; + key = (void*)(size_t)irp->FileId; if (!file) irp->IoStatus = STATUS_UNSUCCESSFUL; @@ -331,6 +331,7 @@ static UINT drive_process_irp_write(DRIVE_DEVICE* drive, IRP* irp) DRIVE_FILE* file; UINT32 Length; UINT64 Offset; + void* ptr; if (!drive || !irp || !irp->input || !irp->output || !irp->Complete) return ERROR_INVALID_PARAMETER; @@ -341,6 +342,9 @@ static UINT drive_process_irp_write(DRIVE_DEVICE* drive, IRP* irp) Stream_Read_UINT32(irp->input, Length); Stream_Read_UINT64(irp->input, Offset); Stream_Seek(irp->input, 20); /* Padding */ + ptr = Stream_Pointer(irp->input); + if (!Stream_SafeSeek(irp->input, Length)) + return ERROR_INVALID_DATA; file = drive_get_file_by_id(drive, irp->FileId); if (!file) @@ -353,7 +357,7 @@ static UINT drive_process_irp_write(DRIVE_DEVICE* drive, IRP* irp) irp->IoStatus = drive_map_windows_err(GetLastError()); Length = 0; } - else if (!drive_file_write(file, Stream_Pointer(irp->input), Length)) + else if (!drive_file_write(file, ptr, Length)) { irp->IoStatus = drive_map_windows_err(GetLastError()); Length = 0; @@ -421,8 +425,7 @@ static UINT drive_process_irp_set_information(DRIVE_DEVICE* drive, IRP* irp) { irp->IoStatus = STATUS_UNSUCCESSFUL; } - else if (!drive_file_set_information(file, FsInformationClass, Length, - irp->input)) + else if (!drive_file_set_information(file, FsInformationClass, Length, irp->input)) { irp->IoStatus = drive_map_windows_err(GetLastError()); } @@ -434,19 +437,17 @@ static UINT drive_process_irp_set_information(DRIVE_DEVICE* drive, IRP* irp) return irp->Complete(irp); } - /** * Function description * * @return 0 on success, otherwise a Win32 error code */ -static UINT drive_process_irp_query_volume_information(DRIVE_DEVICE* drive, - IRP* irp) +static UINT drive_process_irp_query_volume_information(DRIVE_DEVICE* drive, IRP* irp) { UINT32 FsInformationClass; wStream* output = NULL; - char* volumeLabel = {"FREERDP"}; - char* diskType = {"FAT32"}; + char* volumeLabel = { "FREERDP" }; + char* diskType = { "FAT32" }; WCHAR* outStr = NULL; int length; DWORD lpSectorsPerCluster; @@ -489,10 +490,11 @@ static UINT drive_process_irp_query_volume_information(DRIVE_DEVICE* drive, GetFileAttributesExW(drive->path, GetFileExInfoStandard, &wfad); Stream_Write_UINT32(output, wfad.ftCreationTime.dwLowDateTime); /* VolumeCreationTime */ - Stream_Write_UINT32(output, wfad.ftCreationTime.dwHighDateTime); /* VolumeCreationTime */ + Stream_Write_UINT32(output, + wfad.ftCreationTime.dwHighDateTime); /* VolumeCreationTime */ Stream_Write_UINT32(output, lpNumberOfFreeClusters & 0xffff); /* VolumeSerialNumber */ - Stream_Write_UINT32(output, length); /* VolumeLabelLength */ - Stream_Write_UINT8(output, 0); /* SupportsObjects */ + Stream_Write_UINT32(output, length); /* VolumeLabelLength */ + Stream_Write_UINT8(output, 0); /* SupportsObjects */ /* Reserved(1), MUST NOT be added! */ Stream_Write(output, outStr, length); /* VolumeLabel (Unicode) */ free(outStr); @@ -509,9 +511,9 @@ static UINT drive_process_irp_query_volume_information(DRIVE_DEVICE* drive, } Stream_Write_UINT64(output, lpTotalNumberOfClusters); /* TotalAllocationUnits */ - Stream_Write_UINT64(output, lpNumberOfFreeClusters); /* AvailableAllocationUnits */ - Stream_Write_UINT32(output, lpSectorsPerCluster); /* SectorsPerAllocationUnit */ - Stream_Write_UINT32(output, lpBytesPerSector); /* BytesPerSector */ + Stream_Write_UINT64(output, lpNumberOfFreeClusters); /* AvailableAllocationUnits */ + Stream_Write_UINT32(output, lpSectorsPerCluster); /* SectorsPerAllocationUnit */ + Stream_Write_UINT32(output, lpBytesPerSector); /* BytesPerSector */ break; case FileFsAttributeInformation: @@ -532,13 +534,11 @@ static UINT drive_process_irp_query_volume_information(DRIVE_DEVICE* drive, return CHANNEL_RC_NO_MEMORY; } - Stream_Write_UINT32(output, - FILE_CASE_SENSITIVE_SEARCH | - FILE_CASE_PRESERVED_NAMES | - FILE_UNICODE_ON_DISK); /* FileSystemAttributes */ - Stream_Write_UINT32(output, MAX_PATH); /* MaximumComponentNameLength */ - Stream_Write_UINT32(output, length); /* FileSystemNameLength */ - Stream_Write(output, outStr, length); /* FileSystemName (Unicode) */ + Stream_Write_UINT32(output, FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | + FILE_UNICODE_ON_DISK); /* FileSystemAttributes */ + Stream_Write_UINT32(output, MAX_PATH); /* MaximumComponentNameLength */ + Stream_Write_UINT32(output, length); /* FileSystemNameLength */ + Stream_Write(output, outStr, length); /* FileSystemName (Unicode) */ free(outStr); break; @@ -553,10 +553,11 @@ static UINT drive_process_irp_query_volume_information(DRIVE_DEVICE* drive, } Stream_Write_UINT64(output, lpTotalNumberOfClusters); /* TotalAllocationUnits */ - Stream_Write_UINT64(output, lpNumberOfFreeClusters); /* CallerAvailableAllocationUnits */ + Stream_Write_UINT64(output, + lpNumberOfFreeClusters); /* CallerAvailableAllocationUnits */ Stream_Write_UINT64(output, lpNumberOfFreeClusters); /* AvailableAllocationUnits */ - Stream_Write_UINT32(output, lpSectorsPerCluster); /* SectorsPerAllocationUnit */ - Stream_Write_UINT32(output, lpBytesPerSector); /* BytesPerSector */ + Stream_Write_UINT32(output, lpSectorsPerCluster); /* SectorsPerAllocationUnit */ + Stream_Write_UINT32(output, lpBytesPerSector); /* BytesPerSector */ break; case FileFsDeviceInformation: @@ -570,7 +571,7 @@ static UINT drive_process_irp_query_volume_information(DRIVE_DEVICE* drive, } Stream_Write_UINT32(output, FILE_DEVICE_DISK); /* DeviceType */ - Stream_Write_UINT32(output, 0); /* Characteristics */ + Stream_Write_UINT32(output, 0); /* Characteristics */ break; default: @@ -627,7 +628,7 @@ static UINT drive_process_irp_query_directory(DRIVE_DEVICE* drive, IRP* irp) Stream_Read_UINT8(irp->input, InitialQuery); Stream_Read_UINT32(irp->input, PathLength); Stream_Seek(irp->input, 23); /* Padding */ - path = (WCHAR*) Stream_Pointer(irp->input); + path = (WCHAR*)Stream_Pointer(irp->input); file = drive_get_file_by_id(drive, irp->FileId); if (file == NULL) @@ -754,7 +755,7 @@ static DWORD WINAPI drive_thread_func(LPVOID arg) { IRP* irp; wMessage message; - DRIVE_DEVICE* drive = (DRIVE_DEVICE*) arg; + DRIVE_DEVICE* drive = (DRIVE_DEVICE*)arg; UINT error = CHANNEL_RC_OK; if (!drive) @@ -782,13 +783,13 @@ static DWORD WINAPI drive_thread_func(LPVOID arg) if (message.id == WMQ_QUIT) break; - irp = (IRP*) message.wParam; + irp = (IRP*)message.wParam; if (irp) { if ((error = drive_process_irp(drive, irp))) { - WLog_ERR(TAG, "drive_process_irp failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "drive_process_irp failed with error %" PRIu32 "!", error); break; } } @@ -810,12 +811,12 @@ fail: */ static UINT drive_irp_request(DEVICE* device, IRP* irp) { - DRIVE_DEVICE* drive = (DRIVE_DEVICE*) device; + DRIVE_DEVICE* drive = (DRIVE_DEVICE*)device; if (!drive) return ERROR_INVALID_PARAMETER; - if (!MessageQueue_Post(drive->IrpQueue, NULL, 0, (void*) irp, NULL)) + if (!MessageQueue_Post(drive->IrpQueue, NULL, 0, (void*)irp, NULL)) { WLog_ERR(TAG, "MessageQueue_Post failed!"); return ERROR_INTERNAL_ERROR; @@ -847,17 +848,17 @@ static UINT drive_free_int(DRIVE_DEVICE* drive) */ static UINT drive_free(DEVICE* device) { - DRIVE_DEVICE* drive = (DRIVE_DEVICE*) device; + DRIVE_DEVICE* drive = (DRIVE_DEVICE*)device; UINT error = CHANNEL_RC_OK; if (!drive) return ERROR_INVALID_PARAMETER; - if (MessageQueue_PostQuit(drive->IrpQueue, 0) - && (WaitForSingleObject(drive->thread, INFINITE) == WAIT_FAILED)) + if (MessageQueue_PostQuit(drive->IrpQueue, 0) && + (WaitForSingleObject(drive->thread, INFINITE) == WAIT_FAILED)) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error); return error; } @@ -869,7 +870,7 @@ static UINT drive_free(DEVICE* device) */ static void drive_file_objfree(void* obj) { - drive_file_free((DRIVE_FILE*) obj); + drive_file_free((DRIVE_FILE*)obj); } /** @@ -877,17 +878,24 @@ static void drive_file_objfree(void* obj) * * @return 0 on success, otherwise a Win32 error code */ -static UINT drive_register_drive_path(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, - const char* name, const char* path, BOOL automount) +static UINT drive_register_drive_path(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, const char* name, + const char* path, BOOL automount) { size_t i, length; DRIVE_DEVICE* drive; - UINT error; + UINT error = ERROR_INTERNAL_ERROR; + + if (!pEntryPoints || !name || !path) + { + WLog_ERR(TAG, "[%s] Invalid parameters: pEntryPoints=%p, name=%p, path=%p", pEntryPoints, + name, path); + return ERROR_INVALID_PARAMETER; + } if (name[0] && path[0]) { size_t pathLength = strnlen(path, MAX_PATH); - drive = (DRIVE_DEVICE*) calloc(1, sizeof(DRIVE_DEVICE)); + drive = (DRIVE_DEVICE*)calloc(1, sizeof(DRIVE_DEVICE)); if (!drive) { @@ -896,7 +904,6 @@ static UINT drive_register_drive_path(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, } drive->device.type = RDPDR_DTYP_FILESYSTEM; - drive->device.name = name; drive->device.IRPRequest = drive_irp_request; drive->device.Free = drive_free; drive->rdpcontext = pEntryPoints->rdpcontext; @@ -911,11 +918,34 @@ static UINT drive_register_drive_path(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, goto out_error; } - for (i = 0; i <= length; i++) - Stream_Write_UINT8(drive->device.data, name[i] < 0 ? '_' : name[i]); + for (i = 0; i < length; i++) + { + /* Filter 2.2.1.3 Device Announce Header (DEVICE_ANNOUNCE) forbidden symbols */ + switch (name[i]) + { + case ':': + case '<': + case '>': + case '\"': + case '/': + case '\\': + case '|': + case ' ': + Stream_Write_UINT8(drive->device.data, '_'); + break; + default: + Stream_Write_UINT8(drive->device.data, (BYTE)name[i]); + break; + } + } + Stream_Write_UINT8(drive->device.data, '\0'); + + drive->device.name = (const char*)Stream_Buffer(drive->device.data); + if (!drive->device.name) + goto out_error; if ((pathLength > 1) && (path[pathLength - 1] == '/')) - pathLength --; + pathLength--; if (ConvertToUnicode(sys_code_page, 0, path, pathLength, &drive->path, 0) <= 0) { @@ -943,15 +973,14 @@ static UINT drive_register_drive_path(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, goto out_error; } - if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, - (DEVICE*) drive))) + if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*)drive))) { - WLog_ERR(TAG, "RegisterDevice failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "RegisterDevice failed with error %" PRIu32 "!", error); goto out_error; } - if (!(drive->thread = CreateThread(NULL, 0, drive_thread_func, drive, - CREATE_SUSPENDED, NULL))) + if (!(drive->thread = + CreateThread(NULL, 0, drive_thread_func, drive, CREATE_SUSPENDED, NULL))) { WLog_ERR(TAG, "CreateThread failed!"); goto out_error; @@ -967,9 +996,9 @@ out_error: } #ifdef BUILTIN_CHANNELS -#define DeviceServiceEntry drive_DeviceServiceEntry +#define DeviceServiceEntry drive_DeviceServiceEntry #else -#define DeviceServiceEntry FREERDP_API DeviceServiceEntry +#define DeviceServiceEntry FREERDP_API DeviceServiceEntry #endif /** @@ -988,7 +1017,7 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) char* bufdup; char* devdup; #endif - drive = (RDPDR_DRIVE*) pEntryPoints->device; + drive = (RDPDR_DRIVE*)pEntryPoints->device; #ifndef WIN32 sys_code_page = CP_UTF8; diff --git a/channels/echo/client/echo_main.c b/channels/echo/client/echo_main.c index a16089f..c8dc4d8 100644 --- a/channels/echo/client/echo_main.c +++ b/channels/echo/client/echo_main.c @@ -59,6 +59,7 @@ struct _ECHO_PLUGIN IWTSPlugin iface; ECHO_LISTENER_CALLBACK* listener_callback; + IWTSListener* listener; }; /** @@ -66,9 +67,9 @@ struct _ECHO_PLUGIN * * @return 0 on success, otherwise a Win32 error code */ -static UINT echo_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *data) +static UINT echo_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data) { - ECHO_CHANNEL_CALLBACK* callback = (ECHO_CHANNEL_CALLBACK*) pChannelCallback; + ECHO_CHANNEL_CALLBACK* callback = (ECHO_CHANNEL_CALLBACK*)pChannelCallback; BYTE* pBuffer = Stream_Pointer(data); UINT32 cbSize = Stream_GetRemainingLength(data); @@ -83,7 +84,7 @@ static UINT echo_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, */ static UINT echo_on_close(IWTSVirtualChannelCallback* pChannelCallback) { - ECHO_CHANNEL_CALLBACK* callback = (ECHO_CHANNEL_CALLBACK*) pChannelCallback; + ECHO_CHANNEL_CALLBACK* callback = (ECHO_CHANNEL_CALLBACK*)pChannelCallback; free(callback); @@ -96,13 +97,13 @@ static UINT echo_on_close(IWTSVirtualChannelCallback* pChannelCallback) * @return 0 on success, otherwise a Win32 error code */ static UINT echo_on_new_channel_connection(IWTSListenerCallback* pListenerCallback, - IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept, - IWTSVirtualChannelCallback** ppCallback) + IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept, + IWTSVirtualChannelCallback** ppCallback) { ECHO_CHANNEL_CALLBACK* callback; - ECHO_LISTENER_CALLBACK* listener_callback = (ECHO_LISTENER_CALLBACK*) pListenerCallback; + ECHO_LISTENER_CALLBACK* listener_callback = (ECHO_LISTENER_CALLBACK*)pListenerCallback; - callback = (ECHO_CHANNEL_CALLBACK*) calloc(1, sizeof(ECHO_CHANNEL_CALLBACK)); + callback = (ECHO_CHANNEL_CALLBACK*)calloc(1, sizeof(ECHO_CHANNEL_CALLBACK)); if (!callback) { @@ -116,7 +117,7 @@ static UINT echo_on_new_channel_connection(IWTSListenerCallback* pListenerCallba callback->channel_mgr = listener_callback->channel_mgr; callback->channel = pChannel; - *ppCallback = (IWTSVirtualChannelCallback*) callback; + *ppCallback = (IWTSVirtualChannelCallback*)callback; return CHANNEL_RC_OK; } @@ -128,9 +129,9 @@ static UINT echo_on_new_channel_connection(IWTSListenerCallback* pListenerCallba */ static UINT echo_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr) { - ECHO_PLUGIN* echo = (ECHO_PLUGIN*) pPlugin; + ECHO_PLUGIN* echo = (ECHO_PLUGIN*)pPlugin; - echo->listener_callback = (ECHO_LISTENER_CALLBACK*) calloc(1, sizeof(ECHO_LISTENER_CALLBACK)); + echo->listener_callback = (ECHO_LISTENER_CALLBACK*)calloc(1, sizeof(ECHO_LISTENER_CALLBACK)); if (!echo->listener_callback) { @@ -142,8 +143,8 @@ static UINT echo_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManage echo->listener_callback->plugin = pPlugin; echo->listener_callback->channel_mgr = pChannelMgr; - return pChannelMgr->CreateListener(pChannelMgr, "ECHO", 0, - (IWTSListenerCallback*) echo->listener_callback, NULL); + return pChannelMgr->CreateListener(pChannelMgr, "ECHO", 0, &echo->listener_callback->iface, + &echo->listener); } /** @@ -153,17 +154,22 @@ static UINT echo_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManage */ static UINT echo_plugin_terminated(IWTSPlugin* pPlugin) { - ECHO_PLUGIN* echo = (ECHO_PLUGIN*) pPlugin; - + ECHO_PLUGIN* echo = (ECHO_PLUGIN*)pPlugin; + if (echo && echo->listener_callback) + { + IWTSVirtualChannelManager* mgr = echo->listener_callback->channel_mgr; + if (mgr) + IFCALL(mgr->DestroyListener, mgr, echo->listener); + } free(echo); return CHANNEL_RC_OK; } #ifdef BUILTIN_CHANNELS -#define DVCPluginEntry echo_DVCPluginEntry +#define DVCPluginEntry echo_DVCPluginEntry #else -#define DVCPluginEntry FREERDP_API DVCPluginEntry +#define DVCPluginEntry FREERDP_API DVCPluginEntry #endif /** @@ -176,11 +182,11 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) UINT status = CHANNEL_RC_OK; ECHO_PLUGIN* echo; - echo = (ECHO_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "echo"); + echo = (ECHO_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "echo"); if (!echo) { - echo = (ECHO_PLUGIN*) calloc(1, sizeof(ECHO_PLUGIN)); + echo = (ECHO_PLUGIN*)calloc(1, sizeof(ECHO_PLUGIN)); if (!echo) { @@ -193,7 +199,7 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) echo->iface.Disconnected = NULL; echo->iface.Terminated = echo_plugin_terminated; - status = pEntryPoints->RegisterPlugin(pEntryPoints, "echo", (IWTSPlugin*) echo); + status = pEntryPoints->RegisterPlugin(pEntryPoints, "echo", (IWTSPlugin*)echo); } return status; diff --git a/channels/echo/client/echo_main.h b/channels/echo/client/echo_main.h index 04cda41..06262b1 100644 --- a/channels/echo/client/echo_main.h +++ b/channels/echo/client/echo_main.h @@ -33,8 +33,10 @@ #ifdef WITH_DEBUG_DVC #define DEBUG_DVC(...) WLog_DBG(DVC_TAG, __VA_ARGS__) #else -#define DEBUG_DVC(...) do { } while (0) +#define DEBUG_DVC(...) \ + do \ + { \ + } while (0) #endif #endif /* FREERDP_CHANNEL_ECHO_CLIENT_MAIN_H */ - diff --git a/channels/echo/server/echo_main.c b/channels/echo/server/echo_main.c index b3f8eb0..55e2fa2 100644 --- a/channels/echo/server/echo_main.c +++ b/channels/echo/server/echo_main.c @@ -66,14 +66,14 @@ static UINT echo_server_open_channel(echo_server* echo) DWORD BytesReturned = 0; PULONG pSessionId = NULL; - if (WTSQuerySessionInformationA(echo->context.vcm, WTS_CURRENT_SESSION, - WTSSessionId, (LPSTR*) &pSessionId, &BytesReturned) == FALSE) + if (WTSQuerySessionInformationA(echo->context.vcm, WTS_CURRENT_SESSION, WTSSessionId, + (LPSTR*)&pSessionId, &BytesReturned) == FALSE) { WLog_ERR(TAG, "WTSQuerySessionInformationA failed!"); return ERROR_INTERNAL_ERROR; } - echo->SessionId = (DWORD) * pSessionId; + echo->SessionId = (DWORD)*pSessionId; WTSFreeMemory(pSessionId); hEvent = WTSVirtualChannelManagerGetEventHandle(echo->context.vcm); StartTick = GetTickCount(); @@ -83,12 +83,12 @@ static UINT echo_server_open_channel(echo_server* echo) if (WaitForSingleObject(hEvent, 1000) == WAIT_FAILED) { Error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", Error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", Error); return Error; } - echo->echo_channel = WTSVirtualChannelOpenEx(echo->SessionId, - "ECHO", WTS_CHANNEL_OPTION_DYNAMIC); + echo->echo_channel = + WTSVirtualChannelOpenEx(echo->SessionId, "ECHO", WTS_CHANNEL_OPTION_DYNAMIC); if (echo->echo_channel) break; @@ -114,19 +114,19 @@ static DWORD WINAPI echo_server_thread_func(LPVOID arg) BOOL ready = FALSE; HANDLE ChannelEvent; DWORD BytesReturned = 0; - echo_server* echo = (echo_server*) arg; + echo_server* echo = (echo_server*)arg; UINT error; DWORD status; if ((error = echo_server_open_channel(echo))) { UINT error2 = 0; - WLog_ERR(TAG, "echo_server_open_channel failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "echo_server_open_channel failed with error %" PRIu32 "!", error); IFCALLRET(echo->context.OpenResult, error2, &echo->context, ECHO_SERVER_OPEN_RESULT_NOTSUPPORTED); if (error2) - WLog_ERR(TAG, "echo server's OpenResult callback failed with error %"PRIu32"", + WLog_ERR(TAG, "echo server's OpenResult callback failed with error %" PRIu32 "", error2); goto out; @@ -158,7 +158,7 @@ static DWORD WINAPI echo_server_thread_func(LPVOID arg) if (status == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"", error); + WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error); break; } @@ -168,7 +168,7 @@ static DWORD WINAPI echo_server_thread_func(LPVOID arg) ECHO_SERVER_OPEN_RESULT_CLOSED); if (error) - WLog_ERR(TAG, "OpenResult failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "OpenResult failed with error %" PRIu32 "!", error); break; } @@ -180,21 +180,20 @@ static DWORD WINAPI echo_server_thread_func(LPVOID arg) ECHO_SERVER_OPEN_RESULT_ERROR); if (error) - WLog_ERR(TAG, "OpenResult failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "OpenResult failed with error %" PRIu32 "!", error); break; } - ready = *((BOOL*) buffer); + ready = *((BOOL*)buffer); WTSFreeMemory(buffer); if (ready) { - IFCALLRET(echo->context.OpenResult, error, &echo->context, - ECHO_SERVER_OPEN_RESULT_OK); + IFCALLRET(echo->context.OpenResult, error, &echo->context, ECHO_SERVER_OPEN_RESULT_OK); if (error) - WLog_ERR(TAG, "OpenResult failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "OpenResult failed with error %" PRIu32 "!", error); break; } @@ -217,7 +216,7 @@ static DWORD WINAPI echo_server_thread_func(LPVOID arg) if (status == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"", error); + WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error); break; } @@ -237,20 +236,20 @@ static DWORD WINAPI echo_server_thread_func(LPVOID arg) break; } - if (WTSVirtualChannelRead(echo->echo_channel, 0, (PCHAR) Stream_Buffer(s), - (ULONG) Stream_Capacity(s), &BytesReturned) == FALSE) + if (WTSVirtualChannelRead(echo->echo_channel, 0, (PCHAR)Stream_Buffer(s), + (ULONG)Stream_Capacity(s), &BytesReturned) == FALSE) { WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); error = ERROR_INTERNAL_ERROR; break; } - IFCALLRET(echo->context.Response, error, &echo->context, - (BYTE*) Stream_Buffer(s), BytesReturned); + IFCALLRET(echo->context.Response, error, &echo->context, (BYTE*)Stream_Buffer(s), + BytesReturned); if (error) { - WLog_ERR(TAG, "Response failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "Response failed with error %" PRIu32 "!", error); break; } } @@ -275,7 +274,7 @@ out: */ static UINT echo_server_open(echo_server_context* context) { - echo_server* echo = (echo_server*) context; + echo_server* echo = (echo_server*)context; if (echo->thread == NULL) { @@ -285,7 +284,7 @@ static UINT echo_server_open(echo_server_context* context) return ERROR_INTERNAL_ERROR; } - if (!(echo->thread = CreateThread(NULL, 0, echo_server_thread_func, (void*) echo, 0, NULL))) + if (!(echo->thread = CreateThread(NULL, 0, echo_server_thread_func, (void*)echo, 0, NULL))) { WLog_ERR(TAG, "CreateEvent failed!"); CloseHandle(echo->stopEvent); @@ -305,7 +304,7 @@ static UINT echo_server_open(echo_server_context* context) static UINT echo_server_close(echo_server_context* context) { UINT error = CHANNEL_RC_OK; - echo_server* echo = (echo_server*) context; + echo_server* echo = (echo_server*)context; if (echo->thread) { @@ -314,7 +313,7 @@ static UINT echo_server_close(echo_server_context* context) if (WaitForSingleObject(echo->thread, INFINITE) == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error); return error; } @@ -327,17 +326,16 @@ static UINT echo_server_close(echo_server_context* context) return error; } -static BOOL echo_server_request(echo_server_context* context, - const BYTE* buffer, UINT32 length) +static BOOL echo_server_request(echo_server_context* context, const BYTE* buffer, UINT32 length) { - echo_server* echo = (echo_server*) context; - return WTSVirtualChannelWrite(echo->echo_channel, (PCHAR) buffer, length, NULL); + echo_server* echo = (echo_server*)context; + return WTSVirtualChannelWrite(echo->echo_channel, (PCHAR)buffer, length, NULL); } echo_server_context* echo_server_context_new(HANDLE vcm) { echo_server* echo; - echo = (echo_server*) calloc(1, sizeof(echo_server)); + echo = (echo_server*)calloc(1, sizeof(echo_server)); if (echo) { @@ -349,12 +347,12 @@ echo_server_context* echo_server_context_new(HANDLE vcm) else WLog_ERR(TAG, "calloc failed!"); - return (echo_server_context*) echo; + return (echo_server_context*)echo; } void echo_server_context_free(echo_server_context* context) { - echo_server* echo = (echo_server*) context; + echo_server* echo = (echo_server*)context; echo_server_close(context); free(echo); } diff --git a/channels/encomsp/client/encomsp_main.c b/channels/encomsp/client/encomsp_main.c index d595fef..b384337 100644 --- a/channels/encomsp/client/encomsp_main.c +++ b/channels/encomsp/client/encomsp_main.c @@ -31,6 +31,21 @@ #include "encomsp_main.h" +struct encomsp_plugin +{ + CHANNEL_DEF channelDef; + CHANNEL_ENTRY_POINTS_FREERDP_EX channelEntryPoints; + + EncomspClientContext* context; + + HANDLE thread; + wStream* data_in; + void* InitHandle; + DWORD OpenHandle; + wMessageQueue* queue; + rdpContext* rdpcontext; +}; + /** * Function description * @@ -44,7 +59,7 @@ static UINT encomsp_read_header(wStream* s, ENCOMSP_ORDER_HEADER* header) return ERROR_INVALID_DATA; } - Stream_Read_UINT16(s, header->Type); /* Type (2 bytes) */ + Stream_Read_UINT16(s, header->Type); /* Type (2 bytes) */ Stream_Read_UINT16(s, header->Length); /* Length (2 bytes) */ return CHANNEL_RC_OK; } @@ -54,9 +69,9 @@ static UINT encomsp_read_header(wStream* s, ENCOMSP_ORDER_HEADER* header) * * @return 0 on success, otherwise a Win32 error code */ -static UINT encomsp_write_header(wStream* s, ENCOMSP_ORDER_HEADER* header) +static UINT encomsp_write_header(wStream* s, const ENCOMSP_ORDER_HEADER* header) { - Stream_Write_UINT16(s, header->Type); /* Type (2 bytes) */ + Stream_Write_UINT16(s, header->Type); /* Type (2 bytes) */ Stream_Write_UINT16(s, header->Length); /* Length (2 bytes) */ return CHANNEL_RC_OK; } @@ -80,7 +95,7 @@ static UINT encomsp_read_unicode_string(wStream* s, ENCOMSP_UNICODE_STRING* str) if (str->cchString > 1024) { - WLog_ERR(TAG, "cchString was %"PRIu16" but has to be < 1025!", str->cchString); + WLog_ERR(TAG, "cchString was %" PRIu16 " but has to be < 1025!", str->cchString); return ERROR_INVALID_DATA; } @@ -94,11 +109,10 @@ static UINT encomsp_read_unicode_string(wStream* s, ENCOMSP_UNICODE_STRING* str) return CHANNEL_RC_OK; } -static EncomspClientContext* encomsp_get_client_interface( - encomspPlugin* encomsp) +static EncomspClientContext* encomsp_get_client_interface(encomspPlugin* encomsp) { EncomspClientContext* pInterface; - pInterface = (EncomspClientContext*) encomsp->channelEntryPoints.pInterface; + pInterface = (EncomspClientContext*)encomsp->channelEntryPoints.pInterface; return pInterface; } @@ -112,20 +126,24 @@ static UINT encomsp_virtual_channel_write(encomspPlugin* encomsp, wStream* s) UINT status; if (!encomsp) + { + Stream_Free(s, TRUE); return ERROR_INVALID_HANDLE; + } #if 0 WLog_INFO(TAG, "EncomspWrite (%"PRIuz")", Stream_Length(s)); winpr_HexDump(Stream_Buffer(s), Stream_Length(s)); #endif - status = encomsp->channelEntryPoints.pVirtualChannelWriteEx(encomsp->InitHandle, - encomsp->OpenHandle, - Stream_Buffer(s), (UINT32) Stream_Length(s), s); + status = encomsp->channelEntryPoints.pVirtualChannelWriteEx( + encomsp->InitHandle, encomsp->OpenHandle, Stream_Buffer(s), (UINT32)Stream_Length(s), s); if (status != CHANNEL_RC_OK) - WLog_ERR(TAG, "VirtualChannelWriteEx failed with %s [%08"PRIX32"]", + { + Stream_Free(s, TRUE); + WLog_ERR(TAG, "VirtualChannelWriteEx failed with %s [%08" PRIX32 "]", WTSErrorToString(status), status); - + } return status; } @@ -135,9 +153,9 @@ static UINT encomsp_virtual_channel_write(encomspPlugin* encomsp, wStream* s) * @return 0 on success, otherwise a Win32 error code */ static UINT encomsp_recv_filter_updated_pdu(encomspPlugin* encomsp, wStream* s, - ENCOMSP_ORDER_HEADER* header) + const ENCOMSP_ORDER_HEADER* header) { - int beg, end; + size_t beg, end, pos; EncomspClientContext* context; ENCOMSP_FILTER_UPDATED_PDU pdu; UINT error = CHANNEL_RC_OK; @@ -146,7 +164,10 @@ static UINT encomsp_recv_filter_updated_pdu(encomspPlugin* encomsp, wStream* s, if (!context) return ERROR_INVALID_HANDLE; - beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + pos = Stream_GetPosition(s); + if (pos < ENCOMSP_ORDER_HEADER_SIZE) + return ERROR_INVALID_DATA; + beg = pos - ENCOMSP_ORDER_HEADER_SIZE; CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); if (Stream_GetRemainingLength(s) < 1) @@ -156,7 +177,7 @@ static UINT encomsp_recv_filter_updated_pdu(encomspPlugin* encomsp, wStream* s, } Stream_Read_UINT8(s, pdu.Flags); /* Flags (1 byte) */ - end = (int) Stream_GetPosition(s); + end = Stream_GetPosition(s); if ((beg + header->Length) < end) { @@ -178,7 +199,7 @@ static UINT encomsp_recv_filter_updated_pdu(encomspPlugin* encomsp, wStream* s, IFCALLRET(context->FilterUpdated, error, context, &pdu); if (error) - WLog_ERR(TAG, "context->FilterUpdated failed with error %"PRIu32"", error); + WLog_ERR(TAG, "context->FilterUpdated failed with error %" PRIu32 "", error); return error; } @@ -188,10 +209,10 @@ static UINT encomsp_recv_filter_updated_pdu(encomspPlugin* encomsp, wStream* s, * * @return 0 on success, otherwise a Win32 error code */ -static UINT encomsp_recv_application_created_pdu(encomspPlugin* encomsp, - wStream* s, ENCOMSP_ORDER_HEADER* header) +static UINT encomsp_recv_application_created_pdu(encomspPlugin* encomsp, wStream* s, + const ENCOMSP_ORDER_HEADER* header) { - int beg, end; + size_t beg, end, pos; EncomspClientContext* context; ENCOMSP_APPLICATION_CREATED_PDU pdu; UINT error; @@ -200,25 +221,28 @@ static UINT encomsp_recv_application_created_pdu(encomspPlugin* encomsp, if (!context) return ERROR_INVALID_HANDLE; - beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; - CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); - if (Stream_GetRemainingLength(s) < 6) { WLog_ERR(TAG, "Not enough data!"); return ERROR_INVALID_DATA; } + pos = Stream_GetPosition(s); + if (pos < ENCOMSP_ORDER_HEADER_SIZE) + return ERROR_INVALID_DATA; + beg = pos - ENCOMSP_ORDER_HEADER_SIZE; + CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); + Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */ Stream_Read_UINT32(s, pdu.AppId); /* AppId (4 bytes) */ if ((error = encomsp_read_unicode_string(s, &(pdu.Name)))) { - WLog_ERR(TAG, "encomsp_read_unicode_string failed with error %"PRIu32"", error); + WLog_ERR(TAG, "encomsp_read_unicode_string failed with error %" PRIu32 "", error); return error; } - end = (int) Stream_GetPosition(s); + end = Stream_GetPosition(s); if ((beg + header->Length) < end) { @@ -240,7 +264,7 @@ static UINT encomsp_recv_application_created_pdu(encomspPlugin* encomsp, IFCALLRET(context->ApplicationCreated, error, context, &pdu); if (error) - WLog_ERR(TAG, "context->ApplicationCreated failed with error %"PRIu32"", error); + WLog_ERR(TAG, "context->ApplicationCreated failed with error %" PRIu32 "", error); return error; } @@ -250,10 +274,10 @@ static UINT encomsp_recv_application_created_pdu(encomspPlugin* encomsp, * * @return 0 on success, otherwise a Win32 error code */ -static UINT encomsp_recv_application_removed_pdu(encomspPlugin* encomsp, - wStream* s, ENCOMSP_ORDER_HEADER* header) +static UINT encomsp_recv_application_removed_pdu(encomspPlugin* encomsp, wStream* s, + const ENCOMSP_ORDER_HEADER* header) { - int beg, end; + size_t beg, end, pos; EncomspClientContext* context; ENCOMSP_APPLICATION_REMOVED_PDU pdu; UINT error = CHANNEL_RC_OK; @@ -262,7 +286,10 @@ static UINT encomsp_recv_application_removed_pdu(encomspPlugin* encomsp, if (!context) return ERROR_INVALID_HANDLE; - beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + pos = Stream_GetPosition(s); + if (pos < ENCOMSP_ORDER_HEADER_SIZE) + return ERROR_INVALID_DATA; + beg = pos - ENCOMSP_ORDER_HEADER_SIZE; CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); if (Stream_GetRemainingLength(s) < 4) @@ -272,7 +299,7 @@ static UINT encomsp_recv_application_removed_pdu(encomspPlugin* encomsp, } Stream_Read_UINT32(s, pdu.AppId); /* AppId (4 bytes) */ - end = (int) Stream_GetPosition(s); + end = Stream_GetPosition(s); if ((beg + header->Length) < end) { @@ -294,7 +321,7 @@ static UINT encomsp_recv_application_removed_pdu(encomspPlugin* encomsp, IFCALLRET(context->ApplicationRemoved, error, context, &pdu); if (error) - WLog_ERR(TAG, "context->ApplicationRemoved failed with error %"PRIu32"", error); + WLog_ERR(TAG, "context->ApplicationRemoved failed with error %" PRIu32 "", error); return error; } @@ -305,9 +332,9 @@ static UINT encomsp_recv_application_removed_pdu(encomspPlugin* encomsp, * @return 0 on success, otherwise a Win32 error code */ static UINT encomsp_recv_window_created_pdu(encomspPlugin* encomsp, wStream* s, - ENCOMSP_ORDER_HEADER* header) + const ENCOMSP_ORDER_HEADER* header) { - int beg, end; + size_t beg, end, pos; EncomspClientContext* context; ENCOMSP_WINDOW_CREATED_PDU pdu; UINT error; @@ -316,7 +343,10 @@ static UINT encomsp_recv_window_created_pdu(encomspPlugin* encomsp, wStream* s, if (!context) return ERROR_INVALID_HANDLE; - beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + pos = Stream_GetPosition(s); + if (pos < ENCOMSP_ORDER_HEADER_SIZE) + return ERROR_INVALID_DATA; + beg = pos - ENCOMSP_ORDER_HEADER_SIZE; CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); if (Stream_GetRemainingLength(s) < 10) @@ -331,11 +361,11 @@ static UINT encomsp_recv_window_created_pdu(encomspPlugin* encomsp, wStream* s, if ((error = encomsp_read_unicode_string(s, &(pdu.Name)))) { - WLog_ERR(TAG, "encomsp_read_unicode_string failed with error %"PRIu32"", error); + WLog_ERR(TAG, "encomsp_read_unicode_string failed with error %" PRIu32 "", error); return error; } - end = (int) Stream_GetPosition(s); + end = Stream_GetPosition(s); if ((beg + header->Length) < end) { @@ -357,7 +387,7 @@ static UINT encomsp_recv_window_created_pdu(encomspPlugin* encomsp, wStream* s, IFCALLRET(context->WindowCreated, error, context, &pdu); if (error) - WLog_ERR(TAG, "context->WindowCreated failed with error %"PRIu32"", error); + WLog_ERR(TAG, "context->WindowCreated failed with error %" PRIu32 "", error); return error; } @@ -368,9 +398,9 @@ static UINT encomsp_recv_window_created_pdu(encomspPlugin* encomsp, wStream* s, * @return 0 on success, otherwise a Win32 error code */ static UINT encomsp_recv_window_removed_pdu(encomspPlugin* encomsp, wStream* s, - ENCOMSP_ORDER_HEADER* header) + const ENCOMSP_ORDER_HEADER* header) { - int beg, end; + size_t beg, end, pos; EncomspClientContext* context; ENCOMSP_WINDOW_REMOVED_PDU pdu; UINT error = CHANNEL_RC_OK; @@ -379,7 +409,10 @@ static UINT encomsp_recv_window_removed_pdu(encomspPlugin* encomsp, wStream* s, if (!context) return ERROR_INVALID_HANDLE; - beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + pos = Stream_GetPosition(s); + if (pos < ENCOMSP_ORDER_HEADER_SIZE) + return ERROR_INVALID_DATA; + beg = pos - ENCOMSP_ORDER_HEADER_SIZE; CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); if (Stream_GetRemainingLength(s) < 4) @@ -389,7 +422,7 @@ static UINT encomsp_recv_window_removed_pdu(encomspPlugin* encomsp, wStream* s, } Stream_Read_UINT32(s, pdu.WndId); /* WndId (4 bytes) */ - end = (int) Stream_GetPosition(s); + end = Stream_GetPosition(s); if ((beg + header->Length) < end) { @@ -411,7 +444,7 @@ static UINT encomsp_recv_window_removed_pdu(encomspPlugin* encomsp, wStream* s, IFCALLRET(context->WindowRemoved, error, context, &pdu); if (error) - WLog_ERR(TAG, "context->WindowRemoved failed with error %"PRIu32"", error); + WLog_ERR(TAG, "context->WindowRemoved failed with error %" PRIu32 "", error); return error; } @@ -422,9 +455,9 @@ static UINT encomsp_recv_window_removed_pdu(encomspPlugin* encomsp, wStream* s, * @return 0 on success, otherwise a Win32 error code */ static UINT encomsp_recv_show_window_pdu(encomspPlugin* encomsp, wStream* s, - ENCOMSP_ORDER_HEADER* header) + const ENCOMSP_ORDER_HEADER* header) { - int beg, end; + size_t beg, end, pos; EncomspClientContext* context; ENCOMSP_SHOW_WINDOW_PDU pdu; UINT error = CHANNEL_RC_OK; @@ -433,7 +466,10 @@ static UINT encomsp_recv_show_window_pdu(encomspPlugin* encomsp, wStream* s, if (!context) return ERROR_INVALID_HANDLE; - beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + pos = Stream_GetPosition(s); + if (pos < ENCOMSP_ORDER_HEADER_SIZE) + return ERROR_INVALID_DATA; + beg = pos - ENCOMSP_ORDER_HEADER_SIZE; CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); if (Stream_GetRemainingLength(s) < 4) @@ -443,7 +479,7 @@ static UINT encomsp_recv_show_window_pdu(encomspPlugin* encomsp, wStream* s, } Stream_Read_UINT32(s, pdu.WndId); /* WndId (4 bytes) */ - end = (int) Stream_GetPosition(s); + end = Stream_GetPosition(s); if ((beg + header->Length) < end) { @@ -465,7 +501,7 @@ static UINT encomsp_recv_show_window_pdu(encomspPlugin* encomsp, wStream* s, IFCALLRET(context->ShowWindow, error, context, &pdu); if (error) - WLog_ERR(TAG, "context->ShowWindow failed with error %"PRIu32"", error); + WLog_ERR(TAG, "context->ShowWindow failed with error %" PRIu32 "", error); return error; } @@ -475,10 +511,10 @@ static UINT encomsp_recv_show_window_pdu(encomspPlugin* encomsp, wStream* s, * * @return 0 on success, otherwise a Win32 error code */ -static UINT encomsp_recv_participant_created_pdu(encomspPlugin* encomsp, - wStream* s, ENCOMSP_ORDER_HEADER* header) +static UINT encomsp_recv_participant_created_pdu(encomspPlugin* encomsp, wStream* s, + const ENCOMSP_ORDER_HEADER* header) { - int beg, end; + size_t beg, end, pos; EncomspClientContext* context; ENCOMSP_PARTICIPANT_CREATED_PDU pdu; UINT error; @@ -487,7 +523,10 @@ static UINT encomsp_recv_participant_created_pdu(encomspPlugin* encomsp, if (!context) return ERROR_INVALID_HANDLE; - beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + pos = Stream_GetPosition(s); + if (pos < ENCOMSP_ORDER_HEADER_SIZE) + return ERROR_INVALID_DATA; + beg = pos - ENCOMSP_ORDER_HEADER_SIZE; CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); if (Stream_GetRemainingLength(s) < 10) @@ -497,16 +536,16 @@ static UINT encomsp_recv_participant_created_pdu(encomspPlugin* encomsp, } Stream_Read_UINT32(s, pdu.ParticipantId); /* ParticipantId (4 bytes) */ - Stream_Read_UINT32(s, pdu.GroupId); /* GroupId (4 bytes) */ - Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */ + Stream_Read_UINT32(s, pdu.GroupId); /* GroupId (4 bytes) */ + Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */ if ((error = encomsp_read_unicode_string(s, &(pdu.FriendlyName)))) { - WLog_ERR(TAG, "encomsp_read_unicode_string failed with error %"PRIu32"", error); + WLog_ERR(TAG, "encomsp_read_unicode_string failed with error %" PRIu32 "", error); return error; } - end = (int) Stream_GetPosition(s); + end = Stream_GetPosition(s); if ((beg + header->Length) < end) { @@ -528,7 +567,7 @@ static UINT encomsp_recv_participant_created_pdu(encomspPlugin* encomsp, IFCALLRET(context->ParticipantCreated, error, context, &pdu); if (error) - WLog_ERR(TAG, "context->ParticipantCreated failed with error %"PRIu32"", error); + WLog_ERR(TAG, "context->ParticipantCreated failed with error %" PRIu32 "", error); return error; } @@ -538,10 +577,10 @@ static UINT encomsp_recv_participant_created_pdu(encomspPlugin* encomsp, * * @return 0 on success, otherwise a Win32 error code */ -static UINT encomsp_recv_participant_removed_pdu(encomspPlugin* encomsp, - wStream* s, ENCOMSP_ORDER_HEADER* header) +static UINT encomsp_recv_participant_removed_pdu(encomspPlugin* encomsp, wStream* s, + const ENCOMSP_ORDER_HEADER* header) { - int beg, end; + size_t beg, end; EncomspClientContext* context; ENCOMSP_PARTICIPANT_REMOVED_PDU pdu; UINT error = CHANNEL_RC_OK; @@ -550,19 +589,19 @@ static UINT encomsp_recv_participant_removed_pdu(encomspPlugin* encomsp, if (!context) return ERROR_INVALID_HANDLE; - beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; - CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); - if (Stream_GetRemainingLength(s) < 12) { WLog_ERR(TAG, "Not enough data!"); return ERROR_INVALID_DATA; } + beg = (Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); + Stream_Read_UINT32(s, pdu.ParticipantId); /* ParticipantId (4 bytes) */ - Stream_Read_UINT32(s, pdu.DiscType); /* DiscType (4 bytes) */ - Stream_Read_UINT32(s, pdu.DiscCode); /* DiscCode (4 bytes) */ - end = (int) Stream_GetPosition(s); + Stream_Read_UINT32(s, pdu.DiscType); /* DiscType (4 bytes) */ + Stream_Read_UINT32(s, pdu.DiscCode); /* DiscCode (4 bytes) */ + end = Stream_GetPosition(s); if ((beg + header->Length) < end) { @@ -584,7 +623,7 @@ static UINT encomsp_recv_participant_removed_pdu(encomspPlugin* encomsp, IFCALLRET(context->ParticipantRemoved, error, context, &pdu); if (error) - WLog_ERR(TAG, "context->ParticipantRemoved failed with error %"PRIu32"", error); + WLog_ERR(TAG, "context->ParticipantRemoved failed with error %" PRIu32 "", error); return error; } @@ -594,10 +633,10 @@ static UINT encomsp_recv_participant_removed_pdu(encomspPlugin* encomsp, * * @return 0 on success, otherwise a Win32 error code */ -static UINT encomsp_recv_change_participant_control_level_pdu( - encomspPlugin* encomsp, wStream* s, ENCOMSP_ORDER_HEADER* header) +static UINT encomsp_recv_change_participant_control_level_pdu(encomspPlugin* encomsp, wStream* s, + const ENCOMSP_ORDER_HEADER* header) { - int beg, end; + size_t beg, end, pos; EncomspClientContext* context; ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU pdu; UINT error = CHANNEL_RC_OK; @@ -606,7 +645,10 @@ static UINT encomsp_recv_change_participant_control_level_pdu( if (!context) return ERROR_INVALID_HANDLE; - beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + pos = Stream_GetPosition(s); + if (pos < ENCOMSP_ORDER_HEADER_SIZE) + return ERROR_INVALID_DATA; + beg = pos - ENCOMSP_ORDER_HEADER_SIZE; CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); if (Stream_GetRemainingLength(s) < 6) @@ -615,9 +657,9 @@ static UINT encomsp_recv_change_participant_control_level_pdu( return ERROR_INVALID_DATA; } - Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */ + Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */ Stream_Read_UINT32(s, pdu.ParticipantId); /* ParticipantId (4 bytes) */ - end = (int) Stream_GetPosition(s); + end = Stream_GetPosition(s); if ((beg + header->Length) < end) { @@ -639,7 +681,7 @@ static UINT encomsp_recv_change_participant_control_level_pdu( IFCALLRET(context->ChangeParticipantControlLevel, error, context, &pdu); if (error) - WLog_ERR(TAG, "context->ChangeParticipantControlLevel failed with error %"PRIu32"", + WLog_ERR(TAG, "context->ChangeParticipantControlLevel failed with error %" PRIu32 "", error); return error; @@ -651,16 +693,17 @@ static UINT encomsp_recv_change_participant_control_level_pdu( * @return 0 on success, otherwise a Win32 error code */ static UINT encomsp_send_change_participant_control_level_pdu( - EncomspClientContext* context, - ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU* pdu) + EncomspClientContext* context, const ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU* pdu) { wStream* s; encomspPlugin* encomsp; UINT error; - encomsp = (encomspPlugin*) context->handle; - pdu->Type = ODTYPE_PARTICIPANT_CTRL_CHANGED; - pdu->Length = ENCOMSP_ORDER_HEADER_SIZE + 6; - s = Stream_New(NULL, pdu->Length); + ENCOMSP_ORDER_HEADER header; + + encomsp = (encomspPlugin*)context->handle; + header.Type = ODTYPE_PARTICIPANT_CTRL_CHANGED; + header.Length = ENCOMSP_ORDER_HEADER_SIZE + 6; + s = Stream_New(NULL, header.Length); if (!s) { @@ -668,13 +711,13 @@ static UINT encomsp_send_change_participant_control_level_pdu( return CHANNEL_RC_NO_MEMORY; } - if ((error = encomsp_write_header(s, (ENCOMSP_ORDER_HEADER*) pdu))) + if ((error = encomsp_write_header(s, &header))) { - WLog_ERR(TAG, "encomsp_write_header failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "encomsp_write_header failed with error %" PRIu32 "!", error); return error; } - Stream_Write_UINT16(s, pdu->Flags); /* Flags (2 bytes) */ + Stream_Write_UINT16(s, pdu->Flags); /* Flags (2 bytes) */ Stream_Write_UINT32(s, pdu->ParticipantId); /* ParticipantId (4 bytes) */ Stream_SealLength(s); return encomsp_virtual_channel_write(encomsp, s); @@ -685,10 +728,10 @@ static UINT encomsp_send_change_participant_control_level_pdu( * * @return 0 on success, otherwise a Win32 error code */ -static UINT encomsp_recv_graphics_stream_paused_pdu(encomspPlugin* encomsp, - wStream* s, ENCOMSP_ORDER_HEADER* header) +static UINT encomsp_recv_graphics_stream_paused_pdu(encomspPlugin* encomsp, wStream* s, + const ENCOMSP_ORDER_HEADER* header) { - int beg, end; + size_t beg, end, pos; EncomspClientContext* context; ENCOMSP_GRAPHICS_STREAM_PAUSED_PDU pdu; UINT error = CHANNEL_RC_OK; @@ -697,9 +740,12 @@ static UINT encomsp_recv_graphics_stream_paused_pdu(encomspPlugin* encomsp, if (!context) return ERROR_INVALID_HANDLE; - beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + pos = Stream_GetPosition(s); + if (pos < ENCOMSP_ORDER_HEADER_SIZE) + return ERROR_INVALID_DATA; + beg = pos - ENCOMSP_ORDER_HEADER_SIZE; CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); - end = (int) Stream_GetPosition(s); + end = Stream_GetPosition(s); if ((beg + header->Length) < end) { @@ -721,7 +767,7 @@ static UINT encomsp_recv_graphics_stream_paused_pdu(encomspPlugin* encomsp, IFCALLRET(context->GraphicsStreamPaused, error, context, &pdu); if (error) - WLog_ERR(TAG, "context->GraphicsStreamPaused failed with error %"PRIu32"", error); + WLog_ERR(TAG, "context->GraphicsStreamPaused failed with error %" PRIu32 "", error); return error; } @@ -731,10 +777,10 @@ static UINT encomsp_recv_graphics_stream_paused_pdu(encomspPlugin* encomsp, * * @return 0 on success, otherwise a Win32 error code */ -static UINT encomsp_recv_graphics_stream_resumed_pdu(encomspPlugin* encomsp, - wStream* s, ENCOMSP_ORDER_HEADER* header) +static UINT encomsp_recv_graphics_stream_resumed_pdu(encomspPlugin* encomsp, wStream* s, + const ENCOMSP_ORDER_HEADER* header) { - int beg, end; + size_t beg, end, pos; EncomspClientContext* context; ENCOMSP_GRAPHICS_STREAM_RESUMED_PDU pdu; UINT error = CHANNEL_RC_OK; @@ -743,9 +789,12 @@ static UINT encomsp_recv_graphics_stream_resumed_pdu(encomspPlugin* encomsp, if (!context) return ERROR_INVALID_HANDLE; - beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + pos = Stream_GetPosition(s); + if (pos < ENCOMSP_ORDER_HEADER_SIZE) + return ERROR_INVALID_DATA; + beg = pos - ENCOMSP_ORDER_HEADER_SIZE; CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); - end = (int) Stream_GetPosition(s); + end = Stream_GetPosition(s); if ((beg + header->Length) < end) { @@ -767,7 +816,7 @@ static UINT encomsp_recv_graphics_stream_resumed_pdu(encomspPlugin* encomsp, IFCALLRET(context->GraphicsStreamResumed, error, context, &pdu); if (error) - WLog_ERR(TAG, "context->GraphicsStreamResumed failed with error %"PRIu32"", error); + WLog_ERR(TAG, "context->GraphicsStreamResumed failed with error %" PRIu32 "", error); return error; } @@ -786,18 +835,20 @@ static UINT encomsp_process_receive(encomspPlugin* encomsp, wStream* s) { if ((error = encomsp_read_header(s, &header))) { - WLog_ERR(TAG, "encomsp_read_header failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "encomsp_read_header failed with error %" PRIu32 "!", error); return error; } - //WLog_DBG(TAG, "EncomspReceive: Type: %"PRIu16" Length: %"PRIu16"", header.Type, header.Length); + // WLog_DBG(TAG, "EncomspReceive: Type: %"PRIu16" Length: %"PRIu16"", header.Type, + // header.Length); switch (header.Type) { case ODTYPE_FILTER_STATE_UPDATED: if ((error = encomsp_recv_filter_updated_pdu(encomsp, s, &header))) { - WLog_ERR(TAG, "encomsp_recv_filter_updated_pdu failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "encomsp_recv_filter_updated_pdu failed with error %" PRIu32 "!", + error); return error; } @@ -806,7 +857,8 @@ static UINT encomsp_process_receive(encomspPlugin* encomsp, wStream* s) case ODTYPE_APP_REMOVED: if ((error = encomsp_recv_application_removed_pdu(encomsp, s, &header))) { - WLog_ERR(TAG, "encomsp_recv_application_removed_pdu failed with error %"PRIu32"!", + WLog_ERR(TAG, + "encomsp_recv_application_removed_pdu failed with error %" PRIu32 "!", error); return error; } @@ -816,7 +868,8 @@ static UINT encomsp_process_receive(encomspPlugin* encomsp, wStream* s) case ODTYPE_APP_CREATED: if ((error = encomsp_recv_application_created_pdu(encomsp, s, &header))) { - WLog_ERR(TAG, "encomsp_recv_application_removed_pdu failed with error %"PRIu32"!", + WLog_ERR(TAG, + "encomsp_recv_application_removed_pdu failed with error %" PRIu32 "!", error); return error; } @@ -826,7 +879,8 @@ static UINT encomsp_process_receive(encomspPlugin* encomsp, wStream* s) case ODTYPE_WND_REMOVED: if ((error = encomsp_recv_window_removed_pdu(encomsp, s, &header))) { - WLog_ERR(TAG, "encomsp_recv_window_removed_pdu failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "encomsp_recv_window_removed_pdu failed with error %" PRIu32 "!", + error); return error; } @@ -835,7 +889,8 @@ static UINT encomsp_process_receive(encomspPlugin* encomsp, wStream* s) case ODTYPE_WND_CREATED: if ((error = encomsp_recv_window_created_pdu(encomsp, s, &header))) { - WLog_ERR(TAG, "encomsp_recv_window_created_pdu failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "encomsp_recv_window_created_pdu failed with error %" PRIu32 "!", + error); return error; } @@ -844,7 +899,8 @@ static UINT encomsp_process_receive(encomspPlugin* encomsp, wStream* s) case ODTYPE_WND_SHOW: if ((error = encomsp_recv_show_window_pdu(encomsp, s, &header))) { - WLog_ERR(TAG, "encomsp_recv_show_window_pdu failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "encomsp_recv_show_window_pdu failed with error %" PRIu32 "!", + error); return error; } @@ -853,7 +909,8 @@ static UINT encomsp_process_receive(encomspPlugin* encomsp, wStream* s) case ODTYPE_PARTICIPANT_REMOVED: if ((error = encomsp_recv_participant_removed_pdu(encomsp, s, &header))) { - WLog_ERR(TAG, "encomsp_recv_participant_removed_pdu failed with error %"PRIu32"!", + WLog_ERR(TAG, + "encomsp_recv_participant_removed_pdu failed with error %" PRIu32 "!", error); return error; } @@ -863,7 +920,8 @@ static UINT encomsp_process_receive(encomspPlugin* encomsp, wStream* s) case ODTYPE_PARTICIPANT_CREATED: if ((error = encomsp_recv_participant_created_pdu(encomsp, s, &header))) { - WLog_ERR(TAG, "encomsp_recv_participant_created_pdu failed with error %"PRIu32"!", + WLog_ERR(TAG, + "encomsp_recv_participant_created_pdu failed with error %" PRIu32 "!", error); return error; } @@ -871,11 +929,12 @@ static UINT encomsp_process_receive(encomspPlugin* encomsp, wStream* s) break; case ODTYPE_PARTICIPANT_CTRL_CHANGED: - if ((error = encomsp_recv_change_participant_control_level_pdu(encomsp, s, - &header))) + if ((error = + encomsp_recv_change_participant_control_level_pdu(encomsp, s, &header))) { WLog_ERR(TAG, - "encomsp_recv_change_participant_control_level_pdu failed with error %"PRIu32"!", + "encomsp_recv_change_participant_control_level_pdu failed with error " + "%" PRIu32 "!", error); return error; } @@ -885,7 +944,9 @@ static UINT encomsp_process_receive(encomspPlugin* encomsp, wStream* s) case ODTYPE_GRAPHICS_STREAM_PAUSED: if ((error = encomsp_recv_graphics_stream_paused_pdu(encomsp, s, &header))) { - WLog_ERR(TAG, "encomsp_recv_graphics_stream_paused_pdu failed with error %"PRIu32"!", + WLog_ERR(TAG, + "encomsp_recv_graphics_stream_paused_pdu failed with error %" PRIu32 + "!", error); return error; } @@ -895,7 +956,9 @@ static UINT encomsp_process_receive(encomspPlugin* encomsp, wStream* s) case ODTYPE_GRAPHICS_STREAM_RESUMED: if ((error = encomsp_recv_graphics_stream_resumed_pdu(encomsp, s, &header))) { - WLog_ERR(TAG, "encomsp_recv_graphics_stream_resumed_pdu failed with error %"PRIu32"!", + WLog_ERR(TAG, + "encomsp_recv_graphics_stream_resumed_pdu failed with error %" PRIu32 + "!", error); return error; } @@ -903,9 +966,8 @@ static UINT encomsp_process_receive(encomspPlugin* encomsp, wStream* s) break; default: - WLog_ERR(TAG, "header.Type %"PRIu16" not found", header.Type); + WLog_ERR(TAG, "header.Type %" PRIu16 " not found", header.Type); return ERROR_INVALID_DATA; - break; } } @@ -921,8 +983,9 @@ static void encomsp_process_connect(encomspPlugin* encomsp) * * @return 0 on success, otherwise a Win32 error code */ -static UINT encomsp_virtual_channel_event_data_received(encomspPlugin* encomsp, - void* pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) +static UINT encomsp_virtual_channel_event_data_received(encomspPlugin* encomsp, const void* pData, + UINT32 dataLength, UINT32 totalLength, + UINT32 dataFlags) { wStream* data_in; @@ -945,7 +1008,7 @@ static UINT encomsp_virtual_channel_event_data_received(encomspPlugin* encomsp, data_in = encomsp->data_in; - if (!Stream_EnsureRemainingCapacity(data_in, (int) dataLength)) + if (!Stream_EnsureRemainingCapacity(data_in, dataLength)) { WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); return ERROR_INTERNAL_ERROR; @@ -957,7 +1020,7 @@ static UINT encomsp_virtual_channel_event_data_received(encomspPlugin* encomsp, { if (Stream_Capacity(data_in) != Stream_GetPosition(data_in)) { - WLog_ERR(TAG, "encomsp_plugin_process_received: read error"); + WLog_ERR(TAG, "encomsp_plugin_process_received: read error"); return ERROR_INVALID_DATA; } @@ -965,7 +1028,7 @@ static UINT encomsp_virtual_channel_event_data_received(encomspPlugin* encomsp, Stream_SealLength(data_in); Stream_SetPosition(data_in, 0); - if (!MessageQueue_Post(encomsp->queue, NULL, 0, (void*) data_in, NULL)) + if (!MessageQueue_Post(encomsp->queue, NULL, 0, (void*)data_in, NULL)) { WLog_ERR(TAG, "MessageQueue_Post failed!"); return ERROR_INTERNAL_ERROR; @@ -976,36 +1039,45 @@ static UINT encomsp_virtual_channel_event_data_received(encomspPlugin* encomsp, } static VOID VCAPITYPE encomsp_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle, - UINT event, - LPVOID pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) + UINT event, LPVOID pData, + UINT32 dataLength, UINT32 totalLength, + UINT32 dataFlags) { UINT error = CHANNEL_RC_OK; - encomspPlugin* encomsp = (encomspPlugin*) lpUserParam; - - if (!encomsp || (encomsp->OpenHandle != openHandle)) - { - WLog_ERR(TAG, "error no match"); - return; - } + encomspPlugin* encomsp = (encomspPlugin*)lpUserParam; switch (event) { case CHANNEL_EVENT_DATA_RECEIVED: - if ((error = encomsp_virtual_channel_event_data_received(encomsp, pData, - dataLength, totalLength, dataFlags))) - WLog_ERR(TAG, "encomsp_virtual_channel_event_data_received failed with error %"PRIu32"", error); + if (!encomsp || (encomsp->OpenHandle != openHandle)) + { + WLog_ERR(TAG, "error no match"); + return; + } + if ((error = encomsp_virtual_channel_event_data_received(encomsp, pData, dataLength, + totalLength, dataFlags))) + WLog_ERR(TAG, + "encomsp_virtual_channel_event_data_received failed with error %" PRIu32 + "", + error); break; + case CHANNEL_EVENT_WRITE_CANCELLED: case CHANNEL_EVENT_WRITE_COMPLETE: - break; + { + wStream* s = (wStream*)pData; + Stream_Free(s, TRUE); + } + break; case CHANNEL_EVENT_USER: break; } - if (error && encomsp->rdpcontext) - setChannelError(encomsp->rdpcontext, error, "encomsp_virtual_channel_open_event reported an error"); + if (error && encomsp && encomsp->rdpcontext) + setChannelError(encomsp->rdpcontext, error, + "encomsp_virtual_channel_open_event reported an error"); return; } @@ -1014,7 +1086,7 @@ static DWORD WINAPI encomsp_virtual_channel_client_thread(LPVOID arg) { wStream* data; wMessage message; - encomspPlugin* encomsp = (encomspPlugin*) arg; + encomspPlugin* encomsp = (encomspPlugin*)arg; UINT error = CHANNEL_RC_OK; encomsp_process_connect(encomsp); @@ -1039,13 +1111,16 @@ static DWORD WINAPI encomsp_virtual_channel_client_thread(LPVOID arg) if (message.id == 0) { - data = (wStream*) message.wParam; + data = (wStream*)message.wParam; if ((error = encomsp_process_receive(encomsp, data))) { - WLog_ERR(TAG, "encomsp_process_receive failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "encomsp_process_receive failed with error %" PRIu32 "!", error); + Stream_Free(data, TRUE); break; } + + Stream_Free(data, TRUE); } } @@ -1062,17 +1137,17 @@ static DWORD WINAPI encomsp_virtual_channel_client_thread(LPVOID arg) * * @return 0 on success, otherwise a Win32 error code */ -static UINT encomsp_virtual_channel_event_connected(encomspPlugin* encomsp, - LPVOID pData, UINT32 dataLength) +static UINT encomsp_virtual_channel_event_connected(encomspPlugin* encomsp, LPVOID pData, + UINT32 dataLength) { UINT32 status; - status = encomsp->channelEntryPoints.pVirtualChannelOpenEx(encomsp->InitHandle, - &encomsp->OpenHandle, encomsp->channelDef.name, - encomsp_virtual_channel_open_event_ex); + status = encomsp->channelEntryPoints.pVirtualChannelOpenEx( + encomsp->InitHandle, &encomsp->OpenHandle, encomsp->channelDef.name, + encomsp_virtual_channel_open_event_ex); if (status != CHANNEL_RC_OK) { - WLog_ERR(TAG, "pVirtualChannelOpen failed with %s [%08"PRIX32"]", + WLog_ERR(TAG, "pVirtualChannelOpen failed with %s [%08" PRIX32 "]", WTSErrorToString(status), status); return status; } @@ -1085,9 +1160,8 @@ static UINT encomsp_virtual_channel_event_connected(encomspPlugin* encomsp, return CHANNEL_RC_NO_MEMORY; } - if (!(encomsp->thread = CreateThread(NULL, 0, - encomsp_virtual_channel_client_thread, (void*) encomsp, - 0, NULL))) + if (!(encomsp->thread = CreateThread(NULL, 0, encomsp_virtual_channel_client_thread, + (void*)encomsp, 0, NULL))) { WLog_ERR(TAG, "CreateThread failed!"); MessageQueue_Free(encomsp->queue); @@ -1109,11 +1183,11 @@ static UINT encomsp_virtual_channel_event_disconnected(encomspPlugin* encomsp) if (encomsp->OpenHandle == 0) return CHANNEL_RC_OK; - if (MessageQueue_PostQuit(encomsp->queue, 0) - && (WaitForSingleObject(encomsp->thread, INFINITE) == WAIT_FAILED)) + if (MessageQueue_PostQuit(encomsp->queue, 0) && + (WaitForSingleObject(encomsp->thread, INFINITE) == WAIT_FAILED)) { rc = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", rc); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", rc); return rc; } @@ -1121,12 +1195,13 @@ static UINT encomsp_virtual_channel_event_disconnected(encomspPlugin* encomsp) CloseHandle(encomsp->thread); encomsp->queue = NULL; encomsp->thread = NULL; - rc = encomsp->channelEntryPoints.pVirtualChannelCloseEx(encomsp->InitHandle, encomsp->OpenHandle); + rc = encomsp->channelEntryPoints.pVirtualChannelCloseEx(encomsp->InitHandle, + encomsp->OpenHandle); if (CHANNEL_RC_OK != rc) { - WLog_ERR(TAG, "pVirtualChannelClose failed with %s [%08"PRIX32"]", - WTSErrorToString(rc), rc); + WLog_ERR(TAG, "pVirtualChannelClose failed with %s [%08" PRIX32 "]", WTSErrorToString(rc), + rc); return rc; } @@ -1141,7 +1216,6 @@ static UINT encomsp_virtual_channel_event_disconnected(encomspPlugin* encomsp) return CHANNEL_RC_OK; } - /** * Function description * @@ -1156,23 +1230,24 @@ static UINT encomsp_virtual_channel_event_terminated(encomspPlugin* encomsp) } static VOID VCAPITYPE encomsp_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle, - UINT event, LPVOID pData, UINT dataLength) + UINT event, LPVOID pData, + UINT dataLength) { UINT error = CHANNEL_RC_OK; - encomspPlugin* encomsp = (encomspPlugin*) lpUserParam; + encomspPlugin* encomsp = (encomspPlugin*)lpUserParam; if (!encomsp || (encomsp->InitHandle != pInitHandle)) { - WLog_ERR(TAG, "error no match"); + WLog_ERR(TAG, "error no match"); return; } switch (event) { case CHANNEL_EVENT_CONNECTED: - if ((error = encomsp_virtual_channel_event_connected(encomsp, pData, - dataLength))) - WLog_ERR(TAG, "encomsp_virtual_channel_event_connected failed with error %"PRIu32"", + if ((error = encomsp_virtual_channel_event_connected(encomsp, pData, dataLength))) + WLog_ERR(TAG, + "encomsp_virtual_channel_event_connected failed with error %" PRIu32 "", error); break; @@ -1180,7 +1255,8 @@ static VOID VCAPITYPE encomsp_virtual_channel_init_event_ex(LPVOID lpUserParam, case CHANNEL_EVENT_DISCONNECTED: if ((error = encomsp_virtual_channel_event_disconnected(encomsp))) WLog_ERR(TAG, - "encomsp_virtual_channel_event_disconnected failed with error %"PRIu32"", error); + "encomsp_virtual_channel_event_disconnected failed with error %" PRIu32 "", + error); break; @@ -1189,15 +1265,16 @@ static VOID VCAPITYPE encomsp_virtual_channel_init_event_ex(LPVOID lpUserParam, break; default: - WLog_ERR(TAG, "Unhandled event type %"PRIu32"", event); + break; } if (error && encomsp->rdpcontext) - setChannelError(encomsp->rdpcontext, error, "encomsp_virtual_channel_init_event reported an error"); + setChannelError(encomsp->rdpcontext, error, + "encomsp_virtual_channel_init_event reported an error"); } /* encomsp is always built-in */ -#define VirtualChannelEntryEx encomsp_VirtualChannelEntryEx +#define VirtualChannelEntryEx encomsp_VirtualChannelEntryEx BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS_EX pEntryPoints, PVOID pInitHandle) { @@ -1206,7 +1283,7 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS_EX pEntryPoints, PVOI EncomspClientContext* context = NULL; CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx; BOOL isFreerdp = FALSE; - encomsp = (encomspPlugin*) calloc(1, sizeof(encomspPlugin)); + encomsp = (encomspPlugin*)calloc(1, sizeof(encomspPlugin)); if (!encomsp) { @@ -1214,18 +1291,15 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS_EX pEntryPoints, PVOI return FALSE; } - encomsp->channelDef.options = - CHANNEL_OPTION_INITIALIZED | - CHANNEL_OPTION_ENCRYPT_RDP | - CHANNEL_OPTION_COMPRESS_RDP | - CHANNEL_OPTION_SHOW_PROTOCOL; + encomsp->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP | + CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL; sprintf_s(encomsp->channelDef.name, ARRAYSIZE(encomsp->channelDef.name), "encomsp"); - pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*) pEntryPoints; + pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints; if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) && (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER)) { - context = (EncomspClientContext*) calloc(1, sizeof(EncomspClientContext)); + context = (EncomspClientContext*)calloc(1, sizeof(EncomspClientContext)); if (!context) { @@ -1233,7 +1307,7 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS_EX pEntryPoints, PVOI goto error_out; } - context->handle = (void*) encomsp; + context->handle = (void*)encomsp; context->FilterUpdated = NULL; context->ApplicationCreated = NULL; context->ApplicationRemoved = NULL; @@ -1242,8 +1316,7 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS_EX pEntryPoints, PVOI context->ShowWindow = NULL; context->ParticipantCreated = NULL; context->ParticipantRemoved = NULL; - context->ChangeParticipantControlLevel = - encomsp_send_change_participant_control_level_pdu; + context->ChangeParticipantControlLevel = encomsp_send_change_participant_control_level_pdu; context->GraphicsStreamPaused = NULL; context->GraphicsStreamResumed = NULL; encomsp->context = context; @@ -1254,14 +1327,13 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS_EX pEntryPoints, PVOI CopyMemory(&(encomsp->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)); encomsp->InitHandle = pInitHandle; - rc = encomsp->channelEntryPoints.pVirtualChannelInitEx(encomsp, context, pInitHandle, - &encomsp->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, - encomsp_virtual_channel_init_event_ex); + rc = encomsp->channelEntryPoints.pVirtualChannelInitEx( + encomsp, context, pInitHandle, &encomsp->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, + encomsp_virtual_channel_init_event_ex); if (CHANNEL_RC_OK != rc) { - WLog_ERR(TAG, "failed with %s [%08"PRIX32"]", - WTSErrorToString(rc), rc); + WLog_ERR(TAG, "failed with %s [%08" PRIX32 "]", WTSErrorToString(rc), rc); goto error_out; } diff --git a/channels/encomsp/client/encomsp_main.h b/channels/encomsp/client/encomsp_main.h index 7b23ed1..ad43cea 100644 --- a/channels/encomsp/client/encomsp_main.h +++ b/channels/encomsp/client/encomsp_main.h @@ -37,20 +37,6 @@ #define TAG CHANNELS_TAG("encomsp.client") -struct encomsp_plugin -{ - CHANNEL_DEF channelDef; - CHANNEL_ENTRY_POINTS_FREERDP_EX channelEntryPoints; - - EncomspClientContext* context; - - HANDLE thread; - wStream* data_in; - void* InitHandle; - DWORD OpenHandle; - wMessageQueue* queue; - rdpContext* rdpcontext; -}; typedef struct encomsp_plugin encomspPlugin; #endif /* FREERDP_CHANNEL_ENCOMSP_CLIENT_MAIN_H */ diff --git a/channels/encomsp/server/encomsp_main.c b/channels/encomsp/server/encomsp_main.c index e1b2248..9b1693b 100644 --- a/channels/encomsp/server/encomsp_main.c +++ b/channels/encomsp/server/encomsp_main.c @@ -43,7 +43,7 @@ static UINT encomsp_read_header(wStream* s, ENCOMSP_ORDER_HEADER* header) if (Stream_GetRemainingLength(s) < ENCOMSP_ORDER_HEADER_SIZE) return ERROR_INVALID_DATA; - Stream_Read_UINT16(s, header->Type); /* Type (2 bytes) */ + Stream_Read_UINT16(s, header->Type); /* Type (2 bytes) */ Stream_Read_UINT16(s, header->Length); /* Length (2 bytes) */ return CHANNEL_RC_OK; } @@ -83,13 +83,14 @@ static int encomsp_read_unicode_string(wStream* s, ENCOMSP_UNICODE_STRING* str) * * @return 0 on success, otherwise a Win32 error code */ -static UINT encomsp_recv_change_participant_control_level_pdu( - EncomspServerContext* context, wStream* s, ENCOMSP_ORDER_HEADER* header) +static UINT encomsp_recv_change_participant_control_level_pdu(EncomspServerContext* context, + wStream* s, + ENCOMSP_ORDER_HEADER* header) { int beg, end; ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU pdu; UINT error = CHANNEL_RC_OK; - beg = ((int) Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; + beg = ((int)Stream_GetPosition(s)) - ENCOMSP_ORDER_HEADER_SIZE; CopyMemory(&pdu, header, sizeof(ENCOMSP_ORDER_HEADER)); if (Stream_GetRemainingLength(s) < 6) @@ -98,9 +99,9 @@ static UINT encomsp_recv_change_participant_control_level_pdu( return ERROR_INVALID_DATA; } - Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */ + Stream_Read_UINT16(s, pdu.Flags); /* Flags (2 bytes) */ Stream_Read_UINT32(s, pdu.ParticipantId); /* ParticipantId (4 bytes) */ - end = (int) Stream_GetPosition(s); + end = (int)Stream_GetPosition(s); if ((beg + header->Length) < end) { @@ -110,7 +111,7 @@ static UINT encomsp_recv_change_participant_control_level_pdu( if ((beg + header->Length) > end) { - if (Stream_GetRemainingLength(s) < ((beg + header->Length) - end)) + if (Stream_GetRemainingLength(s) < (size_t)((beg + header->Length) - end)) { WLog_ERR(TAG, "Not enough data!"); return ERROR_INVALID_DATA; @@ -122,7 +123,7 @@ static UINT encomsp_recv_change_participant_control_level_pdu( IFCALLRET(context->ChangeParticipantControlLevel, error, context, &pdu); if (error) - WLog_ERR(TAG, "context->ChangeParticipantControlLevel failed with error %"PRIu32"", + WLog_ERR(TAG, "context->ChangeParticipantControlLevel failed with error %" PRIu32 "", error); return error; @@ -133,8 +134,7 @@ static UINT encomsp_recv_change_participant_control_level_pdu( * * @return 0 on success, otherwise a Win32 error code */ -static UINT encomsp_server_receive_pdu(EncomspServerContext* context, - wStream* s) +static UINT encomsp_server_receive_pdu(EncomspServerContext* context, wStream* s) { UINT error = CHANNEL_RC_OK; ENCOMSP_ORDER_HEADER header; @@ -143,21 +143,22 @@ static UINT encomsp_server_receive_pdu(EncomspServerContext* context, { if ((error = encomsp_read_header(s, &header))) { - WLog_ERR(TAG, "encomsp_read_header failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "encomsp_read_header failed with error %" PRIu32 "!", error); return error; } - WLog_INFO(TAG, "EncomspReceive: Type: %"PRIu16" Length: %"PRIu16"", header.Type, + WLog_INFO(TAG, "EncomspReceive: Type: %" PRIu16 " Length: %" PRIu16 "", header.Type, header.Length); switch (header.Type) { case ODTYPE_PARTICIPANT_CTRL_CHANGED: - if ((error = encomsp_recv_change_participant_control_level_pdu(context, s, - &header))) + if ((error = + encomsp_recv_change_participant_control_level_pdu(context, s, &header))) { WLog_ERR(TAG, - "encomsp_recv_change_participant_control_level_pdu failed with error %"PRIu32"!", + "encomsp_recv_change_participant_control_level_pdu failed with error " + "%" PRIu32 "!", error); return error; } @@ -165,7 +166,7 @@ static UINT encomsp_server_receive_pdu(EncomspServerContext* context, break; default: - WLog_ERR(TAG, "header.Type unknown %"PRIu16"!", header.Type); + WLog_ERR(TAG, "header.Type unknown %" PRIu16 "!", header.Type); return ERROR_INVALID_DATA; break; } @@ -186,7 +187,7 @@ static DWORD WINAPI encomsp_server_thread(LPVOID arg) EncomspServerContext* context; UINT error = CHANNEL_RC_OK; DWORD status; - context = (EncomspServerContext*) arg; + context = (EncomspServerContext*)arg; buffer = NULL; BytesReturned = 0; @@ -200,8 +201,8 @@ static DWORD WINAPI encomsp_server_thread(LPVOID arg) goto out; } - if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, - &buffer, &BytesReturned) == TRUE) + if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, + &BytesReturned) == TRUE) { if (BytesReturned == sizeof(HANDLE)) CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); @@ -220,7 +221,7 @@ static DWORD WINAPI encomsp_server_thread(LPVOID arg) if (status == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"", error); + WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error); break; } @@ -229,7 +230,7 @@ static DWORD WINAPI encomsp_server_thread(LPVOID arg) if (status == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error); break; } @@ -250,8 +251,8 @@ static DWORD WINAPI encomsp_server_thread(LPVOID arg) break; } - if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, - (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned)) + if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, (PCHAR)Stream_Buffer(s), + Stream_Capacity(s), &BytesReturned)) { WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); error = ERROR_INTERNAL_ERROR; @@ -260,7 +261,7 @@ static DWORD WINAPI encomsp_server_thread(LPVOID arg) if (Stream_GetPosition(s) >= ENCOMSP_ORDER_HEADER_SIZE) { - header = (ENCOMSP_ORDER_HEADER*) Stream_Buffer(s); + header = (ENCOMSP_ORDER_HEADER*)Stream_Buffer(s); if (header->Length >= Stream_GetPosition(s)) { @@ -269,7 +270,8 @@ static DWORD WINAPI encomsp_server_thread(LPVOID arg) if ((error = encomsp_server_receive_pdu(context, s))) { - WLog_ERR(TAG, "encomsp_server_receive_pdu failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "encomsp_server_receive_pdu failed with error %" PRIu32 "!", + error); break; } @@ -282,8 +284,7 @@ static DWORD WINAPI encomsp_server_thread(LPVOID arg) out: if (error && context->rdpcontext) - setChannelError(context->rdpcontext, error, - "encomsp_server_thread reported an error"); + setChannelError(context->rdpcontext, error, "encomsp_server_thread reported an error"); ExitThread(error); return error; @@ -296,8 +297,8 @@ out: */ static UINT encomsp_server_start(EncomspServerContext* context) { - context->priv->ChannelHandle = WTSVirtualChannelOpen(context->vcm, - WTS_CURRENT_SESSION, "encomsp"); + context->priv->ChannelHandle = + WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "encomsp"); if (!context->priv->ChannelHandle) return CHANNEL_RC_BAD_CHANNEL; @@ -308,8 +309,8 @@ static UINT encomsp_server_start(EncomspServerContext* context) return ERROR_INTERNAL_ERROR; } - if (!(context->priv->Thread = CreateThread(NULL, 0, - encomsp_server_thread, (void*) context, 0, NULL))) + if (!(context->priv->Thread = + CreateThread(NULL, 0, encomsp_server_thread, (void*)context, 0, NULL))) { WLog_ERR(TAG, "CreateThread failed!"); CloseHandle(context->priv->StopEvent); @@ -333,7 +334,7 @@ static UINT encomsp_server_stop(EncomspServerContext* context) if (WaitForSingleObject(context->priv->Thread, INFINITE) == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error); return error; } @@ -345,14 +346,14 @@ static UINT encomsp_server_stop(EncomspServerContext* context) EncomspServerContext* encomsp_server_context_new(HANDLE vcm) { EncomspServerContext* context; - context = (EncomspServerContext*) calloc(1, sizeof(EncomspServerContext)); + context = (EncomspServerContext*)calloc(1, sizeof(EncomspServerContext)); if (context) { context->vcm = vcm; context->Start = encomsp_server_start; context->Stop = encomsp_server_stop; - context->priv = (EncomspServerPrivate*) calloc(1, sizeof(EncomspServerPrivate)); + context->priv = (EncomspServerPrivate*)calloc(1, sizeof(EncomspServerPrivate)); if (!context->priv) { @@ -371,7 +372,7 @@ void encomsp_server_context_free(EncomspServerContext* context) { if (context->priv->ChannelHandle != INVALID_HANDLE_VALUE) WTSVirtualChannelClose(context->priv->ChannelHandle); - + free(context->priv); free(context); } diff --git a/channels/geometry/client/geometry_main.c b/channels/geometry/client/geometry_main.c index 5ef7def..cb5e2ae 100644 --- a/channels/geometry/client/geometry_main.c +++ b/channels/geometry/client/geometry_main.c @@ -27,7 +27,6 @@ #include #include -#include #include #include #include @@ -72,44 +71,26 @@ struct _GEOMETRY_PLUGIN }; typedef struct _GEOMETRY_PLUGIN GEOMETRY_PLUGIN; - -static UINT32 mappedGeometryHash(UINT64 *g) +static UINT32 mappedGeometryHash(UINT64* g) { return (UINT32)((*g >> 32) + (*g & 0xffffffff)); } -static BOOL mappedGeometryKeyCompare(UINT64 *g1, UINT64 *g2) +static BOOL mappedGeometryKeyCompare(UINT64* g1, UINT64* g2) { return *g1 == *g2; } -void mappedGeometryRef(MAPPED_GEOMETRY *g) -{ - InterlockedIncrement(&g->refCounter); -} - -void mappedGeometryUnref(MAPPED_GEOMETRY *g) -{ - if (InterlockedDecrement(&g->refCounter)) - return; - - g->MappedGeometryUpdate = NULL; - g->MappedGeometryClear = NULL; - g->custom = NULL; - free(g->geometry.rects); - free(g); -} - - -void freerdp_rgndata_reset(FREERDP_RGNDATA *data) +static void freerdp_rgndata_reset(FREERDP_RGNDATA* data) { data->nRectCount = 0; } -static UINT32 geometry_read_RGNDATA(wStream *s, UINT32 len, FREERDP_RGNDATA *rgndata) +static UINT32 geometry_read_RGNDATA(wStream* s, UINT32 len, FREERDP_RGNDATA* rgndata) { UINT32 dwSize, iType; INT32 right, bottom; + INT32 x, y, w, h; if (len < 32) { @@ -129,18 +110,26 @@ static UINT32 geometry_read_RGNDATA(wStream *s, UINT32 len, FREERDP_RGNDATA *rgn if (iType != RDH_RECTANGLE) { - WLog_ERR(TAG, "iType %"PRIu32" for RGNDATA is not supported", iType); + WLog_ERR(TAG, "iType %" PRIu32 " for RGNDATA is not supported", iType); return ERROR_UNSUPPORTED_TYPE; } Stream_Read_UINT32(s, rgndata->nRectCount); Stream_Seek_UINT32(s); /* nRgnSize IGNORED */ - Stream_Read_INT32(s, rgndata->boundingRect.x); - Stream_Read_INT32(s, rgndata->boundingRect.y); + Stream_Read_INT32(s, x); + Stream_Read_INT32(s, y); Stream_Read_INT32(s, right); Stream_Read_INT32(s, bottom); - rgndata->boundingRect.width = right - rgndata->boundingRect.x; - rgndata->boundingRect.height = bottom - rgndata->boundingRect.y; + if ((abs(x) > INT16_MAX) || (abs(y) > INT16_MAX)) + return ERROR_INVALID_DATA; + w = right - x; + h = bottom - y; + if ((abs(w) > INT16_MAX) || (abs(h) > INT16_MAX)) + return ERROR_INVALID_DATA; + rgndata->boundingRect.x = (INT16)x; + rgndata->boundingRect.y = (INT16)y; + rgndata->boundingRect.width = (INT16)w; + rgndata->boundingRect.height = (INT16)h; len -= 32; if (len / (4 * 4) < rgndata->nRectCount) @@ -150,24 +139,32 @@ static UINT32 geometry_read_RGNDATA(wStream *s, UINT32 len, FREERDP_RGNDATA *rgn if (rgndata->nRectCount) { - int i; - RDP_RECT *tmp = realloc(rgndata->rects, rgndata->nRectCount * sizeof(RDP_RECT)); + UINT32 i; + RDP_RECT* tmp = realloc(rgndata->rects, rgndata->nRectCount * sizeof(RDP_RECT)); if (!tmp) { - WLog_ERR(TAG, "unable to allocate memory for %"PRIu32" RECTs", rgndata->nRectCount); + WLog_ERR(TAG, "unable to allocate memory for %" PRIu32 " RECTs", rgndata->nRectCount); return CHANNEL_RC_NO_MEMORY; } rgndata->rects = tmp; for (i = 0; i < rgndata->nRectCount; i++) { - Stream_Read_INT32(s, rgndata->rects[i].x); - Stream_Read_INT32(s, rgndata->rects[i].y); + Stream_Read_INT32(s, x); + Stream_Read_INT32(s, y); Stream_Read_INT32(s, right); Stream_Read_INT32(s, bottom); - rgndata->rects[i].width = right - rgndata->rects[i].x; - rgndata->rects[i].height = bottom - rgndata->rects[i].y; + if ((abs(x) > INT16_MAX) || (abs(y) > INT16_MAX)) + return ERROR_INVALID_DATA; + w = right - x; + h = bottom - y; + if ((abs(w) > INT16_MAX) || (abs(h) > INT16_MAX)) + return ERROR_INVALID_DATA; + rgndata->rects[i].x = (INT16)x; + rgndata->rects[i].y = (INT16)y; + rgndata->rects[i].width = (INT16)w; + rgndata->rects[i].height = (INT16)h; } } @@ -182,14 +179,14 @@ static UINT32 geometry_read_RGNDATA(wStream *s, UINT32 len, FREERDP_RGNDATA *rgn static UINT geometry_recv_pdu(GEOMETRY_CHANNEL_CALLBACK* callback, wStream* s) { UINT32 length, cbGeometryBuffer; - MAPPED_GEOMETRY *mappedGeometry; + MAPPED_GEOMETRY* mappedGeometry; GEOMETRY_PLUGIN* geometry; - GeometryClientContext *context; + GeometryClientContext* context; UINT ret = CHANNEL_RC_OK; UINT32 version, updateType, geometryType; UINT64 id; - geometry = (GEOMETRY_PLUGIN*) callback->plugin; + geometry = (GEOMETRY_PLUGIN*)callback->plugin; context = (GeometryClientContext*)geometry->iface.pInterface; if (Stream_GetRemainingLength(s) < 4) @@ -213,17 +210,18 @@ static UINT geometry_recv_pdu(GEOMETRY_CHANNEL_CALLBACK* callback, wStream* s) mappedGeometry = HashTable_GetItemValue(context->geometries, &id); - if (updateType == GEOMETRY_CLEAR ) + if (updateType == GEOMETRY_CLEAR) { if (!mappedGeometry) { - WLog_ERR(TAG, "geometry 0x%"PRIx64" not found here, ignoring clear command", id); + WLog_ERR(TAG, "geometry 0x%" PRIx64 " not found here, ignoring clear command", id); return CHANNEL_RC_OK; } - WLog_DBG(TAG, "clearing geometry 0x%"PRIx64"", id); + WLog_DBG(TAG, "clearing geometry 0x%" PRIx64 "", id); - if (mappedGeometry->MappedGeometryClear && !mappedGeometry->MappedGeometryClear(mappedGeometry)) + if (mappedGeometry->MappedGeometryClear && + !mappedGeometry->MappedGeometryClear(mappedGeometry)) return ERROR_INTERNAL_ERROR; if (!HashTable_Remove(context->geometries, &id)) @@ -236,7 +234,7 @@ static UINT geometry_recv_pdu(GEOMETRY_CHANNEL_CALLBACK* callback, wStream* s) if (!mappedGeometry) { newOne = TRUE; - WLog_DBG(TAG, "creating geometry 0x%"PRIx64"", id); + WLog_DBG(TAG, "creating geometry 0x%" PRIx64 "", id); mappedGeometry = calloc(1, sizeof(MAPPED_GEOMETRY)); if (!mappedGeometry) return CHANNEL_RC_NO_MEMORY; @@ -244,16 +242,17 @@ static UINT geometry_recv_pdu(GEOMETRY_CHANNEL_CALLBACK* callback, wStream* s) mappedGeometry->refCounter = 1; mappedGeometry->mappingId = id; - if (HashTable_Add(context->geometries, &(mappedGeometry->mappingId), mappedGeometry) < 0) + if (HashTable_Add(context->geometries, &(mappedGeometry->mappingId), mappedGeometry) < + 0) { - WLog_ERR(TAG, "unable to register geometry 0x%"PRIx64" in the table", id); + WLog_ERR(TAG, "unable to register geometry 0x%" PRIx64 " in the table", id); free(mappedGeometry); return CHANNEL_RC_NO_MEMORY; } } else { - WLog_DBG(TAG, "updating geometry 0x%"PRIx64"", id); + WLog_DBG(TAG, "updating geometry 0x%" PRIx64 "", id); } Stream_Read_UINT64(s, mappedGeometry->topLevelId); @@ -290,7 +289,8 @@ static UINT geometry_recv_pdu(GEOMETRY_CHANNEL_CALLBACK* callback, wStream* s) if (newOne) { - if (context->MappedGeometryAdded && !context->MappedGeometryAdded(context, mappedGeometry)) + if (context->MappedGeometryAdded && + !context->MappedGeometryAdded(context, mappedGeometry)) { WLog_ERR(TAG, "geometry added callback failed"); ret = ERROR_INTERNAL_ERROR; @@ -298,7 +298,8 @@ static UINT geometry_recv_pdu(GEOMETRY_CHANNEL_CALLBACK* callback, wStream* s) } else { - if (mappedGeometry->MappedGeometryUpdate && !mappedGeometry->MappedGeometryUpdate(mappedGeometry)) + if (mappedGeometry->MappedGeometryUpdate && + !mappedGeometry->MappedGeometryUpdate(mappedGeometry)) { WLog_ERR(TAG, "geometry update callback failed"); ret = ERROR_INTERNAL_ERROR; @@ -307,11 +308,10 @@ static UINT geometry_recv_pdu(GEOMETRY_CHANNEL_CALLBACK* callback, wStream* s) } else { - WLog_ERR(TAG, "unknown updateType=%"PRIu32"", updateType); + WLog_ERR(TAG, "unknown updateType=%" PRIu32 "", updateType); ret = CHANNEL_RC_OK; } - return ret; } @@ -322,7 +322,7 @@ static UINT geometry_recv_pdu(GEOMETRY_CHANNEL_CALLBACK* callback, wStream* s) */ static UINT geometry_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data) { - GEOMETRY_CHANNEL_CALLBACK* callback = (GEOMETRY_CHANNEL_CALLBACK*) pChannelCallback; + GEOMETRY_CHANNEL_CALLBACK* callback = (GEOMETRY_CHANNEL_CALLBACK*)pChannelCallback; return geometry_recv_pdu(callback, data); } @@ -343,12 +343,17 @@ static UINT geometry_on_close(IWTSVirtualChannelCallback* pChannelCallback) * @return 0 on success, otherwise a Win32 error code */ static UINT geometry_on_new_channel_connection(IWTSListenerCallback* pListenerCallback, - IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept, - IWTSVirtualChannelCallback** ppCallback) + IWTSVirtualChannel* pChannel, BYTE* Data, + BOOL* pbAccept, + IWTSVirtualChannelCallback** ppCallback) { GEOMETRY_CHANNEL_CALLBACK* callback; - GEOMETRY_LISTENER_CALLBACK* listener_callback = (GEOMETRY_LISTENER_CALLBACK*) pListenerCallback; - callback = (GEOMETRY_CHANNEL_CALLBACK*) calloc(1, sizeof(GEOMETRY_CHANNEL_CALLBACK)); + GEOMETRY_LISTENER_CALLBACK* listener_callback = (GEOMETRY_LISTENER_CALLBACK*)pListenerCallback; + + WINPR_UNUSED(Data); + WINPR_UNUSED(pbAccept); + + callback = (GEOMETRY_CHANNEL_CALLBACK*)calloc(1, sizeof(GEOMETRY_CHANNEL_CALLBACK)); if (!callback) { @@ -362,7 +367,7 @@ static UINT geometry_on_new_channel_connection(IWTSListenerCallback* pListenerCa callback->channel_mgr = listener_callback->channel_mgr; callback->channel = pChannel; listener_callback->channel_callback = callback; - *ppCallback = (IWTSVirtualChannelCallback*) callback; + *ppCallback = (IWTSVirtualChannelCallback*)callback; return CHANNEL_RC_OK; } @@ -374,9 +379,9 @@ static UINT geometry_on_new_channel_connection(IWTSListenerCallback* pListenerCa static UINT geometry_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr) { UINT status; - GEOMETRY_PLUGIN* geometry = (GEOMETRY_PLUGIN*) pPlugin; - geometry->listener_callback = (GEOMETRY_LISTENER_CALLBACK*) calloc(1, - sizeof(GEOMETRY_LISTENER_CALLBACK)); + GEOMETRY_PLUGIN* geometry = (GEOMETRY_PLUGIN*)pPlugin; + geometry->listener_callback = + (GEOMETRY_LISTENER_CALLBACK*)calloc(1, sizeof(GEOMETRY_LISTENER_CALLBACK)); if (!geometry->listener_callback) { @@ -387,8 +392,9 @@ static UINT geometry_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelMa geometry->listener_callback->iface.OnNewChannelConnection = geometry_on_new_channel_connection; geometry->listener_callback->plugin = pPlugin; geometry->listener_callback->channel_mgr = pChannelMgr; - status = pChannelMgr->CreateListener(pChannelMgr, GEOMETRY_DVC_CHANNEL_NAME, 0, - (IWTSListenerCallback*) geometry->listener_callback, &(geometry->listener)); + status = + pChannelMgr->CreateListener(pChannelMgr, GEOMETRY_DVC_CHANNEL_NAME, 0, + &geometry->listener_callback->iface, &(geometry->listener)); geometry->listener->pInterface = geometry->iface.pInterface; return status; } @@ -400,8 +406,15 @@ static UINT geometry_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelMa */ static UINT geometry_plugin_terminated(IWTSPlugin* pPlugin) { - GEOMETRY_PLUGIN* geometry = (GEOMETRY_PLUGIN*) pPlugin; - GeometryClientContext* context = (GeometryClientContext *)geometry->iface.pInterface; + GEOMETRY_PLUGIN* geometry = (GEOMETRY_PLUGIN*)pPlugin; + GeometryClientContext* context = (GeometryClientContext*)geometry->iface.pInterface; + + if (geometry && geometry->listener_callback) + { + IWTSVirtualChannelManager* mgr = geometry->listener_callback->channel_mgr; + if (mgr) + IFCALL(mgr->DestroyListener, mgr, geometry->listener); + } if (context) HashTable_Free(context->geometries); @@ -417,9 +430,9 @@ static UINT geometry_plugin_terminated(IWTSPlugin* pPlugin) */ #ifdef BUILTIN_CHANNELS -#define DVCPluginEntry geometry_DVCPluginEntry +#define DVCPluginEntry geometry_DVCPluginEntry #else -#define DVCPluginEntry FREERDP_API DVCPluginEntry +#define DVCPluginEntry FREERDP_API DVCPluginEntry #endif /** @@ -432,11 +445,11 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) UINT error = CHANNEL_RC_OK; GEOMETRY_PLUGIN* geometry; GeometryClientContext* context; - geometry = (GEOMETRY_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "geometry"); + geometry = (GEOMETRY_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "geometry"); if (!geometry) { - geometry = (GEOMETRY_PLUGIN*) calloc(1, sizeof(GEOMETRY_PLUGIN)); + geometry = (GEOMETRY_PLUGIN*)calloc(1, sizeof(GEOMETRY_PLUGIN)); if (!geometry) { @@ -448,7 +461,7 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) geometry->iface.Connected = NULL; geometry->iface.Disconnected = NULL; geometry->iface.Terminated = geometry_plugin_terminated; - context = (GeometryClientContext*) calloc(1, sizeof(GeometryClientContext)); + context = (GeometryClientContext*)calloc(1, sizeof(GeometryClientContext)); if (!context) { @@ -461,10 +474,10 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) context->geometries->keyCompare = (HASH_TABLE_KEY_COMPARE_FN)mappedGeometryKeyCompare; context->geometries->valueFree = (HASH_TABLE_VALUE_FREE_FN)mappedGeometryUnref; - context->handle = (void*) geometry; - geometry->iface.pInterface = (void*) context; + context->handle = (void*)geometry; + geometry->iface.pInterface = (void*)context; geometry->context = context; - error = pEntryPoints->RegisterPlugin(pEntryPoints, "geometry", (IWTSPlugin*) geometry); + error = pEntryPoints->RegisterPlugin(pEntryPoints, "geometry", (IWTSPlugin*)geometry); } else { @@ -477,5 +490,4 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) error_context: free(geometry); return CHANNEL_RC_NO_MEMORY; - } diff --git a/channels/geometry/client/geometry_main.h b/channels/geometry/client/geometry_main.h index 1fb5321..ff6add2 100644 --- a/channels/geometry/client/geometry_main.h +++ b/channels/geometry/client/geometry_main.h @@ -29,6 +29,4 @@ #include #include - #endif /* FREERDP_CHANNEL_GEOMETRY_CLIENT_MAIN_H */ - diff --git a/channels/parallel/client/parallel_main.c b/channels/parallel/client/parallel_main.c index 19ebce3..af3e827 100644 --- a/channels/parallel/client/parallel_main.c +++ b/channels/parallel/client/parallel_main.c @@ -83,16 +83,22 @@ static UINT parallel_process_irp_create(PARALLEL_DEVICE* parallel, IRP* irp) { char* path = NULL; int status; + WCHAR* ptr; UINT32 PathLength; - Stream_Seek(irp->input, 28); + if (!Stream_SafeSeek(irp->input, 28)) + return ERROR_INVALID_DATA; /* DesiredAccess(4) AllocationSize(8), FileAttributes(4) */ /* SharedAccess(4) CreateDisposition(4), CreateOptions(4) */ + if (Stream_GetRemainingLength(irp->input) < 4) + return ERROR_INVALID_DATA; Stream_Read_UINT32(irp->input, PathLength); - status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(irp->input), - PathLength / 2, &path, 0, NULL, NULL); + ptr = (WCHAR*)Stream_Pointer(irp->input); + if (!Stream_SafeSeek(irp->input, PathLength)) + return ERROR_INVALID_DATA; + status = ConvertFromUnicode(CP_UTF8, 0, ptr, PathLength / 2, &path, 0, NULL, NULL); if (status < 1) - if (!(path = (char*) calloc(1, 1))) + if (!(path = (char*)calloc(1, 1))) { WLog_ERR(TAG, "calloc failed!"); return CHANNEL_RC_NO_MEMORY; @@ -149,9 +155,11 @@ static UINT parallel_process_irp_read(PARALLEL_DEVICE* parallel, IRP* irp) UINT64 Offset; ssize_t status; BYTE* buffer = NULL; + if (Stream_GetRemainingLength(irp->input) < 12) + return ERROR_INVALID_DATA; Stream_Read_UINT32(irp->input, Length); Stream_Read_UINT64(irp->input, Offset); - buffer = (BYTE*) malloc(Length); + buffer = (BYTE*)malloc(Length); if (!buffer) { @@ -201,14 +209,22 @@ static UINT parallel_process_irp_write(PARALLEL_DEVICE* parallel, IRP* irp) UINT32 Length; UINT64 Offset; ssize_t status; + void* ptr; + if (Stream_GetRemainingLength(irp->input) > 12) + return ERROR_INVALID_DATA; + Stream_Read_UINT32(irp->input, Length); Stream_Read_UINT64(irp->input, Offset); - Stream_Seek(irp->input, 20); /* Padding */ + if (!Stream_SafeSeek(irp->input, 20)) /* Padding */ + return ERROR_INVALID_DATA; + ptr = Stream_Pointer(irp->input); + if (!Stream_SafeSeek(irp->input, Length)) + return ERROR_INVALID_DATA; len = Length; while (len > 0) { - status = write(parallel->file, Stream_Pointer(irp->input), len); + status = write(parallel->file, ptr, len); if (status < 0) { @@ -231,8 +247,7 @@ static UINT parallel_process_irp_write(PARALLEL_DEVICE* parallel, IRP* irp) * * @return 0 on success, otherwise a Win32 error code */ -static UINT parallel_process_irp_device_control(PARALLEL_DEVICE* parallel, - IRP* irp) +static UINT parallel_process_irp_device_control(PARALLEL_DEVICE* parallel, IRP* irp) { Stream_Write_UINT32(irp->output, 0); /* OutputBufferLength */ return irp->Complete(irp); @@ -252,7 +267,7 @@ static UINT parallel_process_irp(PARALLEL_DEVICE* parallel, IRP* irp) case IRP_MJ_CREATE: if ((error = parallel_process_irp_create(parallel, irp))) { - WLog_ERR(TAG, "parallel_process_irp_create failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "parallel_process_irp_create failed with error %" PRIu32 "!", error); return error; } @@ -261,7 +276,7 @@ static UINT parallel_process_irp(PARALLEL_DEVICE* parallel, IRP* irp) case IRP_MJ_CLOSE: if ((error = parallel_process_irp_close(parallel, irp))) { - WLog_ERR(TAG, "parallel_process_irp_close failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "parallel_process_irp_close failed with error %" PRIu32 "!", error); return error; } @@ -270,7 +285,7 @@ static UINT parallel_process_irp(PARALLEL_DEVICE* parallel, IRP* irp) case IRP_MJ_READ: if ((error = parallel_process_irp_read(parallel, irp))) { - WLog_ERR(TAG, "parallel_process_irp_read failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "parallel_process_irp_read failed with error %" PRIu32 "!", error); return error; } @@ -279,7 +294,7 @@ static UINT parallel_process_irp(PARALLEL_DEVICE* parallel, IRP* irp) case IRP_MJ_WRITE: if ((error = parallel_process_irp_write(parallel, irp))) { - WLog_ERR(TAG, "parallel_process_irp_write failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "parallel_process_irp_write failed with error %" PRIu32 "!", error); return error; } @@ -288,7 +303,7 @@ static UINT parallel_process_irp(PARALLEL_DEVICE* parallel, IRP* irp) case IRP_MJ_DEVICE_CONTROL: if ((error = parallel_process_irp_device_control(parallel, irp))) { - WLog_ERR(TAG, "parallel_process_irp_device_control failed with error %"PRIu32"!", + WLog_ERR(TAG, "parallel_process_irp_device_control failed with error %" PRIu32 "!", error); return error; } @@ -308,7 +323,7 @@ static DWORD WINAPI parallel_thread_func(LPVOID arg) { IRP* irp; wMessage message; - PARALLEL_DEVICE* parallel = (PARALLEL_DEVICE*) arg; + PARALLEL_DEVICE* parallel = (PARALLEL_DEVICE*)arg; UINT error = CHANNEL_RC_OK; while (1) @@ -330,18 +345,17 @@ static DWORD WINAPI parallel_thread_func(LPVOID arg) if (message.id == WMQ_QUIT) break; - irp = (IRP*) message.wParam; + irp = (IRP*)message.wParam; if ((error = parallel_process_irp(parallel, irp))) { - WLog_ERR(TAG, "parallel_process_irp failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "parallel_process_irp failed with error %" PRIu32 "!", error); break; } } if (error && parallel->rdpcontext) - setChannelError(parallel->rdpcontext, error, - "parallel_thread_func reported an error"); + setChannelError(parallel->rdpcontext, error, "parallel_thread_func reported an error"); ExitThread(error); return error; @@ -354,9 +368,9 @@ static DWORD WINAPI parallel_thread_func(LPVOID arg) */ static UINT parallel_irp_request(DEVICE* device, IRP* irp) { - PARALLEL_DEVICE* parallel = (PARALLEL_DEVICE*) device; + PARALLEL_DEVICE* parallel = (PARALLEL_DEVICE*)device; - if (!MessageQueue_Post(parallel->queue, NULL, 0, (void*) irp, NULL)) + if (!MessageQueue_Post(parallel->queue, NULL, 0, (void*)irp, NULL)) { WLog_ERR(TAG, "MessageQueue_Post failed!"); return ERROR_INTERNAL_ERROR; @@ -373,13 +387,13 @@ static UINT parallel_irp_request(DEVICE* device, IRP* irp) static UINT parallel_free(DEVICE* device) { UINT error; - PARALLEL_DEVICE* parallel = (PARALLEL_DEVICE*) device; + PARALLEL_DEVICE* parallel = (PARALLEL_DEVICE*)device; - if (!MessageQueue_PostQuit(parallel->queue, 0) - || (WaitForSingleObject(parallel->thread, INFINITE) == WAIT_FAILED)) + if (!MessageQueue_PostQuit(parallel->queue, 0) || + (WaitForSingleObject(parallel->thread, INFINITE) == WAIT_FAILED)) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error); return error; } @@ -391,9 +405,9 @@ static UINT parallel_free(DEVICE* device) } #ifdef BUILTIN_CHANNELS -#define DeviceServiceEntry parallel_DeviceServiceEntry +#define DeviceServiceEntry parallel_DeviceServiceEntry #else -#define DeviceServiceEntry FREERDP_API DeviceServiceEntry +#define DeviceServiceEntry FREERDP_API DeviceServiceEntry #endif /** @@ -410,7 +424,7 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) RDPDR_PARALLEL* device; PARALLEL_DEVICE* parallel; UINT error; - device = (RDPDR_PARALLEL*) pEntryPoints->device; + device = (RDPDR_PARALLEL*)pEntryPoints->device; name = device->Name; path = device->Path; @@ -422,7 +436,7 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) if (name[0] && path[0]) { - parallel = (PARALLEL_DEVICE*) calloc(1, sizeof(PARALLEL_DEVICE)); + parallel = (PARALLEL_DEVICE*)calloc(1, sizeof(PARALLEL_DEVICE)); if (!parallel) { @@ -458,15 +472,14 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) goto error_out; } - if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, - (DEVICE*) parallel))) + if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*)parallel))) { - WLog_ERR(TAG, "RegisterDevice failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "RegisterDevice failed with error %" PRIu32 "!", error); goto error_out; } - if (!(parallel->thread = CreateThread(NULL, 0, - parallel_thread_func, (void*) parallel, 0, NULL))) + if (!(parallel->thread = + CreateThread(NULL, 0, parallel_thread_func, (void*)parallel, 0, NULL))) { WLog_ERR(TAG, "CreateThread failed!"); error = ERROR_INTERNAL_ERROR; diff --git a/channels/printer/client/CMakeLists.txt b/channels/printer/client/CMakeLists.txt index ea2f0df..58d44f9 100644 --- a/channels/printer/client/CMakeLists.txt +++ b/channels/printer/client/CMakeLists.txt @@ -18,39 +18,23 @@ define_channel_client("printer") set(${MODULE_PREFIX}_SRCS - printer_main.c - printer_main.h) - -if(WITH_CUPS) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} - printer_cups.c - printer_cups.h) - - include_directories(${CUPS_INCLUDE_DIR}) - add_definitions(-DWITH_CUPS) -endif() - -if(WIN32 AND NOT UWP) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} - printer_win.c - printer_win.h) -endif() + printer_main.c) add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DeviceServiceEntry") - - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp) - -if(WITH_CUPS) - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${CUPS_LIBRARIES}) -endif() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - if (WITH_DEBUG_SYMBOLS AND MSVC AND NOT BUILTIN_CHANNELS AND BUILD_SHARED_LIBS) install(FILES ${CMAKE_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${FREERDP_ADDIN_PATH} COMPONENT symbols) endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") + +if(WITH_CUPS) + add_channel_client_subsystem(${MODULE_PREFIX} ${CHANNEL_NAME} "cups" "") +endif() + +if(WIN32 AND NOT UWP) + add_channel_client_subsystem(${MODULE_PREFIX} ${CHANNEL_NAME} "win" "") +endif() diff --git a/channels/printer/client/cups/CMakeLists.txt b/channels/printer/client/cups/CMakeLists.txt new file mode 100644 index 0000000..50d599e --- /dev/null +++ b/channels/printer/client/cups/CMakeLists.txt @@ -0,0 +1,31 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# 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. +define_channel_client_subsystem("printer" "cups" "") + +set(${MODULE_PREFIX}_SRCS + printer_cups.c) + +include_directories(..) +include_directories(${CUPS_INCLUDE_DIR}) + +add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "") + +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${CUPS_LIBRARIES}) + +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/channels/printer/client/cups/printer_cups.c b/channels/printer/client/cups/printer_cups.c new file mode 100644 index 0000000..56cbace --- /dev/null +++ b/channels/printer/client/cups/printer_cups.c @@ -0,0 +1,409 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Print Virtual Channel - CUPS driver + * + * Copyright 2010-2011 Vic Lee + * Copyright 2015 Thincast Technologies GmbH + * Copyright 2015 DI (FH) Martin Haimberger + * Copyright 2016 Armin Novak + * + * 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 + +typedef struct rdp_cups_printer_driver rdpCupsPrinterDriver; +typedef struct rdp_cups_printer rdpCupsPrinter; +typedef struct rdp_cups_print_job rdpCupsPrintJob; + +struct rdp_cups_printer_driver +{ + rdpPrinterDriver driver; + + int id_sequence; + size_t references; +}; + +struct rdp_cups_printer +{ + rdpPrinter printer; + + rdpCupsPrintJob* printjob; +}; + +struct rdp_cups_print_job +{ + rdpPrintJob printjob; + + void* printjob_object; + int printjob_id; +}; + +static void printer_cups_get_printjob_name(char* buf, size_t size, size_t id) +{ + time_t tt; + struct tm tres; + struct tm* t; + + tt = time(NULL); + t = localtime_r(&tt, &tres); + sprintf_s(buf, size - 1, "FreeRDP Print %04d-%02d-%02d %02d-%02d-%02d - Job %" PRIdz, + t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, id); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT printer_cups_write_printjob(rdpPrintJob* printjob, const BYTE* data, size_t size) +{ + rdpCupsPrintJob* cups_printjob = (rdpCupsPrintJob*)printjob; + +#ifndef _CUPS_API_1_4 + + { + FILE* fp; + + fp = fopen((const char*)cups_printjob->printjob_object, "a+b"); + + if (!fp) + return ERROR_INTERNAL_ERROR; + + if (fwrite(data, 1, size, fp) < size) + { + fclose(fp); + return ERROR_INTERNAL_ERROR; + // FIXME once this function doesn't return void anymore! + } + + fclose(fp); + } + +#else + + cupsWriteRequestData((http_t*)cups_printjob->printjob_object, (const char*)data, size); + +#endif + + return CHANNEL_RC_OK; +} + +static void printer_cups_close_printjob(rdpPrintJob* printjob) +{ + rdpCupsPrintJob* cups_printjob = (rdpCupsPrintJob*)printjob; + +#ifndef _CUPS_API_1_4 + + { + char buf[100]; + + printer_cups_get_printjob_name(buf, sizeof(buf), printjob->id); + + if (cupsPrintFile(printjob->printer->name, (const char*)cups_printjob->printjob_object, buf, + 0, NULL) == 0) + { + } + + unlink(cups_printjob->printjob_object); + free(cups_printjob->printjob_object); + } + +#else + + cupsFinishDocument((http_t*)cups_printjob->printjob_object, printjob->printer->name); + cups_printjob->printjob_id = 0; + httpClose((http_t*)cups_printjob->printjob_object); + +#endif + + ((rdpCupsPrinter*)printjob->printer)->printjob = NULL; + free(cups_printjob); +} + +static rdpPrintJob* printer_cups_create_printjob(rdpPrinter* printer, UINT32 id) +{ + rdpCupsPrinter* cups_printer = (rdpCupsPrinter*)printer; + rdpCupsPrintJob* cups_printjob; + + if (cups_printer->printjob != NULL) + return NULL; + + cups_printjob = (rdpCupsPrintJob*)calloc(1, sizeof(rdpCupsPrintJob)); + if (!cups_printjob) + return NULL; + + cups_printjob->printjob.id = id; + cups_printjob->printjob.printer = printer; + + cups_printjob->printjob.Write = printer_cups_write_printjob; + cups_printjob->printjob.Close = printer_cups_close_printjob; + +#ifndef _CUPS_API_1_4 + + cups_printjob->printjob_object = _strdup(tmpnam(NULL)); + if (!cups_printjob->printjob_object) + { + free(cups_printjob); + return NULL; + } + +#else + { + char buf[100]; + +#if !defined(_CUPS_API_1_7) + cups_printjob->printjob_object = + httpConnectEncrypt(cupsServer(), ippPort(), HTTP_ENCRYPT_IF_REQUESTED); +#else + cups_printjob->printjob_object = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC, + HTTP_ENCRYPT_IF_REQUESTED, 1, 10000, NULL); +#endif + if (!cups_printjob->printjob_object) + { + free(cups_printjob); + return NULL; + } + + printer_cups_get_printjob_name(buf, sizeof(buf), cups_printjob->printjob.id); + + cups_printjob->printjob_id = + cupsCreateJob((http_t*)cups_printjob->printjob_object, printer->name, buf, 0, NULL); + + if (!cups_printjob->printjob_id) + { + httpClose((http_t*)cups_printjob->printjob_object); + free(cups_printjob); + return NULL; + } + + cupsStartDocument((http_t*)cups_printjob->printjob_object, printer->name, + cups_printjob->printjob_id, buf, CUPS_FORMAT_AUTO, 1); + } + +#endif + + cups_printer->printjob = cups_printjob; + + return (rdpPrintJob*)cups_printjob; +} + +static rdpPrintJob* printer_cups_find_printjob(rdpPrinter* printer, UINT32 id) +{ + rdpCupsPrinter* cups_printer = (rdpCupsPrinter*)printer; + + if (cups_printer->printjob == NULL) + return NULL; + if (cups_printer->printjob->printjob.id != id) + return NULL; + + return (rdpPrintJob*)cups_printer->printjob; +} + +static void printer_cups_free_printer(rdpPrinter* printer) +{ + rdpCupsPrinter* cups_printer = (rdpCupsPrinter*)printer; + + if (cups_printer->printjob) + cups_printer->printjob->printjob.Close((rdpPrintJob*)cups_printer->printjob); + + if (printer->backend) + printer->backend->ReleaseRef(printer->backend); + free(printer->name); + free(printer->driver); + free(printer); +} + +static void printer_cups_add_ref_printer(rdpPrinter* printer) +{ + if (printer) + printer->references++; +} + +static void printer_cups_release_ref_printer(rdpPrinter* printer) +{ + if (!printer) + return; + if (printer->references <= 1) + printer_cups_free_printer(printer); + else + printer->references--; +} + +static rdpPrinter* printer_cups_new_printer(rdpCupsPrinterDriver* cups_driver, const char* name, + const char* driverName, BOOL is_default) +{ + rdpCupsPrinter* cups_printer; + + cups_printer = (rdpCupsPrinter*)calloc(1, sizeof(rdpCupsPrinter)); + if (!cups_printer) + return NULL; + + cups_printer->printer.backend = &cups_driver->driver; + + cups_printer->printer.id = cups_driver->id_sequence++; + cups_printer->printer.name = _strdup(name); + if (!cups_printer->printer.name) + { + free(cups_printer); + return NULL; + } + + if (driverName) + cups_printer->printer.driver = _strdup(driverName); + else + cups_printer->printer.driver = _strdup("MS Publisher Imagesetter"); + if (!cups_printer->printer.driver) + { + free(cups_printer->printer.name); + free(cups_printer); + return NULL; + } + cups_printer->printer.is_default = is_default; + + cups_printer->printer.CreatePrintJob = printer_cups_create_printjob; + cups_printer->printer.FindPrintJob = printer_cups_find_printjob; + cups_printer->printer.AddRef = printer_cups_add_ref_printer; + cups_printer->printer.ReleaseRef = printer_cups_release_ref_printer; + + cups_printer->printer.AddRef(&cups_printer->printer); + cups_printer->printer.backend->AddRef(cups_printer->printer.backend); + return &cups_printer->printer; +} + +static void printer_cups_release_enum_printers(rdpPrinter** printers) +{ + rdpPrinter** cur = printers; + + while ((cur != NULL) && ((*cur) != NULL)) + { + if ((*cur)->ReleaseRef) + (*cur)->ReleaseRef(*cur); + cur++; + } + free(printers); +} + +static rdpPrinter** printer_cups_enum_printers(rdpPrinterDriver* driver) +{ + rdpPrinter** printers; + int num_printers; + cups_dest_t* dests; + cups_dest_t* dest; + int num_dests; + int i; + + num_dests = cupsGetDests(&dests); + printers = (rdpPrinter**)calloc(num_dests + 1, sizeof(rdpPrinter*)); + if (!printers) + return NULL; + + num_printers = 0; + + for (i = 0, dest = dests; i < num_dests; i++, dest++) + { + if (dest->instance == NULL) + { + rdpPrinter* current = printer_cups_new_printer((rdpCupsPrinterDriver*)driver, + dest->name, NULL, dest->is_default); + if (!current) + { + printer_cups_release_enum_printers(printers); + printers = NULL; + break; + } + + printers[num_printers++] = current; + } + } + cupsFreeDests(num_dests, dests); + + return printers; +} + +static rdpPrinter* printer_cups_get_printer(rdpPrinterDriver* driver, const char* name, + const char* driverName) +{ + rdpCupsPrinterDriver* cups_driver = (rdpCupsPrinterDriver*)driver; + + return printer_cups_new_printer(cups_driver, name, driverName, + cups_driver->id_sequence == 1 ? TRUE : FALSE); +} + +static void printer_cups_add_ref_driver(rdpPrinterDriver* driver) +{ + rdpCupsPrinterDriver* cups_driver = (rdpCupsPrinterDriver*)driver; + if (cups_driver) + cups_driver->references++; +} + +/* Singleton */ +static rdpCupsPrinterDriver* uniq_cups_driver = NULL; + +static void printer_cups_release_ref_driver(rdpPrinterDriver* driver) +{ + rdpCupsPrinterDriver* cups_driver = (rdpCupsPrinterDriver*)driver; + if (cups_driver->references <= 1) + { + if (uniq_cups_driver == cups_driver) + uniq_cups_driver = NULL; + free(cups_driver); + cups_driver = NULL; + } + else + cups_driver->references--; +} + +#ifdef BUILTIN_CHANNELS +rdpPrinterDriver* cups_freerdp_printer_client_subsystem_entry(void) +#else +FREERDP_API rdpPrinterDriver* freerdp_printer_client_subsystem_entry(void) +#endif +{ + if (!uniq_cups_driver) + { + uniq_cups_driver = (rdpCupsPrinterDriver*)calloc(1, sizeof(rdpCupsPrinterDriver)); + + if (!uniq_cups_driver) + return NULL; + + uniq_cups_driver->driver.EnumPrinters = printer_cups_enum_printers; + uniq_cups_driver->driver.ReleaseEnumPrinters = printer_cups_release_enum_printers; + uniq_cups_driver->driver.GetPrinter = printer_cups_get_printer; + + uniq_cups_driver->driver.AddRef = printer_cups_add_ref_driver; + uniq_cups_driver->driver.ReleaseRef = printer_cups_release_ref_driver; + + uniq_cups_driver->id_sequence = 1; + uniq_cups_driver->driver.AddRef(&uniq_cups_driver->driver); + } + + return &uniq_cups_driver->driver; +} diff --git a/channels/printer/client/printer_main.c b/channels/printer/client/printer_main.c index 630c0c0..dbcc07d 100644 --- a/channels/printer/client/printer_main.c +++ b/channels/printer/client/printer_main.c @@ -35,20 +35,14 @@ #include #include #include +#include #include +#include #include "../printer.h" -#ifdef WITH_CUPS -#include "printer_cups.h" -#endif - -#include "printer_main.h" - -#if defined(_WIN32) && !defined(_UWP) -#include "printer_win.h" -#endif +#include #include @@ -71,6 +65,357 @@ 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 || (length > INT32_MAX)) + 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; + + /* base64 char represents 6bit -> 4*(n/3) is the length which is + * always smaller than 2*n */ + b64len = strnlen(base64, 2 * length); + 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, UINT32* length) +{ + DWORD lowSize, highSize; + DWORD read = 0; + BOOL rc = FALSE; + HANDLE file; + char* 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 && (lowSize <= INT_MAX)) + { + int blen = 0; + crypto_base64_decode(fdata, (int)lowSize, (BYTE**)data, &blen); + + if (*data && (blen > 0)) + *length = (UINT32)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; + void* DriverName = NULL; + UINT32 DriverNameLen = 0; + void* PnPName = NULL; + UINT32 PnPNameLen = 0; + void* CachedPrinterConfigData = NULL; + UINT32 CachedFieldsLen = 0; + UINT32 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, (LPWSTR*)&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 * @@ -81,8 +426,8 @@ static UINT printer_process_irp_create(PRINTER_DEVICE* printer_dev, IRP* irp) rdpPrintJob* printjob = NULL; if (printer_dev->printer) - printjob = printer_dev->printer->CreatePrintJob(printer_dev->printer, - irp->devman->id_sequence++); + printjob = + printer_dev->printer->CreatePrintJob(printer_dev->printer, irp->devman->id_sequence++); if (printjob) { @@ -107,8 +452,7 @@ static UINT printer_process_irp_close(PRINTER_DEVICE* printer_dev, IRP* irp) rdpPrintJob* printjob = NULL; if (printer_dev->printer) - printjob = printer_dev->printer->FindPrintJob(printer_dev->printer, - irp->FileId); + printjob = printer_dev->printer->FindPrintJob(printer_dev->printer, irp->FileId); if (!printjob) { @@ -134,13 +478,18 @@ static UINT printer_process_irp_write(PRINTER_DEVICE* printer_dev, IRP* irp) UINT64 Offset; rdpPrintJob* printjob = NULL; UINT error = CHANNEL_RC_OK; + void* ptr; + + if (Stream_GetRemainingLength(irp->input) < 32) + return ERROR_INVALID_DATA; Stream_Read_UINT32(irp->input, Length); Stream_Read_UINT64(irp->input, Offset); Stream_Seek(irp->input, 20); /* Padding */ - + ptr = Stream_Pointer(irp->input); + if (!Stream_SafeSeek(irp->input, Length)) + return ERROR_INVALID_DATA; if (printer_dev->printer) - printjob = printer_dev->printer->FindPrintJob(printer_dev->printer, - irp->FileId); + printjob = printer_dev->printer->FindPrintJob(printer_dev->printer, irp->FileId); if (!printjob) { @@ -149,12 +498,12 @@ static UINT printer_process_irp_write(PRINTER_DEVICE* printer_dev, IRP* irp) } else { - error = printjob->Write(printjob, Stream_Pointer(irp->input), Length); + error = printjob->Write(printjob, ptr, Length); } if (error) { - WLog_ERR(TAG, "printjob->Write failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "printjob->Write failed with error %" PRIu32 "!", error); return error; } @@ -168,8 +517,7 @@ static UINT printer_process_irp_write(PRINTER_DEVICE* printer_dev, IRP* irp) * * @return 0 on success, otherwise a Win32 error code */ -static UINT printer_process_irp_device_control(PRINTER_DEVICE* printer_dev, - IRP* irp) +static UINT printer_process_irp_device_control(PRINTER_DEVICE* printer_dev, IRP* irp) { Stream_Write_UINT32(irp->output, 0); /* OutputBufferLength */ return irp->Complete(irp); @@ -189,7 +537,7 @@ static UINT printer_process_irp(PRINTER_DEVICE* printer_dev, IRP* irp) case IRP_MJ_CREATE: if ((error = printer_process_irp_create(printer_dev, irp))) { - WLog_ERR(TAG, "printer_process_irp_create failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "printer_process_irp_create failed with error %" PRIu32 "!", error); return error; } @@ -198,7 +546,7 @@ static UINT printer_process_irp(PRINTER_DEVICE* printer_dev, IRP* irp) case IRP_MJ_CLOSE: if ((error = printer_process_irp_close(printer_dev, irp))) { - WLog_ERR(TAG, "printer_process_irp_close failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "printer_process_irp_close failed with error %" PRIu32 "!", error); return error; } @@ -207,7 +555,7 @@ static UINT printer_process_irp(PRINTER_DEVICE* printer_dev, IRP* irp) case IRP_MJ_WRITE: if ((error = printer_process_irp_write(printer_dev, irp))) { - WLog_ERR(TAG, "printer_process_irp_write failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "printer_process_irp_write failed with error %" PRIu32 "!", error); return error; } @@ -216,7 +564,7 @@ static UINT printer_process_irp(PRINTER_DEVICE* printer_dev, IRP* irp) case IRP_MJ_DEVICE_CONTROL: if ((error = printer_process_irp_device_control(printer_dev, irp))) { - WLog_ERR(TAG, "printer_process_irp_device_control failed with error %"PRIu32"!", + WLog_ERR(TAG, "printer_process_irp_device_control failed with error %" PRIu32 "!", error); return error; } @@ -235,8 +583,8 @@ static UINT printer_process_irp(PRINTER_DEVICE* printer_dev, IRP* irp) static DWORD WINAPI printer_thread_func(LPVOID arg) { IRP* irp; - PRINTER_DEVICE* printer_dev = (PRINTER_DEVICE*) arg; - HANDLE obj[] = {printer_dev->event, printer_dev->stopEvent}; + PRINTER_DEVICE* printer_dev = (PRINTER_DEVICE*)arg; + HANDLE obj[] = { printer_dev->event, printer_dev->stopEvent }; UINT error = CHANNEL_RC_OK; while (1) @@ -246,7 +594,7 @@ static DWORD WINAPI printer_thread_func(LPVOID arg) if (rc == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", error); break; } @@ -256,7 +604,7 @@ static DWORD WINAPI printer_thread_func(LPVOID arg) continue; ResetEvent(printer_dev->event); - irp = (IRP*) InterlockedPopEntrySList(printer_dev->pIrpList); + irp = (IRP*)InterlockedPopEntrySList(printer_dev->pIrpList); if (irp == NULL) { @@ -267,14 +615,13 @@ static DWORD WINAPI printer_thread_func(LPVOID arg) if ((error = printer_process_irp(printer_dev, irp))) { - WLog_ERR(TAG, "printer_process_irp failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "printer_process_irp failed with error %" PRIu32 "!", error); break; } } if (error && printer_dev->rdpcontext) - setChannelError(printer_dev->rdpcontext, error, - "printer_thread_func reported an error"); + setChannelError(printer_dev->rdpcontext, error, "printer_thread_func reported an error"); ExitThread(error); return error; @@ -287,12 +634,188 @@ static DWORD WINAPI printer_thread_func(LPVOID arg) */ static UINT printer_irp_request(DEVICE* device, IRP* irp) { - PRINTER_DEVICE* printer_dev = (PRINTER_DEVICE*) device; + PRINTER_DEVICE* printer_dev = (PRINTER_DEVICE*)device; InterlockedPushEntrySList(printer_dev->pIrpList, &(irp->ItemEntry)); SetEvent(printer_dev->event); 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 * @@ -301,18 +824,24 @@ static UINT printer_irp_request(DEVICE* device, IRP* irp) static UINT printer_free(DEVICE* device) { IRP* irp; - PRINTER_DEVICE* printer_dev = (PRINTER_DEVICE*) device; + PRINTER_DEVICE* printer_dev = (PRINTER_DEVICE*)device; UINT error; SetEvent(printer_dev->stopEvent); if (WaitForSingleObject(printer_dev->thread, INFINITE) == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error); + 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) + while ((irp = (IRP*)InterlockedPopEntrySList(printer_dev->pIrpList)) != NULL) irp->Discard(irp); CloseHandle(printer_dev->thread); @@ -321,7 +850,7 @@ static UINT printer_free(DEVICE* device) _aligned_free(printer_dev->pIrpList); if (printer_dev->printer) - printer_dev->printer->Free(printer_dev->printer); + printer_dev->printer->ReleaseRef(printer_dev->printer); Stream_Free(printer_dev->device.data, TRUE); free(printer_dev); @@ -333,19 +862,11 @@ static UINT printer_free(DEVICE* device) * * @return 0 on success, otherwise a Win32 error code */ -UINT printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, - rdpPrinter* printer) +static 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; - printer_dev = (PRINTER_DEVICE*) calloc(1, sizeof(PRINTER_DEVICE)); + UINT error = ERROR_INTERNAL_ERROR; + printer_dev = (PRINTER_DEVICE*)calloc(1, sizeof(PRINTER_DEVICE)); if (!printer_dev) { @@ -353,57 +874,21 @@ UINT printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, return CHANNEL_RC_NO_MEMORY; } - sprintf_s(printer_dev->port, sizeof(printer_dev->port), "PRN%d", printer->id); + 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%" PRIdz, 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); + printer_dev->pIrpList = (WINPR_PSLIST_HEADER)_aligned_malloc(sizeof(WINPR_SLIST_HEADER), + MEMORY_ALLOCATION_ALIGNMENT); if (!printer_dev->pIrpList) { @@ -412,6 +897,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))) @@ -428,54 +916,102 @@ UINT printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, goto error_out; } - if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, - (DEVICE*) printer_dev))) + if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*)printer_dev))) { - WLog_ERR(TAG, "RegisterDevice failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "RegisterDevice failed with error %" PRIu32 "!", error); goto error_out; } - if (!(printer_dev->thread = CreateThread(NULL, 0, printer_thread_func, (void*) printer_dev, 0, - NULL))) + if (!(printer_dev->thread = + CreateThread(NULL, 0, printer_thread_func, (void*)printer_dev, 0, NULL))) { WLog_ERR(TAG, "CreateThread failed!"); error = ERROR_INTERNAL_ERROR; goto error_out; } + printer->AddRef(printer); return CHANNEL_RC_OK; error_out: printer_free(&printer_dev->device); return error; } -#ifdef BUILTIN_CHANNELS -#define DeviceServiceEntry printer_DeviceServiceEntry -#else -#define DeviceServiceEntry FREERDP_API DeviceServiceEntry -#endif +static rdpPrinterDriver* printer_load_backend(const char* backend) +{ + typedef rdpPrinterDriver* (*backend_load_t)(void); + union { + PVIRTUALCHANNELENTRY entry; + backend_load_t backend; + } fktconv; + + fktconv.entry = freerdp_load_channel_addin_entry("printer", backend, NULL, 0); + if (!fktconv.entry) + return NULL; + + return fktconv.backend(); +} /** * Function description * * @return 0 on success, otherwise a Win32 error code */ -UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) +UINT +#ifdef BUILTIN_CHANNELS +printer_DeviceServiceEntry +#else + FREERDP_API + DeviceServiceEntry +#endif + (PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) { int i; char* name; char* driver_name; - rdpPrinter* printer; - rdpPrinter** printers; - RDPDR_PRINTER* device; + BOOL default_backend = TRUE; + RDPDR_PRINTER* device = NULL; rdpPrinterDriver* driver = NULL; - UINT error; -#ifdef WITH_CUPS - driver = printer_cups_get_driver(); -#endif -#if defined(_WIN32) && !defined(_UWP) - driver = printer_win_get_driver(); + UINT error = CHANNEL_RC_OK; + + if (!pEntryPoints || !pEntryPoints->device) + return ERROR_INVALID_PARAMETER; + + device = (RDPDR_PRINTER*)pEntryPoints->device; + name = device->Name; + driver_name = device->DriverName; + + /* Secondary argument is one of the following: + * + * ... name of a printer driver + * : ... name of a printer driver and local printer backend to use + */ + if (driver_name) + { + char* sep = strstr(driver_name, ":"); + if (sep) + { + const char* backend = sep + 1; + *sep = '\0'; + driver = printer_load_backend(backend); + default_backend = FALSE; + } + } + + if (!driver && default_backend) + { + const char* backend = +#if defined(WITH_CUPS) + "cups" +#elif defined(_WIN32) + "win" +#else + "" #endif + ; + + driver = printer_load_backend(backend); + } if (!driver) { @@ -483,44 +1019,52 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) return CHANNEL_RC_INITIALIZATION_ERROR; } - device = (RDPDR_PRINTER*) pEntryPoints->device; - name = device->Name; - driver_name = device->DriverName; - if (name && name[0]) { - printer = driver->GetPrinter(driver, name, driver_name); + rdpPrinter* printer = driver->GetPrinter(driver, name, driver_name); if (!printer) { WLog_ERR(TAG, "Could not get printer %s!", name); - return CHANNEL_RC_INITIALIZATION_ERROR; + error = CHANNEL_RC_INITIALIZATION_ERROR; + goto fail; + } + + if (!printer_save_default_config(pEntryPoints->rdpcontext->settings, printer)) + { + error = CHANNEL_RC_INITIALIZATION_ERROR; + printer->ReleaseRef(printer); + goto fail; } if ((error = printer_register(pEntryPoints, printer))) { - WLog_ERR(TAG, "printer_register failed with error %"PRIu32"!", error); - return error; + WLog_ERR(TAG, "printer_register failed with error %" PRIu32 "!", error); + printer->ReleaseRef(printer); + goto fail; } } else { - printers = driver->EnumPrinters(driver); + rdpPrinter** printers = driver->EnumPrinters(driver); + rdpPrinter** current = printers; - for (i = 0; printers[i]; i++) + for (i = 0; current[i]; i++) { - printer = printers[i]; + rdpPrinter* printer = current[i]; if ((error = printer_register(pEntryPoints, printer))) { - WLog_ERR(TAG, "printer_register failed with error %"PRIu32"!", error); - free(printers); - return error; + WLog_ERR(TAG, "printer_register failed with error %" PRIu32 "!", error); + break; } } - free(printers); + driver->ReleaseEnumPrinters(printers); } - return CHANNEL_RC_OK; +fail: + driver->ReleaseRef(driver); + + return error; } diff --git a/channels/printer/client/win/CMakeLists.txt b/channels/printer/client/win/CMakeLists.txt new file mode 100644 index 0000000..aa648fd --- /dev/null +++ b/channels/printer/client/win/CMakeLists.txt @@ -0,0 +1,29 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# 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. +define_channel_client_subsystem("printer" "win" "") + +set(${MODULE_PREFIX}_SRCS + printer_win.c) + +include_directories(..) + +add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "") + +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp) + +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/channels/printer/client/win/printer_win.c b/channels/printer/client/win/printer_win.c new file mode 100644 index 0000000..86b5e66 --- /dev/null +++ b/channels/printer/client/win/printer_win.c @@ -0,0 +1,459 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Print Virtual Channel - WIN driver + * + * Copyright 2012 Gerald Richter + * Copyright 2015 Thincast Technologies GmbH + * Copyright 2015 DI (FH) Martin Haimberger + * Copyright 2016 Armin Novak + * + * 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 + +#define PRINTER_TAG CHANNELS_TAG("printer.client") +#ifdef WITH_DEBUG_WINPR +#define DEBUG_WINPR(...) WLog_DBG(PRINTER_TAG, __VA_ARGS__) +#else +#define DEBUG_WINPR(...) \ + do \ + { \ + } while (0) +#endif + +typedef struct rdp_win_printer_driver rdpWinPrinterDriver; +typedef struct rdp_win_printer rdpWinPrinter; +typedef struct rdp_win_print_job rdpWinPrintJob; + +struct rdp_win_printer_driver +{ + rdpPrinterDriver driver; + + size_t id_sequence; + size_t references; +}; + +struct rdp_win_printer +{ + rdpPrinter printer; + HANDLE hPrinter; + rdpWinPrintJob* printjob; +}; + +struct rdp_win_print_job +{ + rdpPrintJob printjob; + DOC_INFO_1 di; + DWORD handle; + + void* printjob_object; + int printjob_id; +}; + +static WCHAR* printer_win_get_printjob_name(size_t id) +{ + time_t tt; + struct tm tres; + struct tm* t; + WCHAR* str; + size_t len = 1024; + int rc; + + tt = time(NULL); + t = localtime_s(&tt, &tres); + + str = calloc(len, sizeof(WCHAR)); + if (!str) + return NULL; + + rc = swprintf_s(str, len, L"FreeRDP Print %04d-%02d-%02d% 02d-%02d-%02d - Job %lu\0", + t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, + id); + + return str; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT printer_win_write_printjob(rdpPrintJob* printjob, const BYTE* data, size_t size) +{ + rdpWinPrinter* printer; + LPCVOID pBuf = data; + DWORD cbBuf = size; + DWORD pcWritten; + + if (!printjob || !data) + return ERROR_BAD_ARGUMENTS; + + printer = (rdpWinPrinter*)printjob->printer; + if (!printer) + return ERROR_BAD_ARGUMENTS; + + if (!WritePrinter(printer->hPrinter, pBuf, cbBuf, &pcWritten)) + return ERROR_INTERNAL_ERROR; + return CHANNEL_RC_OK; +} + +static void printer_win_close_printjob(rdpPrintJob* printjob) +{ + rdpWinPrintJob* win_printjob = (rdpWinPrintJob*)printjob; + rdpWinPrinter* win_printer; + + if (!printjob) + return; + + win_printer = (rdpWinPrinter*)printjob->printer; + if (!win_printer) + return; + + if (!EndPagePrinter(win_printer->hPrinter)) + { + } + + if (!ClosePrinter(win_printer->hPrinter)) + { + } + + win_printer->printjob = NULL; + + free(win_printjob->di.pDocName); + free(win_printjob); +} + +static rdpPrintJob* printer_win_create_printjob(rdpPrinter* printer, UINT32 id) +{ + rdpWinPrinter* win_printer = (rdpWinPrinter*)printer; + rdpWinPrintJob* win_printjob; + + if (win_printer->printjob != NULL) + return NULL; + + win_printjob = (rdpWinPrintJob*)calloc(1, sizeof(rdpWinPrintJob)); + if (!win_printjob) + return NULL; + + win_printjob->printjob.id = id; + win_printjob->printjob.printer = printer; + win_printjob->di.pDocName = printer_win_get_printjob_name(id); + win_printjob->di.pDatatype = NULL; + win_printjob->di.pOutputFile = NULL; + + win_printjob->handle = StartDocPrinter(win_printer->hPrinter, 1, (LPBYTE) & (win_printjob->di)); + + if (!win_printjob->handle) + { + free(win_printjob->di.pDocName); + free(win_printjob); + return NULL; + } + + if (!StartPagePrinter(win_printer->hPrinter)) + { + free(win_printjob->di.pDocName); + free(win_printjob); + return NULL; + } + + win_printjob->printjob.Write = printer_win_write_printjob; + win_printjob->printjob.Close = printer_win_close_printjob; + + win_printer->printjob = win_printjob; + + return &win_printjob->printjob; +} + +static rdpPrintJob* printer_win_find_printjob(rdpPrinter* printer, UINT32 id) +{ + rdpWinPrinter* win_printer = (rdpWinPrinter*)printer; + + if (!win_printer->printjob) + return NULL; + + if (win_printer->printjob->printjob.id != id) + return NULL; + + return (rdpPrintJob*)win_printer->printjob; +} + +static void printer_win_free_printer(rdpPrinter* printer) +{ + rdpWinPrinter* win_printer = (rdpWinPrinter*)printer; + + if (win_printer->printjob) + win_printer->printjob->printjob.Close((rdpPrintJob*)win_printer->printjob); + + if (printer->backend) + printer->backend->ReleaseRef(printer->backend); + + free(printer->name); + free(printer->driver); + free(printer); +} + +static void printer_win_add_ref_printer(rdpPrinter* printer) +{ + if (printer) + printer->references++; +} + +static void printer_win_release_ref_printer(rdpPrinter* printer) +{ + if (!printer) + return; + if (printer->references <= 1) + printer_win_free_printer(printer); + else + printer->references--; +} + +static rdpPrinter* printer_win_new_printer(rdpWinPrinterDriver* win_driver, const WCHAR* name, + const WCHAR* drivername, BOOL is_default) +{ + rdpWinPrinter* win_printer; + DWORD needed = 0; + int status; + PRINTER_INFO_2* prninfo = NULL; + + win_printer = (rdpWinPrinter*)calloc(1, sizeof(rdpWinPrinter)); + if (!win_printer) + return NULL; + + win_printer->printer.backend = &win_driver->driver; + win_printer->printer.id = win_driver->id_sequence++; + if (ConvertFromUnicode(CP_UTF8, 0, name, -1, &win_printer->printer.name, 0, NULL, NULL) < 1) + { + free(win_printer); + return NULL; + } + + if (!win_printer->printer.name) + { + free(win_printer); + return NULL; + } + win_printer->printer.is_default = is_default; + + win_printer->printer.CreatePrintJob = printer_win_create_printjob; + win_printer->printer.FindPrintJob = printer_win_find_printjob; + win_printer->printer.AddRef = printer_win_add_ref_printer; + win_printer->printer.ReleaseRef = printer_win_release_ref_printer; + + if (!OpenPrinter(name, &(win_printer->hPrinter), NULL)) + { + free(win_printer->printer.name); + free(win_printer); + return NULL; + } + + /* How many memory should be allocated for printer data */ + GetPrinter(win_printer->hPrinter, 2, (LPBYTE)prninfo, 0, &needed); + if (needed == 0) + { + free(win_printer->printer.name); + free(win_printer); + return NULL; + } + + prninfo = (PRINTER_INFO_2*)GlobalAlloc(GPTR, needed); + if (!prninfo) + { + free(win_printer->printer.name); + free(win_printer); + return NULL; + } + + if (!GetPrinter(win_printer->hPrinter, 2, (LPBYTE)prninfo, needed, &needed)) + { + GlobalFree(prninfo); + free(win_printer->printer.name); + free(win_printer); + return NULL; + } + + if (drivername) + status = ConvertFromUnicode(CP_UTF8, 0, drivername, -1, &win_printer->printer.driver, 0, + NULL, NULL); + else + status = ConvertFromUnicode(CP_UTF8, 0, prninfo->pDriverName, -1, + &win_printer->printer.driver, 0, NULL, NULL); + if (!win_printer->printer.driver || (status <= 0)) + { + GlobalFree(prninfo); + free(win_printer->printer.name); + free(win_printer); + return NULL; + } + + win_printer->printer.AddRef(&win_printer->printer); + win_printer->printer.backend->AddRef(win_printer->printer.backend); + return &win_printer->printer; +} + +static void printer_win_release_enum_printers(rdpPrinter** printers) +{ + rdpPrinter** cur = printers; + + while ((cur != NULL) && ((*cur) != NULL)) + { + if ((*cur)->ReleaseRef) + (*cur)->ReleaseRef(*cur); + cur++; + } + free(printers); +} + +static rdpPrinter** printer_win_enum_printers(rdpPrinterDriver* driver) +{ + rdpPrinter** printers; + int num_printers; + int i; + PRINTER_INFO_2* prninfo = NULL; + DWORD needed, returned; + + /* find required size for the buffer */ + EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 2, NULL, 0, &needed, + &returned); + + /* allocate array of PRINTER_INFO structures */ + prninfo = (PRINTER_INFO_2*)GlobalAlloc(GPTR, needed); + if (!prninfo) + return NULL; + + /* call again */ + if (!EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 2, (LPBYTE)prninfo, + needed, &needed, &returned)) + { + } + + printers = (rdpPrinter**)calloc((returned + 1), sizeof(rdpPrinter*)); + if (!printers) + { + GlobalFree(prninfo); + return NULL; + } + + num_printers = 0; + + for (i = 0; i < (int)returned; i++) + { + rdpPrinter* current = printers[num_printers]; + current = printer_win_new_printer((rdpWinPrinterDriver*)driver, prninfo[i].pPrinterName, + prninfo[i].pDriverName, 0); + if (!current) + { + printer_win_release_enum_printers(printers); + printers = NULL; + break; + } + printers[num_printers++] = current; + } + + GlobalFree(prninfo); + return printers; +} + +static rdpPrinter* printer_win_get_printer(rdpPrinterDriver* driver, const char* name, + const char* driverName) +{ + WCHAR* driverNameW = NULL; + WCHAR* nameW = NULL; + rdpWinPrinterDriver* win_driver = (rdpWinPrinterDriver*)driver; + rdpPrinter* myPrinter = NULL; + + if (name) + { + ConvertToUnicode(CP_UTF8, 0, name, -1, &nameW, 0); + if (!driverNameW) + return NULL; + } + if (driverName) + { + ConvertToUnicode(CP_UTF8, 0, driverName, -1, &driverNameW, 0); + if (!driverNameW) + return NULL; + } + + myPrinter = printer_win_new_printer(win_driver, nameW, driverNameW, + win_driver->id_sequence == 1 ? TRUE : FALSE); + free(driverNameW); + free(nameW); + + return myPrinter; +} + +static void printer_win_add_ref_driver(rdpPrinterDriver* driver) +{ + rdpWinPrinterDriver* win = (rdpWinPrinterDriver*)driver; + if (win) + win->references++; +} + +/* Singleton */ +static rdpWinPrinterDriver* win_driver = NULL; + +static void printer_win_release_ref_driver(rdpPrinterDriver* driver) +{ + rdpWinPrinterDriver* win = (rdpWinPrinterDriver*)driver; + if (win->references <= 1) + { + free(win); + win_driver = NULL; + } + else + win->references--; +} + +#ifdef BUILTIN_CHANNELS +rdpPrinterDriver* win_freerdp_printer_client_subsystem_entry(void) +#else +FREERDP_API rdpPrinterDriver* freerdp_printer_client_subsystem_entry(void) +#endif +{ + if (!win_driver) + { + win_driver = (rdpWinPrinterDriver*)calloc(1, sizeof(rdpWinPrinterDriver)); + + if (!win_driver) + return NULL; + + win_driver->driver.EnumPrinters = printer_win_enum_printers; + win_driver->driver.ReleaseEnumPrinters = printer_win_release_enum_printers; + win_driver->driver.GetPrinter = printer_win_get_printer; + + win_driver->driver.AddRef = printer_win_add_ref_driver; + win_driver->driver.ReleaseRef = printer_win_release_ref_driver; + + win_driver->id_sequence = 1; + win_driver->driver.AddRef(&win_driver->driver); + } + + return &win_driver->driver; +} diff --git a/channels/printer/printer.h b/channels/printer/printer.h index 5ce8f5e..ae0902d 100644 --- a/channels/printer/printer.h +++ b/channels/printer/printer.h @@ -21,17 +21,16 @@ #define FREERDP_CHANNEL_PRINTER_PRINTER_H /* SERVER_PRINTER_CACHE_EVENT.cachedata */ -#define RDPDR_ADD_PRINTER_EVENT 0x00000001 -#define RDPDR_UPDATE_PRINTER_EVENT 0x00000002 -#define RDPDR_DELETE_PRINTER_EVENT 0x00000003 -#define RDPDR_RENAME_PRINTER_EVENT 0x00000004 +#define RDPDR_ADD_PRINTER_EVENT 0x00000001 +#define RDPDR_UPDATE_PRINTER_EVENT 0x00000002 +#define RDPDR_DELETE_PRINTER_EVENT 0x00000003 +#define RDPDR_RENAME_PRINTER_EVENT 0x00000004 /* DR_PRN_DEVICE_ANNOUNCE.Flags */ -#define RDPDR_PRINTER_ANNOUNCE_FLAG_ASCII 0x00000001 -#define RDPDR_PRINTER_ANNOUNCE_FLAG_DEFAULTPRINTER 0x00000002 -#define RDPDR_PRINTER_ANNOUNCE_FLAG_NETWORKPRINTER 0x00000004 -#define RDPDR_PRINTER_ANNOUNCE_FLAG_TSPRINTER 0x00000008 -#define RDPDR_PRINTER_ANNOUNCE_FLAG_XPSFORMAT 0x00000010 - +#define RDPDR_PRINTER_ANNOUNCE_FLAG_ASCII 0x00000001 +#define RDPDR_PRINTER_ANNOUNCE_FLAG_DEFAULTPRINTER 0x00000002 +#define RDPDR_PRINTER_ANNOUNCE_FLAG_NETWORKPRINTER 0x00000004 +#define RDPDR_PRINTER_ANNOUNCE_FLAG_TSPRINTER 0x00000008 +#define RDPDR_PRINTER_ANNOUNCE_FLAG_XPSFORMAT 0x00000010 #endif /* FREERDP_CHANNEL_PRINTER_PRINTER_H */ diff --git a/channels/rail/CMakeLists.txt b/channels/rail/CMakeLists.txt index 84100dc..d372dda 100644 --- a/channels/rail/CMakeLists.txt +++ b/channels/rail/CMakeLists.txt @@ -20,3 +20,7 @@ define_channel("rail") 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/rail/client/rail_main.c b/channels/rail/client/rail_main.c index ea772dd..e19cb92 100644 --- a/channels/rail/client/rail_main.c +++ b/channels/rail/client/rail_main.c @@ -42,7 +42,7 @@ RailClientContext* rail_get_client_interface(railPlugin* rail) if (!rail) return NULL; - pInterface = (RailClientContext*) rail->channelEntryPoints.pInterface; + pInterface = (RailClientContext*)rail->channelEntryPoints.pInterface; return pInterface; } @@ -56,15 +56,18 @@ static UINT rail_send(railPlugin* rail, wStream* s) UINT status; if (!rail) + { + Stream_Free(s, TRUE); return CHANNEL_RC_BAD_INIT_HANDLE; + } - status = rail->channelEntryPoints.pVirtualChannelWriteEx(rail->InitHandle, rail->OpenHandle, - Stream_Buffer(s), (UINT32) Stream_GetPosition(s), s); + status = rail->channelEntryPoints.pVirtualChannelWriteEx( + rail->InitHandle, rail->OpenHandle, Stream_Buffer(s), (UINT32)Stream_GetPosition(s), s); if (status != CHANNEL_RC_OK) { Stream_Free(s, TRUE); - WLog_ERR(TAG, "pVirtualChannelWriteEx failed with %s [%08"PRIX32"]", + WLog_ERR(TAG, "pVirtualChannelWriteEx failed with %s [%08" PRIX32 "]", WTSErrorToString(status), status); } @@ -76,13 +79,15 @@ static UINT rail_send(railPlugin* rail, wStream* s) * * @return 0 on success, otherwise a Win32 error code */ -UINT rail_send_channel_data(railPlugin* rail, void* data, size_t length) +UINT rail_send_channel_data(railPlugin* rail, wStream* src) { - wStream* s = NULL; + wStream* s; + size_t length; - if (!rail || !data) + if (!rail || !src) return ERROR_INVALID_PARAMETER; + length = Stream_GetPosition(src); s = Stream_New(NULL, length); if (!s) @@ -91,7 +96,7 @@ UINT rail_send_channel_data(railPlugin* rail, void* data, size_t length) return CHANNEL_RC_NO_MEMORY; } - Stream_Write(s, data, length); + Stream_Write(s, Stream_Buffer(src), length); return rail_send(rail, s); } @@ -104,8 +109,7 @@ UINT rail_send_channel_data(railPlugin* rail, void* data, size_t length) * * @return 0 on success, otherwise a Win32 error code */ -static UINT rail_client_execute(RailClientContext* context, - const RAIL_EXEC_ORDER* exec) +static UINT rail_client_execute(RailClientContext* context, const RAIL_EXEC_ORDER* exec) { char* exeOrFile; UINT error; @@ -118,25 +122,19 @@ static UINT rail_client_execute(RailClientContext* context, if (!context || !exec) return ERROR_INVALID_PARAMETER; - rail = (railPlugin*) context->handle; + rail = (railPlugin*)context->handle; exeOrFile = exec->RemoteApplicationProgram; flags = exec->flags; if (!exeOrFile) return ERROR_INVALID_PARAMETER; - if (strnlen(exeOrFile, MAX_PATH) >= 2) - { - if (strncmp(exeOrFile, "||", 2) != 0) - flags |= RAIL_EXEC_FLAG_FILE; - } - - if (!rail_string_to_unicode_string(exec->RemoteApplicationProgram, - &ruExeOrFile) || /* RemoteApplicationProgram */ - !rail_string_to_unicode_string(exec->RemoteApplicationWorkingDir, - &ruWorkingDir) || /* ShellWorkingDirectory */ - !rail_string_to_unicode_string(exec->RemoteApplicationArguments, - &ruArguments)) /* RemoteApplicationCmdLine */ + if (!utf8_string_to_rail_string(exec->RemoteApplicationProgram, + &ruExeOrFile) || /* RemoteApplicationProgram */ + !utf8_string_to_rail_string(exec->RemoteApplicationWorkingDir, + &ruWorkingDir) || /* ShellWorkingDirectory */ + !utf8_string_to_rail_string(exec->RemoteApplicationArguments, + &ruArguments)) /* RemoteApplicationCmdLine */ error = ERROR_INTERNAL_ERROR; else error = rail_send_client_exec_order(rail, flags, &ruExeOrFile, &ruWorkingDir, &ruArguments); @@ -152,15 +150,14 @@ static UINT rail_client_execute(RailClientContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rail_client_activate(RailClientContext* context, - const RAIL_ACTIVATE_ORDER* activate) +static UINT rail_client_activate(RailClientContext* context, const RAIL_ACTIVATE_ORDER* activate) { railPlugin* rail; if (!context || !activate) return ERROR_INVALID_PARAMETER; - rail = (railPlugin*) context->handle; + rail = (railPlugin*)context->handle; return rail_send_client_activate_order(rail, activate); } @@ -169,18 +166,18 @@ static UINT rail_client_activate(RailClientContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rail_send_client_sysparam(RailClientContext* context, - RAIL_SYSPARAM_ORDER* sysparam) +static UINT rail_send_client_sysparam(RailClientContext* context, RAIL_SYSPARAM_ORDER* sysparam) { wStream* s; size_t length = RAIL_SYSPARAM_ORDER_LENGTH; railPlugin* rail; UINT error; + BOOL extendedSpiSupported; if (!context || !sysparam) return ERROR_INVALID_PARAMETER; - rail = (railPlugin*) context->handle; + rail = (railPlugin*)context->handle; switch (sysparam->param) { @@ -201,9 +198,18 @@ static UINT rail_send_client_sysparam(RailClientContext* context, length += sysparam->highContrast.colorSchemeLength + 10; break; - default: - length += 8; + case SPI_SETFILTERKEYS: + length += 20; break; + + case SPI_SETSTICKYKEYS: + case SPI_SETCARETWIDTH: + case SPI_SETTOGGLEKEYS: + length += 4; + break; + + default: + return ERROR_BAD_ARGUMENTS; } s = rail_pdu_init(length); @@ -214,16 +220,17 @@ static UINT rail_send_client_sysparam(RailClientContext* context, return CHANNEL_RC_NO_MEMORY; } - if ((error = rail_write_client_sysparam_order(s, sysparam))) + extendedSpiSupported = rail_is_extended_spi_supported(rail->channelFlags); + if ((error = rail_write_sysparam_order(s, sysparam, extendedSpiSupported))) { - WLog_ERR(TAG, "rail_write_client_sysparam_order failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rail_write_client_sysparam_order failed with error %" PRIu32 "!", error); Stream_Free(s, TRUE); return error; } - if ((error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_SYSPARAM))) + if ((error = rail_send_pdu(rail, s, TS_RAIL_ORDER_SYSPARAM))) { - WLog_ERR(TAG, "rail_send_pdu failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rail_send_pdu failed with error %" PRIu32 "!", error); } Stream_Free(s, TRUE); @@ -252,7 +259,7 @@ static UINT rail_client_system_param(RailClientContext* context, if ((error = rail_send_client_sysparam(context, &sysparam))) { - WLog_ERR(TAG, "rail_send_client_sysparam failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error); return error; } } @@ -263,7 +270,7 @@ static UINT rail_client_system_param(RailClientContext* context, if ((error = rail_send_client_sysparam(context, &sysparam))) { - WLog_ERR(TAG, "rail_send_client_sysparam failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error); return error; } } @@ -274,7 +281,7 @@ static UINT rail_client_system_param(RailClientContext* context, if ((error = rail_send_client_sysparam(context, &sysparam))) { - WLog_ERR(TAG, "rail_send_client_sysparam failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error); return error; } } @@ -285,7 +292,7 @@ static UINT rail_client_system_param(RailClientContext* context, if ((error = rail_send_client_sysparam(context, &sysparam))) { - WLog_ERR(TAG, "rail_send_client_sysparam failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error); return error; } } @@ -296,7 +303,7 @@ static UINT rail_client_system_param(RailClientContext* context, if ((error = rail_send_client_sysparam(context, &sysparam))) { - WLog_ERR(TAG, "rail_send_client_sysparam failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error); return error; } } @@ -307,7 +314,7 @@ static UINT rail_client_system_param(RailClientContext* context, if ((error = rail_send_client_sysparam(context, &sysparam))) { - WLog_ERR(TAG, "rail_send_client_sysparam failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error); return error; } } @@ -318,7 +325,7 @@ static UINT rail_client_system_param(RailClientContext* context, if ((error = rail_send_client_sysparam(context, &sysparam))) { - WLog_ERR(TAG, "rail_send_client_sysparam failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rail_send_client_sysparam failed with error %" PRIu32 "!", error); return error; } } @@ -331,20 +338,6 @@ static UINT rail_client_system_param(RailClientContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rail_server_system_param(RailClientContext* context, - const RAIL_SYSPARAM_ORDER* sysparam) -{ - if (!context || !sysparam) - return ERROR_INVALID_PARAMETER; - - return CHANNEL_RC_OK; /* stub - should be registered by client */ -} - -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ static UINT rail_client_system_command(RailClientContext* context, const RAIL_SYSCOMMAND_ORDER* syscommand) { @@ -353,7 +346,7 @@ static UINT rail_client_system_command(RailClientContext* context, if (!context || !syscommand) return ERROR_INVALID_PARAMETER; - rail = (railPlugin*) context->handle; + rail = (railPlugin*)context->handle; return rail_send_client_syscommand_order(rail, syscommand); } @@ -362,15 +355,14 @@ static UINT rail_client_system_command(RailClientContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rail_client_handshake(RailClientContext* context, - const RAIL_HANDSHAKE_ORDER* handshake) +static UINT rail_client_handshake(RailClientContext* context, const RAIL_HANDSHAKE_ORDER* handshake) { railPlugin* rail; if (!context || !handshake) return ERROR_INVALID_PARAMETER; - rail = (railPlugin*) context->handle; + rail = (railPlugin*)context->handle; return rail_send_handshake_order(rail, handshake); } @@ -379,51 +371,6 @@ static UINT rail_client_handshake(RailClientContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rail_server_handshake(RailClientContext* context, - const RAIL_HANDSHAKE_ORDER* handshake) -{ - if (!context || !handshake) - return ERROR_INVALID_PARAMETER; - - return CHANNEL_RC_OK; /* stub - should be registered by client */ -} - -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT rail_client_handshake_ex(RailClientContext* context, - const RAIL_HANDSHAKE_EX_ORDER* handshakeEx) -{ - railPlugin* rail; - - if (!context || !handshakeEx) - return ERROR_INVALID_PARAMETER; - - rail = (railPlugin*) context->handle; - return rail_send_handshake_ex_order(rail, handshakeEx); -} - -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT rail_server_handshake_ex(RailClientContext* context, - const RAIL_HANDSHAKE_EX_ORDER* handshakeEx) -{ - if (!context || !handshakeEx) - return ERROR_INVALID_PARAMETER; - - return CHANNEL_RC_OK; /* stub - should be registered by client */ -} - -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ static UINT rail_client_notify_event(RailClientContext* context, const RAIL_NOTIFY_EVENT_ORDER* notifyEvent) { @@ -432,7 +379,7 @@ static UINT rail_client_notify_event(RailClientContext* context, if (!context || !notifyEvent) return ERROR_INVALID_PARAMETER; - rail = (railPlugin*) context->handle; + rail = (railPlugin*)context->handle; return rail_send_client_notify_event_order(rail, notifyEvent); } @@ -449,7 +396,7 @@ static UINT rail_client_window_move(RailClientContext* context, if (!context || !windowMove) return ERROR_INVALID_PARAMETER; - rail = (railPlugin*) context->handle; + rail = (railPlugin*)context->handle; return rail_send_client_window_move_order(rail, windowMove); } @@ -458,34 +405,6 @@ static UINT rail_client_window_move(RailClientContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rail_server_local_move_size(RailClientContext* context, - const RAIL_LOCALMOVESIZE_ORDER* localMoveSize) -{ - if (!context || !localMoveSize) - return ERROR_INVALID_PARAMETER; - - return CHANNEL_RC_OK; /* stub - should be registered by client */ -} - -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT rail_server_min_max_info(RailClientContext* context, - const RAIL_MINMAXINFO_ORDER* minMaxInfo) -{ - if (!context || !minMaxInfo) - return ERROR_INVALID_PARAMETER; - - return CHANNEL_RC_OK; /* stub - should be registered by client */ -} - -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ static UINT rail_client_information(RailClientContext* context, const RAIL_CLIENT_STATUS_ORDER* clientStatus) { @@ -494,7 +413,7 @@ static UINT rail_client_information(RailClientContext* context, if (!context || !clientStatus) return ERROR_INVALID_PARAMETER; - rail = (railPlugin*) context->handle; + rail = (railPlugin*)context->handle; return rail_send_client_status_order(rail, clientStatus); } @@ -503,15 +422,14 @@ static UINT rail_client_information(RailClientContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rail_client_system_menu(RailClientContext* context, - const RAIL_SYSMENU_ORDER* sysmenu) +static UINT rail_client_system_menu(RailClientContext* context, const RAIL_SYSMENU_ORDER* sysmenu) { railPlugin* rail; if (!context || !sysmenu) return ERROR_INVALID_PARAMETER; - rail = (railPlugin*) context->handle; + rail = (railPlugin*)context->handle; return rail_send_client_sysmenu_order(rail, sysmenu); } @@ -521,29 +439,27 @@ static UINT rail_client_system_menu(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT rail_client_language_bar_info(RailClientContext* context, - const RAIL_LANGBAR_INFO_ORDER* langBarInfo) + const RAIL_LANGBAR_INFO_ORDER* langBarInfo) { railPlugin* rail; if (!context || !langBarInfo) return ERROR_INVALID_PARAMETER; - rail = (railPlugin*) context->handle; + rail = (railPlugin*)context->handle; return rail_send_client_langbar_info_order(rail, langBarInfo); } -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT rail_server_language_bar_info(RailClientContext* context, - const RAIL_LANGBAR_INFO_ORDER* langBarInfo) +static UINT rail_client_language_ime_info(RailClientContext* context, + const RAIL_LANGUAGEIME_INFO_ORDER* langImeInfo) { - if (!context || !langBarInfo) + railPlugin* rail; + + if (!context || !langImeInfo) return ERROR_INVALID_PARAMETER; - return CHANNEL_RC_OK; /* stub - should be registered by client */ + rail = (railPlugin*)context->handle; + return rail_send_client_languageime_info_order(rail, langImeInfo); } /** @@ -551,44 +467,50 @@ static UINT rail_server_language_bar_info(RailClientContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rail_server_execute_result(RailClientContext* context, - const RAIL_EXEC_RESULT_ORDER* execResult) +static UINT rail_client_get_appid_request(RailClientContext* context, + const RAIL_GET_APPID_REQ_ORDER* getAppIdReq) { - if (!context || !execResult) + railPlugin* rail; + + if (!context || !getAppIdReq || !context->handle) return ERROR_INVALID_PARAMETER; - return CHANNEL_RC_OK; /* stub - should be registered by client */ + rail = (railPlugin*)context->handle; + return rail_send_client_get_appid_req_order(rail, getAppIdReq); } -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT rail_client_get_appid_request(RailClientContext* context, - const RAIL_GET_APPID_REQ_ORDER* getAppIdReq) +static UINT rail_client_compartment_info(RailClientContext* context, + const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo) { railPlugin* rail; - if (!context || !getAppIdReq || !context->handle) + if (!context || !compartmentInfo || !context->handle) return ERROR_INVALID_PARAMETER; - rail = (railPlugin*) context->handle; - return rail_send_client_get_appid_req_order(rail, getAppIdReq); + rail = (railPlugin*)context->handle; + return rail_send_client_compartment_info_order(rail, compartmentInfo); } -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT rail_server_get_appid_response(RailClientContext* context, - const RAIL_GET_APPID_RESP_ORDER* getAppIdResp) +static UINT rail_client_cloak(RailClientContext* context, const RAIL_CLOAK* cloak) +{ + railPlugin* rail; + + if (!context || !cloak || !context->handle) + return ERROR_INVALID_PARAMETER; + + rail = (railPlugin*)context->handle; + return rail_send_client_cloak_order(rail, cloak); +} + +static UINT rail_client_snap_arrange(RailClientContext* context, const RAIL_SNAP_ARRANGE* snap) { - if (!context || !getAppIdResp) + railPlugin* rail; + + if (!context || !snap || !context->handle) return ERROR_INVALID_PARAMETER; - return CHANNEL_RC_OK; /* stub - should be registered by client */ + rail = (railPlugin*)context->handle; + return rail_send_client_snap_arrange_order(rail, snap); } /** @@ -596,8 +518,9 @@ static UINT rail_server_get_appid_response(RailClientContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rail_virtual_channel_event_data_received(railPlugin* rail, - void* pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) +static UINT rail_virtual_channel_event_data_received(railPlugin* rail, void* pData, + UINT32 dataLength, UINT32 totalLength, + UINT32 dataFlags) { wStream* data_in; @@ -622,7 +545,7 @@ static UINT rail_virtual_channel_event_data_received(railPlugin* rail, data_in = rail->data_in; - if (!Stream_EnsureRemainingCapacity(data_in, (int) dataLength)) + if (!Stream_EnsureRemainingCapacity(data_in, dataLength)) { WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); return CHANNEL_RC_NO_MEMORY; @@ -634,7 +557,7 @@ static UINT rail_virtual_channel_event_data_received(railPlugin* rail, { if (Stream_Capacity(data_in) != Stream_GetPosition(data_in)) { - WLog_ERR(TAG, "rail_plugin_process_received: read error"); + WLog_ERR(TAG, "rail_plugin_process_received: read error"); return ERROR_INTERNAL_ERROR; } @@ -642,7 +565,7 @@ static UINT rail_virtual_channel_event_data_received(railPlugin* rail, Stream_SealLength(data_in); Stream_SetPosition(data_in, 0); - if (!MessageQueue_Post(rail->queue, NULL, 0, (void*) data_in, NULL)) + if (!MessageQueue_Post(rail->queue, NULL, 0, (void*)data_in, NULL)) { WLog_ERR(TAG, "MessageQueue_Post failed!"); return ERROR_INTERNAL_ERROR; @@ -653,36 +576,42 @@ static UINT rail_virtual_channel_event_data_received(railPlugin* rail, } static VOID VCAPITYPE rail_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle, - UINT event, - LPVOID pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) + UINT event, LPVOID pData, + UINT32 dataLength, UINT32 totalLength, + UINT32 dataFlags) { UINT error = CHANNEL_RC_OK; - railPlugin* rail = (railPlugin*) lpUserParam; - - if (!rail || (rail->OpenHandle != openHandle)) - { - WLog_ERR(TAG, "error no match"); - return; - } + railPlugin* rail = (railPlugin*)lpUserParam; switch (event) { case CHANNEL_EVENT_DATA_RECEIVED: + if (!rail || (rail->OpenHandle != openHandle)) + { + WLog_ERR(TAG, "error no match"); + return; + } if ((error = rail_virtual_channel_event_data_received(rail, pData, dataLength, - totalLength, dataFlags))) - WLog_ERR(TAG, "rail_virtual_channel_event_data_received failed with error %"PRIu32"!", + totalLength, dataFlags))) + WLog_ERR(TAG, + "rail_virtual_channel_event_data_received failed with error %" PRIu32 "!", error); break; + case CHANNEL_EVENT_WRITE_CANCELLED: case CHANNEL_EVENT_WRITE_COMPLETE: - break; + { + wStream* s = (wStream*)pData; + Stream_Free(s, TRUE); + } + break; case CHANNEL_EVENT_USER: break; } - if (error && rail->rdpcontext) + if (error && rail && rail->rdpcontext) setChannelError(rail->rdpcontext, error, "rail_virtual_channel_open_event reported an error"); @@ -693,7 +622,7 @@ static DWORD WINAPI rail_virtual_channel_client_thread(LPVOID arg) { wStream* data; wMessage message; - railPlugin* rail = (railPlugin*) arg; + railPlugin* rail = (railPlugin*)arg; UINT error = CHANNEL_RC_OK; while (1) @@ -717,13 +646,13 @@ static DWORD WINAPI rail_virtual_channel_client_thread(LPVOID arg) if (message.id == 0) { - data = (wStream*) message.wParam; + data = (wStream*)message.wParam; error = rail_order_recv(rail, data); Stream_Free(data, TRUE); if (error) { - WLog_ERR(TAG, "rail_order_recv failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rail_order_recv failed with error %" PRIu32 "!", error); break; } } @@ -742,20 +671,30 @@ static DWORD WINAPI rail_virtual_channel_client_thread(LPVOID arg) * * @return 0 on success, otherwise a Win32 error code */ -static UINT rail_virtual_channel_event_connected(railPlugin* rail, LPVOID pData, - UINT32 dataLength) +static UINT rail_virtual_channel_event_connected(railPlugin* rail, LPVOID pData, UINT32 dataLength) { + RailClientContext* context = rail_get_client_interface(rail); UINT status; - status = rail->channelEntryPoints.pVirtualChannelOpenEx(rail->InitHandle, - &rail->OpenHandle, rail->channelDef.name, rail_virtual_channel_open_event_ex); + status = rail->channelEntryPoints.pVirtualChannelOpenEx(rail->InitHandle, &rail->OpenHandle, + rail->channelDef.name, + rail_virtual_channel_open_event_ex); if (status != CHANNEL_RC_OK) { - WLog_ERR(TAG, "pVirtualChannelOpen failed with %s [%08"PRIX32"]", + WLog_ERR(TAG, "pVirtualChannelOpen failed with %s [%08" PRIX32 "]", WTSErrorToString(status), status); return status; } + if (context) + { + IFCALLRET(context->OnOpen, status, context, &rail->sendHandshake); + + if (status != CHANNEL_RC_OK) + WLog_ERR(TAG, "context->OnOpen failed with %s [%08" PRIX32 "]", + WTSErrorToString(status), status); + } + rail->queue = MessageQueue_New(NULL); if (!rail->queue) @@ -764,9 +703,8 @@ static UINT rail_virtual_channel_event_connected(railPlugin* rail, LPVOID pData, return CHANNEL_RC_NO_MEMORY; } - if (!(rail->thread = CreateThread(NULL, 0, - rail_virtual_channel_client_thread, (void*) rail, 0, - NULL))) + if (!(rail->thread = + CreateThread(NULL, 0, rail_virtual_channel_client_thread, (void*)rail, 0, NULL))) { WLog_ERR(TAG, "CreateThread failed!"); MessageQueue_Free(rail->queue); @@ -789,11 +727,11 @@ static UINT rail_virtual_channel_event_disconnected(railPlugin* rail) if (rail->OpenHandle == 0) return CHANNEL_RC_OK; - if (MessageQueue_PostQuit(rail->queue, 0) - && (WaitForSingleObject(rail->thread, INFINITE) == WAIT_FAILED)) + if (MessageQueue_PostQuit(rail->queue, 0) && + (WaitForSingleObject(rail->thread, INFINITE) == WAIT_FAILED)) { rc = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", rc); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", rc); return rc; } @@ -805,8 +743,8 @@ static UINT rail_virtual_channel_event_disconnected(railPlugin* rail) if (CHANNEL_RC_OK != rc) { - WLog_ERR(TAG, "pVirtualChannelCloseEx failed with %s [%08"PRIX32"]", - WTSErrorToString(rc), rc); + WLog_ERR(TAG, "pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]", WTSErrorToString(rc), + rc); return rc; } @@ -829,14 +767,14 @@ static void rail_virtual_channel_event_terminated(railPlugin* rail) } static VOID VCAPITYPE rail_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle, - UINT event, LPVOID pData, UINT dataLength) + UINT event, LPVOID pData, UINT dataLength) { UINT error = CHANNEL_RC_OK; - railPlugin* rail = (railPlugin*) lpUserParam; + railPlugin* rail = (railPlugin*)lpUserParam; if (!rail || (rail->InitHandle != pInitHandle)) { - WLog_ERR(TAG, "error no match"); + WLog_ERR(TAG, "error no match"); return; } @@ -844,14 +782,15 @@ static VOID VCAPITYPE rail_virtual_channel_init_event_ex(LPVOID lpUserParam, LPV { case CHANNEL_EVENT_CONNECTED: if ((error = rail_virtual_channel_event_connected(rail, pData, dataLength))) - WLog_ERR(TAG, "rail_virtual_channel_event_connected failed with error %"PRIu32"!", + WLog_ERR(TAG, "rail_virtual_channel_event_connected failed with error %" PRIu32 "!", error); break; case CHANNEL_EVENT_DISCONNECTED: if ((error = rail_virtual_channel_event_disconnected(rail))) - WLog_ERR(TAG, "rail_virtual_channel_event_disconnected failed with error %"PRIu32"!", + WLog_ERR(TAG, + "rail_virtual_channel_event_disconnected failed with error %" PRIu32 "!", error); break; @@ -867,11 +806,12 @@ static VOID VCAPITYPE rail_virtual_channel_init_event_ex(LPVOID lpUserParam, LPV } if (error && rail->rdpcontext) - setChannelError(rail->rdpcontext, error, "rail_virtual_channel_init_event_ex reported an error"); + setChannelError(rail->rdpcontext, error, + "rail_virtual_channel_init_event_ex reported an error"); } /* rail is always built-in */ -#define VirtualChannelEntryEx rail_VirtualChannelEntryEx +#define VirtualChannelEntryEx rail_VirtualChannelEntryEx BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID pInitHandle) { @@ -880,7 +820,7 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p RailClientContext* context = NULL; CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx; BOOL isFreerdp = FALSE; - rail = (railPlugin*) calloc(1, sizeof(railPlugin)); + rail = (railPlugin*)calloc(1, sizeof(railPlugin)); if (!rail) { @@ -888,18 +828,17 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p return FALSE; } - rail->channelDef.options = - CHANNEL_OPTION_INITIALIZED | - CHANNEL_OPTION_ENCRYPT_RDP | - CHANNEL_OPTION_COMPRESS_RDP | - CHANNEL_OPTION_SHOW_PROTOCOL; - sprintf_s(rail->channelDef.name, ARRAYSIZE(rail->channelDef.name), "rail"); - pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*) pEntryPoints; + /* Default to automatically replying to server handshakes */ + rail->sendHandshake = TRUE; + rail->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP | + CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL; + sprintf_s(rail->channelDef.name, ARRAYSIZE(rail->channelDef.name), RAIL_SVC_CHANNEL_NAME); + pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints; if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) && (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER)) { - context = (RailClientContext*) calloc(1, sizeof(RailClientContext)); + context = (RailClientContext*)calloc(1, sizeof(RailClientContext)); if (!context) { @@ -908,28 +847,23 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p return FALSE; } - context->handle = (void*) rail; + context->handle = (void*)rail; context->custom = NULL; context->ClientExecute = rail_client_execute; context->ClientActivate = rail_client_activate; context->ClientSystemParam = rail_client_system_param; - context->ServerSystemParam = rail_server_system_param; context->ClientSystemCommand = rail_client_system_command; context->ClientHandshake = rail_client_handshake; - context->ServerHandshake = rail_server_handshake; - context->ClientHandshakeEx = rail_client_handshake_ex; - context->ServerHandshakeEx = rail_server_handshake_ex; context->ClientNotifyEvent = rail_client_notify_event; context->ClientWindowMove = rail_client_window_move; - context->ServerLocalMoveSize = rail_server_local_move_size; - context->ServerMinMaxInfo = rail_server_min_max_info; context->ClientInformation = rail_client_information; context->ClientSystemMenu = rail_client_system_menu; context->ClientLanguageBarInfo = rail_client_language_bar_info; - context->ServerLanguageBarInfo = rail_server_language_bar_info; - context->ServerExecuteResult = rail_server_execute_result; + context->ClientLanguageIMEInfo = rail_client_language_ime_info; context->ClientGetAppIdRequest = rail_client_get_appid_request; - context->ServerGetAppIdResponse = rail_server_get_appid_response; + context->ClientSnapArrange = rail_client_snap_arrange; + context->ClientCloak = rail_client_cloak; + context->ClientCompartmentInfo = rail_client_compartment_info; rail->rdpcontext = pEntryPointsEx->context; rail->context = context; isFreerdp = TRUE; @@ -937,17 +871,15 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p rail->log = WLog_Get("com.freerdp.channels.rail.client"); WLog_Print(rail->log, WLOG_DEBUG, "VirtualChannelEntryEx"); - CopyMemory(&(rail->channelEntryPoints), pEntryPoints, - sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)); + CopyMemory(&(rail->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)); rail->InitHandle = pInitHandle; - rc = rail->channelEntryPoints.pVirtualChannelInitEx(rail, context, pInitHandle, - &rail->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, - rail_virtual_channel_init_event_ex); + rc = rail->channelEntryPoints.pVirtualChannelInitEx( + rail, context, pInitHandle, &rail->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, + rail_virtual_channel_init_event_ex); if (CHANNEL_RC_OK != rc) { - WLog_ERR(TAG, "failed with %s [%08"PRIX32"]", - WTSErrorToString(rc), rc); + WLog_ERR(TAG, "failed with %s [%08" PRIX32 "]", WTSErrorToString(rc), rc); goto error_out; } diff --git a/channels/rail/client/rail_main.h b/channels/rail/client/rail_main.h index 86e752f..63e522e 100644 --- a/channels/rail/client/rail_main.h +++ b/channels/rail/client/rail_main.h @@ -50,10 +50,14 @@ struct rail_plugin DWORD OpenHandle; wMessageQueue* queue; rdpContext* rdpcontext; + DWORD channelBuildNumber; + DWORD channelFlags; + RAIL_CLIENT_STATUS_ORDER clientStatus; + BOOL sendHandshake; }; typedef struct rail_plugin railPlugin; RailClientContext* rail_get_client_interface(railPlugin* rail); -UINT rail_send_channel_data(railPlugin* rail, void* data, size_t length); +UINT rail_send_channel_data(railPlugin* rail, wStream* s); #endif /* FREERDP_CHANNEL_RAIL_CLIENT_MAIN_H */ diff --git a/channels/rail/client/rail_orders.c b/channels/rail/client/rail_orders.c index 7e6cf42..c394a59 100644 --- a/channels/rail/client/rail_orders.c +++ b/channels/rail/client/rail_orders.c @@ -37,55 +37,6 @@ * * @return 0 on success, otherwise a Win32 error code */ -static UINT rail_write_unicode_string(wStream* s, const RAIL_UNICODE_STRING* unicode_string) -{ - if (!s || !unicode_string) - return ERROR_INVALID_PARAMETER; - - if (!Stream_EnsureRemainingCapacity(s, 2 + unicode_string->length)) - { - WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); - return CHANNEL_RC_NO_MEMORY; - } - - Stream_Write_UINT16(s, unicode_string->length); /* cbString (2 bytes) */ - Stream_Write(s, unicode_string->string, unicode_string->length); /* string */ - return CHANNEL_RC_OK; -} - -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT rail_write_unicode_string_value(wStream* s, const RAIL_UNICODE_STRING* unicode_string) -{ - size_t length; - - if (!s || !unicode_string) - return ERROR_INVALID_PARAMETER; - - length = unicode_string->length; - - if (length > 0) - { - if (!Stream_EnsureRemainingCapacity(s, length)) - { - WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); - return CHANNEL_RC_NO_MEMORY; - } - - Stream_Write(s, unicode_string->string, length); /* string */ - } - - return CHANNEL_RC_OK; -} - -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ UINT rail_send_pdu(railPlugin* rail, wStream* s, UINT16 orderType) { UINT16 orderLength; @@ -93,31 +44,13 @@ UINT rail_send_pdu(railPlugin* rail, wStream* s, UINT16 orderType) if (!rail || !s) return ERROR_INVALID_PARAMETER; - orderLength = (UINT16) Stream_GetPosition(s); + orderLength = (UINT16)Stream_GetPosition(s); Stream_SetPosition(s, 0); rail_write_pdu_header(s, orderType, orderLength); Stream_SetPosition(s, orderLength); - WLog_Print(rail->log, WLOG_DEBUG, "Sending %s PDU, length: %"PRIu16"", - RAIL_ORDER_TYPE_STRINGS[((orderType & 0xF0) >> 3) + (orderType & 0x0F)], orderLength); - return rail_send_channel_data(rail, Stream_Buffer(s), orderLength); -} - -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT rail_write_high_contrast(wStream* s, const RAIL_HIGH_CONTRAST* highContrast) -{ - UINT32 colorSchemeLength; - - if (!s || !highContrast) - return ERROR_INVALID_PARAMETER; - - colorSchemeLength = highContrast->colorScheme.length + 2; - Stream_Write_UINT32(s, highContrast->flags); /* flags (4 bytes) */ - Stream_Write_UINT32(s, colorSchemeLength); /* colorSchemeLength (4 bytes) */ - return rail_write_unicode_string(s, &highContrast->colorScheme); /* colorScheme */ + WLog_Print(rail->log, WLOG_DEBUG, "Sending %s PDU, length: %" PRIu16 "", + rail_get_order_type_string(orderType), orderLength); + return rail_send_channel_data(rail, s); } /** @@ -130,56 +63,19 @@ static UINT rail_read_server_exec_result_order(wStream* s, RAIL_EXEC_RESULT_ORDE if (!s || !execResult) return ERROR_INVALID_PARAMETER; - if (Stream_GetRemainingLength(s) < 8) + if (Stream_GetRemainingLength(s) < RAIL_EXEC_RESULT_ORDER_LENGTH) { WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); return ERROR_INVALID_DATA; } - Stream_Read_UINT16(s, execResult->flags); /* flags (2 bytes) */ + Stream_Read_UINT16(s, execResult->flags); /* flags (2 bytes) */ Stream_Read_UINT16(s, execResult->execResult); /* execResult (2 bytes) */ - Stream_Read_UINT32(s, execResult->rawResult); /* rawResult (4 bytes) */ - Stream_Seek_UINT16(s); /* padding (2 bytes) */ - return rail_read_unicode_string(s, - &execResult->exeOrFile) ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; /* exeOrFile */ -} - -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT rail_read_server_sysparam_order(wStream* s, RAIL_SYSPARAM_ORDER* sysparam) -{ - BYTE body; - - if (!s || !sysparam) - return ERROR_INVALID_PARAMETER; - - if (Stream_GetRemainingLength(s) < 5) - { - WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); - return ERROR_INVALID_DATA; - } - - Stream_Read_UINT32(s, sysparam->param); /* systemParam (4 bytes) */ - Stream_Read_UINT8(s, body); /* body (1 byte) */ - - switch (sysparam->param) - { - case SPI_SET_SCREEN_SAVE_ACTIVE: - sysparam->setScreenSaveActive = (body != 0) ? TRUE : FALSE; - break; - - case SPI_SET_SCREEN_SAVE_SECURE: - sysparam->setScreenSaveSecure = (body != 0) ? TRUE : FALSE; - break; - - default: - break; - } - - return CHANNEL_RC_OK; + Stream_Read_UINT32(s, execResult->rawResult); /* rawResult (4 bytes) */ + Stream_Seek_UINT16(s); /* padding (2 bytes) */ + return rail_read_unicode_string(s, &execResult->exeOrFile) + ? CHANNEL_RC_OK + : ERROR_INTERNAL_ERROR; /* exeOrFile */ } /** @@ -192,21 +88,21 @@ static UINT rail_read_server_minmaxinfo_order(wStream* s, RAIL_MINMAXINFO_ORDER* if (!s || !minmaxinfo) return ERROR_INVALID_PARAMETER; - if (Stream_GetRemainingLength(s) < 20) + if (Stream_GetRemainingLength(s) < RAIL_MINMAXINFO_ORDER_LENGTH) { WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); return ERROR_INVALID_DATA; } - Stream_Read_UINT32(s, minmaxinfo->windowId); /* windowId (4 bytes) */ - Stream_Read_UINT16(s, minmaxinfo->maxWidth); /* maxWidth (2 bytes) */ - Stream_Read_UINT16(s, minmaxinfo->maxHeight); /* maxHeight (2 bytes) */ - Stream_Read_UINT16(s, minmaxinfo->maxPosX); /* maxPosX (2 bytes) */ - Stream_Read_UINT16(s, minmaxinfo->maxPosY); /* maxPosY (2 bytes) */ - Stream_Read_UINT16(s, minmaxinfo->minTrackWidth); /* minTrackWidth (2 bytes) */ - Stream_Read_UINT16(s, minmaxinfo->minTrackHeight); /* minTrackHeight (2 bytes) */ - Stream_Read_UINT16(s, minmaxinfo->maxTrackWidth); /* maxTrackWidth (2 bytes) */ - Stream_Read_UINT16(s, minmaxinfo->maxTrackHeight); /* maxTrackHeight (2 bytes) */ + Stream_Read_UINT32(s, minmaxinfo->windowId); /* windowId (4 bytes) */ + Stream_Read_INT16(s, minmaxinfo->maxWidth); /* maxWidth (2 bytes) */ + Stream_Read_INT16(s, minmaxinfo->maxHeight); /* maxHeight (2 bytes) */ + Stream_Read_INT16(s, minmaxinfo->maxPosX); /* maxPosX (2 bytes) */ + Stream_Read_INT16(s, minmaxinfo->maxPosY); /* maxPosY (2 bytes) */ + Stream_Read_INT16(s, minmaxinfo->minTrackWidth); /* minTrackWidth (2 bytes) */ + Stream_Read_INT16(s, minmaxinfo->minTrackHeight); /* minTrackHeight (2 bytes) */ + Stream_Read_INT16(s, minmaxinfo->maxTrackWidth); /* maxTrackWidth (2 bytes) */ + Stream_Read_INT16(s, minmaxinfo->maxTrackHeight); /* maxTrackHeight (2 bytes) */ return CHANNEL_RC_OK; } @@ -216,25 +112,25 @@ static UINT rail_read_server_minmaxinfo_order(wStream* s, RAIL_MINMAXINFO_ORDER* * @return 0 on success, otherwise a Win32 error code */ static UINT rail_read_server_localmovesize_order(wStream* s, - RAIL_LOCALMOVESIZE_ORDER* localMoveSize) + RAIL_LOCALMOVESIZE_ORDER* localMoveSize) { UINT16 isMoveSizeStart; if (!s || !localMoveSize) return ERROR_INVALID_PARAMETER; - if (Stream_GetRemainingLength(s) < 12) + if (Stream_GetRemainingLength(s) < RAIL_LOCALMOVESIZE_ORDER_LENGTH) { WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); return ERROR_INVALID_DATA; } Stream_Read_UINT32(s, localMoveSize->windowId); /* windowId (4 bytes) */ - Stream_Read_UINT16(s, isMoveSizeStart); /* isMoveSizeStart (2 bytes) */ + Stream_Read_UINT16(s, isMoveSizeStart); /* isMoveSizeStart (2 bytes) */ localMoveSize->isMoveSizeStart = (isMoveSizeStart != 0) ? TRUE : FALSE; Stream_Read_UINT16(s, localMoveSize->moveSizeType); /* moveSizeType (2 bytes) */ - Stream_Read_UINT16(s, localMoveSize->posX); /* posX (2 bytes) */ - Stream_Read_UINT16(s, localMoveSize->posY); /* posY (2 bytes) */ + Stream_Read_INT16(s, localMoveSize->posX); /* posX (2 bytes) */ + Stream_Read_INT16(s, localMoveSize->posY); /* posY (2 bytes) */ return CHANNEL_RC_OK; } @@ -244,20 +140,21 @@ static UINT rail_read_server_localmovesize_order(wStream* s, * @return 0 on success, otherwise a Win32 error code */ static UINT rail_read_server_get_appid_resp_order(wStream* s, - RAIL_GET_APPID_RESP_ORDER* getAppidResp) + RAIL_GET_APPID_RESP_ORDER* getAppidResp) { if (!s || !getAppidResp) return ERROR_INVALID_PARAMETER; - if (Stream_GetRemainingLength(s) < 516) + if (Stream_GetRemainingLength(s) < RAIL_GET_APPID_RESP_ORDER_LENGTH) { WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); return ERROR_INVALID_DATA; } Stream_Read_UINT32(s, getAppidResp->windowId); /* windowId (4 bytes) */ - Stream_Read(s, (BYTE*) & (getAppidResp->applicationId), - 512); /* applicationId (256 UNICODE chars) */ + Stream_Read_UTF16_String( + s, getAppidResp->applicationId, + ARRAYSIZE(getAppidResp->applicationId)); /* applicationId (260 UNICODE chars) */ return CHANNEL_RC_OK; } @@ -271,7 +168,7 @@ static UINT rail_read_langbar_info_order(wStream* s, RAIL_LANGBAR_INFO_ORDER* la if (!s || !langbarInfo) return ERROR_INVALID_PARAMETER; - if (Stream_GetRemainingLength(s) < 4) + if (Stream_GetRemainingLength(s) < RAIL_LANGBAR_INFO_ORDER_LENGTH) { WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); return ERROR_INVALID_DATA; @@ -296,8 +193,9 @@ static UINT rail_write_client_status_order(wStream* s, const RAIL_CLIENT_STATUS_ * @return 0 on success, otherwise a Win32 error code */ static UINT rail_write_client_exec_order(wStream* s, UINT16 flags, - const RAIL_UNICODE_STRING* exeOrFile, const RAIL_UNICODE_STRING* workingDir, - const RAIL_UNICODE_STRING* arguments) + const RAIL_UNICODE_STRING* exeOrFile, + const RAIL_UNICODE_STRING* workingDir, + const RAIL_UNICODE_STRING* arguments) { UINT error; @@ -306,107 +204,41 @@ static UINT rail_write_client_exec_order(wStream* s, UINT16 flags, /* [MS-RDPERP] 2.2.2.3.1 Client Execute PDU (TS_RAIL_ORDER_EXEC) * Check argument limits */ - if ((exeOrFile->length > 520) || (workingDir->length > 520) || - (arguments->length > 16000)) + if ((exeOrFile->length > 520) || (workingDir->length > 520) || (arguments->length > 16000)) { WLog_ERR(TAG, - "TS_RAIL_ORDER_EXEC argument limits exceeded: ExeOrFile=%"PRIu16" [max=520], WorkingDir=%"PRIu16" [max=520], Arguments=%"PRIu16" [max=16000]", + "TS_RAIL_ORDER_EXEC argument limits exceeded: ExeOrFile=%" PRIu16 + " [max=520], WorkingDir=%" PRIu16 " [max=520], Arguments=%" PRIu16 " [max=16000]", exeOrFile->length, workingDir->length, arguments->length); return ERROR_BAD_ARGUMENTS; } - Stream_Write_UINT16(s, flags); /* flags (2 bytes) */ - Stream_Write_UINT16(s, exeOrFile->length); /* exeOrFileLength (2 bytes) */ + Stream_Write_UINT16(s, flags); /* flags (2 bytes) */ + Stream_Write_UINT16(s, exeOrFile->length); /* exeOrFileLength (2 bytes) */ Stream_Write_UINT16(s, workingDir->length); /* workingDirLength (2 bytes) */ - Stream_Write_UINT16(s, arguments->length); /* argumentsLength (2 bytes) */ + Stream_Write_UINT16(s, arguments->length); /* argumentsLength (2 bytes) */ if ((error = rail_write_unicode_string_value(s, exeOrFile))) { - WLog_ERR(TAG, "rail_write_unicode_string_value failed with error %"PRIu32"", error); + WLog_ERR(TAG, "rail_write_unicode_string_value failed with error %" PRIu32 "", error); return error; } if ((error = rail_write_unicode_string_value(s, workingDir))) { - WLog_ERR(TAG, "rail_write_unicode_string_value failed with error %"PRIu32"", error); + WLog_ERR(TAG, "rail_write_unicode_string_value failed with error %" PRIu32 "", error); return error; } if ((error = rail_write_unicode_string_value(s, arguments))) { - WLog_ERR(TAG, "rail_write_unicode_string_value failed with error %"PRIu32"", error); + WLog_ERR(TAG, "rail_write_unicode_string_value failed with error %" PRIu32 "", error); return error; } return error; } -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -UINT rail_write_client_sysparam_order(wStream* s, const RAIL_SYSPARAM_ORDER* sysparam) -{ - BYTE body; - UINT error = CHANNEL_RC_OK; - - if (!s || !sysparam) - return ERROR_INVALID_PARAMETER; - - Stream_Write_UINT32(s, sysparam->param); /* systemParam (4 bytes) */ - - switch (sysparam->param) - { - case SPI_SET_DRAG_FULL_WINDOWS: - body = sysparam->dragFullWindows ? 1 : 0; - Stream_Write_UINT8(s, body); - break; - - case SPI_SET_KEYBOARD_CUES: - body = sysparam->keyboardCues ? 1 : 0; - Stream_Write_UINT8(s, body); - break; - - case SPI_SET_KEYBOARD_PREF: - body = sysparam->keyboardPref ? 1 : 0; - Stream_Write_UINT8(s, body); - break; - - case SPI_SET_MOUSE_BUTTON_SWAP: - body = sysparam->mouseButtonSwap ? 1 : 0; - Stream_Write_UINT8(s, body); - break; - - case SPI_SET_WORK_AREA: - Stream_Write_UINT16(s, sysparam->workArea.left); /* left (2 bytes) */ - Stream_Write_UINT16(s, sysparam->workArea.top); /* top (2 bytes) */ - Stream_Write_UINT16(s, sysparam->workArea.right); /* right (2 bytes) */ - Stream_Write_UINT16(s, sysparam->workArea.bottom); /* bottom (2 bytes) */ - break; - - case SPI_DISPLAY_CHANGE: - Stream_Write_UINT16(s, sysparam->displayChange.left); /* left (2 bytes) */ - Stream_Write_UINT16(s, sysparam->displayChange.top); /* top (2 bytes) */ - Stream_Write_UINT16(s, sysparam->displayChange.right); /* right (2 bytes) */ - Stream_Write_UINT16(s, sysparam->displayChange.bottom); /* bottom (2 bytes) */ - break; - - case SPI_TASKBAR_POS: - Stream_Write_UINT16(s, sysparam->taskbarPos.left); /* left (2 bytes) */ - Stream_Write_UINT16(s, sysparam->taskbarPos.top); /* top (2 bytes) */ - Stream_Write_UINT16(s, sysparam->taskbarPos.right); /* right (2 bytes) */ - Stream_Write_UINT16(s, sysparam->taskbarPos.bottom); /* bottom (2 bytes) */ - break; - - case SPI_SET_HIGH_CONTRAST: - error = rail_write_high_contrast(s, &sysparam->highContrast); - break; - } - - return error; -} - static UINT rail_write_client_activate_order(wStream* s, const RAIL_ACTIVATE_ORDER* activate) { BYTE enabled; @@ -426,8 +258,8 @@ static UINT rail_write_client_sysmenu_order(wStream* s, const RAIL_SYSMENU_ORDER return ERROR_INVALID_PARAMETER; Stream_Write_UINT32(s, sysmenu->windowId); /* windowId (4 bytes) */ - Stream_Write_UINT16(s, sysmenu->left); /* left (2 bytes) */ - Stream_Write_UINT16(s, sysmenu->top); /* top (2 bytes) */ + Stream_Write_INT16(s, sysmenu->left); /* left (2 bytes) */ + Stream_Write_INT16(s, sysmenu->top); /* top (2 bytes) */ return ERROR_SUCCESS; } @@ -437,38 +269,38 @@ static UINT rail_write_client_syscommand_order(wStream* s, const RAIL_SYSCOMMAND return ERROR_INVALID_PARAMETER; Stream_Write_UINT32(s, syscommand->windowId); /* windowId (4 bytes) */ - Stream_Write_UINT16(s, syscommand->command); /* command (2 bytes) */ + Stream_Write_UINT16(s, syscommand->command); /* command (2 bytes) */ return ERROR_SUCCESS; } static UINT rail_write_client_notify_event_order(wStream* s, - const RAIL_NOTIFY_EVENT_ORDER* notifyEvent) + const RAIL_NOTIFY_EVENT_ORDER* notifyEvent) { if (!s || !notifyEvent) return ERROR_INVALID_PARAMETER; - Stream_Write_UINT32(s, notifyEvent->windowId); /* windowId (4 bytes) */ + Stream_Write_UINT32(s, notifyEvent->windowId); /* windowId (4 bytes) */ Stream_Write_UINT32(s, notifyEvent->notifyIconId); /* notifyIconId (4 bytes) */ - Stream_Write_UINT32(s, notifyEvent->message); /* notifyIconId (4 bytes) */ + Stream_Write_UINT32(s, notifyEvent->message); /* notifyIconId (4 bytes) */ return ERROR_SUCCESS; } static UINT rail_write_client_window_move_order(wStream* s, - const RAIL_WINDOW_MOVE_ORDER* windowMove) + const RAIL_WINDOW_MOVE_ORDER* windowMove) { if (!s || !windowMove) return ERROR_INVALID_PARAMETER; Stream_Write_UINT32(s, windowMove->windowId); /* windowId (4 bytes) */ - Stream_Write_UINT16(s, windowMove->left); /* left (2 bytes) */ - Stream_Write_UINT16(s, windowMove->top); /* top (2 bytes) */ - Stream_Write_UINT16(s, windowMove->right); /* right (2 bytes) */ - Stream_Write_UINT16(s, windowMove->bottom); /* bottom (2 bytes) */ + Stream_Write_INT16(s, windowMove->left); /* left (2 bytes) */ + Stream_Write_INT16(s, windowMove->top); /* top (2 bytes) */ + Stream_Write_INT16(s, windowMove->right); /* right (2 bytes) */ + Stream_Write_INT16(s, windowMove->bottom); /* bottom (2 bytes) */ return ERROR_SUCCESS; } static UINT rail_write_client_get_appid_req_order(wStream* s, - const RAIL_GET_APPID_REQ_ORDER* getAppidReq) + const RAIL_GET_APPID_REQ_ORDER* getAppidReq) { if (!s || !getAppidReq) return ERROR_INVALID_PARAMETER; @@ -486,62 +318,137 @@ static UINT rail_write_langbar_info_order(wStream* s, const RAIL_LANGBAR_INFO_OR return ERROR_SUCCESS; } +static UINT rail_write_languageime_info_order(wStream* s, + const RAIL_LANGUAGEIME_INFO_ORDER* langImeInfo) +{ + if (!s || !langImeInfo) + return ERROR_INVALID_PARAMETER; + + Stream_Write_UINT32(s, langImeInfo->ProfileType); + Stream_Write_UINT16(s, langImeInfo->LanguageID); + Stream_Write(s, &langImeInfo->LanguageProfileCLSID, sizeof(langImeInfo->LanguageProfileCLSID)); + Stream_Write(s, &langImeInfo->ProfileGUID, sizeof(langImeInfo->ProfileGUID)); + Stream_Write_UINT32(s, langImeInfo->KeyboardLayout); + return ERROR_SUCCESS; +} + +static UINT rail_write_compartment_info_order(wStream* s, + const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo) +{ + if (!s || !compartmentInfo) + return ERROR_INVALID_PARAMETER; + + Stream_Write_UINT32(s, compartmentInfo->ImeState); + Stream_Write_UINT32(s, compartmentInfo->ImeConvMode); + Stream_Write_UINT32(s, compartmentInfo->ImeSentenceMode); + Stream_Write_UINT32(s, compartmentInfo->KanaMode); + return ERROR_SUCCESS; +} + /** * Function description * * @return 0 on success, otherwise a Win32 error code */ -static UINT rail_recv_handshake_order(railPlugin* rail, RAIL_HANDSHAKE_ORDER* handshake, wStream* s) +static UINT rail_recv_handshake_order(railPlugin* rail, wStream* s) { RailClientContext* context = rail_get_client_interface(rail); + RAIL_HANDSHAKE_ORDER serverHandshake = { 0 }; UINT error; - if (!context || !handshake || !s) + if (!context || !s) return ERROR_INVALID_PARAMETER; - if ((error = rail_read_handshake_order(s, handshake))) + if ((error = rail_read_handshake_order(s, &serverHandshake))) { - WLog_ERR(TAG, "rail_read_handshake_order failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rail_read_handshake_order failed with error %" PRIu32 "!", error); return error; } + rail->channelBuildNumber = serverHandshake.buildNumber; + + if (rail->sendHandshake) + { + RAIL_HANDSHAKE_ORDER clientHandshake = { 0 }; + clientHandshake.buildNumber = 0x00001DB0; + error = context->ClientHandshake(context, &clientHandshake); + } + + if (error != CHANNEL_RC_OK) + return error; + if (context->custom) { - IFCALLRET(context->ServerHandshake, error, context, handshake); + IFCALLRET(context->ServerHandshake, error, context, &serverHandshake); if (error) - WLog_ERR(TAG, "context.ServerHandshake failed with error %"PRIu32"", error); + WLog_ERR(TAG, "context.ServerHandshake failed with error %" PRIu32 "", error); } return error; } +static BOOL rail_is_feature_supported(const rdpContext* context, UINT32 featureMask) +{ + UINT32 supported, masked; + + if (!context || !context->settings) + return FALSE; + + supported = context->settings->RemoteApplicationSupportLevel & + context->settings->RemoteApplicationSupportMask; + masked = (supported & featureMask); + + if (masked != featureMask) + return FALSE; + + return TRUE; +} + /** * Function description * * @return 0 on success, otherwise a Win32 error code */ -static UINT rail_recv_handshake_ex_order(railPlugin* rail, RAIL_HANDSHAKE_EX_ORDER* handshakeEx, - wStream* s) +static UINT rail_recv_handshake_ex_order(railPlugin* rail, wStream* s) { RailClientContext* context = rail_get_client_interface(rail); + RAIL_HANDSHAKE_EX_ORDER serverHandshake = { 0 }; UINT error; - if (!context || !handshakeEx || !s) + if (!rail || !context || !s) return ERROR_INVALID_PARAMETER; - if ((error = rail_read_handshake_ex_order(s, handshakeEx))) + if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_HANDSHAKE_EX_SUPPORTED)) + return ERROR_BAD_CONFIGURATION; + + if ((error = rail_read_handshake_ex_order(s, &serverHandshake))) { - WLog_ERR(TAG, "rail_read_handshake_ex_order failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rail_read_handshake_ex_order failed with error %" PRIu32 "!", error); return error; } + rail->channelBuildNumber = serverHandshake.buildNumber; + rail->channelFlags = serverHandshake.railHandshakeFlags; + + if (rail->sendHandshake) + { + RAIL_HANDSHAKE_ORDER clientHandshake = { 0 }; + clientHandshake.buildNumber = 0x00001DB0; + /* 2.2.2.2.3 HandshakeEx PDU (TS_RAIL_ORDER_HANDSHAKE_EX) + * Client response is really a Handshake PDU */ + error = context->ClientHandshake(context, &clientHandshake); + } + + if (error != CHANNEL_RC_OK) + return error; + if (context->custom) { - IFCALLRET(context->ClientHandshakeEx, error, context, handshakeEx); + IFCALLRET(context->ServerHandshakeEx, error, context, &serverHandshake); if (error) - WLog_ERR(TAG, "context.ClientHandshakeEx failed with error %"PRIu32"", error); + WLog_ERR(TAG, "context.ServerHandshakeEx failed with error %" PRIu32 "", error); } return error; @@ -552,31 +459,31 @@ static UINT rail_recv_handshake_ex_order(railPlugin* rail, RAIL_HANDSHAKE_EX_ORD * * @return 0 on success, otherwise a Win32 error code */ -static UINT rail_recv_exec_result_order(railPlugin* rail, RAIL_EXEC_RESULT_ORDER* execResult, - wStream* s) +static UINT rail_recv_exec_result_order(railPlugin* rail, wStream* s) { RailClientContext* context = rail_get_client_interface(rail); + RAIL_EXEC_RESULT_ORDER execResult = { 0 }; UINT error; - if (!context || !execResult || !s) + if (!context || !s) return ERROR_INVALID_PARAMETER; - ZeroMemory(execResult, sizeof(RAIL_EXEC_RESULT_ORDER)); - - if ((error = rail_read_server_exec_result_order(s, execResult))) + if ((error = rail_read_server_exec_result_order(s, &execResult))) { - WLog_ERR(TAG, "rail_read_server_exec_result_order failed with error %"PRIu32"!", error); - return error; + WLog_ERR(TAG, "rail_read_server_exec_result_order failed with error %" PRIu32 "!", error); + goto fail; } if (context->custom) { - IFCALLRET(context->ServerExecuteResult, error, context, execResult); + IFCALLRET(context->ServerExecuteResult, error, context, &execResult); if (error) - WLog_ERR(TAG, "context.ServerExecuteResult failed with error %"PRIu32"", error); + WLog_ERR(TAG, "context.ServerExecuteResult failed with error %" PRIu32 "", error); } +fail: + free(execResult.exeOrFile.string); return error; } @@ -585,27 +492,29 @@ static UINT rail_recv_exec_result_order(railPlugin* rail, RAIL_EXEC_RESULT_ORDER * * @return 0 on success, otherwise a Win32 error code */ -static UINT rail_recv_server_sysparam_order(railPlugin* rail, RAIL_SYSPARAM_ORDER* sysparam, - wStream* s) +static UINT rail_recv_server_sysparam_order(railPlugin* rail, wStream* s) { RailClientContext* context = rail_get_client_interface(rail); + RAIL_SYSPARAM_ORDER sysparam; UINT error; + BOOL extendedSpiSupported; - if (!context || !sysparam || !s) + if (!context || !s) return ERROR_INVALID_PARAMETER; - if ((error = rail_read_server_sysparam_order(s, sysparam))) + extendedSpiSupported = rail_is_extended_spi_supported(rail->channelFlags); + if ((error = rail_read_sysparam_order(s, &sysparam, extendedSpiSupported))) { - WLog_ERR(TAG, "rail_read_server_sysparam_order failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rail_read_sysparam_order failed with error %" PRIu32 "!", error); return error; } if (context->custom) { - IFCALLRET(context->ServerSystemParam, error, context, sysparam); + IFCALLRET(context->ServerSystemParam, error, context, &sysparam); if (error) - WLog_ERR(TAG, "context.ServerSystemParam failed with error %"PRIu32"", error); + WLog_ERR(TAG, "context.ServerSystemParam failed with error %" PRIu32 "", error); } return error; @@ -616,27 +525,27 @@ static UINT rail_recv_server_sysparam_order(railPlugin* rail, RAIL_SYSPARAM_ORDE * * @return 0 on success, otherwise a Win32 error code */ -static UINT rail_recv_server_minmaxinfo_order(railPlugin* rail, RAIL_MINMAXINFO_ORDER* minMaxInfo, - wStream* s) +static UINT rail_recv_server_minmaxinfo_order(railPlugin* rail, wStream* s) { RailClientContext* context = rail_get_client_interface(rail); + RAIL_MINMAXINFO_ORDER minMaxInfo = { 0 }; UINT error; - if (!context || !minMaxInfo || !s) + if (!context || !s) return ERROR_INVALID_PARAMETER; - if ((error = rail_read_server_minmaxinfo_order(s, minMaxInfo))) + if ((error = rail_read_server_minmaxinfo_order(s, &minMaxInfo))) { - WLog_ERR(TAG, "rail_read_server_minmaxinfo_order failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rail_read_server_minmaxinfo_order failed with error %" PRIu32 "!", error); return error; } if (context->custom) { - IFCALLRET(context->ServerMinMaxInfo, error, context, minMaxInfo); + IFCALLRET(context->ServerMinMaxInfo, error, context, &minMaxInfo); if (error) - WLog_ERR(TAG, "context.ServerMinMaxInfo failed with error %"PRIu32"", error); + WLog_ERR(TAG, "context.ServerMinMaxInfo failed with error %" PRIu32 "", error); } return error; @@ -647,28 +556,27 @@ static UINT rail_recv_server_minmaxinfo_order(railPlugin* rail, RAIL_MINMAXINFO_ * * @return 0 on success, otherwise a Win32 error code */ -static UINT rail_recv_server_localmovesize_order(railPlugin* rail, - RAIL_LOCALMOVESIZE_ORDER* localMoveSize, - wStream* s) +static UINT rail_recv_server_localmovesize_order(railPlugin* rail, wStream* s) { RailClientContext* context = rail_get_client_interface(rail); + RAIL_LOCALMOVESIZE_ORDER localMoveSize = { 0 }; UINT error; - if (!context || !localMoveSize || !s) + if (!context || !s) return ERROR_INVALID_PARAMETER; - if ((error = rail_read_server_localmovesize_order(s, localMoveSize))) + if ((error = rail_read_server_localmovesize_order(s, &localMoveSize))) { - WLog_ERR(TAG, "rail_read_server_localmovesize_order failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rail_read_server_localmovesize_order failed with error %" PRIu32 "!", error); return error; } if (context->custom) { - IFCALLRET(context->ServerLocalMoveSize, error, context, localMoveSize); + IFCALLRET(context->ServerLocalMoveSize, error, context, &localMoveSize); if (error) - WLog_ERR(TAG, "context.ServerLocalMoveSize failed with error %"PRIu32"", error); + WLog_ERR(TAG, "context.ServerLocalMoveSize failed with error %" PRIu32 "", error); } return error; @@ -679,27 +587,28 @@ static UINT rail_recv_server_localmovesize_order(railPlugin* rail, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rail_recv_server_get_appid_resp_order(railPlugin* rail, - RAIL_GET_APPID_RESP_ORDER* getAppIdResp, wStream* s) +static UINT rail_recv_server_get_appid_resp_order(railPlugin* rail, wStream* s) { RailClientContext* context = rail_get_client_interface(rail); + RAIL_GET_APPID_RESP_ORDER getAppIdResp = { 0 }; UINT error; - if (!context || !getAppIdResp || !s) + if (!context || !s) return ERROR_INVALID_PARAMETER; - if ((error = rail_read_server_get_appid_resp_order(s, getAppIdResp))) + if ((error = rail_read_server_get_appid_resp_order(s, &getAppIdResp))) { - WLog_ERR(TAG, "rail_read_server_get_appid_resp_order failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rail_read_server_get_appid_resp_order failed with error %" PRIu32 "!", + error); return error; } if (context->custom) { - IFCALLRET(context->ServerGetAppIdResponse, error, context, getAppIdResp); + IFCALLRET(context->ServerGetAppIdResponse, error, context, &getAppIdResp); if (error) - WLog_ERR(TAG, "context.ServerGetAppIdResponse failed with error %"PRIu32"", error); + WLog_ERR(TAG, "context.ServerGetAppIdResponse failed with error %" PRIu32 "", error); } return error; @@ -710,27 +619,286 @@ static UINT rail_recv_server_get_appid_resp_order(railPlugin* rail, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rail_recv_langbar_info_order(railPlugin* rail, RAIL_LANGBAR_INFO_ORDER* langBarInfo, - wStream* s) +static UINT rail_recv_langbar_info_order(railPlugin* rail, wStream* s) +{ + RailClientContext* context = rail_get_client_interface(rail); + RAIL_LANGBAR_INFO_ORDER langBarInfo = { 0 }; + UINT error; + + if (!context) + return ERROR_INVALID_PARAMETER; + + if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED)) + return ERROR_BAD_CONFIGURATION; + + if ((error = rail_read_langbar_info_order(s, &langBarInfo))) + { + WLog_ERR(TAG, "rail_read_langbar_info_order failed with error %" PRIu32 "!", error); + return error; + } + + if (context->custom) + { + IFCALLRET(context->ServerLanguageBarInfo, error, context, &langBarInfo); + + if (error) + WLog_ERR(TAG, "context.ServerLanguageBarInfo failed with error %" PRIu32 "", error); + } + + return error; +} + +static UINT rail_read_taskbar_info_order(wStream* s, RAIL_TASKBAR_INFO_ORDER* taskbarInfo) +{ + if (!s || !taskbarInfo) + return ERROR_INVALID_PARAMETER; + + if (Stream_GetRemainingLength(s) < RAIL_TASKBAR_INFO_ORDER_LENGTH) + { + WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT32(s, taskbarInfo->TaskbarMessage); + Stream_Read_UINT32(s, taskbarInfo->WindowIdTab); + Stream_Read_UINT32(s, taskbarInfo->Body); + return CHANNEL_RC_OK; +} + +static UINT rail_recv_taskbar_info_order(railPlugin* rail, wStream* s) +{ + RailClientContext* context = rail_get_client_interface(rail); + RAIL_TASKBAR_INFO_ORDER taskBarInfo = { 0 }; + UINT error; + + if (!context) + return ERROR_INVALID_PARAMETER; + + /* 2.2.2.14.1 Taskbar Tab Info PDU (TS_RAIL_ORDER_TASKBARINFO) + * server -> client message only supported if announced. */ + if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_SHELL_INTEGRATION_SUPPORTED)) + return ERROR_BAD_CONFIGURATION; + + if ((error = rail_read_taskbar_info_order(s, &taskBarInfo))) + { + WLog_ERR(TAG, "rail_read_langbar_info_order failed with error %" PRIu32 "!", error); + return error; + } + + if (context->custom) + { + IFCALLRET(context->ServerTaskBarInfo, error, context, &taskBarInfo); + + if (error) + WLog_ERR(TAG, "context.ServerTaskBarInfo failed with error %" PRIu32 "", error); + } + + return error; +} + +static UINT rail_read_zorder_sync_order(wStream* s, RAIL_ZORDER_SYNC* zorder) +{ + if (!s || !zorder) + return ERROR_INVALID_PARAMETER; + + if (Stream_GetRemainingLength(s) < RAIL_Z_ORDER_SYNC_ORDER_LENGTH) + { + WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT32(s, zorder->windowIdMarker); + return CHANNEL_RC_OK; +} + +static UINT rail_recv_zorder_sync_order(railPlugin* rail, wStream* s) { RailClientContext* context = rail_get_client_interface(rail); + RAIL_ZORDER_SYNC zorder = { 0 }; UINT error; - if (!context || !langBarInfo) + if (!context) return ERROR_INVALID_PARAMETER; - if ((error = rail_read_langbar_info_order(s, langBarInfo))) + if ((rail->clientStatus.flags & TS_RAIL_CLIENTSTATUS_ZORDER_SYNC) == 0) + return ERROR_INVALID_DATA; + + if ((error = rail_read_zorder_sync_order(s, &zorder))) { - WLog_ERR(TAG, "rail_read_langbar_info_order failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rail_read_zorder_sync_order failed with error %" PRIu32 "!", error); return error; } if (context->custom) { - IFCALLRET(context->ServerLanguageBarInfo, error, context, langBarInfo); + IFCALLRET(context->ServerZOrderSync, error, context, &zorder); if (error) - WLog_ERR(TAG, "context.ServerLanguageBarInfo failed with error %"PRIu32"", error); + WLog_ERR(TAG, "context.ServerZOrderSync failed with error %" PRIu32 "", error); + } + + return error; +} + +static UINT rail_read_cloak_order(wStream* s, RAIL_CLOAK* cloak) +{ + BYTE cloaked; + + if (Stream_GetRemainingLength(s) < RAIL_CLOAK_ORDER_LENGTH) + { + WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT32(s, cloak->windowId); /* WindowId (4 bytes) */ + Stream_Read_UINT8(s, cloaked); /* Cloaked (1 byte) */ + cloak->cloak = (cloaked != 0) ? TRUE : FALSE; + return CHANNEL_RC_OK; +} + +static UINT rail_recv_cloak_order(railPlugin* rail, wStream* s) +{ + RailClientContext* context = rail_get_client_interface(rail); + RAIL_CLOAK cloak = { 0 }; + UINT error; + + if (!context) + return ERROR_INVALID_PARAMETER; + + /* 2.2.2.12.1 Window Cloak State Change PDU (TS_RAIL_ORDER_CLOAK) + * server -> client message only supported if announced. */ + if ((rail->clientStatus.flags & TS_RAIL_CLIENTSTATUS_BIDIRECTIONAL_CLOAK_SUPPORTED) == 0) + return ERROR_INVALID_DATA; + + if ((error = rail_read_cloak_order(s, &cloak))) + { + WLog_ERR(TAG, "rail_read_zorder_sync_order failed with error %" PRIu32 "!", error); + return error; + } + + if (context->custom) + { + IFCALLRET(context->ServerCloak, error, context, &cloak); + + if (error) + WLog_ERR(TAG, "context.ServerZOrderSync failed with error %" PRIu32 "", error); + } + + return error; +} + +static UINT rail_read_power_display_request_order(wStream* s, RAIL_POWER_DISPLAY_REQUEST* power) +{ + UINT32 active; + + if (!s || !power) + return ERROR_INVALID_PARAMETER; + + if (Stream_GetRemainingLength(s) < RAIL_POWER_DISPLAY_REQUEST_ORDER_LENGTH) + { + WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT32(s, active); + power->active = active != 0; + return CHANNEL_RC_OK; +} + +static UINT rail_recv_power_display_request_order(railPlugin* rail, wStream* s) +{ + RailClientContext* context = rail_get_client_interface(rail); + RAIL_POWER_DISPLAY_REQUEST power = { 0 }; + UINT error; + + if (!context) + return ERROR_INVALID_PARAMETER; + + /* 2.2.2.13.1 Power Display Request PDU(TS_RAIL_ORDER_POWER_DISPLAY_REQUEST) + */ + if ((rail->clientStatus.flags & TS_RAIL_CLIENTSTATUS_POWER_DISPLAY_REQUEST_SUPPORTED) == 0) + return ERROR_INVALID_DATA; + + if ((error = rail_read_power_display_request_order(s, &power))) + { + WLog_ERR(TAG, "rail_read_zorder_sync_order failed with error %" PRIu32 "!", error); + return error; + } + + if (context->custom) + { + IFCALLRET(context->ServerPowerDisplayRequest, error, context, &power); + + if (error) + WLog_ERR(TAG, "context.ServerPowerDisplayRequest failed with error %" PRIu32 "", error); + } + + return error; +} + +static UINT rail_read_get_application_id_extended_response_order(wStream* s, + RAIL_GET_APPID_RESP_EX* id) +{ + if (!s || !id) + return ERROR_INVALID_PARAMETER; + + if (Stream_GetRemainingLength(s) < 4) + { + WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT32(s, id->windowID); + + if (!Stream_Read_UTF16_String(s, id->applicationID, ARRAYSIZE(id->applicationID))) + return ERROR_INVALID_DATA; + + if (_wcsnlen(id->applicationID, ARRAYSIZE(id->applicationID)) >= ARRAYSIZE(id->applicationID)) + return ERROR_INVALID_DATA; + + if (Stream_GetRemainingLength(s) < 4) + { + WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT32(s, id->processId); + + if (!Stream_Read_UTF16_String(s, id->processImageName, ARRAYSIZE(id->processImageName))) + return ERROR_INVALID_DATA; + + if (_wcsnlen(id->applicationID, ARRAYSIZE(id->processImageName)) >= + ARRAYSIZE(id->processImageName)) + return ERROR_INVALID_DATA; + + return CHANNEL_RC_OK; +} + +static UINT rail_recv_get_application_id_extended_response_order(railPlugin* rail, wStream* s) +{ + RailClientContext* context = rail_get_client_interface(rail); + RAIL_GET_APPID_RESP_EX id = { 0 }; + UINT error; + + if (!context) + return ERROR_INVALID_PARAMETER; + + if ((error = rail_read_get_application_id_extended_response_order(s, &id))) + { + WLog_ERR(TAG, + "rail_read_get_application_id_extended_response_order failed with error %" PRIu32 + "!", + error); + return error; + } + + if (context->custom) + { + IFCALLRET(context->ServerGetAppidResponseExtended, error, context, &id); + + if (error) + WLog_ERR(TAG, "context.ServerGetAppidResponseExtended failed with error %" PRIu32 "", + error); } return error; @@ -752,67 +920,56 @@ UINT rail_order_recv(railPlugin* rail, wStream* s) if ((error = rail_read_pdu_header(s, &orderType, &orderLength))) { - WLog_ERR(TAG, "rail_read_pdu_header failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rail_read_pdu_header failed with error %" PRIu32 "!", error); return error; } - WLog_Print(rail->log, WLOG_DEBUG, "Received %s PDU, length:%"PRIu16"", - RAIL_ORDER_TYPE_STRINGS[((orderType & 0xF0) >> 3) + (orderType & 0x0F)], orderLength); + WLog_Print(rail->log, WLOG_DEBUG, "Received %s PDU, length:%" PRIu16 "", + rail_get_order_type_string(orderType), orderLength); switch (orderType) { - case RDP_RAIL_ORDER_HANDSHAKE: - { - RAIL_HANDSHAKE_ORDER handshake; - return rail_recv_handshake_order(rail, &handshake, s); - } - - case RDP_RAIL_ORDER_HANDSHAKE_EX: - { - RAIL_HANDSHAKE_EX_ORDER handshakeEx; - return rail_recv_handshake_ex_order(rail, &handshakeEx, s); - } - - case RDP_RAIL_ORDER_EXEC_RESULT: - { - RAIL_EXEC_RESULT_ORDER execResult = { 0 }; - error = rail_recv_exec_result_order(rail, &execResult, s); - free(execResult.exeOrFile.string); - return error; - } - - case RDP_RAIL_ORDER_SYSPARAM: - { - RAIL_SYSPARAM_ORDER sysparam; - return rail_recv_server_sysparam_order(rail, &sysparam, s); - } - - case RDP_RAIL_ORDER_MINMAXINFO: - { - RAIL_MINMAXINFO_ORDER minMaxInfo; - return rail_recv_server_minmaxinfo_order(rail, &minMaxInfo, s); - } - - case RDP_RAIL_ORDER_LOCALMOVESIZE: - { - RAIL_LOCALMOVESIZE_ORDER localMoveSize; - return rail_recv_server_localmovesize_order(rail, &localMoveSize, s); - } - - case RDP_RAIL_ORDER_GET_APPID_RESP: - { - RAIL_GET_APPID_RESP_ORDER getAppIdResp; - return rail_recv_server_get_appid_resp_order(rail, &getAppIdResp, s); - } - - case RDP_RAIL_ORDER_LANGBARINFO: - { - RAIL_LANGBAR_INFO_ORDER langBarInfo; - return rail_recv_langbar_info_order(rail, &langBarInfo, s); - } + case TS_RAIL_ORDER_HANDSHAKE: + return rail_recv_handshake_order(rail, s); + + case TS_RAIL_ORDER_HANDSHAKE_EX: + return rail_recv_handshake_ex_order(rail, s); + + case TS_RAIL_ORDER_EXEC_RESULT: + return rail_recv_exec_result_order(rail, s); + + case TS_RAIL_ORDER_SYSPARAM: + return rail_recv_server_sysparam_order(rail, s); + + case TS_RAIL_ORDER_MINMAXINFO: + return rail_recv_server_minmaxinfo_order(rail, s); + + case TS_RAIL_ORDER_LOCALMOVESIZE: + return rail_recv_server_localmovesize_order(rail, s); + + case TS_RAIL_ORDER_GET_APPID_RESP: + return rail_recv_server_get_appid_resp_order(rail, s); + + case TS_RAIL_ORDER_LANGBARINFO: + return rail_recv_langbar_info_order(rail, s); + + case TS_RAIL_ORDER_TASKBARINFO: + return rail_recv_taskbar_info_order(rail, s); + + case TS_RAIL_ORDER_ZORDER_SYNC: + return rail_recv_zorder_sync_order(rail, s); + + case TS_RAIL_ORDER_CLOAK: + return rail_recv_cloak_order(rail, s); + + case TS_RAIL_ORDER_POWER_DISPLAY_REQUEST: + return rail_recv_power_display_request_order(rail, s); + + case TS_RAIL_ORDER_GET_APPID_RESP_EX: + return rail_recv_get_application_id_extended_response_order(rail, s); default: - WLog_ERR(TAG, "Unknown RAIL PDU order reveived."); + WLog_ERR(TAG, "Unknown RAIL PDU order reveived."); return ERROR_INVALID_DATA; } @@ -841,7 +998,7 @@ UINT rail_send_handshake_order(railPlugin* rail, const RAIL_HANDSHAKE_ORDER* han } rail_write_handshake_order(s, handshake); - error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_HANDSHAKE); + error = rail_send_pdu(rail, s, TS_RAIL_ORDER_HANDSHAKE); Stream_Free(s, TRUE); return error; } @@ -868,7 +1025,7 @@ UINT rail_send_handshake_ex_order(railPlugin* rail, const RAIL_HANDSHAKE_EX_ORDE } rail_write_handshake_ex_order(s, handshakeEx); - error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_HANDSHAKE_EX); + error = rail_send_pdu(rail, s, TS_RAIL_ORDER_HANDSHAKE_EX); Stream_Free(s, TRUE); return error; } @@ -886,6 +1043,7 @@ UINT rail_send_client_status_order(railPlugin* rail, const RAIL_CLIENT_STATUS_OR if (!rail || !clientStatus) return ERROR_INVALID_PARAMETER; + rail->clientStatus = *clientStatus; s = rail_pdu_init(RAIL_CLIENT_STATUS_ORDER_LENGTH); if (!s) @@ -897,7 +1055,7 @@ UINT rail_send_client_status_order(railPlugin* rail, const RAIL_CLIENT_STATUS_OR error = rail_write_client_status_order(s, clientStatus); if (error == ERROR_SUCCESS) - error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_CLIENTSTATUS); + error = rail_send_pdu(rail, s, TS_RAIL_ORDER_CLIENTSTATUS); Stream_Free(s, TRUE); return error; @@ -909,7 +1067,8 @@ UINT rail_send_client_status_order(railPlugin* rail, const RAIL_CLIENT_STATUS_OR * @return 0 on success, otherwise a Win32 error code */ UINT rail_send_client_exec_order(railPlugin* rail, UINT16 flags, - const RAIL_UNICODE_STRING* exeOrFile, const RAIL_UNICODE_STRING* workingDir, + const RAIL_UNICODE_STRING* exeOrFile, + const RAIL_UNICODE_STRING* workingDir, const RAIL_UNICODE_STRING* arguments) { wStream* s; @@ -919,10 +1078,7 @@ UINT rail_send_client_exec_order(railPlugin* rail, UINT16 flags, if (!rail || !exeOrFile || !workingDir || !arguments) return ERROR_INVALID_PARAMETER; - length = RAIL_EXEC_ORDER_LENGTH + - exeOrFile->length + - workingDir->length + - arguments->length; + length = RAIL_EXEC_ORDER_LENGTH + exeOrFile->length + workingDir->length + arguments->length; s = rail_pdu_init(length); if (!s) @@ -933,13 +1089,13 @@ UINT rail_send_client_exec_order(railPlugin* rail, UINT16 flags, if ((error = rail_write_client_exec_order(s, flags, exeOrFile, workingDir, arguments))) { - WLog_ERR(TAG, "rail_write_client_exec_order failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rail_write_client_exec_order failed with error %" PRIu32 "!", error); goto out; } - if ((error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_EXEC))) + if ((error = rail_send_pdu(rail, s, TS_RAIL_ORDER_EXEC))) { - WLog_ERR(TAG, "rail_send_pdu failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rail_send_pdu failed with error %" PRIu32 "!", error); goto out; } @@ -953,40 +1109,15 @@ out: * * @return 0 on success, otherwise a Win32 error code */ -static UINT rail_send_client_sysparam_order(railPlugin* rail, const RAIL_SYSPARAM_ORDER* sysparam) +UINT rail_send_client_activate_order(railPlugin* rail, const RAIL_ACTIVATE_ORDER* activate) { wStream* s; - size_t length = RAIL_SYSPARAM_ORDER_LENGTH; UINT error; - if (!rail || !sysparam) + if (!rail || !activate) return ERROR_INVALID_PARAMETER; - switch (sysparam->param) - { - case SPI_SET_DRAG_FULL_WINDOWS: - case SPI_SET_KEYBOARD_CUES: - case SPI_SET_KEYBOARD_PREF: - case SPI_SET_MOUSE_BUTTON_SWAP: - length += 1; - break; - - case SPI_SET_WORK_AREA: - case SPI_DISPLAY_CHANGE: - case SPI_TASKBAR_POS: - length += 8; - break; - - case SPI_SET_HIGH_CONTRAST: - length += sysparam->highContrast.colorSchemeLength + 10; - break; - - default: - length += 8; - break; - } - - s = rail_pdu_init(length); + s = rail_pdu_init(RAIL_ACTIVATE_ORDER_LENGTH); if (!s) { @@ -994,19 +1125,11 @@ static UINT rail_send_client_sysparam_order(railPlugin* rail, const RAIL_SYSPARA return CHANNEL_RC_NO_MEMORY; } - if ((error = rail_write_client_sysparam_order(s, sysparam))) - { - WLog_ERR(TAG, "rail_write_client_sysparam_order failed with error %"PRIu32"!", error); - goto out; - } + error = rail_write_client_activate_order(s, activate); - if ((error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_SYSPARAM))) - { - WLog_ERR(TAG, "rail_send_pdu failed with error %"PRIu32"!", error); - goto out; - } + if (error == ERROR_SUCCESS) + error = rail_send_pdu(rail, s, TS_RAIL_ORDER_ACTIVATE); -out: Stream_Free(s, TRUE); return error; } @@ -1016,90 +1139,58 @@ out: * * @return 0 on success, otherwise a Win32 error code */ -static UINT rail_send_client_sysparams_order(railPlugin* rail, RAIL_SYSPARAM_ORDER* sysparam) +UINT rail_send_client_sysmenu_order(railPlugin* rail, const RAIL_SYSMENU_ORDER* sysmenu) { - UINT error = CHANNEL_RC_OK; + wStream* s; + UINT error; - if (!rail || !sysparam) + if (!rail || !sysmenu) return ERROR_INVALID_PARAMETER; - if (sysparam->params & SPI_MASK_SET_HIGH_CONTRAST) - { - sysparam->param = SPI_SET_HIGH_CONTRAST; - - if ((error = rail_send_client_sysparam_order(rail, sysparam))) - { - WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %"PRIu32"!", error); - return error; - } - } + s = rail_pdu_init(RAIL_SYSMENU_ORDER_LENGTH); - if (sysparam->params & SPI_MASK_TASKBAR_POS) + if (!s) { - sysparam->param = SPI_TASKBAR_POS; - - if ((error = rail_send_client_sysparam_order(rail, sysparam))) - { - WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %"PRIu32"!", error); - return error; - } + WLog_ERR(TAG, "rail_pdu_init failed!"); + return CHANNEL_RC_NO_MEMORY; } - if (sysparam->params & SPI_MASK_SET_MOUSE_BUTTON_SWAP) - { - sysparam->param = SPI_SET_MOUSE_BUTTON_SWAP; + error = rail_write_client_sysmenu_order(s, sysmenu); - if ((error = rail_send_client_sysparam_order(rail, sysparam))) - { - WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %"PRIu32"!", error); - return error; - } - } + if (error == ERROR_SUCCESS) + error = rail_send_pdu(rail, s, TS_RAIL_ORDER_SYSMENU); - if (sysparam->params & SPI_MASK_SET_KEYBOARD_PREF) - { - sysparam->param = SPI_SET_KEYBOARD_PREF; + Stream_Free(s, TRUE); + return error; +} - if ((error = rail_send_client_sysparam_order(rail, sysparam))) - { - WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %"PRIu32"!", error); - return error; - } - } +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +UINT rail_send_client_syscommand_order(railPlugin* rail, const RAIL_SYSCOMMAND_ORDER* syscommand) +{ + wStream* s; + UINT error; - if (sysparam->params & SPI_MASK_SET_DRAG_FULL_WINDOWS) - { - sysparam->param = SPI_SET_DRAG_FULL_WINDOWS; + if (!rail || !syscommand) + return ERROR_INVALID_PARAMETER; - if ((error = rail_send_client_sysparam_order(rail, sysparam))) - { - WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %"PRIu32"!", error); - return error; - } - } + s = rail_pdu_init(RAIL_SYSCOMMAND_ORDER_LENGTH); - if (sysparam->params & SPI_MASK_SET_KEYBOARD_CUES) + if (!s) { - sysparam->param = SPI_SET_KEYBOARD_CUES; - - if ((error = rail_send_client_sysparam_order(rail, sysparam))) - { - WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %"PRIu32"!", error); - return error; - } + WLog_ERR(TAG, "rail_pdu_init failed!"); + return CHANNEL_RC_NO_MEMORY; } - if (sysparam->params & SPI_MASK_SET_WORK_AREA) - { - sysparam->param = SPI_SET_WORK_AREA; + error = rail_write_client_syscommand_order(s, syscommand); - if ((error = rail_send_client_sysparam_order(rail, sysparam))) - { - WLog_ERR(TAG, "rail_send_client_sysparam_order failed with error %"PRIu32"!", error); - return error; - } - } + if (error == ERROR_SUCCESS) + error = rail_send_pdu(rail, s, TS_RAIL_ORDER_SYSCOMMAND); + Stream_Free(s, TRUE); return error; } @@ -1108,15 +1199,16 @@ static UINT rail_send_client_sysparams_order(railPlugin* rail, RAIL_SYSPARAM_ORD * * @return 0 on success, otherwise a Win32 error code */ -UINT rail_send_client_activate_order(railPlugin* rail, const RAIL_ACTIVATE_ORDER* activate) +UINT rail_send_client_notify_event_order(railPlugin* rail, + const RAIL_NOTIFY_EVENT_ORDER* notifyEvent) { wStream* s; UINT error; - if (!rail || !activate) + if (!rail || !notifyEvent) return ERROR_INVALID_PARAMETER; - s = rail_pdu_init(RAIL_ACTIVATE_ORDER_LENGTH); + s = rail_pdu_init(RAIL_NOTIFY_EVENT_ORDER_LENGTH); if (!s) { @@ -1124,10 +1216,10 @@ UINT rail_send_client_activate_order(railPlugin* rail, const RAIL_ACTIVATE_ORDER return CHANNEL_RC_NO_MEMORY; } - error = rail_write_client_activate_order(s, activate); + error = rail_write_client_notify_event_order(s, notifyEvent); - if (error == ERROR_SUCCESS) - error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_ACTIVATE); + if (ERROR_SUCCESS == error) + error = rail_send_pdu(rail, s, TS_RAIL_ORDER_NOTIFY_EVENT); Stream_Free(s, TRUE); return error; @@ -1138,15 +1230,15 @@ UINT rail_send_client_activate_order(railPlugin* rail, const RAIL_ACTIVATE_ORDER * * @return 0 on success, otherwise a Win32 error code */ -UINT rail_send_client_sysmenu_order(railPlugin* rail, const RAIL_SYSMENU_ORDER* sysmenu) +UINT rail_send_client_window_move_order(railPlugin* rail, const RAIL_WINDOW_MOVE_ORDER* windowMove) { wStream* s; UINT error; - if (!rail || !sysmenu) + if (!rail || !windowMove) return ERROR_INVALID_PARAMETER; - s = rail_pdu_init(RAIL_SYSMENU_ORDER_LENGTH); + s = rail_pdu_init(RAIL_WINDOW_MOVE_ORDER_LENGTH); if (!s) { @@ -1154,10 +1246,10 @@ UINT rail_send_client_sysmenu_order(railPlugin* rail, const RAIL_SYSMENU_ORDER* return CHANNEL_RC_NO_MEMORY; } - error = rail_write_client_sysmenu_order(s, sysmenu); + error = rail_write_client_window_move_order(s, windowMove); if (error == ERROR_SUCCESS) - error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_SYSMENU); + error = rail_send_pdu(rail, s, TS_RAIL_ORDER_WINDOWMOVE); Stream_Free(s, TRUE); return error; @@ -1168,15 +1260,16 @@ UINT rail_send_client_sysmenu_order(railPlugin* rail, const RAIL_SYSMENU_ORDER* * * @return 0 on success, otherwise a Win32 error code */ -UINT rail_send_client_syscommand_order(railPlugin* rail, const RAIL_SYSCOMMAND_ORDER* syscommand) +UINT rail_send_client_get_appid_req_order(railPlugin* rail, + const RAIL_GET_APPID_REQ_ORDER* getAppIdReq) { wStream* s; UINT error; - if (!rail || !syscommand) + if (!rail || !getAppIdReq) return ERROR_INVALID_PARAMETER; - s = rail_pdu_init(RAIL_SYSCOMMAND_ORDER_LENGTH); + s = rail_pdu_init(RAIL_GET_APPID_REQ_ORDER_LENGTH); if (!s) { @@ -1184,10 +1277,10 @@ UINT rail_send_client_syscommand_order(railPlugin* rail, const RAIL_SYSCOMMAND_O return CHANNEL_RC_NO_MEMORY; } - error = rail_write_client_syscommand_order(s, syscommand); + error = rail_write_client_get_appid_req_order(s, getAppIdReq); if (error == ERROR_SUCCESS) - error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_SYSCOMMAND); + error = rail_send_pdu(rail, s, TS_RAIL_ORDER_GET_APPID_REQ); Stream_Free(s, TRUE); return error; @@ -1198,16 +1291,19 @@ UINT rail_send_client_syscommand_order(railPlugin* rail, const RAIL_SYSCOMMAND_O * * @return 0 on success, otherwise a Win32 error code */ -UINT rail_send_client_notify_event_order(railPlugin* rail, - const RAIL_NOTIFY_EVENT_ORDER* notifyEvent) +UINT rail_send_client_langbar_info_order(railPlugin* rail, + const RAIL_LANGBAR_INFO_ORDER* langBarInfo) { wStream* s; UINT error; - if (!rail || !notifyEvent) + if (!rail || !langBarInfo) return ERROR_INVALID_PARAMETER; - s = rail_pdu_init(RAIL_NOTIFY_EVENT_ORDER_LENGTH); + if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED)) + return ERROR_BAD_CONFIGURATION; + + s = rail_pdu_init(RAIL_LANGBAR_INFO_ORDER_LENGTH); if (!s) { @@ -1215,29 +1311,28 @@ UINT rail_send_client_notify_event_order(railPlugin* rail, return CHANNEL_RC_NO_MEMORY; } - error = rail_write_client_notify_event_order(s, notifyEvent); + error = rail_write_langbar_info_order(s, langBarInfo); if (ERROR_SUCCESS == error) - error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_NOTIFY_EVENT); + error = rail_send_pdu(rail, s, TS_RAIL_ORDER_LANGBARINFO); Stream_Free(s, TRUE); return error; } -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -UINT rail_send_client_window_move_order(railPlugin* rail, const RAIL_WINDOW_MOVE_ORDER* windowMove) +UINT rail_send_client_languageime_info_order(railPlugin* rail, + const RAIL_LANGUAGEIME_INFO_ORDER* langImeInfo) { wStream* s; UINT error; - if (!rail || !windowMove) + if (!rail || !langImeInfo) return ERROR_INVALID_PARAMETER; - s = rail_pdu_init(RAIL_WINDOW_MOVE_ORDER_LENGTH); + if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED)) + return ERROR_BAD_CONFIGURATION; + + s = rail_pdu_init(RAIL_LANGUAGEIME_INFO_ORDER_LENGTH); if (!s) { @@ -1245,30 +1340,25 @@ UINT rail_send_client_window_move_order(railPlugin* rail, const RAIL_WINDOW_MOVE return CHANNEL_RC_NO_MEMORY; } - error = rail_write_client_window_move_order(s, windowMove); + error = rail_write_languageime_info_order(s, langImeInfo); - if (error == ERROR_SUCCESS) - error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_WINDOWMOVE); + if (ERROR_SUCCESS == error) + error = rail_send_pdu(rail, s, TS_RAIL_ORDER_LANGUAGEIMEINFO); Stream_Free(s, TRUE); return error; } -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -UINT rail_send_client_get_appid_req_order(railPlugin* rail, - const RAIL_GET_APPID_REQ_ORDER* getAppIdReq) +UINT rail_send_client_compartment_info_order(railPlugin* rail, + const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo) { wStream* s; UINT error; - if (!rail || !getAppIdReq) + if (!rail || !compartmentInfo) return ERROR_INVALID_PARAMETER; - s = rail_pdu_init(RAIL_GET_APPID_REQ_ORDER_LENGTH); + s = rail_pdu_init(RAIL_COMPARTMENT_INFO_ORDER_LENGTH); if (!s) { @@ -1276,30 +1366,24 @@ UINT rail_send_client_get_appid_req_order(railPlugin* rail, return CHANNEL_RC_NO_MEMORY; } - error = rail_write_client_get_appid_req_order(s, getAppIdReq); + error = rail_write_compartment_info_order(s, compartmentInfo); - if (error == ERROR_SUCCESS) - error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_GET_APPID_REQ); + if (ERROR_SUCCESS == error) + error = rail_send_pdu(rail, s, TS_RAIL_ORDER_COMPARTMENTINFO); Stream_Free(s, TRUE); return error; } -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -UINT rail_send_client_langbar_info_order(railPlugin* rail, - const RAIL_LANGBAR_INFO_ORDER* langBarInfo) +UINT rail_send_client_cloak_order(railPlugin* rail, const RAIL_CLOAK* cloak) { wStream* s; UINT error; - if (!rail || !langBarInfo) + if (!rail || !cloak) return ERROR_INVALID_PARAMETER; - s = rail_pdu_init(RAIL_LANGBAR_INFO_ORDER_LENGTH); + s = rail_pdu_init(5); if (!s) { @@ -1307,11 +1391,47 @@ UINT rail_send_client_langbar_info_order(railPlugin* rail, return CHANNEL_RC_NO_MEMORY; } - error = rail_write_langbar_info_order(s, langBarInfo); + Stream_Write_UINT32(s, cloak->windowId); + Stream_Write_UINT8(s, cloak->cloak ? 1 : 0); + error = rail_send_pdu(rail, s, TS_RAIL_ORDER_CLOAK); + Stream_Free(s, TRUE); + return error; +} - if (ERROR_SUCCESS == error) - error = rail_send_pdu(rail, s, RDP_RAIL_ORDER_LANGBARINFO); +UINT rail_send_client_snap_arrange_order(railPlugin* rail, const RAIL_SNAP_ARRANGE* snap) +{ + wStream* s; + UINT error; + + if (!rail) + return ERROR_INVALID_PARAMETER; + + /* 2.2.2.7.5 Client Window Snap PDU (TS_RAIL_ORDER_SNAP_ARRANGE) */ + if ((rail->channelFlags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_SNAP_ARRANGE_SUPPORTED) == 0) + { + RAIL_WINDOW_MOVE_ORDER move = { 0 }; + move.top = snap->top; + move.left = snap->left; + move.right = snap->right; + move.bottom = snap->bottom; + move.windowId = snap->windowId; + return rail_send_client_window_move_order(rail, &move); + } + + s = rail_pdu_init(12); + + if (!s) + { + WLog_ERR(TAG, "rail_pdu_init failed!"); + return CHANNEL_RC_NO_MEMORY; + } + Stream_Write_UINT32(s, snap->windowId); + Stream_Write_INT16(s, snap->left); + Stream_Write_INT16(s, snap->top); + Stream_Write_INT16(s, snap->right); + Stream_Write_INT16(s, snap->bottom); + error = rail_send_pdu(rail, s, TS_RAIL_ORDER_SNAP_ARRANGE); Stream_Free(s, TRUE); return error; } diff --git a/channels/rail/client/rail_orders.h b/channels/rail/client/rail_orders.h index 0b4fd93..89ba6cc 100644 --- a/channels/rail/client/rail_orders.h +++ b/channels/rail/client/rail_orders.h @@ -29,8 +29,6 @@ #define TAG CHANNELS_TAG("rail.client") -UINT rail_write_client_sysparam_order(wStream* s, const RAIL_SYSPARAM_ORDER* sysparam); - UINT rail_order_recv(railPlugin* rail, wStream* s); UINT rail_send_pdu(railPlugin* rail, wStream* s, UINT16 orderType); @@ -38,18 +36,25 @@ UINT rail_send_handshake_order(railPlugin* rail, const RAIL_HANDSHAKE_ORDER* han UINT rail_send_handshake_ex_order(railPlugin* rail, const RAIL_HANDSHAKE_EX_ORDER* handshakeEx); UINT rail_send_client_status_order(railPlugin* rail, const RAIL_CLIENT_STATUS_ORDER* clientStatus); UINT rail_send_client_exec_order(railPlugin* rail, UINT16 flags, - const RAIL_UNICODE_STRING* exeOrFile, const RAIL_UNICODE_STRING* workingDir, + const RAIL_UNICODE_STRING* exeOrFile, + const RAIL_UNICODE_STRING* workingDir, const RAIL_UNICODE_STRING* arguments); UINT rail_send_client_activate_order(railPlugin* rail, const RAIL_ACTIVATE_ORDER* activate); UINT rail_send_client_sysmenu_order(railPlugin* rail, const RAIL_SYSMENU_ORDER* sysmenu); UINT rail_send_client_syscommand_order(railPlugin* rail, const RAIL_SYSCOMMAND_ORDER* syscommand); UINT rail_send_client_notify_event_order(railPlugin* rail, - const RAIL_NOTIFY_EVENT_ORDER* notifyEvent); + const RAIL_NOTIFY_EVENT_ORDER* notifyEvent); UINT rail_send_client_window_move_order(railPlugin* rail, const RAIL_WINDOW_MOVE_ORDER* windowMove); UINT rail_send_client_get_appid_req_order(railPlugin* rail, - const RAIL_GET_APPID_REQ_ORDER* getAppIdReq); + const RAIL_GET_APPID_REQ_ORDER* getAppIdReq); UINT rail_send_client_langbar_info_order(railPlugin* rail, - const RAIL_LANGBAR_INFO_ORDER* langBarInfo); + const RAIL_LANGBAR_INFO_ORDER* langBarInfo); +UINT rail_send_client_languageime_info_order(railPlugin* rail, + const RAIL_LANGUAGEIME_INFO_ORDER* langImeInfo); +UINT rail_send_client_cloak_order(railPlugin* rail, const RAIL_CLOAK* cloak); +UINT rail_send_client_snap_arrange_order(railPlugin* rail, const RAIL_SNAP_ARRANGE* snap); +UINT rail_send_client_compartment_info_order(railPlugin* rail, + const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo); #endif /* FREERDP_CHANNEL_RAIL_CLIENT_ORDERS_H */ diff --git a/channels/rail/rail_common.c b/channels/rail/rail_common.c index ac0103f..b6d69b7 100644 --- a/channels/rail/rail_common.c +++ b/channels/rail/rail_common.c @@ -23,56 +23,41 @@ #include "rail_common.h" #include +#include -const char* const RAIL_ORDER_TYPE_STRINGS[] = -{ - "", - "Execute", - "Activate", - "System Parameters Update", - "System Command", - "Handshake", - "Notify Event", - "", - "Window Move", - "Local Move/Size", - "Min Max Info", - "Client Status", - "System Menu", - "Language Bar Info", - "Get Application ID Request", - "Get Application ID Response", - "Execute Result", - "", - "", - "", - "", - "", - "" -}; - -BOOL rail_string_to_unicode_string(const char* string, RAIL_UNICODE_STRING* unicode_string) -{ - WCHAR* buffer = NULL; - int length = 0; - free(unicode_string->string); - unicode_string->string = NULL; - unicode_string->length = 0; - - if (!string || strlen(string) < 1) - return TRUE; - - length = ConvertToUnicode(CP_UTF8, 0, string, -1, &buffer, 0); - - if ((length < 0) || ((size_t)length * sizeof(WCHAR) > UINT16_MAX)) - { - free(buffer); - return FALSE; - } +#define TAG CHANNELS_TAG("rail.common") + +static const char* const RAIL_ORDER_TYPE_STRINGS[] = { "", + "Execute", + "Activate", + "System Parameters Update", + "System Command", + "Handshake", + "Notify Event", + "", + "Window Move", + "Local Move/Size", + "Min Max Info", + "Client Status", + "System Menu", + "Language Bar Info", + "Get Application ID Request", + "Get Application ID Response", + "Execute Result", + "", + "", + "", + "", + "", + "" }; - unicode_string->string = (BYTE*) buffer; - unicode_string->length = (UINT16) length * sizeof(WCHAR); - return TRUE; +const char* rail_get_order_type_string(UINT16 orderType) +{ + UINT32 index = ((orderType & 0xF0) >> 3) + (orderType & 0x0F); + if (index >= ARRAYSIZE(RAIL_ORDER_TYPE_STRINGS)) + return "UNKNOWN"; + + return RAIL_ORDER_TYPE_STRINGS[index]; } /** @@ -88,14 +73,14 @@ UINT rail_read_pdu_header(wStream* s, UINT16* orderType, UINT16* orderLength) if (Stream_GetRemainingLength(s) < 4) return ERROR_INVALID_DATA; - Stream_Read_UINT16(s, *orderType); /* orderType (2 bytes) */ + Stream_Read_UINT16(s, *orderType); /* orderType (2 bytes) */ Stream_Read_UINT16(s, *orderLength); /* orderLength (2 bytes) */ return CHANNEL_RC_OK; } void rail_write_pdu_header(wStream* s, UINT16 orderType, UINT16 orderLength) { - Stream_Write_UINT16(s, orderType); /* orderType (2 bytes) */ + Stream_Write_UINT16(s, orderType); /* orderType (2 bytes) */ Stream_Write_UINT16(s, orderLength); /* orderLength (2 bytes) */ } @@ -140,13 +125,459 @@ UINT rail_read_handshake_ex_order(wStream* s, RAIL_HANDSHAKE_EX_ORDER* handshake if (Stream_GetRemainingLength(s) < 8) return ERROR_INVALID_DATA; - Stream_Read_UINT32(s, handshakeEx->buildNumber); /* buildNumber (4 bytes) */ + Stream_Read_UINT32(s, handshakeEx->buildNumber); /* buildNumber (4 bytes) */ Stream_Read_UINT32(s, handshakeEx->railHandshakeFlags); /* railHandshakeFlags (4 bytes) */ return CHANNEL_RC_OK; } void rail_write_handshake_ex_order(wStream* s, const RAIL_HANDSHAKE_EX_ORDER* handshakeEx) { - Stream_Write_UINT32(s, handshakeEx->buildNumber); /* buildNumber (4 bytes) */ + Stream_Write_UINT32(s, handshakeEx->buildNumber); /* buildNumber (4 bytes) */ Stream_Write_UINT32(s, handshakeEx->railHandshakeFlags); /* railHandshakeFlags (4 bytes) */ } + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +UINT rail_write_unicode_string(wStream* s, const RAIL_UNICODE_STRING* unicode_string) +{ + if (!s || !unicode_string) + return ERROR_INVALID_PARAMETER; + + if (!Stream_EnsureRemainingCapacity(s, 2 + unicode_string->length)) + { + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + Stream_Write_UINT16(s, unicode_string->length); /* cbString (2 bytes) */ + Stream_Write(s, unicode_string->string, unicode_string->length); /* string */ + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +UINT rail_write_unicode_string_value(wStream* s, const RAIL_UNICODE_STRING* unicode_string) +{ + size_t length; + + if (!s || !unicode_string) + return ERROR_INVALID_PARAMETER; + + length = unicode_string->length; + + if (length > 0) + { + if (!Stream_EnsureRemainingCapacity(s, length)) + { + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + Stream_Write(s, unicode_string->string, length); /* string */ + } + + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_read_high_contrast(wStream* s, RAIL_HIGH_CONTRAST* highContrast) +{ + if (!s || !highContrast) + return ERROR_INVALID_PARAMETER; + + if (Stream_GetRemainingLength(s) < 8) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, highContrast->flags); /* flags (4 bytes) */ + Stream_Read_UINT32(s, highContrast->colorSchemeLength); /* colorSchemeLength (4 bytes) */ + + if (!rail_read_unicode_string(s, &highContrast->colorScheme)) /* colorScheme */ + return ERROR_INTERNAL_ERROR; + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_write_high_contrast(wStream* s, const RAIL_HIGH_CONTRAST* highContrast) +{ + UINT32 colorSchemeLength; + + if (!s || !highContrast) + return ERROR_INVALID_PARAMETER; + + if (!Stream_EnsureRemainingCapacity(s, 8)) + return CHANNEL_RC_NO_MEMORY; + + colorSchemeLength = highContrast->colorScheme.length + 2; + Stream_Write_UINT32(s, highContrast->flags); /* flags (4 bytes) */ + Stream_Write_UINT32(s, colorSchemeLength); /* colorSchemeLength (4 bytes) */ + return rail_write_unicode_string(s, &highContrast->colorScheme); /* colorScheme */ +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_read_filterkeys(wStream* s, TS_FILTERKEYS* filterKeys) +{ + if (!s || !filterKeys) + return ERROR_INVALID_PARAMETER; + + if (Stream_GetRemainingLength(s) < 20) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, filterKeys->Flags); + Stream_Read_UINT32(s, filterKeys->WaitTime); + Stream_Read_UINT32(s, filterKeys->DelayTime); + Stream_Read_UINT32(s, filterKeys->RepeatTime); + Stream_Read_UINT32(s, filterKeys->BounceTime); + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_write_filterkeys(wStream* s, const TS_FILTERKEYS* filterKeys) +{ + if (!s || !filterKeys) + return ERROR_INVALID_PARAMETER; + + if (!Stream_EnsureRemainingCapacity(s, 20)) + return CHANNEL_RC_NO_MEMORY; + + Stream_Write_UINT32(s, filterKeys->Flags); + Stream_Write_UINT32(s, filterKeys->WaitTime); + Stream_Write_UINT32(s, filterKeys->DelayTime); + Stream_Write_UINT32(s, filterKeys->RepeatTime); + Stream_Write_UINT32(s, filterKeys->BounceTime); + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +UINT rail_read_sysparam_order(wStream* s, RAIL_SYSPARAM_ORDER* sysparam, BOOL extendedSpiSupported) +{ + BYTE body; + UINT error = CHANNEL_RC_OK; + + if (!s || !sysparam) + return ERROR_INVALID_PARAMETER; + + if (Stream_GetRemainingLength(s) < 5) + { + WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT32(s, sysparam->param); /* systemParam (4 bytes) */ + + sysparam->params = 0; /* bitflags of received params */ + + switch (sysparam->param) + { + /* Client sysparams */ + case SPI_SET_DRAG_FULL_WINDOWS: + sysparam->params |= SPI_MASK_SET_DRAG_FULL_WINDOWS; + Stream_Read_UINT8(s, body); /* body (1 byte) */ + sysparam->dragFullWindows = body != 0; + break; + + case SPI_SET_KEYBOARD_CUES: + sysparam->params |= SPI_MASK_SET_KEYBOARD_CUES; + Stream_Read_UINT8(s, body); /* body (1 byte) */ + sysparam->keyboardCues = body != 0; + break; + + case SPI_SET_KEYBOARD_PREF: + sysparam->params |= SPI_MASK_SET_KEYBOARD_PREF; + Stream_Read_UINT8(s, body); /* body (1 byte) */ + sysparam->keyboardPref = body != 0; + break; + + case SPI_SET_MOUSE_BUTTON_SWAP: + sysparam->params |= SPI_MASK_SET_MOUSE_BUTTON_SWAP; + Stream_Read_UINT8(s, body); /* body (1 byte) */ + sysparam->mouseButtonSwap = body != 0; + break; + + case SPI_SET_WORK_AREA: + sysparam->params |= SPI_MASK_SET_WORK_AREA; + + if (Stream_GetRemainingLength(s) < 8) + { + WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT16(s, sysparam->workArea.left); /* left (2 bytes) */ + Stream_Read_UINT16(s, sysparam->workArea.top); /* top (2 bytes) */ + Stream_Read_UINT16(s, sysparam->workArea.right); /* right (2 bytes) */ + Stream_Read_UINT16(s, sysparam->workArea.bottom); /* bottom (2 bytes) */ + break; + + case SPI_DISPLAY_CHANGE: + sysparam->params |= SPI_MASK_DISPLAY_CHANGE; + + if (Stream_GetRemainingLength(s) < 8) + { + WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT16(s, sysparam->displayChange.left); /* left (2 bytes) */ + Stream_Read_UINT16(s, sysparam->displayChange.top); /* top (2 bytes) */ + Stream_Read_UINT16(s, sysparam->displayChange.right); /* right (2 bytes) */ + Stream_Read_UINT16(s, sysparam->displayChange.bottom); /* bottom (2 bytes) */ + break; + + case SPI_TASKBAR_POS: + sysparam->params |= SPI_MASK_TASKBAR_POS; + + if (Stream_GetRemainingLength(s) < 8) + { + WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT16(s, sysparam->taskbarPos.left); /* left (2 bytes) */ + Stream_Read_UINT16(s, sysparam->taskbarPos.top); /* top (2 bytes) */ + Stream_Read_UINT16(s, sysparam->taskbarPos.right); /* right (2 bytes) */ + Stream_Read_UINT16(s, sysparam->taskbarPos.bottom); /* bottom (2 bytes) */ + break; + + case SPI_SET_HIGH_CONTRAST: + sysparam->params |= SPI_MASK_SET_HIGH_CONTRAST; + if (Stream_GetRemainingLength(s) < 8) + { + WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); + return ERROR_INVALID_DATA; + } + + error = rail_read_high_contrast(s, &sysparam->highContrast); + break; + + case SPI_SETCARETWIDTH: + sysparam->params |= SPI_MASK_SET_CARET_WIDTH; + + if (!extendedSpiSupported) + return ERROR_INVALID_DATA; + + if (Stream_GetRemainingLength(s) < 4) + { + WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT32(s, sysparam->caretWidth); + + if (sysparam->caretWidth < 0x0001) + return ERROR_INVALID_DATA; + + break; + + case SPI_SETSTICKYKEYS: + sysparam->params |= SPI_MASK_SET_STICKY_KEYS; + + if (!extendedSpiSupported) + return ERROR_INVALID_DATA; + + if (Stream_GetRemainingLength(s) < 4) + { + WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT32(s, sysparam->stickyKeys); + break; + + case SPI_SETTOGGLEKEYS: + sysparam->params |= SPI_MASK_SET_TOGGLE_KEYS; + + if (!extendedSpiSupported) + return ERROR_INVALID_DATA; + + if (Stream_GetRemainingLength(s) < 4) + { + WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT32(s, sysparam->toggleKeys); + break; + + case SPI_SETFILTERKEYS: + sysparam->params |= SPI_MASK_SET_FILTER_KEYS; + + if (!extendedSpiSupported) + return ERROR_INVALID_DATA; + + if (Stream_GetRemainingLength(s) < 20) + { + WLog_ERR(TAG, "Stream_GetRemainingLength failed!"); + return ERROR_INVALID_DATA; + } + + error = rail_read_filterkeys(s, &sysparam->filterKeys); + break; + + /* Server sysparams */ + case SPI_SETSCREENSAVEACTIVE: + sysparam->params |= SPI_MASK_SET_SCREEN_SAVE_ACTIVE; + + Stream_Read_UINT8(s, body); /* body (1 byte) */ + sysparam->setScreenSaveActive = body != 0; + break; + + case SPI_SETSCREENSAVESECURE: + sysparam->params |= SPI_MASK_SET_SET_SCREEN_SAVE_SECURE; + + Stream_Read_UINT8(s, body); /* body (1 byte) */ + sysparam->setScreenSaveSecure = body != 0; + break; + + default: + break; + } + + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 err2or code + */ +UINT rail_write_sysparam_order(wStream* s, const RAIL_SYSPARAM_ORDER* sysparam, + BOOL extendedSpiSupported) +{ + BYTE body; + UINT error = CHANNEL_RC_OK; + + if (!s || !sysparam) + return ERROR_INVALID_PARAMETER; + + if (!Stream_EnsureRemainingCapacity(s, 12)) + return CHANNEL_RC_NO_MEMORY; + + Stream_Write_UINT32(s, sysparam->param); /* systemParam (4 bytes) */ + + switch (sysparam->param) + { + /* Client sysparams */ + case SPI_SET_DRAG_FULL_WINDOWS: + body = sysparam->dragFullWindows ? 1 : 0; + Stream_Write_UINT8(s, body); + break; + + case SPI_SET_KEYBOARD_CUES: + body = sysparam->keyboardCues ? 1 : 0; + Stream_Write_UINT8(s, body); + break; + + case SPI_SET_KEYBOARD_PREF: + body = sysparam->keyboardPref ? 1 : 0; + Stream_Write_UINT8(s, body); + break; + + case SPI_SET_MOUSE_BUTTON_SWAP: + body = sysparam->mouseButtonSwap ? 1 : 0; + Stream_Write_UINT8(s, body); + break; + + case SPI_SET_WORK_AREA: + Stream_Write_UINT16(s, sysparam->workArea.left); /* left (2 bytes) */ + Stream_Write_UINT16(s, sysparam->workArea.top); /* top (2 bytes) */ + Stream_Write_UINT16(s, sysparam->workArea.right); /* right (2 bytes) */ + Stream_Write_UINT16(s, sysparam->workArea.bottom); /* bottom (2 bytes) */ + break; + + case SPI_DISPLAY_CHANGE: + Stream_Write_UINT16(s, sysparam->displayChange.left); /* left (2 bytes) */ + Stream_Write_UINT16(s, sysparam->displayChange.top); /* top (2 bytes) */ + Stream_Write_UINT16(s, sysparam->displayChange.right); /* right (2 bytes) */ + Stream_Write_UINT16(s, sysparam->displayChange.bottom); /* bottom (2 bytes) */ + break; + + case SPI_TASKBAR_POS: + Stream_Write_UINT16(s, sysparam->taskbarPos.left); /* left (2 bytes) */ + Stream_Write_UINT16(s, sysparam->taskbarPos.top); /* top (2 bytes) */ + Stream_Write_UINT16(s, sysparam->taskbarPos.right); /* right (2 bytes) */ + Stream_Write_UINT16(s, sysparam->taskbarPos.bottom); /* bottom (2 bytes) */ + break; + + case SPI_SET_HIGH_CONTRAST: + error = rail_write_high_contrast(s, &sysparam->highContrast); + break; + + case SPI_SETCARETWIDTH: + if (!extendedSpiSupported) + return ERROR_INVALID_DATA; + + if (sysparam->caretWidth < 0x0001) + return ERROR_INVALID_DATA; + + Stream_Write_UINT32(s, sysparam->caretWidth); + break; + + case SPI_SETSTICKYKEYS: + if (!extendedSpiSupported) + return ERROR_INVALID_DATA; + + Stream_Write_UINT32(s, sysparam->stickyKeys); + break; + + case SPI_SETTOGGLEKEYS: + if (!extendedSpiSupported) + return ERROR_INVALID_DATA; + + Stream_Write_UINT32(s, sysparam->toggleKeys); + break; + + case SPI_SETFILTERKEYS: + if (!extendedSpiSupported) + return ERROR_INVALID_DATA; + + error = rail_write_filterkeys(s, &sysparam->filterKeys); + break; + + /* Server sysparams */ + case SPI_SETSCREENSAVEACTIVE: + body = sysparam->setScreenSaveActive ? 1 : 0; + Stream_Write_UINT8(s, body); + break; + + case SPI_SETSCREENSAVESECURE: + body = sysparam->setScreenSaveSecure ? 1 : 0; + Stream_Write_UINT8(s, body); + break; + + default: + return ERROR_INVALID_PARAMETER; + } + + return error; +} + +BOOL rail_is_extended_spi_supported(UINT32 channelFlags) +{ + return channelFlags & TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_SUPPORTED; +} diff --git a/channels/rail/rail_common.h b/channels/rail/rail_common.h index fe1bc02..e13412d 100644 --- a/channels/rail/rail_common.h +++ b/channels/rail/rail_common.h @@ -26,25 +26,34 @@ #include -extern const char* const RAIL_ORDER_TYPE_STRINGS[]; - -#define RAIL_PDU_HEADER_LENGTH 4 +#define RAIL_PDU_HEADER_LENGTH 4 /* Fixed length of PDUs, excluding variable lengths */ -#define RAIL_HANDSHAKE_ORDER_LENGTH 4 /* fixed */ -#define RAIL_HANDSHAKE_EX_ORDER_LENGTH 8 /* fixed */ -#define RAIL_CLIENT_STATUS_ORDER_LENGTH 4 /* fixed */ -#define RAIL_EXEC_ORDER_LENGTH 8 /* variable */ -#define RAIL_SYSPARAM_ORDER_LENGTH 4 /* variable */ -#define RAIL_ACTIVATE_ORDER_LENGTH 5 /* fixed */ -#define RAIL_SYSMENU_ORDER_LENGTH 8 /* fixed */ -#define RAIL_SYSCOMMAND_ORDER_LENGTH 6 /* fixed */ -#define RAIL_NOTIFY_EVENT_ORDER_LENGTH 12 /* fixed */ -#define RAIL_WINDOW_MOVE_ORDER_LENGTH 12 /* fixed */ -#define RAIL_GET_APPID_REQ_ORDER_LENGTH 4 /* fixed */ -#define RAIL_LANGBAR_INFO_ORDER_LENGTH 4 /* fixed */ - -BOOL rail_string_to_unicode_string(const char* string, RAIL_UNICODE_STRING* unicode_string); +#define RAIL_HANDSHAKE_ORDER_LENGTH 4 /* fixed */ +#define RAIL_HANDSHAKE_EX_ORDER_LENGTH 8 /* fixed */ +#define RAIL_CLIENT_STATUS_ORDER_LENGTH 4 /* fixed */ +#define RAIL_EXEC_ORDER_LENGTH 8 /* variable */ +#define RAIL_EXEC_RESULT_ORDER_LENGTH 12 /* variable */ +#define RAIL_SYSPARAM_ORDER_LENGTH 4 /* variable */ +#define RAIL_MINMAXINFO_ORDER_LENGTH 20 /* fixed */ +#define RAIL_LOCALMOVESIZE_ORDER_LENGTH 12 /* fixed */ +#define RAIL_ACTIVATE_ORDER_LENGTH 5 /* fixed */ +#define RAIL_SYSMENU_ORDER_LENGTH 8 /* fixed */ +#define RAIL_SYSCOMMAND_ORDER_LENGTH 6 /* fixed */ +#define RAIL_NOTIFY_EVENT_ORDER_LENGTH 12 /* fixed */ +#define RAIL_WINDOW_MOVE_ORDER_LENGTH 12 /* fixed */ +#define RAIL_SNAP_ARRANGE_ORDER_LENGTH 12 /* fixed */ +#define RAIL_GET_APPID_REQ_ORDER_LENGTH 4 /* fixed */ +#define RAIL_LANGBAR_INFO_ORDER_LENGTH 4 /* fixed */ +#define RAIL_LANGUAGEIME_INFO_ORDER_LENGTH 42 /* fixed */ +#define RAIL_COMPARTMENT_INFO_ORDER_LENGTH 16 /* fixed */ +#define RAIL_CLOAK_ORDER_LENGTH 5 /* fixed */ +#define RAIL_TASKBAR_INFO_ORDER_LENGTH 12 /* fixed */ +#define RAIL_Z_ORDER_SYNC_ORDER_LENGTH 4 /* fixed */ +#define RAIL_POWER_DISPLAY_REQUEST_ORDER_LENGTH 4 /* fixed */ +#define RAIL_GET_APPID_RESP_ORDER_LENGTH 524 /* fixed */ +#define RAIL_GET_APPID_RESP_EX_ORDER_LENGTH 1048 /* fixed */ + UINT rail_read_handshake_order(wStream* s, RAIL_HANDSHAKE_ORDER* handshake); void rail_write_handshake_order(wStream* s, const RAIL_HANDSHAKE_ORDER* handshake); UINT rail_read_handshake_ex_order(wStream* s, RAIL_HANDSHAKE_EX_ORDER* handshakeEx); @@ -54,4 +63,13 @@ wStream* rail_pdu_init(size_t length); UINT rail_read_pdu_header(wStream* s, UINT16* orderType, UINT16* orderLength); void rail_write_pdu_header(wStream* s, UINT16 orderType, UINT16 orderLength); +UINT rail_write_unicode_string(wStream* s, const RAIL_UNICODE_STRING* unicode_string); +UINT rail_write_unicode_string_value(wStream* s, const RAIL_UNICODE_STRING* unicode_string); + +UINT rail_read_sysparam_order(wStream* s, RAIL_SYSPARAM_ORDER* sysparam, BOOL extendedSpiSupported); +UINT rail_write_sysparam_order(wStream* s, const RAIL_SYSPARAM_ORDER* sysparam, + BOOL extendedSpiSupported); +BOOL rail_is_extended_spi_supported(UINT32 channelsFlags); +const char* rail_get_order_type_string(UINT16 orderType); + #endif /* FREERDP_CHANNEL_RAIL_COMMON_H */ diff --git a/channels/rail/server/CMakeLists.txt b/channels/rail/server/CMakeLists.txt new file mode 100644 index 0000000..c7f1c7a --- /dev/null +++ b/channels/rail/server/CMakeLists.txt @@ -0,0 +1,32 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2019 Mati Shabtay +# +# 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("rail") + +set(${MODULE_PREFIX}_SRCS + ../rail_common.c + ../rail_common.h + rail_main.c + rail_main.h) + +include_directories(..) + +add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntryEx") + +target_link_libraries(${MODULE_NAME} freerdp) + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server") diff --git a/channels/rail/server/rail_main.c b/channels/rail/server/rail_main.c new file mode 100644 index 0000000..db38928 --- /dev/null +++ b/channels/rail/server/rail_main.c @@ -0,0 +1,1686 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * RAIL Virtual Channel Plugin + * + * Copyright 2019 Mati Shabtay + * + + * 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 "rail_main.h" + +#define TAG CHANNELS_TAG("rail.server") + +/** + * Sends a single rail PDU on the channel + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_send(RailServerContext* context, wStream* s, ULONG length) +{ + UINT status = CHANNEL_RC_OK; + ULONG written; + + if (!context) + return CHANNEL_RC_BAD_INIT_HANDLE; + + if (!WTSVirtualChannelWrite(context->priv->rail_channel, (PCHAR)Stream_Buffer(s), length, + &written)) + { + WLog_ERR(TAG, "WTSVirtualChannelWrite failed!"); + status = ERROR_INTERNAL_ERROR; + } + + return status; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_server_send_pdu(RailServerContext* context, wStream* s, UINT16 orderType) +{ + UINT16 orderLength; + + if (!context || !s) + return ERROR_INVALID_PARAMETER; + + orderLength = (UINT16)Stream_GetPosition(s); + Stream_SetPosition(s, 0); + rail_write_pdu_header(s, orderType, orderLength); + Stream_SetPosition(s, orderLength); + WLog_DBG(TAG, "Sending %s PDU, length: %" PRIu16 "", rail_get_order_type_string(orderType), + orderLength); + return rail_send(context, s, orderLength); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_write_local_move_size_order(wStream* s, + const RAIL_LOCALMOVESIZE_ORDER* localMoveSize) +{ + if (!s || !localMoveSize) + return ERROR_INVALID_PARAMETER; + + Stream_Write_UINT32(s, localMoveSize->windowId); /* WindowId (4 bytes) */ + Stream_Write_UINT16(s, localMoveSize->isMoveSizeStart ? 1 : 0); /* IsMoveSizeStart (2 bytes) */ + Stream_Write_UINT16(s, localMoveSize->moveSizeType); /* MoveSizeType (2 bytes) */ + Stream_Write_UINT16(s, localMoveSize->posX); /* PosX (2 bytes) */ + Stream_Write_UINT16(s, localMoveSize->posY); /* PosY (2 bytes) */ + return ERROR_SUCCESS; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_write_min_max_info_order(wStream* s, const RAIL_MINMAXINFO_ORDER* minMaxInfo) +{ + if (!s || !minMaxInfo) + return ERROR_INVALID_PARAMETER; + + Stream_Write_UINT32(s, minMaxInfo->windowId); /* WindowId (4 bytes) */ + Stream_Write_INT16(s, minMaxInfo->maxWidth); /* MaxWidth (2 bytes) */ + Stream_Write_INT16(s, minMaxInfo->maxHeight); /* MaxHeight (2 bytes) */ + Stream_Write_INT16(s, minMaxInfo->maxPosX); /* MaxPosX (2 bytes) */ + Stream_Write_INT16(s, minMaxInfo->maxPosY); /* MaxPosY (2 bytes) */ + Stream_Write_INT16(s, minMaxInfo->minTrackWidth); /* MinTrackWidth (2 bytes) */ + Stream_Write_INT16(s, minMaxInfo->minTrackHeight); /* MinTrackHeight (2 bytes) */ + Stream_Write_INT16(s, minMaxInfo->maxTrackWidth); /* MaxTrackWidth (2 bytes) */ + Stream_Write_INT16(s, minMaxInfo->maxTrackHeight); /* MaxTrackHeight (2 bytes) */ + return ERROR_SUCCESS; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_write_taskbar_info_order(wStream* s, const RAIL_TASKBAR_INFO_ORDER* taskbarInfo) +{ + if (!s || !taskbarInfo) + return ERROR_INVALID_PARAMETER; + + Stream_Write_UINT32(s, taskbarInfo->TaskbarMessage); /* TaskbarMessage (4 bytes) */ + Stream_Write_UINT32(s, taskbarInfo->WindowIdTab); /* WindowIdTab (4 bytes) */ + Stream_Write_UINT32(s, taskbarInfo->Body); /* Body (4 bytes) */ + return ERROR_SUCCESS; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_write_langbar_info_order(wStream* s, const RAIL_LANGBAR_INFO_ORDER* langbarInfo) +{ + if (!s || !langbarInfo) + return ERROR_INVALID_PARAMETER; + + Stream_Write_UINT32(s, langbarInfo->languageBarStatus); /* LanguageBarStatus (4 bytes) */ + return ERROR_SUCCESS; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_write_exec_result_order(wStream* s, const RAIL_EXEC_RESULT_ORDER* execResult) +{ + if (!s || !execResult) + return ERROR_INVALID_PARAMETER; + + if (execResult->exeOrFile.length > 520 || execResult->exeOrFile.length < 1) + return ERROR_INVALID_DATA; + + Stream_Write_UINT16(s, execResult->flags); /* Flags (2 bytes) */ + Stream_Write_UINT16(s, execResult->execResult); /* ExecResult (2 bytes) */ + Stream_Write_UINT32(s, execResult->rawResult); /* RawResult (4 bytes) */ + Stream_Write_UINT16(s, 0); /* Padding (2 bytes) */ + Stream_Write_UINT16(s, execResult->exeOrFile.length); /* ExeOrFileLength (2 bytes) */ + Stream_Write(s, execResult->exeOrFile.string, + execResult->exeOrFile.length); /* ExeOrFile (variable) */ + return ERROR_SUCCESS; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_write_z_order_sync_order(wStream* s, const RAIL_ZORDER_SYNC* zOrderSync) +{ + if (!s || !zOrderSync) + return ERROR_INVALID_PARAMETER; + + Stream_Write_UINT32(s, zOrderSync->windowIdMarker); /* WindowIdMarker (4 bytes) */ + return ERROR_SUCCESS; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_write_cloak_order(wStream* s, const RAIL_CLOAK* cloak) +{ + if (!s || !cloak) + return ERROR_INVALID_PARAMETER; + + Stream_Write_UINT32(s, cloak->windowId); /* WindowId (4 bytes) */ + Stream_Write_UINT8(s, cloak->cloak ? 1 : 0); /* Cloaked (1 byte) */ + return ERROR_SUCCESS; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT +rail_write_power_display_request_order(wStream* s, + const RAIL_POWER_DISPLAY_REQUEST* powerDisplayRequest) +{ + if (!s || !powerDisplayRequest) + return ERROR_INVALID_PARAMETER; + + Stream_Write_UINT32(s, powerDisplayRequest->active ? 1 : 0); /* Active (4 bytes) */ + return ERROR_SUCCESS; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_write_get_app_id_resp_order(wStream* s, + const RAIL_GET_APPID_RESP_ORDER* getAppidResp) +{ + if (!s || !getAppidResp) + return ERROR_INVALID_PARAMETER; + + Stream_Write_UINT32(s, getAppidResp->windowId); /* WindowId (4 bytes) */ + Stream_Write_UTF16_String( + s, getAppidResp->applicationId, + ARRAYSIZE(getAppidResp->applicationId)); /* ApplicationId (512 bytes) */ + return ERROR_SUCCESS; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_write_get_appid_resp_ex_order(wStream* s, + const RAIL_GET_APPID_RESP_EX* getAppidRespEx) +{ + if (!s || !getAppidRespEx) + return ERROR_INVALID_PARAMETER; + + Stream_Write_UINT32(s, getAppidRespEx->windowID); /* WindowId (4 bytes) */ + Stream_Write_UTF16_String( + s, getAppidRespEx->applicationID, + ARRAYSIZE(getAppidRespEx->applicationID)); /* ApplicationId (520 bytes) */ + Stream_Write_UINT32(s, getAppidRespEx->processId); /* ProcessId (4 bytes) */ + Stream_Write_UTF16_String( + s, getAppidRespEx->processImageName, + ARRAYSIZE(getAppidRespEx->processImageName)); /* ProcessImageName (520 bytes) */ + return ERROR_SUCCESS; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_send_server_handshake(RailServerContext* context, + const RAIL_HANDSHAKE_ORDER* handshake) +{ + wStream* s; + UINT error; + + if (!context || !handshake) + return ERROR_INVALID_PARAMETER; + + s = rail_pdu_init(RAIL_HANDSHAKE_ORDER_LENGTH); + + if (!s) + { + WLog_ERR(TAG, "rail_pdu_init failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + rail_write_handshake_order(s, handshake); + error = rail_server_send_pdu(context, s, TS_RAIL_ORDER_HANDSHAKE); + Stream_Free(s, TRUE); + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_send_server_handshake_ex(RailServerContext* context, + const RAIL_HANDSHAKE_EX_ORDER* handshakeEx) +{ + wStream* s; + UINT error; + + if (!context || !handshakeEx || !context->priv) + return ERROR_INVALID_PARAMETER; + + s = rail_pdu_init(RAIL_HANDSHAKE_EX_ORDER_LENGTH); + + if (!s) + { + WLog_ERR(TAG, "rail_pdu_init failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + rail_server_set_handshake_ex_flags(context, handshakeEx->railHandshakeFlags); + + rail_write_handshake_ex_order(s, handshakeEx); + error = rail_server_send_pdu(context, s, TS_RAIL_ORDER_HANDSHAKE_EX); + Stream_Free(s, TRUE); + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_send_server_sysparam(RailServerContext* context, + const RAIL_SYSPARAM_ORDER* sysparam) +{ + wStream* s; + UINT error; + RailServerPrivate* priv; + BOOL extendedSpiSupported; + + if (!context || !sysparam) + return ERROR_INVALID_PARAMETER; + + priv = context->priv; + + if (!priv) + return ERROR_INVALID_PARAMETER; + + extendedSpiSupported = rail_is_extended_spi_supported(context->priv->channelFlags); + s = rail_pdu_init(RAIL_SYSPARAM_ORDER_LENGTH); + + if (!s) + { + WLog_ERR(TAG, "rail_pdu_init failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + rail_write_sysparam_order(s, sysparam, extendedSpiSupported); + error = rail_server_send_pdu(context, s, TS_RAIL_ORDER_SYSPARAM); + Stream_Free(s, TRUE); + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_send_server_local_move_size(RailServerContext* context, + const RAIL_LOCALMOVESIZE_ORDER* localMoveSize) +{ + wStream* s; + UINT error; + + if (!context || !localMoveSize) + return ERROR_INVALID_PARAMETER; + + s = rail_pdu_init(RAIL_LOCALMOVESIZE_ORDER_LENGTH); + + if (!s) + { + WLog_ERR(TAG, "rail_pdu_init failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + rail_write_local_move_size_order(s, localMoveSize); + error = rail_server_send_pdu(context, s, TS_RAIL_ORDER_LOCALMOVESIZE); + Stream_Free(s, TRUE); + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_send_server_min_max_info(RailServerContext* context, + const RAIL_MINMAXINFO_ORDER* minMaxInfo) +{ + wStream* s; + UINT error; + + if (!context || !minMaxInfo) + return ERROR_INVALID_PARAMETER; + + s = rail_pdu_init(RAIL_MINMAXINFO_ORDER_LENGTH); + + if (!s) + { + WLog_ERR(TAG, "rail_pdu_init failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + rail_write_min_max_info_order(s, minMaxInfo); + error = rail_server_send_pdu(context, s, TS_RAIL_ORDER_MINMAXINFO); + Stream_Free(s, TRUE); + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_send_server_taskbar_info(RailServerContext* context, + const RAIL_TASKBAR_INFO_ORDER* taskbarInfo) +{ + wStream* s; + UINT error; + + if (!context || !taskbarInfo) + return ERROR_INVALID_PARAMETER; + + s = rail_pdu_init(RAIL_TASKBAR_INFO_ORDER_LENGTH); + + if (!s) + { + WLog_ERR(TAG, "rail_pdu_init failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + rail_write_taskbar_info_order(s, taskbarInfo); + error = rail_server_send_pdu(context, s, TS_RAIL_ORDER_TASKBARINFO); + Stream_Free(s, TRUE); + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_send_server_langbar_info(RailServerContext* context, + const RAIL_LANGBAR_INFO_ORDER* langbarInfo) +{ + wStream* s; + UINT error; + + if (!context || !langbarInfo) + return ERROR_INVALID_PARAMETER; + + s = rail_pdu_init(RAIL_LANGBAR_INFO_ORDER_LENGTH); + + if (!s) + { + WLog_ERR(TAG, "rail_pdu_init failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + rail_write_langbar_info_order(s, langbarInfo); + error = rail_server_send_pdu(context, s, TS_RAIL_ORDER_LANGBARINFO); + Stream_Free(s, TRUE); + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_send_server_exec_result(RailServerContext* context, + const RAIL_EXEC_RESULT_ORDER* execResult) +{ + wStream* s; + UINT error; + + if (!context || !execResult) + return ERROR_INVALID_PARAMETER; + + s = rail_pdu_init(RAIL_EXEC_RESULT_ORDER_LENGTH + execResult->exeOrFile.length); + + if (!s) + { + WLog_ERR(TAG, "rail_pdu_init failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + rail_write_exec_result_order(s, execResult); + error = rail_server_send_pdu(context, s, TS_RAIL_ORDER_EXEC_RESULT); + Stream_Free(s, TRUE); + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_send_server_z_order_sync(RailServerContext* context, + const RAIL_ZORDER_SYNC* zOrderSync) +{ + wStream* s; + UINT error; + + if (!context || !zOrderSync) + return ERROR_INVALID_PARAMETER; + + s = rail_pdu_init(RAIL_Z_ORDER_SYNC_ORDER_LENGTH); + + if (!s) + { + WLog_ERR(TAG, "rail_pdu_init failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + rail_write_z_order_sync_order(s, zOrderSync); + error = rail_server_send_pdu(context, s, TS_RAIL_ORDER_ZORDER_SYNC); + Stream_Free(s, TRUE); + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_send_server_cloak(RailServerContext* context, const RAIL_CLOAK* cloak) +{ + wStream* s; + UINT error; + + if (!context || !cloak) + return ERROR_INVALID_PARAMETER; + + s = rail_pdu_init(RAIL_CLOAK_ORDER_LENGTH); + + if (!s) + { + WLog_ERR(TAG, "rail_pdu_init failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + rail_write_cloak_order(s, cloak); + error = rail_server_send_pdu(context, s, TS_RAIL_ORDER_CLOAK); + Stream_Free(s, TRUE); + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT +rail_send_server_power_display_request(RailServerContext* context, + const RAIL_POWER_DISPLAY_REQUEST* powerDisplayRequest) +{ + wStream* s; + UINT error; + + if (!context || !powerDisplayRequest) + return ERROR_INVALID_PARAMETER; + + s = rail_pdu_init(RAIL_POWER_DISPLAY_REQUEST_ORDER_LENGTH); + + if (!s) + { + WLog_ERR(TAG, "rail_pdu_init failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + rail_write_power_display_request_order(s, powerDisplayRequest); + error = rail_server_send_pdu(context, s, TS_RAIL_ORDER_POWER_DISPLAY_REQUEST); + Stream_Free(s, TRUE); + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error coie + */ +static UINT rail_send_server_get_app_id_resp(RailServerContext* context, + const RAIL_GET_APPID_RESP_ORDER* getAppidResp) +{ + wStream* s; + UINT error; + + if (!context || !getAppidResp) + return ERROR_INVALID_PARAMETER; + + s = rail_pdu_init(RAIL_GET_APPID_RESP_ORDER_LENGTH); + + if (!s) + { + WLog_ERR(TAG, "rail_pdu_init failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + rail_write_get_app_id_resp_order(s, getAppidResp); + error = rail_server_send_pdu(context, s, TS_RAIL_ORDER_GET_APPID_RESP); + Stream_Free(s, TRUE); + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_send_server_get_appid_resp_ex(RailServerContext* context, + const RAIL_GET_APPID_RESP_EX* getAppidRespEx) +{ + wStream* s; + UINT error; + + if (!context || !getAppidRespEx) + return ERROR_INVALID_PARAMETER; + + s = rail_pdu_init(RAIL_GET_APPID_RESP_EX_ORDER_LENGTH); + + if (!s) + { + WLog_ERR(TAG, "rail_pdu_init failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + rail_write_get_appid_resp_ex_order(s, getAppidRespEx); + error = rail_server_send_pdu(context, s, TS_RAIL_ORDER_GET_APPID_RESP_EX); + Stream_Free(s, TRUE); + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_read_client_status_order(wStream* s, RAIL_CLIENT_STATUS_ORDER* clientStatus) +{ + if (Stream_GetRemainingLength(s) < RAIL_CLIENT_STATUS_ORDER_LENGTH) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, clientStatus->flags); /* Flags (4 bytes) */ + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_read_exec_order(wStream* s, RAIL_EXEC_ORDER* exec) +{ + RAIL_EXEC_ORDER order = { 0 }; + UINT16 exeLen, workLen, argLen; + + if (Stream_GetRemainingLength(s) < RAIL_EXEC_ORDER_LENGTH) + return ERROR_INVALID_DATA; + + Stream_Read_UINT16(s, exec->flags); /* Flags (2 bytes) */ + Stream_Read_UINT16(s, exeLen); /* ExeOrFileLength (2 bytes) */ + Stream_Read_UINT16(s, workLen); /* WorkingDirLength (2 bytes) */ + Stream_Read_UINT16(s, argLen); /* ArgumentsLength (2 bytes) */ + + if (Stream_GetRemainingLength(s) < (size_t)exeLen + workLen + argLen) + return ERROR_INVALID_DATA; + + { + const int len = exeLen / sizeof(WCHAR); + int rc; + const WCHAR* str = (const WCHAR*)Stream_Pointer(s); + rc = ConvertFromUnicode(CP_UTF8, 0, str, len, &exec->RemoteApplicationProgram, 0, NULL, + NULL); + if (rc != len) + goto fail; + Stream_Seek(s, exeLen); + } + { + const int len = workLen / sizeof(WCHAR); + int rc; + + const WCHAR* str = (const WCHAR*)Stream_Pointer(s); + rc = ConvertFromUnicode(CP_UTF8, 0, str, len, &exec->RemoteApplicationProgram, 0, NULL, + NULL); + if (rc != len) + goto fail; + Stream_Seek(s, workLen); + } + { + const int len = argLen / sizeof(WCHAR); + int rc; + const WCHAR* str = (const WCHAR*)Stream_Pointer(s); + rc = ConvertFromUnicode(CP_UTF8, 0, str, len, &exec->RemoteApplicationProgram, 0, NULL, + NULL); + if (rc != len) + goto fail; + Stream_Seek(s, argLen); + } + + return CHANNEL_RC_OK; +fail: + free(exec->RemoteApplicationProgram); + free(exec->RemoteApplicationArguments); + free(exec->RemoteApplicationWorkingDir); + *exec = order; + return ERROR_INTERNAL_ERROR; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_read_activate_order(wStream* s, RAIL_ACTIVATE_ORDER* activate) +{ + BYTE enabled; + + if (Stream_GetRemainingLength(s) < RAIL_ACTIVATE_ORDER_LENGTH) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, activate->windowId); /* WindowId (4 bytes) */ + Stream_Read_UINT8(s, enabled); /* Enabled (1 byte) */ + activate->enabled = (enabled != 0) ? TRUE : FALSE; + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_read_sysmenu_order(wStream* s, RAIL_SYSMENU_ORDER* sysmenu) +{ + if (Stream_GetRemainingLength(s) < RAIL_SYSMENU_ORDER_LENGTH) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, sysmenu->windowId); /* WindowId (4 bytes) */ + Stream_Read_INT16(s, sysmenu->left); /* Left (2 bytes) */ + Stream_Read_INT16(s, sysmenu->top); /* Top (2 bytes) */ + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_read_syscommand_order(wStream* s, RAIL_SYSCOMMAND_ORDER* syscommand) +{ + if (Stream_GetRemainingLength(s) < RAIL_SYSCOMMAND_ORDER_LENGTH) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, syscommand->windowId); /* WindowId (4 bytes) */ + Stream_Read_UINT16(s, syscommand->command); /* Command (2 bytes) */ + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_read_notify_event_order(wStream* s, RAIL_NOTIFY_EVENT_ORDER* notifyEvent) +{ + if (Stream_GetRemainingLength(s) < RAIL_NOTIFY_EVENT_ORDER_LENGTH) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, notifyEvent->windowId); /* WindowId (4 bytes) */ + Stream_Read_UINT32(s, notifyEvent->notifyIconId); /* NotifyIconId (4 bytes) */ + Stream_Read_UINT32(s, notifyEvent->message); /* Message (4 bytes) */ + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_read_get_appid_req_order(wStream* s, RAIL_GET_APPID_REQ_ORDER* getAppidReq) +{ + if (Stream_GetRemainingLength(s) < RAIL_GET_APPID_REQ_ORDER_LENGTH) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, getAppidReq->windowId); /* WindowId (4 bytes) */ + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_read_window_move_order(wStream* s, RAIL_WINDOW_MOVE_ORDER* windowMove) +{ + if (Stream_GetRemainingLength(s) < RAIL_WINDOW_MOVE_ORDER_LENGTH) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, windowMove->windowId); /* WindowId (4 bytes) */ + Stream_Read_INT16(s, windowMove->left); /* Left (2 bytes) */ + Stream_Read_INT16(s, windowMove->top); /* Top (2 bytes) */ + Stream_Read_INT16(s, windowMove->right); /* Right (2 bytes) */ + Stream_Read_INT16(s, windowMove->bottom); /* Bottom (2 bytes) */ + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_read_snap_arange_order(wStream* s, RAIL_SNAP_ARRANGE* snapArrange) +{ + if (Stream_GetRemainingLength(s) < RAIL_SNAP_ARRANGE_ORDER_LENGTH) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, snapArrange->windowId); /* WindowId (4 bytes) */ + Stream_Read_INT16(s, snapArrange->left); /* Left (2 bytes) */ + Stream_Read_INT16(s, snapArrange->top); /* Top (2 bytes) */ + Stream_Read_INT16(s, snapArrange->right); /* Right (2 bytes) */ + Stream_Read_INT16(s, snapArrange->bottom); /* Bottom (2 bytes) */ + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_read_langbar_info_order(wStream* s, RAIL_LANGBAR_INFO_ORDER* langbarInfo) +{ + if (Stream_GetRemainingLength(s) < RAIL_LANGBAR_INFO_ORDER_LENGTH) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, langbarInfo->languageBarStatus); /* LanguageBarStatus (4 bytes) */ + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_read_language_ime_info_order(wStream* s, + RAIL_LANGUAGEIME_INFO_ORDER* languageImeInfo) +{ + if (Stream_GetRemainingLength(s) < RAIL_LANGUAGEIME_INFO_ORDER_LENGTH) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, languageImeInfo->ProfileType); /* ProfileType (4 bytes) */ + Stream_Read_UINT16(s, languageImeInfo->LanguageID); /* LanguageID (2 bytes) */ + Stream_Read( + s, &languageImeInfo->LanguageProfileCLSID, + sizeof(languageImeInfo->LanguageProfileCLSID)); /* LanguageProfileCLSID (16 bytes) */ + Stream_Read(s, &languageImeInfo->ProfileGUID, + sizeof(languageImeInfo->ProfileGUID)); /* ProfileGUID (16 bytes) */ + Stream_Read_UINT32(s, languageImeInfo->KeyboardLayout); /* KeyboardLayout (4 bytes) */ + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_read_compartment_info_order(wStream* s, + RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo) +{ + if (Stream_GetRemainingLength(s) < RAIL_COMPARTMENT_INFO_ORDER_LENGTH) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, compartmentInfo->ImeState); /* ImeState (4 bytes) */ + Stream_Read_UINT32(s, compartmentInfo->ImeConvMode); /* ImeConvMode (4 bytes) */ + Stream_Read_UINT32(s, compartmentInfo->ImeSentenceMode); /* ImeSentenceMode (4 bytes) */ + Stream_Read_UINT32(s, compartmentInfo->KanaMode); /* KANAMode (4 bytes) */ + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_read_cloak_order(wStream* s, RAIL_CLOAK* cloak) +{ + BYTE cloaked; + + if (Stream_GetRemainingLength(s) < RAIL_CLOAK_ORDER_LENGTH) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, cloak->windowId); /* WindowId (4 bytes) */ + Stream_Read_UINT8(s, cloaked); /* Cloaked (1 byte) */ + cloak->cloak = (cloaked != 0) ? TRUE : FALSE; + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_recv_client_handshake_order(RailServerContext* context, + RAIL_HANDSHAKE_ORDER* handshake, wStream* s) +{ + UINT error; + + if (!context || !handshake || !s) + return ERROR_INVALID_PARAMETER; + + if ((error = rail_read_handshake_order(s, handshake))) + { + WLog_ERR(TAG, "rail_read_handshake_order failed with error %" PRIu32 "!", error); + return error; + } + + IFCALLRET(context->ClientHandshake, error, context, handshake); + + if (error) + WLog_ERR(TAG, "context.ClientHandshake failed with error %" PRIu32 "", error); + + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_recv_client_client_status_order(RailServerContext* context, + RAIL_CLIENT_STATUS_ORDER* clientStatus, wStream* s) +{ + UINT error; + + if (!context || !clientStatus || !s) + return ERROR_INVALID_PARAMETER; + + if ((error = rail_read_client_status_order(s, clientStatus))) + { + WLog_ERR(TAG, "rail_read_client_status_order failed with error %" PRIu32 "!", error); + return error; + } + + IFCALLRET(context->ClientClientStatus, error, context, clientStatus); + + if (error) + WLog_ERR(TAG, "context.ClientClientStatus failed with error %" PRIu32 "", error); + + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_recv_client_exec_order(RailServerContext* context, wStream* s) +{ + UINT error; + RAIL_EXEC_ORDER exec = { 0 }; + + if (!context || !s) + return ERROR_INVALID_PARAMETER; + + if ((error = rail_read_exec_order(s, &exec))) + { + WLog_ERR(TAG, "rail_read_client_status_order failed with error %" PRIu32 "!", error); + return error; + } + + IFCALLRET(context->ClientExec, error, context, &exec); + + if (error) + WLog_ERR(TAG, "context.Exec failed with error %" PRIu32 "", error); + + free(exec.RemoteApplicationProgram); + free(exec.RemoteApplicationArguments); + free(exec.RemoteApplicationWorkingDir); + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_recv_client_sysparam_order(RailServerContext* context, + RAIL_SYSPARAM_ORDER* sysparam, wStream* s) +{ + UINT error; + BOOL extendedSpiSupported; + + if (!context || !sysparam || !s) + return ERROR_INVALID_PARAMETER; + + extendedSpiSupported = rail_is_extended_spi_supported(context->priv->channelFlags); + if ((error = rail_read_sysparam_order(s, sysparam, extendedSpiSupported))) + { + WLog_ERR(TAG, "rail_read_sysparam_order failed with error %" PRIu32 "!", error); + return error; + } + + IFCALLRET(context->ClientSysparam, error, context, sysparam); + + if (error) + WLog_ERR(TAG, "context.ClientSysparam failed with error %" PRIu32 "", error); + + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_recv_client_activate_order(RailServerContext* context, + RAIL_ACTIVATE_ORDER* activate, wStream* s) +{ + UINT error; + + if (!context || !activate || !s) + return ERROR_INVALID_PARAMETER; + + if ((error = rail_read_activate_order(s, activate))) + { + WLog_ERR(TAG, "rail_read_activate_order failed with error %" PRIu32 "!", error); + return error; + } + + IFCALLRET(context->ClientActivate, error, context, activate); + + if (error) + WLog_ERR(TAG, "context.ClientActivate failed with error %" PRIu32 "", error); + + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_recv_client_sysmenu_order(RailServerContext* context, RAIL_SYSMENU_ORDER* sysmenu, + wStream* s) +{ + UINT error; + + if (!context || !sysmenu || !s) + return ERROR_INVALID_PARAMETER; + + if ((error = rail_read_sysmenu_order(s, sysmenu))) + { + WLog_ERR(TAG, "rail_read_sysmenu_order failed with error %" PRIu32 "!", error); + return error; + } + + IFCALLRET(context->ClientSysmenu, error, context, sysmenu); + + if (error) + WLog_ERR(TAG, "context.ClientSysmenu failed with error %" PRIu32 "", error); + + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_recv_client_syscommand_order(RailServerContext* context, + RAIL_SYSCOMMAND_ORDER* syscommand, wStream* s) +{ + UINT error; + + if (!context || !syscommand || !s) + return ERROR_INVALID_PARAMETER; + + if ((error = rail_read_syscommand_order(s, syscommand))) + { + WLog_ERR(TAG, "rail_read_syscommand_order failed with error %" PRIu32 "!", error); + return error; + } + + IFCALLRET(context->ClientSyscommand, error, context, syscommand); + + if (error) + WLog_ERR(TAG, "context.ClientSyscommand failed with error %" PRIu32 "", error); + + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_recv_client_notify_event_order(RailServerContext* context, + RAIL_NOTIFY_EVENT_ORDER* notifyEvent, wStream* s) +{ + UINT error; + + if (!context || !notifyEvent || !s) + return ERROR_INVALID_PARAMETER; + + if ((error = rail_read_notify_event_order(s, notifyEvent))) + { + WLog_ERR(TAG, "rail_read_notify_event_order failed with error %" PRIu32 "!", error); + return error; + } + + IFCALLRET(context->ClientNotifyEvent, error, context, notifyEvent); + + if (error) + WLog_ERR(TAG, "context.ClientNotifyEvent failed with error %" PRIu32 "", error); + + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_recv_client_window_move_order(RailServerContext* context, + RAIL_WINDOW_MOVE_ORDER* windowMove, wStream* s) +{ + UINT error; + + if (!context || !windowMove || !s) + return ERROR_INVALID_PARAMETER; + + if ((error = rail_read_window_move_order(s, windowMove))) + { + WLog_ERR(TAG, "rail_read_window_move_order failed with error %" PRIu32 "!", error); + return error; + } + + IFCALLRET(context->ClientWindowMove, error, context, windowMove); + + if (error) + WLog_ERR(TAG, "context.ClientWindowMove failed with error %" PRIu32 "", error); + + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_recv_client_snap_arrange_order(RailServerContext* context, + RAIL_SNAP_ARRANGE* snapArrange, wStream* s) +{ + UINT error; + + if (!context || !snapArrange || !s) + return ERROR_INVALID_PARAMETER; + + if ((error = rail_read_snap_arange_order(s, snapArrange))) + { + WLog_ERR(TAG, "rail_read_snap_arange_order failed with error %" PRIu32 "!", error); + return error; + } + + IFCALLRET(context->ClientSnapArrange, error, context, snapArrange); + + if (error) + WLog_ERR(TAG, "context.ClientSnapArrange failed with error %" PRIu32 "", error); + + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_recv_client_get_appid_req_order(RailServerContext* context, + RAIL_GET_APPID_REQ_ORDER* getAppidReq, wStream* s) +{ + UINT error; + + if (!context || !getAppidReq || !s) + return ERROR_INVALID_PARAMETER; + + if ((error = rail_read_get_appid_req_order(s, getAppidReq))) + { + WLog_ERR(TAG, "rail_read_get_appid_req_order failed with error %" PRIu32 "!", error); + return error; + } + + IFCALLRET(context->ClientGetAppidReq, error, context, getAppidReq); + + if (error) + WLog_ERR(TAG, "context.ClientGetAppidReq failed with error %" PRIu32 "", error); + + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_recv_client_langbar_info_order(RailServerContext* context, + RAIL_LANGBAR_INFO_ORDER* langbarInfo, wStream* s) +{ + UINT error; + + if (!context || !langbarInfo || !s) + return ERROR_INVALID_PARAMETER; + + if ((error = rail_read_langbar_info_order(s, langbarInfo))) + { + WLog_ERR(TAG, "rail_read_langbar_info_order failed with error %" PRIu32 "!", error); + return error; + } + + IFCALLRET(context->ClientLangbarInfo, error, context, langbarInfo); + + if (error) + WLog_ERR(TAG, "context.ClientLangbarInfo failed with error %" PRIu32 "", error); + + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_recv_client_language_ime_info_order(RailServerContext* context, + RAIL_LANGUAGEIME_INFO_ORDER* languageImeInfo, + wStream* s) +{ + UINT error; + + if (!context || !languageImeInfo || !s) + return ERROR_INVALID_PARAMETER; + + if ((error = rail_read_language_ime_info_order(s, languageImeInfo))) + { + WLog_ERR(TAG, "rail_read_language_ime_info_order failed with error %" PRIu32 "!", error); + return error; + } + + IFCALLRET(context->ClientLanguageImeInfo, error, context, languageImeInfo); + + if (error) + WLog_ERR(TAG, "context.ClientLanguageImeInfo failed with error %" PRIu32 "", error); + + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_recv_client_compartment_info(RailServerContext* context, + RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo, + wStream* s) +{ + UINT error; + + if (!context || !compartmentInfo || !s) + return ERROR_INVALID_PARAMETER; + + if ((error = rail_read_compartment_info_order(s, compartmentInfo))) + { + WLog_ERR(TAG, "rail_read_compartment_info_order failed with error %" PRIu32 "!", error); + return error; + } + + IFCALLRET(context->ClientCompartmentInfo, error, context, compartmentInfo); + + if (error) + WLog_ERR(TAG, "context.ClientCompartmentInfo failed with error %" PRIu32 "", error); + + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_recv_client_cloak_order(RailServerContext* context, RAIL_CLOAK* cloak, wStream* s) +{ + UINT error; + + if (!context || !cloak || !s) + return ERROR_INVALID_PARAMETER; + + if ((error = rail_read_cloak_order(s, cloak))) + { + WLog_ERR(TAG, "rail_read_cloak_order failed with error %" PRIu32 "!", error); + return error; + } + + IFCALLRET(context->ClientCloak, error, context, cloak); + + if (error) + WLog_ERR(TAG, "context.Cloak failed with error %" PRIu32 "", error); + + return error; +} + +static DWORD WINAPI rail_server_thread(LPVOID arg) +{ + RailServerContext* context = (RailServerContext*)arg; + RailServerPrivate* priv = context->priv; + DWORD status; + DWORD nCount = 0; + HANDLE events[8]; + UINT error = CHANNEL_RC_OK; + events[nCount++] = priv->channelEvent; + events[nCount++] = priv->stopEvent; + + while (TRUE) + { + status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); + + if (status == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", error); + break; + } + + status = WaitForSingleObject(context->priv->stopEvent, 0); + + if (status == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error); + break; + } + + if (status == WAIT_OBJECT_0) + break; + + status = WaitForSingleObject(context->priv->channelEvent, 0); + + if (status == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR( + TAG, + "WaitForSingleObject(context->priv->channelEvent, 0) failed with error %" PRIu32 + "!", + error); + break; + } + + if (status == WAIT_OBJECT_0) + { + if ((error = rail_server_handle_messages(context))) + { + WLog_ERR(TAG, "rail_server_handle_messages failed with error %" PRIu32 "", error); + break; + } + } + } + + if (error && context->rdpcontext) + setChannelError(context->rdpcontext, error, "rail_server_thread reported an error"); + + ExitThread(error); + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rail_server_start(RailServerContext* context) +{ + void* buffer = NULL; + DWORD bytesReturned; + RailServerPrivate* priv = context->priv; + UINT error = ERROR_INTERNAL_ERROR; + priv->rail_channel = + WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, RAIL_SVC_CHANNEL_NAME); + + if (!priv->rail_channel) + { + WLog_ERR(TAG, "WTSVirtualChannelOpen failed!"); + return error; + } + + if (!WTSVirtualChannelQuery(priv->rail_channel, WTSVirtualEventHandle, &buffer, + &bytesReturned) || + (bytesReturned != sizeof(HANDLE))) + { + WLog_ERR(TAG, + "error during WTSVirtualChannelQuery(WTSVirtualEventHandle) or invalid returned " + "size(%" PRIu32 ")", + bytesReturned); + + if (buffer) + WTSFreeMemory(buffer); + + goto out_close; + } + + CopyMemory(&priv->channelEvent, buffer, sizeof(HANDLE)); + WTSFreeMemory(buffer); + context->priv->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + if (!context->priv->stopEvent) + { + WLog_ERR(TAG, "CreateEvent failed!"); + goto out_close; + } + + context->priv->thread = CreateThread(NULL, 0, rail_server_thread, (void*)context, 0, NULL); + + if (!context->priv->thread) + { + WLog_ERR(TAG, "CreateThread failed!"); + goto out_stop_event; + } + + return CHANNEL_RC_OK; +out_stop_event: + CloseHandle(context->priv->stopEvent); + context->priv->stopEvent = NULL; +out_close: + WTSVirtualChannelClose(context->priv->rail_channel); + context->priv->rail_channel = NULL; + return error; +} + +static BOOL rail_server_stop(RailServerContext* context) +{ + RailServerPrivate* priv = (RailServerPrivate*)context->priv; + + if (priv->thread) + { + SetEvent(priv->stopEvent); + + if (WaitForSingleObject(priv->thread, INFINITE) == WAIT_FAILED) + { + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", GetLastError()); + return FALSE; + } + + CloseHandle(priv->thread); + CloseHandle(priv->stopEvent); + priv->thread = NULL; + priv->stopEvent = NULL; + } + + if (priv->rail_channel) + { + WTSVirtualChannelClose(priv->rail_channel); + priv->rail_channel = NULL; + } + + priv->channelEvent = NULL; + return TRUE; +} + +RailServerContext* rail_server_context_new(HANDLE vcm) +{ + RailServerContext* context; + RailServerPrivate* priv; + context = (RailServerContext*)calloc(1, sizeof(RailServerContext)); + + if (!context) + { + WLog_ERR(TAG, "calloc failed!"); + return NULL; + } + + context->vcm = vcm; + context->Start = rail_server_start; + context->Stop = rail_server_stop; + context->ServerHandshake = rail_send_server_handshake; + context->ServerHandshakeEx = rail_send_server_handshake_ex; + context->ServerSysparam = rail_send_server_sysparam; + context->ServerLocalMoveSize = rail_send_server_local_move_size; + context->ServerMinMaxInfo = rail_send_server_min_max_info; + context->ServerTaskbarInfo = rail_send_server_taskbar_info; + context->ServerLangbarInfo = rail_send_server_langbar_info; + context->ServerExecResult = rail_send_server_exec_result; + context->ServerGetAppidResp = rail_send_server_get_app_id_resp; + context->ServerZOrderSync = rail_send_server_z_order_sync; + context->ServerCloak = rail_send_server_cloak; + context->ServerPowerDisplayRequest = rail_send_server_power_display_request; + context->ServerGetAppidRespEx = rail_send_server_get_appid_resp_ex; + context->priv = priv = (RailServerPrivate*)calloc(1, sizeof(RailServerPrivate)); + + if (!priv) + { + WLog_ERR(TAG, "calloc failed!"); + goto out_free; + } + + /* Create shared input stream */ + priv->input_stream = Stream_New(NULL, 4096); + + if (!priv->input_stream) + { + WLog_ERR(TAG, "Stream_New failed!"); + goto out_free_priv; + } + + return context; +out_free_priv: + free(context->priv); +out_free: + free(context); + return NULL; +} + +void rail_server_context_free(RailServerContext* context) +{ + if (context->priv) + Stream_Free(context->priv->input_stream, TRUE); + + free(context->priv); + free(context); +} + +void rail_server_set_handshake_ex_flags(RailServerContext* context, DWORD flags) +{ + RailServerPrivate* priv; + + if (!context || !context->priv) + return; + + priv = context->priv; + priv->channelFlags = flags; +} + +UINT rail_server_handle_messages(RailServerContext* context) +{ + UINT status = CHANNEL_RC_OK; + DWORD bytesReturned; + UINT16 orderType; + UINT16 orderLength; + RailServerPrivate* priv = context->priv; + wStream* s = priv->input_stream; + + /* Read header */ + if (!Stream_EnsureRemainingCapacity(s, RAIL_PDU_HEADER_LENGTH)) + { + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed, RAIL_PDU_HEADER_LENGTH"); + return CHANNEL_RC_NO_MEMORY; + } + + if (!WTSVirtualChannelRead(priv->rail_channel, 0, (PCHAR)Stream_Pointer(s), + RAIL_PDU_HEADER_LENGTH, &bytesReturned)) + { + if (GetLastError() == ERROR_NO_DATA) + return ERROR_NO_DATA; + + WLog_ERR(TAG, "channel connection closed"); + return ERROR_INTERNAL_ERROR; + } + + /* Parse header */ + if ((status = rail_read_pdu_header(s, &orderType, &orderLength)) != CHANNEL_RC_OK) + { + WLog_ERR(TAG, "rail_read_pdu_header failed with error %" PRIu32 "!", status); + return status; + } + + if (!Stream_EnsureRemainingCapacity(s, orderLength - RAIL_PDU_HEADER_LENGTH)) + { + WLog_ERR(TAG, + "Stream_EnsureRemainingCapacity failed, orderLength - RAIL_PDU_HEADER_LENGTH"); + return CHANNEL_RC_NO_MEMORY; + } + + /* Read body */ + if (!WTSVirtualChannelRead(priv->rail_channel, 0, (PCHAR)Stream_Pointer(s), + orderLength - RAIL_PDU_HEADER_LENGTH, &bytesReturned)) + { + if (GetLastError() == ERROR_NO_DATA) + return ERROR_NO_DATA; + + WLog_ERR(TAG, "channel connection closed"); + return ERROR_INTERNAL_ERROR; + } + + WLog_DBG(TAG, "Received %s PDU, length:%" PRIu16 "", rail_get_order_type_string(orderType), + orderLength); + + switch (orderType) + { + case TS_RAIL_ORDER_HANDSHAKE: + { + RAIL_HANDSHAKE_ORDER handshake; + return rail_recv_client_handshake_order(context, &handshake, s); + } + + case TS_RAIL_ORDER_CLIENTSTATUS: + { + RAIL_CLIENT_STATUS_ORDER clientStatus; + return rail_recv_client_client_status_order(context, &clientStatus, s); + } + + case TS_RAIL_ORDER_EXEC: + return rail_recv_client_exec_order(context, s); + + case TS_RAIL_ORDER_SYSPARAM: + { + RAIL_SYSPARAM_ORDER sysparam = { 0 }; + return rail_recv_client_sysparam_order(context, &sysparam, s); + } + + case TS_RAIL_ORDER_ACTIVATE: + { + RAIL_ACTIVATE_ORDER activate; + return rail_recv_client_activate_order(context, &activate, s); + } + + case TS_RAIL_ORDER_SYSMENU: + { + RAIL_SYSMENU_ORDER sysmenu; + return rail_recv_client_sysmenu_order(context, &sysmenu, s); + } + + case TS_RAIL_ORDER_SYSCOMMAND: + { + RAIL_SYSCOMMAND_ORDER syscommand; + return rail_recv_client_syscommand_order(context, &syscommand, s); + } + + case TS_RAIL_ORDER_NOTIFY_EVENT: + { + RAIL_NOTIFY_EVENT_ORDER notifyEvent; + return rail_recv_client_notify_event_order(context, ¬ifyEvent, s); + } + + case TS_RAIL_ORDER_WINDOWMOVE: + { + RAIL_WINDOW_MOVE_ORDER windowMove; + return rail_recv_client_window_move_order(context, &windowMove, s); + } + + case TS_RAIL_ORDER_SNAP_ARRANGE: + { + RAIL_SNAP_ARRANGE snapArrange; + return rail_recv_client_snap_arrange_order(context, &snapArrange, s); + } + + case TS_RAIL_ORDER_GET_APPID_REQ: + { + RAIL_GET_APPID_REQ_ORDER getAppidReq; + return rail_recv_client_get_appid_req_order(context, &getAppidReq, s); + } + + case TS_RAIL_ORDER_LANGBARINFO: + { + RAIL_LANGBAR_INFO_ORDER langbarInfo; + return rail_recv_client_langbar_info_order(context, &langbarInfo, s); + } + + case TS_RAIL_ORDER_LANGUAGEIMEINFO: + { + RAIL_LANGUAGEIME_INFO_ORDER languageImeInfo; + return rail_recv_client_language_ime_info_order(context, &languageImeInfo, s); + } + + case TS_RAIL_ORDER_COMPARTMENTINFO: + { + RAIL_COMPARTMENT_INFO_ORDER compartmentInfo; + return rail_recv_client_compartment_info(context, &compartmentInfo, s); + } + + case TS_RAIL_ORDER_CLOAK: + { + RAIL_CLOAK cloak; + return rail_recv_client_cloak_order(context, &cloak, s); + } + + default: + WLog_ERR(TAG, "Unknown RAIL PDU order received."); + return ERROR_INVALID_DATA; + } + + Stream_SetPosition(s, 0); + return status; +} diff --git a/channels/rail/server/rail_main.h b/channels/rail/server/rail_main.h new file mode 100644 index 0000000..5c56331 --- /dev/null +++ b/channels/rail/server/rail_main.h @@ -0,0 +1,44 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * RAIL Virtual Channel Plugin + * + * Copyright 2019 Mati Shabtay + * + * 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_CHANNEL_RAIL_SERVER_MAIN_H +#define FREERDP_CHANNEL_RAIL_SERVER_MAIN_H + +#include +#include + +#include +#include +#include + +#include "../rail_common.h" + +struct _rail_server_private +{ + HANDLE thread; + HANDLE stopEvent; + HANDLE channelEvent; + void* rail_channel; + + wStream* input_stream; + + DWORD channelFlags; +}; + +#endif /* FREERDP_CHANNEL_RAIL_SERVER_MAIN_H */ \ No newline at end of file diff --git a/channels/rdp2tcp/CMakeLists.txt b/channels/rdp2tcp/CMakeLists.txt new file mode 100644 index 0000000..31de127 --- /dev/null +++ b/channels/rdp2tcp/CMakeLists.txt @@ -0,0 +1,22 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# 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. + +define_channel("rdp2tcp") + +if(WITH_CLIENT_CHANNELS) + add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME}) +endif() diff --git a/channels/rdp2tcp/ChannelOptions.cmake b/channels/rdp2tcp/ChannelOptions.cmake new file mode 100644 index 0000000..3cad9b1 --- /dev/null +++ b/channels/rdp2tcp/ChannelOptions.cmake @@ -0,0 +1,10 @@ +set(OPTION_DEFAULT OFF) +set(OPTION_CLIENT_DEFAULT ON) +set(OPTION_SERVER_DEFAULT OFF) + +define_channel_options(NAME "rdp2tcp" TYPE "static" + DESCRIPTION "Tunneling TCP over RDP" + DEFAULT ${OPTION_DEFAULT}) + +define_channel_client_options(${OPTION_CLIENT_DEFAULT}) +define_channel_server_options(${OPTION_SERVER_DEFAULT}) diff --git a/channels/rdp2tcp/client/CMakeLists.txt b/channels/rdp2tcp/client/CMakeLists.txt new file mode 100644 index 0000000..2e51020 --- /dev/null +++ b/channels/rdp2tcp/client/CMakeLists.txt @@ -0,0 +1,27 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# 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. + +define_channel_client("rdp2tcp") + +set(${MODULE_PREFIX}_SRCS + rdp2tcp_main.c) + +add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "VirtualChannelEntryEx") + +target_link_libraries(${MODULE_NAME} freerdp) + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/rdp2tcp/client/rdp2tcp_main.c b/channels/rdp2tcp/client/rdp2tcp_main.c new file mode 100644 index 0000000..58a2ef5 --- /dev/null +++ b/channels/rdp2tcp/client/rdp2tcp_main.c @@ -0,0 +1,327 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * rdp2tcp Virtual Channel Extension + * + * Copyright 2017 Artur Zaprzala + * + * 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 + +#define RDP2TCP_CHAN_NAME "rdp2tcp" + +#include +#define TAG CLIENT_TAG(RDP2TCP_CHAN_NAME) + +static int const debug = 0; + +typedef struct +{ + HANDLE hStdOutputRead; + HANDLE hStdInputWrite; + HANDLE hProcess; + HANDLE copyThread; + HANDLE writeComplete; + DWORD openHandle; + void* initHandle; + CHANNEL_ENTRY_POINTS_FREERDP_EX channelEntryPoints; + char buffer[16 * 1024]; +} Plugin; + +static int init_external_addin(Plugin* plugin) +{ + SECURITY_ATTRIBUTES saAttr; + STARTUPINFO siStartInfo; + PROCESS_INFORMATION procInfo; + saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + saAttr.bInheritHandle = TRUE; + saAttr.lpSecurityDescriptor = NULL; + siStartInfo.cb = sizeof(STARTUPINFO); + siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); + siStartInfo.dwFlags = STARTF_USESTDHANDLES; + + // Create pipes + if (!CreatePipe(&plugin->hStdOutputRead, &siStartInfo.hStdOutput, &saAttr, 0)) + { + WLog_ERR(TAG, "stdout CreatePipe"); + return -1; + } + + if (!SetHandleInformation(plugin->hStdOutputRead, HANDLE_FLAG_INHERIT, 0)) + { + WLog_ERR(TAG, "stdout SetHandleInformation"); + return -1; + } + + if (!CreatePipe(&siStartInfo.hStdInput, &plugin->hStdInputWrite, &saAttr, 0)) + { + WLog_ERR(TAG, "stdin CreatePipe"); + return -1; + } + + if (!SetHandleInformation(plugin->hStdInputWrite, HANDLE_FLAG_INHERIT, 0)) + { + WLog_ERR(TAG, "stdin SetHandleInformation"); + return -1; + } + + // Execute plugin + if (!CreateProcess(NULL, + plugin->channelEntryPoints.pExtendedData, // command line + NULL, // process security attributes + NULL, // primary thread security attributes + TRUE, // handles are inherited + 0, // creation flags + NULL, // use parent's environment + NULL, // use parent's current directory + &siStartInfo, // STARTUPINFO pointer + &procInfo // receives PROCESS_INFORMATION + )) + { + WLog_ERR(TAG, "fork for addin"); + return -1; + } + + plugin->hProcess = procInfo.hProcess; + CloseHandle(procInfo.hThread); + CloseHandle(siStartInfo.hStdOutput); + CloseHandle(siStartInfo.hStdInput); + return 0; +} + +static void dumpData(char* data, unsigned length) +{ + unsigned const limit = 98; + unsigned l = length > limit ? limit / 2 : length; + unsigned i; + + for (i = 0; i < l; ++i) + { + printf("%02hhx", data[i]); + } + + if (length > limit) + { + printf("..."); + + for (i = length - l; i < length; ++i) + printf("%02hhx", data[i]); + } + + puts(""); +} + +static DWORD WINAPI copyThread(void* data) +{ + Plugin* plugin = (Plugin*)data; + size_t const bufsize = 16 * 1024; + + while (1) + { + DWORD dwRead; + char* buffer = malloc(bufsize); + + if (!buffer) + { + fprintf(stderr, "rdp2tcp copyThread: malloc failed\n"); + goto fail; + } + + // if (!ReadFile(plugin->hStdOutputRead, plugin->buffer, sizeof plugin->buffer, &dwRead, + // NULL)) + if (!ReadFile(plugin->hStdOutputRead, buffer, bufsize, &dwRead, NULL)) + { + free(buffer); + goto fail; + } + + if (debug > 1) + { + printf(">%8u ", (unsigned)dwRead); + dumpData(buffer, dwRead); + } + + if (plugin->channelEntryPoints.pVirtualChannelWriteEx( + plugin->initHandle, plugin->openHandle, buffer, dwRead, buffer) != CHANNEL_RC_OK) + { + free(buffer); + fprintf(stderr, "rdp2tcp copyThread failed %i\n", (int)dwRead); + goto fail; + } + + WaitForSingleObject(plugin->writeComplete, INFINITE); + ResetEvent(plugin->writeComplete); + } + +fail: + ExitThread(0); + return 0; +} + +static void closeChannel(Plugin* plugin) +{ + if (debug) + puts("rdp2tcp closing channel"); + + plugin->channelEntryPoints.pVirtualChannelCloseEx(plugin->initHandle, plugin->openHandle); +} + +static void dataReceived(Plugin* plugin, void* pData, UINT32 dataLength, UINT32 totalLength, + UINT32 dataFlags) +{ + DWORD dwWritten; + + if (dataFlags & CHANNEL_FLAG_SUSPEND) + { + if (debug) + puts("rdp2tcp Channel Suspend"); + + return; + } + + if (dataFlags & CHANNEL_FLAG_RESUME) + { + if (debug) + puts("rdp2tcp Channel Resume"); + + return; + } + + if (debug > 1) + { + printf("<%c%3u/%3u ", dataFlags & CHANNEL_FLAG_FIRST ? ' ' : '+', totalLength, dataLength); + dumpData(pData, dataLength); + } + + if (dataFlags & CHANNEL_FLAG_FIRST) + { + if (!WriteFile(plugin->hStdInputWrite, &totalLength, sizeof(totalLength), &dwWritten, NULL)) + closeChannel(plugin); + } + + if (!WriteFile(plugin->hStdInputWrite, pData, dataLength, &dwWritten, NULL)) + closeChannel(plugin); +} + +static void VCAPITYPE VirtualChannelOpenEventEx(LPVOID lpUserParam, DWORD openHandle, UINT event, + LPVOID pData, UINT32 dataLength, UINT32 totalLength, + UINT32 dataFlags) +{ + Plugin* plugin = (Plugin*)lpUserParam; + + switch (event) + { + case CHANNEL_EVENT_DATA_RECEIVED: + dataReceived(plugin, pData, dataLength, totalLength, dataFlags); + break; + + case CHANNEL_EVENT_WRITE_CANCELLED: + free(pData); + break; + case CHANNEL_EVENT_WRITE_COMPLETE: + SetEvent(plugin->writeComplete); + free(pData); + break; + } +} + +static VOID VCAPITYPE VirtualChannelInitEventEx(LPVOID lpUserParam, LPVOID pInitHandle, UINT event, + LPVOID pData, UINT dataLength) +{ + Plugin* plugin = (Plugin*)lpUserParam; + + switch (event) + { + case CHANNEL_EVENT_CONNECTED: + if (debug) + puts("rdp2tcp connected"); + + plugin->writeComplete = CreateEvent(NULL, TRUE, FALSE, NULL); + plugin->copyThread = CreateThread(NULL, 0, copyThread, plugin, 0, NULL); + + if (plugin->channelEntryPoints.pVirtualChannelOpenEx( + pInitHandle, &plugin->openHandle, RDP2TCP_CHAN_NAME, + VirtualChannelOpenEventEx) != CHANNEL_RC_OK) + return; + + break; + + case CHANNEL_EVENT_DISCONNECTED: + if (debug) + puts("rdp2tcp disconnected"); + + break; + + case CHANNEL_EVENT_TERMINATED: + if (debug) + puts("rdp2tcp terminated"); + + if (plugin->copyThread) + { + TerminateThread(plugin->copyThread, 0); + CloseHandle(plugin->writeComplete); + } + + CloseHandle(plugin->hStdInputWrite); + CloseHandle(plugin->hStdOutputRead); + TerminateProcess(plugin->hProcess, 0); + CloseHandle(plugin->hProcess); + free(plugin); + break; + } +} + +#if 1 +#define VirtualChannelEntryEx rdp2tcp_VirtualChannelEntryEx +#else +#define VirtualChannelEntryEx FREERDP_API VirtualChannelEntryEx +#endif +BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID pInitHandle) +{ + CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx; + CHANNEL_DEF channelDef; + Plugin* plugin = (Plugin*)calloc(1, sizeof(Plugin)); + + if (!plugin) + return FALSE; + + pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints; + assert(pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX) && + pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER); + plugin->initHandle = pInitHandle; + plugin->channelEntryPoints = *pEntryPointsEx; + + if (init_external_addin(plugin) < 0) + return FALSE; + + strncpy(channelDef.name, RDP2TCP_CHAN_NAME, sizeof(channelDef.name)); + channelDef.options = + CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_COMPRESS_RDP; + + if (pEntryPointsEx->pVirtualChannelInitEx(plugin, NULL, pInitHandle, &channelDef, 1, + VIRTUAL_CHANNEL_VERSION_WIN2000, + VirtualChannelInitEventEx) != CHANNEL_RC_OK) + return FALSE; + + return TRUE; +} + +// vim:ts=4 diff --git a/channels/rdpdr/client/devman.c b/channels/rdpdr/client/devman.c index 93db1b7..af3cdd6 100644 --- a/channels/rdpdr/client/devman.c +++ b/channels/rdpdr/client/devman.c @@ -43,7 +43,7 @@ static void devman_device_free(void* obj) { - DEVICE* device = (DEVICE*) obj; + DEVICE* device = (DEVICE*)obj; if (!device) return; @@ -58,27 +58,26 @@ DEVMAN* devman_new(rdpdrPlugin* rdpdr) if (!rdpdr) return NULL; - devman = (DEVMAN*) calloc(1, sizeof(DEVMAN)); + devman = (DEVMAN*)calloc(1, sizeof(DEVMAN)); if (!devman) { - WLog_INFO(TAG, "calloc failed!"); + WLog_INFO(TAG, "calloc failed!"); return NULL; } - devman->plugin = (void*) rdpdr; + devman->plugin = (void*)rdpdr; devman->id_sequence = 1; - devman->devices = ListDictionary_New(TRUE); + if (!devman->devices) { - WLog_INFO(TAG, "ListDictionary_New failed!"); + WLog_INFO(TAG, "ListDictionary_New failed!"); free(devman); return NULL; } ListDictionary_ValueObject(devman->devices)->fnObjectFree = devman_device_free; - return devman; } @@ -95,7 +94,7 @@ void devman_unregister_device(DEVMAN* devman, void* key) if (!devman || !key) return; - device = (DEVICE*) ListDictionary_Remove(devman->devices, key); + device = (DEVICE*)ListDictionary_Remove(devman->devices, key); if (device) devman_device_free(device); @@ -114,46 +113,82 @@ 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!"); + 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); + 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; } -static char DRIVE_SERVICE_NAME[] = "drive"; -static char PRINTER_SERVICE_NAME[] = "printer"; -static char SMARTCARD_SERVICE_NAME[] = "smartcard"; -static char SERIAL_SERVICE_NAME[] = "serial"; -static char PARALLEL_SERVICE_NAME[] = "parallel"; +static const char DRIVE_SERVICE_NAME[] = "drive"; +static const char PRINTER_SERVICE_NAME[] = "printer"; +static const char SMARTCARD_SERVICE_NAME[] = "smartcard"; +static const char SERIAL_SERVICE_NAME[] = "serial"; +static const char PARALLEL_SERVICE_NAME[] = "parallel"; /** * Function description * * @return 0 on success, otherwise a Win32 error code */ -UINT devman_load_device_service(DEVMAN* devman, RDPDR_DEVICE* device, rdpContext* rdpcontext) +UINT devman_load_device_service(DEVMAN* devman, const RDPDR_DEVICE* device, rdpContext* rdpcontext) { - char* ServiceName = NULL; + const char* ServiceName = NULL; DEVICE_SERVICE_ENTRY_POINTS ep; PDEVICE_SERVICE_ENTRY entry = NULL; + union { + const RDPDR_DEVICE* cdp; + RDPDR_DEVICE* dp; + } devconv; + devconv.cdp = device; if (!devman || !device || !rdpcontext) return ERROR_INVALID_PARAMETER; @@ -170,26 +205,27 @@ UINT devman_load_device_service(DEVMAN* devman, RDPDR_DEVICE* device, rdpContext if (!ServiceName) { - WLog_INFO(TAG, "ServiceName %s did not match!", ServiceName); + WLog_INFO(TAG, "ServiceName %s did not match!", ServiceName); return ERROR_INVALID_NAME; } if (device->Name) - WLog_INFO(TAG, "Loading device service %s [%s] (static)", ServiceName, device->Name); + 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); + WLog_INFO(TAG, "Loading device service %s (static)", ServiceName); + + entry = (PDEVICE_SERVICE_ENTRY)freerdp_load_channel_addin_entry(ServiceName, NULL, + "DeviceServiceEntry", 0); if (!entry) { - WLog_INFO(TAG, "freerdp_load_channel_addin_entry failed!"); + WLog_INFO(TAG, "freerdp_load_channel_addin_entry failed!"); return ERROR_INTERNAL_ERROR; } ep.devman = devman; ep.RegisterDevice = devman_register_device; - ep.device = device; + ep.device = devconv.dp; ep.rdpcontext = rdpcontext; - return entry(&ep); } diff --git a/channels/rdpdr/client/devman.h b/channels/rdpdr/client/devman.h index c99a179..2e6019e 100644 --- a/channels/rdpdr/client/devman.h +++ b/channels/rdpdr/client/devman.h @@ -26,8 +26,9 @@ #include "rdpdr_main.h" void devman_unregister_device(DEVMAN* devman, void* key); -UINT devman_load_device_service(DEVMAN* devman, RDPDR_DEVICE* device, rdpContext* rdpcontext); +UINT devman_load_device_service(DEVMAN* devman, const 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/irp.c b/channels/rdpdr/client/irp.c index 21d4a46..b818b67 100644 --- a/channels/rdpdr/client/irp.c +++ b/channels/rdpdr/client/irp.c @@ -63,7 +63,7 @@ static UINT irp_complete(IRP* irp) rdpdrPlugin* rdpdr; UINT error; - rdpdr = (rdpdrPlugin*) irp->devman->plugin; + rdpdr = (rdpdrPlugin*)irp->devman->plugin; pos = Stream_GetPosition(irp->output); Stream_SetPosition(irp->output, RDPDR_DEVICE_IO_RESPONSE_LENGTH - 4); @@ -73,8 +73,7 @@ static UINT irp_complete(IRP* irp) error = rdpdr_send(rdpdr, irp->output); irp->output = NULL; - irp_free(irp); - return error; + return irp_free(irp); } IRP* irp_new(DEVMAN* devman, wStream* s, UINT* error) @@ -102,7 +101,7 @@ IRP* irp_new(DEVMAN* devman, wStream* s, UINT* error) return NULL; }; - irp = (IRP*) _aligned_malloc(sizeof(IRP), MEMORY_ALLOCATION_ALIGNMENT); + irp = (IRP*)_aligned_malloc(sizeof(IRP), MEMORY_ALLOCATION_ALIGNMENT); if (!irp) { @@ -112,15 +111,14 @@ IRP* irp_new(DEVMAN* devman, wStream* s, UINT* error) return NULL; } - ZeroMemory(irp, sizeof(IRP)); irp->input = s; irp->device = device; irp->devman = devman; - Stream_Read_UINT32(s, irp->FileId); /* FileId (4 bytes) */ - Stream_Read_UINT32(s, irp->CompletionId); /* CompletionId (4 bytes) */ + Stream_Read_UINT32(s, irp->FileId); /* FileId (4 bytes) */ + Stream_Read_UINT32(s, irp->CompletionId); /* CompletionId (4 bytes) */ Stream_Read_UINT32(s, irp->MajorFunction); /* MajorFunction (4 bytes) */ Stream_Read_UINT32(s, irp->MinorFunction); /* MinorFunction (4 bytes) */ @@ -133,11 +131,11 @@ IRP* irp_new(DEVMAN* devman, wStream* s, UINT* error) *error = CHANNEL_RC_NO_MEMORY; return NULL; } - Stream_Write_UINT16(irp->output, RDPDR_CTYP_CORE); /* Component (2 bytes) */ + Stream_Write_UINT16(irp->output, RDPDR_CTYP_CORE); /* Component (2 bytes) */ Stream_Write_UINT16(irp->output, PAKID_CORE_DEVICE_IOCOMPLETION); /* PacketId (2 bytes) */ - Stream_Write_UINT32(irp->output, DeviceId); /* DeviceId (4 bytes) */ - Stream_Write_UINT32(irp->output, irp->CompletionId); /* CompletionId (4 bytes) */ - Stream_Write_UINT32(irp->output, 0); /* IoStatus (4 bytes) */ + Stream_Write_UINT32(irp->output, DeviceId); /* DeviceId (4 bytes) */ + Stream_Write_UINT32(irp->output, irp->CompletionId); /* CompletionId (4 bytes) */ + Stream_Write_UINT32(irp->output, 0); /* IoStatus (4 bytes) */ irp->Complete = irp_complete; irp->Discard = irp_free; diff --git a/channels/rdpdr/client/rdpdr_capabilities.c b/channels/rdpdr/client/rdpdr_capabilities.c index 4ff3ef5..97c876b 100644 --- a/channels/rdpdr/client/rdpdr_capabilities.c +++ b/channels/rdpdr/client/rdpdr_capabilities.c @@ -36,7 +36,8 @@ #include "rdpdr_capabilities.h" /* Output device redirection capability set header */ -static void rdpdr_write_capset_header(wStream* s, UINT16 capabilityType, UINT16 capabilityLength, UINT32 version) +static void rdpdr_write_capset_header(wStream* s, UINT16 capabilityType, UINT16 capabilityLength, + UINT32 version) { Stream_Write_UINT16(s, capabilityType); Stream_Write_UINT16(s, capabilityLength); @@ -46,41 +47,47 @@ static void rdpdr_write_capset_header(wStream* s, UINT16 capabilityType, UINT16 /* Output device direction general capability set */ static void rdpdr_write_general_capset(rdpdrPlugin* rdpdr, wStream* s) { + WINPR_UNUSED(rdpdr); rdpdr_write_capset_header(s, CAP_GENERAL_TYPE, 44, GENERAL_CAPABILITY_VERSION_02); - Stream_Write_UINT32(s, 0); /* osType, ignored on receipt */ Stream_Write_UINT32(s, 0); /* osVersion, unused and must be set to zero */ Stream_Write_UINT16(s, 1); /* protocolMajorVersion, must be set to 1 */ Stream_Write_UINT16(s, RDPDR_MINOR_RDP_VERSION_5_2); /* protocolMinorVersion */ - Stream_Write_UINT32(s, 0x0000FFFF); /* ioCode1 */ + Stream_Write_UINT32(s, 0x0000FFFF); /* ioCode1 */ Stream_Write_UINT32(s, 0); /* ioCode2, must be set to zero, reserved for future use */ - Stream_Write_UINT32(s, RDPDR_DEVICE_REMOVE_PDUS | RDPDR_CLIENT_DISPLAY_NAME_PDU | RDPDR_USER_LOGGEDON_PDU); /* extendedPDU */ - Stream_Write_UINT32(s, ENABLE_ASYNCIO); /* extraFlags1 */ + Stream_Write_UINT32(s, RDPDR_DEVICE_REMOVE_PDUS | RDPDR_CLIENT_DISPLAY_NAME_PDU | + RDPDR_USER_LOGGEDON_PDU); /* extendedPDU */ + Stream_Write_UINT32(s, ENABLE_ASYNCIO); /* extraFlags1 */ Stream_Write_UINT32(s, 0); /* extraFlags2, must be set to zero, reserved for future use */ - Stream_Write_UINT32(s, 0); /* SpecialTypeDeviceCap, number of special devices to be redirected before logon */ + Stream_Write_UINT32( + s, 0); /* SpecialTypeDeviceCap, number of special devices to be redirected before logon */ } /* Process device direction general capability set */ static UINT rdpdr_process_general_capset(rdpdrPlugin* rdpdr, wStream* s) { UINT16 capabilityLength; + WINPR_UNUSED(rdpdr); if (Stream_GetRemainingLength(s) < 2) return ERROR_INVALID_DATA; Stream_Read_UINT16(s, capabilityLength); - if (Stream_GetRemainingLength(s) < capabilityLength - 4) + if (capabilityLength < 4) return ERROR_INVALID_DATA; - Stream_Seek(s, capabilityLength - 4); + if (Stream_GetRemainingLength(s) < capabilityLength - 4U) + return ERROR_INVALID_DATA; + Stream_Seek(s, capabilityLength - 4U); return CHANNEL_RC_OK; } /* Output printer direction capability set */ static void rdpdr_write_printer_capset(rdpdrPlugin* rdpdr, wStream* s) { + WINPR_UNUSED(rdpdr); rdpdr_write_capset_header(s, CAP_PRINTER_TYPE, 8, PRINT_CAPABILITY_VERSION_01); } @@ -88,23 +95,27 @@ static void rdpdr_write_printer_capset(rdpdrPlugin* rdpdr, wStream* s) static UINT rdpdr_process_printer_capset(rdpdrPlugin* rdpdr, wStream* s) { UINT16 capabilityLength; + WINPR_UNUSED(rdpdr); if (Stream_GetRemainingLength(s) < 2) return ERROR_INVALID_DATA; Stream_Read_UINT16(s, capabilityLength); - if (Stream_GetRemainingLength(s) < capabilityLength - 4) + if (capabilityLength < 4) return ERROR_INVALID_DATA; - Stream_Seek(s, capabilityLength - 4); + if (Stream_GetRemainingLength(s) < capabilityLength - 4U) + return ERROR_INVALID_DATA; + Stream_Seek(s, capabilityLength - 4U); return CHANNEL_RC_OK; } /* Output port redirection capability set */ static void rdpdr_write_port_capset(rdpdrPlugin* rdpdr, wStream* s) { + WINPR_UNUSED(rdpdr); rdpdr_write_capset_header(s, CAP_PORT_TYPE, 8, PORT_CAPABILITY_VERSION_01); } @@ -112,23 +123,27 @@ static void rdpdr_write_port_capset(rdpdrPlugin* rdpdr, wStream* s) static UINT rdpdr_process_port_capset(rdpdrPlugin* rdpdr, wStream* s) { UINT16 capabilityLength; + WINPR_UNUSED(rdpdr); if (Stream_GetRemainingLength(s) < 2) return ERROR_INVALID_DATA; Stream_Read_UINT16(s, capabilityLength); - if (Stream_GetRemainingLength(s) < capabilityLength - 4) + if (capabilityLength < 4U) return ERROR_INVALID_DATA; - Stream_Seek(s, capabilityLength - 4); + if (Stream_GetRemainingLength(s) < capabilityLength - 4U) + return ERROR_INVALID_DATA; + Stream_Seek(s, capabilityLength - 4U); return CHANNEL_RC_OK; } /* Output drive redirection capability set */ static void rdpdr_write_drive_capset(rdpdrPlugin* rdpdr, wStream* s) { + WINPR_UNUSED(rdpdr); rdpdr_write_capset_header(s, CAP_DRIVE_TYPE, 8, DRIVE_CAPABILITY_VERSION_02); } @@ -136,23 +151,27 @@ static void rdpdr_write_drive_capset(rdpdrPlugin* rdpdr, wStream* s) static UINT rdpdr_process_drive_capset(rdpdrPlugin* rdpdr, wStream* s) { UINT16 capabilityLength; + WINPR_UNUSED(rdpdr); if (Stream_GetRemainingLength(s) < 2) return ERROR_INVALID_DATA; Stream_Read_UINT16(s, capabilityLength); - if (Stream_GetRemainingLength(s) < capabilityLength - 4) + if (capabilityLength < 4) return ERROR_INVALID_DATA; - Stream_Seek(s, capabilityLength - 4); + if (Stream_GetRemainingLength(s) < capabilityLength - 4U) + return ERROR_INVALID_DATA; + Stream_Seek(s, capabilityLength - 4U); return CHANNEL_RC_OK; } /* Output smart card redirection capability set */ static void rdpdr_write_smartcard_capset(rdpdrPlugin* rdpdr, wStream* s) { + WINPR_UNUSED(rdpdr); rdpdr_write_capset_header(s, CAP_SMARTCARD_TYPE, 8, SMARTCARD_CAPABILITY_VERSION_01); } @@ -160,17 +179,20 @@ static void rdpdr_write_smartcard_capset(rdpdrPlugin* rdpdr, wStream* s) static UINT rdpdr_process_smartcard_capset(rdpdrPlugin* rdpdr, wStream* s) { UINT16 capabilityLength; + WINPR_UNUSED(rdpdr); if (Stream_GetRemainingLength(s) < 2) return ERROR_INVALID_DATA; Stream_Read_UINT16(s, capabilityLength); - if (Stream_GetRemainingLength(s) < capabilityLength - 4) + if (capabilityLength < 4) return ERROR_INVALID_DATA; - Stream_Seek(s, capabilityLength - 4); + if (Stream_GetRemainingLength(s) < capabilityLength - 4U) + return ERROR_INVALID_DATA; + Stream_Seek(s, capabilityLength - 4U); return CHANNEL_RC_OK; } @@ -199,28 +221,28 @@ UINT rdpdr_process_capability_request(rdpdrPlugin* rdpdr, wStream* s) switch (capabilityType) { - case CAP_GENERAL_TYPE: - status = rdpdr_process_general_capset(rdpdr, s); - break; + case CAP_GENERAL_TYPE: + status = rdpdr_process_general_capset(rdpdr, s); + break; - case CAP_PRINTER_TYPE: - status = rdpdr_process_printer_capset(rdpdr, s); - break; + case CAP_PRINTER_TYPE: + status = rdpdr_process_printer_capset(rdpdr, s); + break; - case CAP_PORT_TYPE: - status = rdpdr_process_port_capset(rdpdr, s); - break; + case CAP_PORT_TYPE: + status = rdpdr_process_port_capset(rdpdr, s); + break; - case CAP_DRIVE_TYPE: - status = rdpdr_process_drive_capset(rdpdr, s); - break; + case CAP_DRIVE_TYPE: + status = rdpdr_process_drive_capset(rdpdr, s); + break; - case CAP_SMARTCARD_TYPE: - status = rdpdr_process_smartcard_capset(rdpdr, s); - break; + case CAP_SMARTCARD_TYPE: + status = rdpdr_process_smartcard_capset(rdpdr, s); + break; - default: - break; + default: + break; } if (status != CHANNEL_RC_OK) @@ -238,8 +260,8 @@ UINT rdpdr_process_capability_request(rdpdrPlugin* rdpdr, wStream* s) UINT rdpdr_send_capability_response(rdpdrPlugin* rdpdr) { wStream* s; - s = Stream_New(NULL, 256); + if (!s) { WLog_ERR(TAG, "Stream_New failed!"); @@ -248,15 +270,12 @@ UINT rdpdr_send_capability_response(rdpdrPlugin* rdpdr) Stream_Write_UINT16(s, RDPDR_CTYP_CORE); Stream_Write_UINT16(s, PAKID_CORE_CLIENT_CAPABILITY); - Stream_Write_UINT16(s, 5); /* numCapabilities */ Stream_Write_UINT16(s, 0); /* pad */ - rdpdr_write_general_capset(rdpdr, s); rdpdr_write_printer_capset(rdpdr, s); rdpdr_write_port_capset(rdpdr, s); rdpdr_write_drive_capset(rdpdr, s); rdpdr_write_smartcard_capset(rdpdr, s); - return rdpdr_send(rdpdr, s); } diff --git a/channels/rdpdr/client/rdpdr_main.c b/channels/rdpdr/client/rdpdr_main.c index 602268f..25c758c 100644 --- a/channels/rdpdr/client/rdpdr_main.c +++ b/channels/rdpdr/client/rdpdr_main.c @@ -81,16 +81,14 @@ struct _DEVICE_DRIVE_EXT * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, - BOOL userLoggedOn); +static UINT rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, BOOL userLoggedOn); /** * Function description * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_send_device_list_remove_request(rdpdrPlugin* rdpdr, - UINT32 count, UINT32 ids[]) +static UINT rdpdr_send_device_list_remove_request(rdpdrPlugin* rdpdr, UINT32 count, UINT32 ids[]) { UINT32 i; wStream* s; @@ -113,7 +111,7 @@ static UINT rdpdr_send_device_list_remove_request(rdpdrPlugin* rdpdr, return rdpdr_send(rdpdr, s); } -#ifdef _UWP +#if defined(_UWP) || defined(__IOS__) void first_hotplug(rdpdrPlugin* rdpdr) { @@ -135,7 +133,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); @@ -143,28 +142,26 @@ BOOL check_path(char* path) void first_hotplug(rdpdrPlugin* rdpdr) { - int i; - char drive_path[5] = { 'c', ':', '\\', '\0' }; + size_t i; DWORD unitmask = GetLogicalDrives(); for (i = 0; i < 26; i++) { if (unitmask & 0x01) { - RDPDR_DRIVE* drive; - drive_path[0] = 'A' + i; - drive_path[1] = ':'; + char drive_path[] = { 'c', ':', '\\', '\0' }; + char drive_name[] = { 'c', '\0' }; + RDPDR_DRIVE drive = { 0 }; + drive_path[0] = 'A' + (char)i; + drive_name[0] = 'A' + (char)i; if (check_path(drive_path)) { - drive = (RDPDR_DRIVE*)malloc(sizeof(RDPDR_DRIVE)); - ZeroMemory(drive, sizeof(RDPDR_DRIVE)); - drive->Type = RDPDR_DTYP_FILESYSTEM; - drive->Path = _strdup(drive_path); - drive_path[1] = '\0'; - drive->Name = _strdup(drive_path); - drive->automount = TRUE; - devman_load_device_service(rdpdr->devman, (RDPDR_DEVICE*)drive, + drive.Type = RDPDR_DTYP_FILESYSTEM; + drive.Path = drive_path; + drive.Name = drive_name; + drive.automount = TRUE; + devman_load_device_service(rdpdr->devman, (const RDPDR_DEVICE*)&drive, rdpdr->rdpcontext); } } @@ -186,31 +183,32 @@ LRESULT CALLBACK hotplug_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) switch (wParam) { case DBT_DEVICEARRIVAL: - if (lpdb -> dbch_devicetype == DBT_DEVTYP_VOLUME) + if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME) { PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb; DWORD unitmask = lpdbv->dbcv_unitmask; int i; - char drive_path[4] = { 'c', ':', '/', '\0'}; for (i = 0; i < 26; i++) { if (unitmask & 0x01) { - RDPDR_DRIVE* drive; - drive_path[0] = 'A' + i; - drive_path[1] = ':'; + char drive_path[] = { 'c', ':', '/', '\0' }; + char drive_name[] = { 'c', '\0' }; + drive_path[0] = 'A' + (char)i; + drive_name[0] = 'A' + (char)i; if (check_path(drive_path)) { - drive = (RDPDR_DRIVE*) malloc(sizeof(RDPDR_DRIVE)); - ZeroMemory(drive, sizeof(RDPDR_DRIVE)); - drive->Type = RDPDR_DTYP_FILESYSTEM; - drive->Path = _strdup(drive_path); + RDPDR_DRIVE drive = { 0 }; + + drive.Type = RDPDR_DTYP_FILESYSTEM; + drive.Path = drive_path; drive_path[1] = '\0'; - drive->automount = TRUE; - drive->Name = _strdup(drive_path); - devman_load_device_service(rdpdr->devman, (RDPDR_DEVICE*)drive, + drive.automount = TRUE; + drive.Name = drive_name; + devman_load_device_service(rdpdr->devman, + (const RDPDR_DEVICE*)&drive, rdpdr->rdpcontext); rdpdr_send_device_list_announce_request(rdpdr, TRUE); } @@ -223,7 +221,7 @@ LRESULT CALLBACK hotplug_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) break; case DBT_DEVICEREMOVECOMPLETE: - if (lpdb -> dbch_devicetype == DBT_DEVTYP_VOLUME) + if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME) { PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb; DWORD unitmask = lpdbv->dbcv_unitmask; @@ -244,21 +242,25 @@ LRESULT CALLBACK hotplug_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) for (j = 0; j < count; j++) { device_ext = (DEVICE_DRIVE_EXT*)ListDictionary_GetItemValue( - rdpdr->devman->devices, (void*)keys[j]); + rdpdr->devman->devices, (void*)keys[j]); - if (device_ext->path[0] == drive_name_upper - || device_ext->path[0] == drive_name_lower) + if (device_ext->path[0] == drive_name_upper || + device_ext->path[0] == drive_name_lower) { if (device_ext->automount) { devman_unregister_device(rdpdr->devman, (void*)keys[j]); ids[0] = keys[j]; - if ((error = rdpdr_send_device_list_remove_request(rdpdr, 1, ids))) + if ((error = rdpdr_send_device_list_remove_request( + rdpdr, 1, ids))) { // dont end on error, just report ? - WLog_ERR(TAG, "rdpdr_send_device_list_remove_request failed with error %"PRIu32"!", - error); + WLog_ERR( + TAG, + "rdpdr_send_device_list_remove_request failed " + "with error %" PRIu32 "!", + error); } break; @@ -299,30 +301,27 @@ static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg) HDEVNOTIFY hDevNotify; rdpdr = (rdpdrPlugin*)arg; /* init windows class */ - wnd_cls.cbSize = sizeof(WNDCLASSEX); - wnd_cls.style = CS_HREDRAW | CS_VREDRAW; - wnd_cls.lpfnWndProc = hotplug_proc; - wnd_cls.cbClsExtra = 0; - wnd_cls.cbWndExtra = 0; - wnd_cls.hIcon = LoadIcon(NULL, IDI_APPLICATION); - wnd_cls.hCursor = NULL; + wnd_cls.cbSize = sizeof(WNDCLASSEX); + wnd_cls.style = CS_HREDRAW | CS_VREDRAW; + wnd_cls.lpfnWndProc = hotplug_proc; + wnd_cls.cbClsExtra = 0; + wnd_cls.cbWndExtra = 0; + wnd_cls.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wnd_cls.hCursor = NULL; wnd_cls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); - wnd_cls.lpszMenuName = NULL; + wnd_cls.lpszMenuName = NULL; wnd_cls.lpszClassName = L"DRIVE_HOTPLUG"; - wnd_cls.hInstance = NULL; - wnd_cls.hIconSm = LoadIcon(NULL, IDI_APPLICATION); + wnd_cls.hInstance = NULL; + wnd_cls.hIconSm = LoadIcon(NULL, IDI_APPLICATION); RegisterClassEx(&wnd_cls); /* create window */ - hwnd = CreateWindowEx(0, L"DRIVE_HOTPLUG", NULL, - 0, 0, 0, 0, 0, - NULL, NULL, NULL, NULL); + hwnd = CreateWindowEx(0, L"DRIVE_HOTPLUG", NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)rdpdr); rdpdr->hotplug_wnd = hwnd; /* register device interface to hwnd */ NotificationFilter.dbch_size = sizeof(DEV_BROADCAST_HANDLE); NotificationFilter.dbch_devicetype = DBT_DEVTYP_HANDLE; - hDevNotify = RegisterDeviceNotification(hwnd, &NotificationFilter, - DEVICE_NOTIFY_WINDOW_HANDLE); + hDevNotify = RegisterDeviceNotification(hwnd, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE); /* message loop */ while ((bRet = GetMessage(&msg, 0, 0, 0)) != 0) @@ -354,23 +353,22 @@ static UINT drive_hotplug_thread_terminate(rdpdrPlugin* rdpdr) if (rdpdr->hotplug_wnd && !PostMessage(rdpdr->hotplug_wnd, WM_QUIT, 0, 0)) { error = GetLastError(); - WLog_ERR(TAG, "PostMessage failed with error %"PRIu32"", error); + WLog_ERR(TAG, "PostMessage failed with error %" PRIu32 "", error); } return error; } -#elif __MACOSX__ +#elif defined(__MACOSX__) #define MAX_USB_DEVICES 100 typedef struct _hotplug_dev { char* path; - BOOL to_add; + BOOL to_add; } hotplug_dev; - /** * Function description * @@ -404,7 +402,8 @@ static UINT handle_hotplug(rdpdrPlugin* rdpdr) if (pDirent->d_name[0] != '.') { sprintf_s(fullpath, ARRAYSIZE(fullpath), "%s/%s", szdir, pDirent->d_name); - lstat(fullpath, &buf); + if (stat(fullpath, &buf) != 0) + continue; if (S_ISDIR(buf.st_mode)) { @@ -430,12 +429,15 @@ static UINT handle_hotplug(rdpdrPlugin* rdpdr) { char* path = NULL; BOOL dev_found = FALSE; - device_ext = (DEVICE_DRIVE_EXT*)ListDictionary_GetItemValue( - rdpdr->devman->devices, (void*)keys[j]); + device_ext = + (DEVICE_DRIVE_EXT*)ListDictionary_GetItemValue(rdpdr->devman->devices, (void*)keys[j]); if (!device_ext || !device_ext->automount) continue; + if (device_ext->device.type != RDPDR_DTYP_FILESYSTEM) + continue; + if (device_ext->path == NULL) continue; @@ -468,7 +470,8 @@ static UINT handle_hotplug(rdpdrPlugin* rdpdr) if ((error = rdpdr_send_device_list_remove_request(rdpdr, 1, ids))) { - WLog_ERR(TAG, "rdpdr_send_device_list_remove_request failed with error %"PRIu32"!", + WLog_ERR(TAG, + "rdpdr_send_device_list_remove_request failed with error %" PRIu32 "!", error); goto cleanup; } @@ -478,43 +481,27 @@ static UINT handle_hotplug(rdpdrPlugin* rdpdr) /* add new devices */ for (i = 0; i < size; i++) { - RDPDR_DRIVE* drive; - if (dev_array[i].to_add) { + RDPDR_DRIVE drive = { 0 }; char* name; - drive = (RDPDR_DRIVE*) calloc(1, sizeof(RDPDR_DRIVE)); - - if (!drive) - { - WLog_ERR(TAG, "calloc failed!"); - error = CHANNEL_RC_NO_MEMORY; - goto cleanup; - } - drive->Type = RDPDR_DTYP_FILESYSTEM; - drive->Path = dev_array[i].path; - drive->automount = TRUE; - dev_array[i].path = NULL; - name = strrchr(drive->Path, '/') + 1; - drive->Name = _strdup(name); + drive.Type = RDPDR_DTYP_FILESYSTEM; + drive.Path = dev_array[i].path; + drive.automount = TRUE; + name = strrchr(drive.Path, '/') + 1; + drive.Name = name; - if (!drive->Name) + if (!drive.Name) { - WLog_ERR(TAG, "_strdup failed!"); - free(drive->Path); - free(drive); error = CHANNEL_RC_NO_MEMORY; goto cleanup; } - if ((error = devman_load_device_service(rdpdr->devman, (RDPDR_DEVICE*)drive, + if ((error = devman_load_device_service(rdpdr->devman, (RDPDR_DEVICE*)&drive, rdpdr->rdpcontext))) { WLog_ERR(TAG, "devman_load_device_service failed!"); - free(drive->Path); - free(drive->Name); - free(drive); error = CHANNEL_RC_NO_MEMORY; goto cleanup; } @@ -530,17 +517,17 @@ cleanup: return error; } - static void drive_hotplug_fsevent_callback(ConstFSEventStreamRef streamRef, - void* clientCallBackInfo, - size_t numEvents, void* eventPaths, const FSEventStreamEventFlags eventFlags[], - const FSEventStreamEventId eventIds[]) + void* clientCallBackInfo, size_t numEvents, + void* eventPaths, + const FSEventStreamEventFlags eventFlags[], + const FSEventStreamEventId eventIds[]) { rdpdrPlugin* rdpdr; - int i; + size_t i; UINT error; char** paths = (char**)eventPaths; - rdpdr = (rdpdrPlugin*) clientCallBackInfo; + rdpdr = (rdpdrPlugin*)clientCallBackInfo; for (i = 0; i < numEvents; i++) { @@ -548,7 +535,7 @@ static void drive_hotplug_fsevent_callback(ConstFSEventStreamRef streamRef, { if ((error = handle_hotplug(rdpdr))) { - WLog_ERR(TAG, "handle_hotplug failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "handle_hotplug failed with error %" PRIu32 "!", error); } else rdpdr_send_device_list_announce_request(rdpdr, TRUE); @@ -564,7 +551,7 @@ void first_hotplug(rdpdrPlugin* rdpdr) if ((error = handle_hotplug(rdpdr))) { - WLog_ERR(TAG, "handle_hotplug failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "handle_hotplug failed with error %" PRIu32 "!", error); } } @@ -572,16 +559,15 @@ static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg) { rdpdrPlugin* rdpdr; FSEventStreamRef fsev; - rdpdr = (rdpdrPlugin*) arg; + rdpdr = (rdpdrPlugin*)arg; CFStringRef path = CFSTR("/Volumes/"); - CFArrayRef pathsToWatch = CFArrayCreate(kCFAllocatorMalloc, (const void**)&path, - 1, NULL); + CFArrayRef pathsToWatch = CFArrayCreate(kCFAllocatorMalloc, (const void**)&path, 1, NULL); FSEventStreamContext ctx; ZeroMemory(&ctx, sizeof(ctx)); ctx.info = arg; - fsev = FSEventStreamCreate(kCFAllocatorMalloc, drive_hotplug_fsevent_callback, - &ctx, pathsToWatch, kFSEventStreamEventIdSinceNow, 1, - kFSEventStreamCreateFlagNone); + fsev = + FSEventStreamCreate(kCFAllocatorMalloc, drive_hotplug_fsevent_callback, &ctx, pathsToWatch, + kFSEventStreamEventIdSinceNow, 1, kFSEventStreamCreateFlagNone); rdpdr->runLoop = CFRunLoopGetCurrent(); FSEventStreamScheduleWithRunLoop(fsev, rdpdr->runLoop, kCFRunLoopDefaultMode); FSEventStreamStart(fsev); @@ -592,52 +578,19 @@ static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg) return CHANNEL_RC_OK; } - -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT drive_hotplug_thread_terminate(rdpdrPlugin* rdpdr) -{ - UINT error; - - if (rdpdr->hotplugThread) - { - CFRunLoopStop(rdpdr->runLoop); - - if (WaitForSingleObject(rdpdr->hotplugThread, INFINITE) == WAIT_FAILED) - { - error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); - return error; - } - - rdpdr->hotplugThread = NULL; - } - - return CHANNEL_RC_OK; -} - #else +#include #define MAX_USB_DEVICES 100 typedef struct _hotplug_dev { char* path; - BOOL to_add; + BOOL to_add; } hotplug_dev; - -static const char* automountLocations[] = -{ - "/run/user/%lu/gvfs", - "/run/media/%s", - "/media/%s", - "/media", - "/mnt" -}; +static const char* automountLocations[] = { "/run/user/%lu/gvfs", "/run/media/%s", "/media/%s", + "/media", "/mnt" }; static BOOL isAutomountLocation(const char* path) { @@ -645,7 +598,14 @@ static BOOL isAutomountLocation(const char* path) size_t x; char buffer[MAX_PATH]; uid_t uid = getuid(); - const char* uname = getlogin(); + char uname[MAX_PATH] = { 0 }; + +#ifndef HAVE_GETLOGIN_R + strncpy(uname, getlogin(), sizeof(uname)); +#else + if (getlogin_r(uname, sizeof(uname)) != 0) + return FALSE; +#endif if (!path) return FALSE; @@ -685,99 +645,6 @@ static BOOL isAutomountLocation(const char* path) return FALSE; } -static char* next_line(FILE* fd, size_t* len) -{ - size_t newsiz; - int c; - char* newbuf; - char* lrbuf; - int lrsiz; - *len = 0; - lrsiz = 0; - lrbuf = NULL; - newbuf = NULL; - - for (;;) - { - c = fgetc(fd); - - if (ferror(fd)) - { - free(newbuf); - return NULL; - } - - if (c == EOF) - { - if (*len == 0) - return NULL; - else - { - lrbuf[(*len)] = '\0'; - return lrbuf; - } - } - else - { - if (*len == lrsiz) - { - newsiz = lrsiz + 4096; - newbuf = realloc(lrbuf, newsiz); - - if (newbuf == NULL) - return NULL; - - lrbuf = newbuf; - lrsiz = newsiz; - } - - lrbuf[(*len)] = c; - - if (c == '\n') - { - lrbuf[(*len)] = '\0'; - return lrbuf; - } - - (*len)++; - } - } -} - -static char* get_word(char* str, unsigned int* offset) -{ - char* p; - char* tmp; - char* word; - int wlen; - - if (*offset >= strlen(str)) - return NULL; - - p = str + *offset; - tmp = p; - - while (*tmp != ' ' && *tmp != '\0') - tmp++; - - wlen = tmp - p; - *offset += wlen; - - /* in case there are more than one space between words */ - while (*(str + *offset) == ' ') - (*offset)++; - - word = malloc(wlen + 1); - - if (word != NULL) - { - CopyMemory(word, p, wlen); - word[wlen] = '\0'; - } - - return word; -} - /** * Function description * @@ -786,18 +653,15 @@ static char* get_word(char* str, unsigned int* offset) static UINT handle_hotplug(rdpdrPlugin* rdpdr) { FILE* f; - size_t len; - char* line; - char* word; - unsigned int wlen; - hotplug_dev dev_array[MAX_USB_DEVICES]; - int i, j; - int size = 0; - int count; + hotplug_dev dev_array[MAX_USB_DEVICES] = { 0 }; + size_t i; + size_t size = 0; + int count, j; + struct mntent* ent; ULONG_PTR* keys = NULL; UINT32 ids[1]; UINT error = 0; - memset(dev_array, 0, sizeof(dev_array)); + f = fopen("/proc/mounts", "r"); if (f == NULL) @@ -806,23 +670,18 @@ static UINT handle_hotplug(rdpdrPlugin* rdpdr) return ERROR_OPEN_FAILED; } - while ((line = next_line(f, &len))) + while ((ent = getmntent(f)) != NULL) { - wlen = 0; - - while ((word = get_word(line, &wlen))) + /* Copy the line, path must obviously be shorter */ + const char* path = ent->mnt_dir; + if (!path) + continue; + /* copy hotpluged device mount point to the dev_array */ + if (isAutomountLocation(path) && (size < MAX_USB_DEVICES)) { - /* copy hotpluged device mount point to the dev_array */ - if (isAutomountLocation(word)) - { - dev_array[size].path = word; - dev_array[size++].to_add = TRUE; - } - else - free(word); + dev_array[size].path = _strdup(path); + dev_array[size++].to_add = TRUE; } - - free(line); } fclose(f); @@ -833,10 +692,11 @@ static UINT handle_hotplug(rdpdrPlugin* rdpdr) { char* path = NULL; BOOL dev_found = FALSE; - DEVICE_DRIVE_EXT* device_ext = (DEVICE_DRIVE_EXT*)ListDictionary_GetItemValue( - rdpdr->devman->devices, (void*)keys[j]); + DEVICE_DRIVE_EXT* device_ext = + (DEVICE_DRIVE_EXT*)ListDictionary_GetItemValue(rdpdr->devman->devices, (void*)keys[j]); - if (!device_ext || !device_ext->path || !device_ext->automount) + if (!device_ext || (device_ext->device.type != RDPDR_DTYP_FILESYSTEM) || + !device_ext->path || !device_ext->automount) continue; ConvertFromUnicode(CP_UTF8, 0, device_ext->path, -1, &path, 0, NULL, NULL); @@ -867,7 +727,8 @@ static UINT handle_hotplug(rdpdrPlugin* rdpdr) if ((error = rdpdr_send_device_list_remove_request(rdpdr, 1, ids))) { - WLog_ERR(TAG, "rdpdr_send_device_list_remove_request failed with error %"PRIu32"!", + WLog_ERR(TAG, + "rdpdr_send_device_list_remove_request failed with error %" PRIu32 "!", error); goto cleanup; } @@ -877,43 +738,28 @@ static UINT handle_hotplug(rdpdrPlugin* rdpdr) /* add new devices */ for (i = 0; i < size; i++) { - RDPDR_DRIVE* drive; - if (dev_array[i].to_add) { + RDPDR_DRIVE drive = { 0 }; char* name; - drive = (RDPDR_DRIVE*) calloc(1, sizeof(RDPDR_DRIVE)); - - if (!drive) - { - WLog_ERR(TAG, "calloc failed!"); - error = CHANNEL_RC_NO_MEMORY; - goto cleanup; - } - drive->Type = RDPDR_DTYP_FILESYSTEM; - drive->Path = dev_array[i].path; - drive->automount = TRUE; - dev_array[i].path = NULL; - name = strrchr(drive->Path, '/') + 1; - drive->Name = _strdup(name); + drive.Type = RDPDR_DTYP_FILESYSTEM; + drive.Path = dev_array[i].path; + drive.automount = TRUE; + name = strrchr(drive.Path, '/') + 1; + drive.Name = name; - if (!drive->Name) + if (!drive.Name) { WLog_ERR(TAG, "_strdup failed!"); - free(drive->Path); - free(drive); error = CHANNEL_RC_NO_MEMORY; goto cleanup; } - if ((error = devman_load_device_service(rdpdr->devman, (RDPDR_DEVICE*)drive, + if ((error = devman_load_device_service(rdpdr->devman, (const RDPDR_DEVICE*)&drive, rdpdr->rdpcontext))) { WLog_ERR(TAG, "devman_load_device_service failed!"); - free(drive->Path); - free(drive->Name); - free(drive); goto cleanup; } } @@ -934,7 +780,7 @@ static void first_hotplug(rdpdrPlugin* rdpdr) if ((error = handle_hotplug(rdpdr))) { - WLog_ERR(TAG, "handle_hotplug failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "handle_hotplug failed with error %" PRIu32 "!", error); } } @@ -947,15 +793,7 @@ static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg) int rv; UINT error = 0; DWORD status; - rdpdr = (rdpdrPlugin*) arg; - - if (!(rdpdr->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) - { - WLog_ERR(TAG, "CreateEvent failed!"); - error = ERROR_INTERNAL_ERROR; - goto out; - } - + rdpdr = (rdpdrPlugin*)arg; mfd = open("/proc/mounts", O_RDONLY, 0); if (mfd < 0) @@ -977,7 +815,7 @@ static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg) if (status == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error); goto out; } @@ -989,7 +827,7 @@ static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg) /* file /proc/mounts changed, handle this */ if ((error = handle_hotplug(rdpdr))) { - WLog_ERR(TAG, "handle_hotplug failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "handle_hotplug failed with error %" PRIu32 "!", error); goto out; } else @@ -1005,14 +843,15 @@ static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg) out: if (error && rdpdr->rdpcontext) - setChannelError(rdpdr->rdpcontext, error, - "drive_hotplug_thread_func reported an error"); + setChannelError(rdpdr->rdpcontext, error, "drive_hotplug_thread_func reported an error"); - CloseHandle(rdpdr->stopEvent); ExitThread(error); return error; } +#endif + +#if !defined(_WIN32) && !defined(__IOS__) /** * Function description * @@ -1024,16 +863,21 @@ static UINT drive_hotplug_thread_terminate(rdpdrPlugin* rdpdr) if (rdpdr->hotplugThread) { - if (rdpdr->stopEvent) - SetEvent(rdpdr->stopEvent); + SetEvent(rdpdr->stopEvent); +#ifdef __MACOSX__ + CFRunLoopStop(rdpdr->runLoop); +#endif if (WaitForSingleObject(rdpdr->hotplugThread, INFINITE) == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error); return error; } + CloseHandle(rdpdr->hotplugThread); + CloseHandle(rdpdr->stopEvent); + rdpdr->stopEvent = NULL; rdpdr->hotplugThread = NULL; } @@ -1042,7 +886,6 @@ static UINT drive_hotplug_thread_terminate(rdpdrPlugin* rdpdr) #endif - /** * Function description * @@ -1051,7 +894,6 @@ static UINT drive_hotplug_thread_terminate(rdpdrPlugin* rdpdr) static UINT rdpdr_process_connect(rdpdrPlugin* rdpdr) { UINT32 index; - RDPDR_DEVICE* device; rdpSettings* settings; UINT error = CHANNEL_RC_OK; rdpdr->devman = devman_new(rdpdr); @@ -1062,31 +904,45 @@ static UINT rdpdr_process_connect(rdpdrPlugin* rdpdr) return CHANNEL_RC_NO_MEMORY; } - settings = (rdpSettings*) rdpdr->channelEntryPoints.pExtendedData; + settings = (rdpSettings*)rdpdr->channelEntryPoints.pExtendedData; if (settings->ClientHostname) - strncpy(rdpdr->computerName, settings->ClientHostname, - sizeof(rdpdr->computerName) - 1); + strncpy(rdpdr->computerName, settings->ClientHostname, sizeof(rdpdr->computerName) - 1); else - strncpy(rdpdr->computerName, settings->ComputerName, - sizeof(rdpdr->computerName) - 1); + strncpy(rdpdr->computerName, settings->ComputerName, sizeof(rdpdr->computerName) - 1); for (index = 0; index < settings->DeviceCount; index++) { - device = settings->DeviceArray[index]; + const RDPDR_DEVICE* device = settings->DeviceArray[index]; if (device->Type == RDPDR_DTYP_FILESYSTEM) { - RDPDR_DRIVE* drive = (RDPDR_DRIVE*)device; - - if (drive->Path && (strcmp(drive->Path, "*") == 0)) + const char DynamicDrives[] = "DynamicDrives"; + const RDPDR_DRIVE* drive = (const RDPDR_DRIVE*)device; + BOOL hotplugAll = strncmp(drive->Path, "*", 2) == 0; + BOOL hotplugLater = strncmp(drive->Path, DynamicDrives, sizeof(DynamicDrives)) == 0; + if (drive->Path && (hotplugAll || hotplugLater)) { - first_hotplug(rdpdr); + if (hotplugAll) + first_hotplug(rdpdr); +#ifndef _WIN32 - if (!(rdpdr->hotplugThread = CreateThread(NULL, 0, - drive_hotplug_thread_func, rdpdr, 0, NULL))) + if (!(rdpdr->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) + { + WLog_ERR(TAG, "CreateEvent failed!"); + return ERROR_INTERNAL_ERROR; + } + +#endif + + if (!(rdpdr->hotplugThread = + CreateThread(NULL, 0, drive_hotplug_thread_func, rdpdr, 0, NULL))) { WLog_ERR(TAG, "CreateThread failed!"); +#ifndef _WIN32 + CloseHandle(rdpdr->stopEvent); + rdpdr->stopEvent = NULL; +#endif return ERROR_INTERNAL_ERROR; } @@ -1094,10 +950,9 @@ static UINT rdpdr_process_connect(rdpdrPlugin* rdpdr) } } - if ((error = devman_load_device_service(rdpdr->devman, device, - rdpdr->rdpcontext))) + if ((error = devman_load_device_service(rdpdr->devman, device, rdpdr->rdpcontext))) { - WLog_ERR(TAG, "devman_load_device_service failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "devman_load_device_service failed with error %" PRIu32 "!", error); return error; } } @@ -1105,8 +960,7 @@ static UINT rdpdr_process_connect(rdpdrPlugin* rdpdr) return error; } -static UINT rdpdr_process_server_announce_request(rdpdrPlugin* rdpdr, - wStream* s) +static UINT rdpdr_process_server_announce_request(rdpdrPlugin* rdpdr, wStream* s) { if (Stream_GetRemainingLength(s) < 8) return ERROR_INVALID_DATA; @@ -1134,11 +988,11 @@ static UINT rdpdr_send_client_announce_reply(rdpdrPlugin* rdpdr) return CHANNEL_RC_NO_MEMORY; } - Stream_Write_UINT16(s, RDPDR_CTYP_CORE); /* Component (2 bytes) */ + Stream_Write_UINT16(s, RDPDR_CTYP_CORE); /* Component (2 bytes) */ Stream_Write_UINT16(s, PAKID_CORE_CLIENTID_CONFIRM); /* PacketId (2 bytes) */ Stream_Write_UINT16(s, rdpdr->versionMajor); Stream_Write_UINT16(s, rdpdr->versionMinor); - Stream_Write_UINT32(s, (UINT32) rdpdr->clientID); + Stream_Write_UINT32(s, (UINT32)rdpdr->clientID); return rdpdr_send(rdpdr, s); } @@ -1156,8 +1010,7 @@ static UINT rdpdr_send_client_name_request(rdpdrPlugin* rdpdr) if (!rdpdr->computerName[0]) gethostname(rdpdr->computerName, sizeof(rdpdr->computerName) - 1); - computerNameLenW = ConvertToUnicode(CP_UTF8, 0, rdpdr->computerName, -1, - &computerNameW, 0) * 2; + computerNameLenW = ConvertToUnicode(CP_UTF8, 0, rdpdr->computerName, -1, &computerNameW, 0) * 2; s = Stream_New(NULL, 16 + computerNameLenW + 2); if (!s) @@ -1167,20 +1020,18 @@ static UINT rdpdr_send_client_name_request(rdpdrPlugin* rdpdr) return CHANNEL_RC_NO_MEMORY; } - Stream_Write_UINT16(s, RDPDR_CTYP_CORE); /* Component (2 bytes) */ + Stream_Write_UINT16(s, RDPDR_CTYP_CORE); /* Component (2 bytes) */ Stream_Write_UINT16(s, PAKID_CORE_CLIENT_NAME); /* PacketId (2 bytes) */ - Stream_Write_UINT32(s, 1); /* unicodeFlag, 0 for ASCII and 1 for Unicode */ - Stream_Write_UINT32(s, 0); /* codePage, must be set to zero */ - Stream_Write_UINT32(s, computerNameLenW + - 2); /* computerNameLen, including null terminator */ + Stream_Write_UINT32(s, 1); /* unicodeFlag, 0 for ASCII and 1 for Unicode */ + Stream_Write_UINT32(s, 0); /* codePage, must be set to zero */ + Stream_Write_UINT32(s, computerNameLenW + 2); /* computerNameLen, including null terminator */ Stream_Write(s, computerNameW, computerNameLenW); Stream_Write_UINT16(s, 0); /* null terminator */ free(computerNameW); return rdpdr_send(rdpdr, s); } -static UINT rdpdr_process_server_clientid_confirm(rdpdrPlugin* rdpdr, - wStream* s) +static UINT rdpdr_process_server_clientid_confirm(rdpdrPlugin* rdpdr, wStream* s) { UINT16 versionMajor; UINT16 versionMinor; @@ -1210,8 +1061,7 @@ static UINT rdpdr_process_server_clientid_confirm(rdpdrPlugin* rdpdr, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, - BOOL userLoggedOn) +static UINT rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, BOOL userLoggedOn) { int i; BYTE c; @@ -1232,7 +1082,7 @@ static UINT rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, return CHANNEL_RC_NO_MEMORY; } - Stream_Write_UINT16(s, RDPDR_CTYP_CORE); /* Component (2 bytes) */ + Stream_Write_UINT16(s, RDPDR_CTYP_CORE); /* Component (2 bytes) */ Stream_Write_UINT16(s, PAKID_CORE_DEVICELIST_ANNOUNCE); /* PacketId (2 bytes) */ count_pos = Stream_GetPosition(s); count = 0; @@ -1242,8 +1092,7 @@ static UINT rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, for (index = 0; index < keyCount; index++) { - device = (DEVICE*) ListDictionary_GetItemValue(rdpdr->devman->devices, - (void*) pKeys[index]); + device = (DEVICE*)ListDictionary_GetItemValue(rdpdr->devman->devices, (void*)pKeys[index]); /** * 1. versionMinor 0x0005 doesn't send PAKID_CORE_USER_LOGGEDON @@ -1252,8 +1101,8 @@ static UINT rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, * 3. other devices are sent only after user_loggedon */ - if ((rdpdr->versionMinor == 0x0005) || - (device->type == RDPDR_DTYP_SMARTCARD) || userLoggedOn) + if ((rdpdr->versionMinor == 0x0005) || (device->type == RDPDR_DTYP_SMARTCARD) || + userLoggedOn) { data_len = (device->data == NULL ? 0 : Stream_GetPosition(device->data)); @@ -1266,8 +1115,8 @@ static UINT rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, } Stream_Write_UINT32(s, device->type); /* deviceType */ - Stream_Write_UINT32(s, device->id); /* deviceID */ - strncpy((char*) Stream_Pointer(s), device->name, 8); + Stream_Write_UINT32(s, device->id); /* deviceID */ + strncpy((char*)Stream_Pointer(s), device->name, 8); for (i = 0; i < 8; i++) { @@ -1285,7 +1134,7 @@ static UINT rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, Stream_Write(s, Stream_Buffer(device->data), data_len); count++; - WLog_INFO(TAG, "registered device #%"PRIu32": %s (type=%"PRIu32" id=%"PRIu32")", + WLog_INFO(TAG, "registered device #%" PRIu32 ": %s (type=%" PRIu32 " id=%" PRIu32 ")", count, device->name, device->type, device->id); } } @@ -1299,6 +1148,40 @@ static UINT rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, return rdpdr_send(rdpdr, s); } +static UINT dummy_irp_response(rdpdrPlugin* rdpdr, wStream* s) +{ + + UINT32 DeviceId; + UINT32 FileId; + UINT32 CompletionId; + + wStream* output = Stream_New(NULL, 256); // RDPDR_DEVICE_IO_RESPONSE_LENGTH + if (!output) + { + WLog_ERR(TAG, "Stream_New failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + Stream_SetPosition(s, 4); /* see "rdpdr_process_receive" */ + + Stream_Read_UINT32(s, DeviceId); /* DeviceId (4 bytes) */ + Stream_Read_UINT32(s, FileId); /* FileId (4 bytes) */ + Stream_Read_UINT32(s, CompletionId); /* CompletionId (4 bytes) */ + + Stream_Write_UINT16(output, RDPDR_CTYP_CORE); /* Component (2 bytes) */ + Stream_Write_UINT16(output, PAKID_CORE_DEVICE_IOCOMPLETION); /* PacketId (2 bytes) */ + Stream_Write_UINT32(output, DeviceId); /* DeviceId (4 bytes) */ + Stream_Write_UINT32(output, CompletionId); /* CompletionId (4 bytes) */ + Stream_Write_UINT32(output, STATUS_UNSUCCESSFUL); /* IoStatus (4 bytes) */ + + Stream_Zero(output, 256 - RDPDR_DEVICE_IO_RESPONSE_LENGTH); + // or usage + // Stream_Write_UINT32(output, 0); /* Length */ + // Stream_Write_UINT8(output, 0); /* Padding */ + + return rdpdr_send(rdpdr, output); +} + /** * Function description * @@ -1312,18 +1195,49 @@ static UINT rdpdr_process_irp(rdpdrPlugin* rdpdr, wStream* s) if (!irp) { - WLog_ERR(TAG, "irp_new failed with %"PRIu32"!", error); + WLog_ERR(TAG, "irp_new failed with %" PRIu32 "!", error); + + if (error == CHANNEL_RC_OK) + { + return dummy_irp_response(rdpdr, s); + } + return error; } IFCALLRET(irp->device->IRPRequest, error, irp->device, irp); if (error) - WLog_ERR(TAG, "device->IRPRequest failed with error %"PRIu32"", error); + WLog_ERR(TAG, "device->IRPRequest failed with error %" PRIu32 "", error); 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 * @@ -1341,8 +1255,7 @@ static UINT rdpdr_process_init(rdpdrPlugin* rdpdr) for (index = 0; index < keyCount; index++) { - device = (DEVICE*) ListDictionary_GetItemValue(rdpdr->devman->devices, - (void*) pKeys[index]); + device = (DEVICE*)ListDictionary_GetItemValue(rdpdr->devman->devices, (void*)pKeys[index]); IFCALLRET(device->Init, error, device); if (error != CHANNEL_RC_OK) @@ -1368,141 +1281,125 @@ 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) - { - case PAKID_CORE_SERVER_ANNOUNCE: - if ((error = rdpdr_process_server_announce_request(rdpdr, s))) - return error; - - if ((error = rdpdr_send_client_announce_reply(rdpdr))) - { - WLog_ERR(TAG, "rdpdr_send_client_announce_reply failed with error %"PRIu32"", error); - return error; - } - - if ((error = rdpdr_send_client_name_request(rdpdr))) - { - WLog_ERR(TAG, "rdpdr_send_client_name_request failed with error %"PRIu32"", error); - return error; - } - - if ((error = rdpdr_process_init(rdpdr))) - { - WLog_ERR(TAG, "rdpdr_process_init failed with error %"PRIu32"", error); - return error; - } + Stream_Read_UINT16(s, component); /* Component (2 bytes) */ + Stream_Read_UINT16(s, packetId); /* PacketId (2 bytes) */ - break; - - case PAKID_CORE_SERVER_CAPABILITY: - if ((error = rdpdr_process_capability_request(rdpdr, s))) - return error; + if (component == RDPDR_CTYP_CORE) + { + 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_capability_response(rdpdr))) - { - WLog_ERR(TAG, "rdpdr_send_capability_response failed with error %"PRIu32"", error); - return error; - } + break; - break; + 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); + } - case PAKID_CORE_CLIENTID_CONFIRM: - if ((error = rdpdr_process_server_clientid_confirm(rdpdr, s))) - return error; + break; - 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; - } + 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); + } - 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_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_DEVICE_REPLY: + case PAKID_CORE_DEVICE_REPLY: - /* connect to a specific resource */ - if (Stream_GetRemainingLength(s) < 8) - return ERROR_INVALID_DATA; + /* connect to a specific resource */ + if (Stream_GetRemainingLength(s) >= 8) + { + Stream_Read_UINT32(s, deviceId); + Stream_Read_UINT32(s, status); + error = CHANNEL_RC_OK; + } - Stream_Read_UINT32(s, deviceId); - Stream_Read_UINT32(s, status); - break; + 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; - } + 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; - s = NULL; - break; + 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; - - 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; + error = rdpdr_process_component(rdpdr, component, packetId, s); - 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; } /** @@ -1513,23 +1410,30 @@ static UINT rdpdr_process_receive(rdpdrPlugin* rdpdr, wStream* s) UINT rdpdr_send(rdpdrPlugin* rdpdr, wStream* s) { UINT status; - rdpdrPlugin* plugin = (rdpdrPlugin*) rdpdr; + rdpdrPlugin* plugin = (rdpdrPlugin*)rdpdr; if (!rdpdr || !s) + { + Stream_Free(s, TRUE); return CHANNEL_RC_NULL_DATA; + } if (!plugin) + { + Stream_Free(s, TRUE); status = CHANNEL_RC_BAD_INIT_HANDLE; + } else { - status = plugin->channelEntryPoints.pVirtualChannelWriteEx(plugin->InitHandle, plugin->OpenHandle, - Stream_Buffer(s), (UINT32) Stream_GetPosition(s), s); + status = plugin->channelEntryPoints.pVirtualChannelWriteEx( + plugin->InitHandle, plugin->OpenHandle, Stream_Buffer(s), (UINT32)Stream_GetPosition(s), + s); } if (status != CHANNEL_RC_OK) { Stream_Free(s, TRUE); - WLog_ERR(TAG, "pVirtualChannelWriteEx failed with %s [%08"PRIX32"]", + WLog_ERR(TAG, "pVirtualChannelWriteEx failed with %s [%08" PRIX32 "]", WTSErrorToString(status), status); } @@ -1541,8 +1445,9 @@ UINT rdpdr_send(rdpdrPlugin* rdpdr, wStream* s) * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_virtual_channel_event_data_received(rdpdrPlugin* rdpdr, - void* pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) +static UINT rdpdr_virtual_channel_event_data_received(rdpdrPlugin* rdpdr, void* pData, + UINT32 dataLength, UINT32 totalLength, + UINT32 dataFlags) { wStream* data_in; @@ -1566,16 +1471,16 @@ static UINT rdpdr_virtual_channel_event_data_received(rdpdrPlugin* rdpdr, if (!rdpdr->data_in) { - WLog_ERR(TAG, "Stream_New failed!"); + WLog_ERR(TAG, "Stream_New failed!"); return CHANNEL_RC_NO_MEMORY; } } data_in = rdpdr->data_in; - if (!Stream_EnsureRemainingCapacity(data_in, (int) dataLength)) + if (!Stream_EnsureRemainingCapacity(data_in, dataLength)) { - WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); return ERROR_INVALID_DATA; } @@ -1593,7 +1498,7 @@ static UINT rdpdr_virtual_channel_event_data_received(rdpdrPlugin* rdpdr, Stream_SealLength(data_in); Stream_SetPosition(data_in, 0); - if (!MessageQueue_Post(rdpdr->queue, NULL, 0, (void*) data_in, NULL)) + if (!MessageQueue_Post(rdpdr->queue, NULL, 0, (void*)data_in, NULL)) { WLog_ERR(TAG, "MessageQueue_Post failed!"); return ERROR_INTERNAL_ERROR; @@ -1604,36 +1509,42 @@ static UINT rdpdr_virtual_channel_event_data_received(rdpdrPlugin* rdpdr, } static VOID VCAPITYPE rdpdr_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle, - UINT event, - LPVOID pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) + UINT event, LPVOID pData, + UINT32 dataLength, UINT32 totalLength, + UINT32 dataFlags) { UINT error = CHANNEL_RC_OK; - rdpdrPlugin* rdpdr = (rdpdrPlugin*) lpUserParam; - - if (!rdpdr || !pData || (rdpdr->OpenHandle != openHandle)) - { - WLog_ERR(TAG, "error no match"); - return; - } + rdpdrPlugin* rdpdr = (rdpdrPlugin*)lpUserParam; switch (event) { case CHANNEL_EVENT_DATA_RECEIVED: - if ((error = rdpdr_virtual_channel_event_data_received(rdpdr, pData, - dataLength, totalLength, dataFlags))) + if (!rdpdr || !pData || (rdpdr->OpenHandle != openHandle)) + { + WLog_ERR(TAG, "error no match"); + return; + } + if ((error = rdpdr_virtual_channel_event_data_received(rdpdr, pData, dataLength, + totalLength, dataFlags))) WLog_ERR(TAG, - "rdpdr_virtual_channel_event_data_received failed with error %"PRIu32"!", error); + "rdpdr_virtual_channel_event_data_received failed with error %" PRIu32 "!", + error); break; + case CHANNEL_EVENT_WRITE_CANCELLED: case CHANNEL_EVENT_WRITE_COMPLETE: - break; + { + wStream* s = (wStream*)pData; + Stream_Free(s, TRUE); + } + break; case CHANNEL_EVENT_USER: break; } - if (error && rdpdr->rdpcontext) + if (error && rdpdr && rdpdr->rdpcontext) setChannelError(rdpdr->rdpcontext, error, "rdpdr_virtual_channel_open_event_ex reported an error"); @@ -1644,18 +1555,18 @@ static DWORD WINAPI rdpdr_virtual_channel_client_thread(LPVOID arg) { wStream* data; wMessage message; - rdpdrPlugin* rdpdr = (rdpdrPlugin*) arg; + rdpdrPlugin* rdpdr = (rdpdrPlugin*)arg; UINT error; if (!rdpdr) { - ExitThread((DWORD) CHANNEL_RC_NULL_DATA); + ExitThread((DWORD)CHANNEL_RC_NULL_DATA); return CHANNEL_RC_NULL_DATA; } if ((error = rdpdr_process_connect(rdpdr))) { - WLog_ERR(TAG, "rdpdr_process_connect failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rdpdr_process_connect failed with error %" PRIu32 "!", error); if (rdpdr->rdpcontext) setChannelError(rdpdr->rdpcontext, error, @@ -1677,17 +1588,17 @@ static DWORD WINAPI rdpdr_virtual_channel_client_thread(LPVOID arg) if (message.id == 0) { - data = (wStream*) message.wParam; + data = (wStream*)message.wParam; if ((error = rdpdr_process_receive(rdpdr, data))) { - WLog_ERR(TAG, "rdpdr_process_receive failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rdpdr_process_receive failed with error %" PRIu32 "!", error); if (rdpdr->rdpcontext) setChannelError(rdpdr->rdpcontext, error, "rdpdr_virtual_channel_client_thread reported an error"); - ExitThread((DWORD) error); + ExitThread((DWORD)error); return error; } } @@ -1698,21 +1609,28 @@ static DWORD WINAPI rdpdr_virtual_channel_client_thread(LPVOID arg) return 0; } +static void queue_free(void* obj) +{ + wStream* s = obj; + Stream_Free(s, TRUE); +} + /** * Function description * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_virtual_channel_event_connected(rdpdrPlugin* rdpdr, - LPVOID pData, UINT32 dataLength) +static UINT rdpdr_virtual_channel_event_connected(rdpdrPlugin* rdpdr, LPVOID pData, + UINT32 dataLength) { UINT32 status; - status = rdpdr->channelEntryPoints.pVirtualChannelOpenEx(rdpdr->InitHandle, - &rdpdr->OpenHandle, rdpdr->channelDef.name, rdpdr_virtual_channel_open_event_ex); + status = rdpdr->channelEntryPoints.pVirtualChannelOpenEx(rdpdr->InitHandle, &rdpdr->OpenHandle, + rdpdr->channelDef.name, + rdpdr_virtual_channel_open_event_ex); if (status != CHANNEL_RC_OK) { - WLog_ERR(TAG, "pVirtualChannelOpenEx failed with %s [%08"PRIX32"]", + WLog_ERR(TAG, "pVirtualChannelOpenEx failed with %s [%08" PRIX32 "]", WTSErrorToString(status), status); return status; } @@ -1725,9 +1643,10 @@ static UINT rdpdr_virtual_channel_event_connected(rdpdrPlugin* rdpdr, return CHANNEL_RC_NO_MEMORY; } - if (!(rdpdr->thread = CreateThread(NULL, 0, - rdpdr_virtual_channel_client_thread, (void*) rdpdr, 0, - NULL))) + rdpdr->queue->object.fnObjectFree = queue_free; + + if (!(rdpdr->thread = + CreateThread(NULL, 0, rdpdr_virtual_channel_client_thread, (void*)rdpdr, 0, NULL))) { WLog_ERR(TAG, "CreateThread failed!"); return ERROR_INTERNAL_ERROR; @@ -1748,11 +1667,11 @@ static UINT rdpdr_virtual_channel_event_disconnected(rdpdrPlugin* rdpdr) if (rdpdr->OpenHandle == 0) return CHANNEL_RC_OK; - if (MessageQueue_PostQuit(rdpdr->queue, 0) - && (WaitForSingleObject(rdpdr->thread, INFINITE) == WAIT_FAILED)) + if (MessageQueue_PostQuit(rdpdr->queue, 0) && + (WaitForSingleObject(rdpdr->thread, INFINITE) == WAIT_FAILED)) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error); return error; } @@ -1763,7 +1682,7 @@ static UINT rdpdr_virtual_channel_event_disconnected(rdpdrPlugin* rdpdr) if ((error = drive_hotplug_thread_terminate(rdpdr))) { - WLog_ERR(TAG, "drive_hotplug_thread_terminate failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "drive_hotplug_thread_terminate failed with error %" PRIu32 "!", error); return error; } @@ -1771,7 +1690,7 @@ static UINT rdpdr_virtual_channel_event_disconnected(rdpdrPlugin* rdpdr) if (CHANNEL_RC_OK != error) { - WLog_ERR(TAG, "pVirtualChannelCloseEx failed with %s [%08"PRIX32"]", + WLog_ERR(TAG, "pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]", WTSErrorToString(error), error); } @@ -1799,11 +1718,10 @@ static void rdpdr_virtual_channel_event_terminated(rdpdrPlugin* rdpdr) } static VOID VCAPITYPE rdpdr_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle, - UINT event, - LPVOID pData, UINT dataLength) + UINT event, LPVOID pData, UINT dataLength) { UINT error = CHANNEL_RC_OK; - rdpdrPlugin* rdpdr = (rdpdrPlugin*) lpUserParam; + rdpdrPlugin* rdpdr = (rdpdrPlugin*)lpUserParam; if (!rdpdr || (rdpdr->InitHandle != pInitHandle)) { @@ -1818,14 +1736,16 @@ static VOID VCAPITYPE rdpdr_virtual_channel_init_event_ex(LPVOID lpUserParam, LP case CHANNEL_EVENT_CONNECTED: if ((error = rdpdr_virtual_channel_event_connected(rdpdr, pData, dataLength))) - WLog_ERR(TAG, "rdpdr_virtual_channel_event_connected failed with error %"PRIu32"!", + WLog_ERR(TAG, + "rdpdr_virtual_channel_event_connected failed with error %" PRIu32 "!", error); break; case CHANNEL_EVENT_DISCONNECTED: if ((error = rdpdr_virtual_channel_event_disconnected(rdpdr))) - WLog_ERR(TAG, "rdpdr_virtual_channel_event_disconnected failed with error %"PRIu32"!", + WLog_ERR(TAG, + "rdpdr_virtual_channel_event_disconnected failed with error %" PRIu32 "!", error); break; @@ -1837,7 +1757,7 @@ static VOID VCAPITYPE rdpdr_virtual_channel_init_event_ex(LPVOID lpUserParam, LP case CHANNEL_EVENT_ATTACHED: case CHANNEL_EVENT_DETACHED: default: - WLog_ERR(TAG, "unknown event %"PRIu32"!", event); + WLog_ERR(TAG, "unknown event %" PRIu32 "!", event); break; } @@ -1847,14 +1767,14 @@ static VOID VCAPITYPE rdpdr_virtual_channel_init_event_ex(LPVOID lpUserParam, LP } /* rdpdr is always built-in */ -#define VirtualChannelEntryEx rdpdr_VirtualChannelEntryEx +#define VirtualChannelEntryEx rdpdr_VirtualChannelEntryEx BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID pInitHandle) { UINT rc; rdpdrPlugin* rdpdr; CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx; - rdpdr = (rdpdrPlugin*) calloc(1, sizeof(rdpdrPlugin)); + rdpdr = (rdpdrPlugin*)calloc(1, sizeof(rdpdrPlugin)); if (!rdpdr) { @@ -1863,12 +1783,10 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p } rdpdr->channelDef.options = - CHANNEL_OPTION_INITIALIZED | - CHANNEL_OPTION_ENCRYPT_RDP | - CHANNEL_OPTION_COMPRESS_RDP; + CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_COMPRESS_RDP; sprintf_s(rdpdr->channelDef.name, ARRAYSIZE(rdpdr->channelDef.name), "rdpdr"); rdpdr->sequenceId = 0; - pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*) pEntryPoints; + pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints; if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) && (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER)) @@ -1876,17 +1794,16 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p rdpdr->rdpcontext = pEntryPointsEx->context; } - CopyMemory(&(rdpdr->channelEntryPoints), pEntryPoints, - sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)); + CopyMemory(&(rdpdr->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)); rdpdr->InitHandle = pInitHandle; - rc = rdpdr->channelEntryPoints.pVirtualChannelInitEx(rdpdr, NULL, pInitHandle, - &rdpdr->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, - rdpdr_virtual_channel_init_event_ex); + rc = rdpdr->channelEntryPoints.pVirtualChannelInitEx( + rdpdr, NULL, pInitHandle, &rdpdr->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, + rdpdr_virtual_channel_init_event_ex); if (CHANNEL_RC_OK != rc) { - WLog_ERR(TAG, "pVirtualChannelInitEx failed with %s [%08"PRIX32"]", - WTSErrorToString(rc), rc); + WLog_ERR(TAG, "pVirtualChannelInitEx failed with %s [%08" PRIX32 "]", WTSErrorToString(rc), + rc); free(rdpdr); return FALSE; } diff --git a/channels/rdpdr/client/rdpdr_main.h b/channels/rdpdr/client/rdpdr_main.h index 1cdd2ce..4c372da 100644 --- a/channels/rdpdr/client/rdpdr_main.h +++ b/channels/rdpdr/client/rdpdr_main.h @@ -70,9 +70,11 @@ struct rdpdr_plugin HANDLE hotplugThread; #ifdef _WIN32 HWND hotplug_wnd; -#elif __MACOSX__ +#endif +#ifdef __MACOSX__ CFRunLoopRef runLoop; -#else +#endif +#ifndef _WIN32 HANDLE stopEvent; #endif rdpContext* rdpcontext; diff --git a/channels/rdpdr/server/rdpdr_main.c b/channels/rdpdr/server/rdpdr_main.c index 5abf8d0..3e005da 100644 --- a/channels/rdpdr/server/rdpdr_main.c +++ b/channels/rdpdr/server/rdpdr_main.c @@ -39,7 +39,7 @@ static UINT32 g_ClientId = 0; static RDPDR_IRP* rdpdr_server_irp_new() { RDPDR_IRP* irp; - irp = (RDPDR_IRP*) calloc(1, sizeof(RDPDR_IRP)); + irp = (RDPDR_IRP*)calloc(1, sizeof(RDPDR_IRP)); return irp; } @@ -48,19 +48,15 @@ static void rdpdr_server_irp_free(RDPDR_IRP* irp) free(irp); } -static BOOL rdpdr_server_enqueue_irp(RdpdrServerContext* context, - RDPDR_IRP* irp) +static BOOL rdpdr_server_enqueue_irp(RdpdrServerContext* context, RDPDR_IRP* irp) { - return ListDictionary_Add(context->priv->IrpList, - (void*)(size_t) irp->CompletionId, irp); + return ListDictionary_Add(context->priv->IrpList, (void*)(size_t)irp->CompletionId, irp); } -static RDPDR_IRP* rdpdr_server_dequeue_irp(RdpdrServerContext* context, - UINT32 completionId) +static RDPDR_IRP* rdpdr_server_dequeue_irp(RdpdrServerContext* context, UINT32 completionId) { RDPDR_IRP* irp; - irp = (RDPDR_IRP*) ListDictionary_Remove(context->priv->IrpList, - (void*)(size_t) completionId); + irp = (RDPDR_IRP*)ListDictionary_Remove(context->priv->IrpList, (void*)(size_t)completionId); return irp; } @@ -86,17 +82,15 @@ static UINT rdpdr_server_send_announce_request(RdpdrServerContext* context) return CHANNEL_RC_NO_MEMORY; } - Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */ - Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */ - Stream_Write_UINT16(s, - context->priv->VersionMajor); /* VersionMajor (2 bytes) */ - Stream_Write_UINT16(s, - context->priv->VersionMinor); /* VersionMinor (2 bytes) */ - Stream_Write_UINT32(s, context->priv->ClientId); /* ClientId (4 bytes) */ + Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */ + Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */ + Stream_Write_UINT16(s, context->priv->VersionMajor); /* VersionMajor (2 bytes) */ + Stream_Write_UINT16(s, context->priv->VersionMinor); /* VersionMinor (2 bytes) */ + Stream_Write_UINT32(s, context->priv->ClientId); /* ClientId (4 bytes) */ Stream_SealLength(s); winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), Stream_Length(s)); - status = WTSVirtualChannelWrite(context->priv->ChannelHandle, - (PCHAR) Stream_Buffer(s), Stream_Length(s), &written); + status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR)Stream_Buffer(s), + Stream_Length(s), &written); Stream_Free(s, TRUE); return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; } @@ -106,8 +100,8 @@ static UINT rdpdr_server_send_announce_request(RdpdrServerContext* context) * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_receive_announce_response(RdpdrServerContext* context, - wStream* s, RDPDR_HEADER* header) +static UINT rdpdr_server_receive_announce_response(RdpdrServerContext* context, wStream* s, + RDPDR_HEADER* header) { UINT32 ClientId; UINT16 VersionMajor; @@ -121,9 +115,10 @@ static UINT rdpdr_server_receive_announce_response(RdpdrServerContext* context, Stream_Read_UINT16(s, VersionMajor); /* VersionMajor (2 bytes) */ Stream_Read_UINT16(s, VersionMinor); /* VersionMinor (2 bytes) */ - Stream_Read_UINT32(s, ClientId); /* ClientId (4 bytes) */ + Stream_Read_UINT32(s, ClientId); /* ClientId (4 bytes) */ WLog_DBG(TAG, - "Client Announce Response: VersionMajor: 0x%08"PRIX16" VersionMinor: 0x%04"PRIX16" ClientId: 0x%08"PRIX32"", + "Client Announce Response: VersionMajor: 0x%08" PRIX16 " VersionMinor: 0x%04" PRIX16 + " ClientId: 0x%08" PRIX32 "", VersionMajor, VersionMinor, ClientId); context->priv->ClientId = ClientId; return CHANNEL_RC_OK; @@ -134,8 +129,8 @@ static UINT rdpdr_server_receive_announce_response(RdpdrServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_receive_client_name_request(RdpdrServerContext* - context, wStream* s, RDPDR_HEADER* header) +static UINT rdpdr_server_receive_client_name_request(RdpdrServerContext* context, wStream* s, + RDPDR_HEADER* header) { UINT32 UnicodeFlag; UINT32 ComputerNameLen; @@ -146,8 +141,8 @@ static UINT rdpdr_server_receive_client_name_request(RdpdrServerContext* return ERROR_INVALID_DATA; } - Stream_Read_UINT32(s, UnicodeFlag); /* UnicodeFlag (4 bytes) */ - Stream_Seek_UINT32(s); /* CodePage (4 bytes), MUST be set to zero */ + Stream_Read_UINT32(s, UnicodeFlag); /* UnicodeFlag (4 bytes) */ + Stream_Seek_UINT32(s); /* CodePage (4 bytes), MUST be set to zero */ Stream_Read_UINT32(s, ComputerNameLen); /* ComputerNameLen (4 bytes) */ /* UnicodeFlag is either 0 or 1, the other 31 bits must be ignored. */ @@ -162,7 +157,7 @@ static UINT rdpdr_server_receive_client_name_request(RdpdrServerContext* { if ((ComputerNameLen % 2) || ComputerNameLen > 512 || ComputerNameLen < 2) { - WLog_ERR(TAG, "invalid unicode computer name length: %"PRIu32"", ComputerNameLen); + WLog_ERR(TAG, "invalid unicode computer name length: %" PRIu32 "", ComputerNameLen); return ERROR_INVALID_DATA; } } @@ -170,7 +165,7 @@ static UINT rdpdr_server_receive_client_name_request(RdpdrServerContext* { if (ComputerNameLen > 256 || ComputerNameLen < 1) { - WLog_ERR(TAG, "invalid ascii computer name length: %"PRIu32"", ComputerNameLen); + WLog_ERR(TAG, "invalid ascii computer name length: %" PRIu32 "", ComputerNameLen); return ERROR_INVALID_DATA; } } @@ -198,7 +193,7 @@ static UINT rdpdr_server_receive_client_name_request(RdpdrServerContext* if (UnicodeFlag) { - if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), -1, + if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*)Stream_Pointer(s), -1, &(context->priv->ClientComputerName), 0, NULL, NULL) < 1) { WLog_ERR(TAG, "failed to convert client computer name"); @@ -207,7 +202,7 @@ static UINT rdpdr_server_receive_client_name_request(RdpdrServerContext* } else { - context->priv->ClientComputerName = _strdup((char*) Stream_Pointer(s)); + context->priv->ClientComputerName = _strdup((char*)Stream_Pointer(s)); if (!context->priv->ClientComputerName) { @@ -226,8 +221,7 @@ static UINT rdpdr_server_receive_client_name_request(RdpdrServerContext* * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_read_capability_set_header(wStream* s, - RDPDR_CAPABILITY_HEADER* header) +static UINT rdpdr_server_read_capability_set_header(wStream* s, RDPDR_CAPABILITY_HEADER* header) { if (Stream_GetRemainingLength(s) < 8) { @@ -235,10 +229,9 @@ static UINT rdpdr_server_read_capability_set_header(wStream* s, return ERROR_INVALID_DATA; } - Stream_Read_UINT16(s, header->CapabilityType); /* CapabilityType (2 bytes) */ - Stream_Read_UINT16(s, - header->CapabilityLength); /* CapabilityLength (2 bytes) */ - Stream_Read_UINT32(s, header->Version); /* Version (4 bytes) */ + Stream_Read_UINT16(s, header->CapabilityType); /* CapabilityType (2 bytes) */ + Stream_Read_UINT16(s, header->CapabilityLength); /* CapabilityLength (2 bytes) */ + Stream_Read_UINT32(s, header->Version); /* Version (4 bytes) */ return CHANNEL_RC_OK; } @@ -247,8 +240,7 @@ static UINT rdpdr_server_read_capability_set_header(wStream* s, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_write_capability_set_header(wStream* s, - RDPDR_CAPABILITY_HEADER* header) +static UINT rdpdr_server_write_capability_set_header(wStream* s, RDPDR_CAPABILITY_HEADER* header) { if (!Stream_EnsureRemainingCapacity(s, 8)) { @@ -256,10 +248,9 @@ static UINT rdpdr_server_write_capability_set_header(wStream* s, return ERROR_INVALID_DATA; } - Stream_Write_UINT16(s, header->CapabilityType); /* CapabilityType (2 bytes) */ - Stream_Write_UINT16(s, - header->CapabilityLength); /* CapabilityLength (2 bytes) */ - Stream_Write_UINT32(s, header->Version); /* Version (4 bytes) */ + Stream_Write_UINT16(s, header->CapabilityType); /* CapabilityType (2 bytes) */ + Stream_Write_UINT16(s, header->CapabilityLength); /* CapabilityLength (2 bytes) */ + Stream_Write_UINT32(s, header->Version); /* Version (4 bytes) */ return CHANNEL_RC_OK; } @@ -268,8 +259,8 @@ static UINT rdpdr_server_write_capability_set_header(wStream* s, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_read_general_capability_set(RdpdrServerContext* - context, wStream* s, RDPDR_CAPABILITY_HEADER* header) +static UINT rdpdr_server_read_general_capability_set(RdpdrServerContext* context, wStream* s, + RDPDR_CAPABILITY_HEADER* header) { UINT32 ioCode1; UINT32 extraFlags1; @@ -284,17 +275,15 @@ static UINT rdpdr_server_read_general_capability_set(RdpdrServerContext* return ERROR_INVALID_DATA; } - Stream_Seek_UINT32(s); /* osType (4 bytes), ignored on receipt */ - Stream_Seek_UINT32(s); /* osVersion (4 bytes), unused and must be set to zero */ + Stream_Seek_UINT32(s); /* osType (4 bytes), ignored on receipt */ + Stream_Seek_UINT32(s); /* osVersion (4 bytes), unused and must be set to zero */ Stream_Read_UINT16(s, VersionMajor); /* protocolMajorVersion (2 bytes) */ Stream_Read_UINT16(s, VersionMinor); /* protocolMinorVersion (2 bytes) */ - Stream_Read_UINT32(s, ioCode1); /* ioCode1 (4 bytes) */ - Stream_Seek_UINT32( - s); /* ioCode2 (4 bytes), must be set to zero, reserved for future use */ + Stream_Read_UINT32(s, ioCode1); /* ioCode1 (4 bytes) */ + Stream_Seek_UINT32(s); /* ioCode2 (4 bytes), must be set to zero, reserved for future use */ Stream_Read_UINT32(s, extendedPdu); /* extendedPdu (4 bytes) */ Stream_Read_UINT32(s, extraFlags1); /* extraFlags1 (4 bytes) */ - Stream_Seek_UINT32( - s); /* extraFlags2 (4 bytes), must be set to zero, reserved for future use */ + Stream_Seek_UINT32(s); /* extraFlags2 (4 bytes), must be set to zero, reserved for future use */ if (header->Version == GENERAL_CAPABILITY_VERSION_02) { @@ -304,12 +293,10 @@ static UINT rdpdr_server_read_general_capability_set(RdpdrServerContext* return ERROR_INVALID_DATA; } - Stream_Read_UINT32(s, - SpecialTypeDeviceCap); /* SpecialTypeDeviceCap (4 bytes) */ + Stream_Read_UINT32(s, SpecialTypeDeviceCap); /* SpecialTypeDeviceCap (4 bytes) */ } - context->priv->UserLoggedOnPdu = (extendedPdu & RDPDR_USER_LOGGEDON_PDU) ? - TRUE : FALSE; + context->priv->UserLoggedOnPdu = (extendedPdu & RDPDR_USER_LOGGEDON_PDU) ? TRUE : FALSE; return CHANNEL_RC_OK; } @@ -318,8 +305,7 @@ static UINT rdpdr_server_read_general_capability_set(RdpdrServerContext* * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_write_general_capability_set(RdpdrServerContext* - context, wStream* s) +static UINT rdpdr_server_write_general_capability_set(RdpdrServerContext* context, wStream* s) { UINT32 ioCode1; UINT32 extendedPdu; @@ -330,25 +316,25 @@ static UINT rdpdr_server_write_general_capability_set(RdpdrServerContext* header.CapabilityLength = RDPDR_CAPABILITY_HEADER_LENGTH + 36; header.Version = GENERAL_CAPABILITY_VERSION_02; ioCode1 = 0; - ioCode1 |= RDPDR_IRP_MJ_CREATE; /* always set */ - ioCode1 |= RDPDR_IRP_MJ_CLEANUP; /* always set */ - ioCode1 |= RDPDR_IRP_MJ_CLOSE; /* always set */ - ioCode1 |= RDPDR_IRP_MJ_READ; /* always set */ - ioCode1 |= RDPDR_IRP_MJ_WRITE; /* always set */ - ioCode1 |= RDPDR_IRP_MJ_FLUSH_BUFFERS; /* always set */ - ioCode1 |= RDPDR_IRP_MJ_SHUTDOWN; /* always set */ - ioCode1 |= RDPDR_IRP_MJ_DEVICE_CONTROL; /* always set */ + ioCode1 |= RDPDR_IRP_MJ_CREATE; /* always set */ + ioCode1 |= RDPDR_IRP_MJ_CLEANUP; /* always set */ + ioCode1 |= RDPDR_IRP_MJ_CLOSE; /* always set */ + ioCode1 |= RDPDR_IRP_MJ_READ; /* always set */ + ioCode1 |= RDPDR_IRP_MJ_WRITE; /* always set */ + ioCode1 |= RDPDR_IRP_MJ_FLUSH_BUFFERS; /* always set */ + ioCode1 |= RDPDR_IRP_MJ_SHUTDOWN; /* always set */ + ioCode1 |= RDPDR_IRP_MJ_DEVICE_CONTROL; /* always set */ ioCode1 |= RDPDR_IRP_MJ_QUERY_VOLUME_INFORMATION; /* always set */ - ioCode1 |= RDPDR_IRP_MJ_SET_VOLUME_INFORMATION; /* always set */ - ioCode1 |= RDPDR_IRP_MJ_QUERY_INFORMATION; /* always set */ - ioCode1 |= RDPDR_IRP_MJ_SET_INFORMATION; /* always set */ - ioCode1 |= RDPDR_IRP_MJ_DIRECTORY_CONTROL; /* always set */ - ioCode1 |= RDPDR_IRP_MJ_LOCK_CONTROL; /* always set */ - ioCode1 |= RDPDR_IRP_MJ_QUERY_SECURITY; /* optional */ - ioCode1 |= RDPDR_IRP_MJ_SET_SECURITY; /* optional */ + ioCode1 |= RDPDR_IRP_MJ_SET_VOLUME_INFORMATION; /* always set */ + ioCode1 |= RDPDR_IRP_MJ_QUERY_INFORMATION; /* always set */ + ioCode1 |= RDPDR_IRP_MJ_SET_INFORMATION; /* always set */ + ioCode1 |= RDPDR_IRP_MJ_DIRECTORY_CONTROL; /* always set */ + ioCode1 |= RDPDR_IRP_MJ_LOCK_CONTROL; /* always set */ + ioCode1 |= RDPDR_IRP_MJ_QUERY_SECURITY; /* optional */ + ioCode1 |= RDPDR_IRP_MJ_SET_SECURITY; /* optional */ extendedPdu = 0; extendedPdu |= RDPDR_CLIENT_DISPLAY_NAME_PDU; /* always set */ - extendedPdu |= RDPDR_DEVICE_REMOVE_PDUS; /* optional */ + extendedPdu |= RDPDR_DEVICE_REMOVE_PDUS; /* optional */ if (context->priv->UserLoggedOnPdu) extendedPdu |= RDPDR_USER_LOGGEDON_PDU; /* optional */ @@ -365,21 +351,16 @@ static UINT rdpdr_server_write_general_capability_set(RdpdrServerContext* rdpdr_server_write_capability_set_header(s, &header); Stream_Write_UINT32(s, 0); /* osType (4 bytes), ignored on receipt */ - Stream_Write_UINT32(s, - 0); /* osVersion (4 bytes), unused and must be set to zero */ - Stream_Write_UINT16(s, - context->priv->VersionMajor); /* protocolMajorVersion (2 bytes) */ - Stream_Write_UINT16(s, - context->priv->VersionMinor); /* protocolMinorVersion (2 bytes) */ - Stream_Write_UINT32(s, ioCode1); /* ioCode1 (4 bytes) */ - Stream_Write_UINT32(s, - 0); /* ioCode2 (4 bytes), must be set to zero, reserved for future use */ + Stream_Write_UINT32(s, 0); /* osVersion (4 bytes), unused and must be set to zero */ + Stream_Write_UINT16(s, context->priv->VersionMajor); /* protocolMajorVersion (2 bytes) */ + Stream_Write_UINT16(s, context->priv->VersionMinor); /* protocolMinorVersion (2 bytes) */ + Stream_Write_UINT32(s, ioCode1); /* ioCode1 (4 bytes) */ + Stream_Write_UINT32(s, 0); /* ioCode2 (4 bytes), must be set to zero, reserved for future use */ Stream_Write_UINT32(s, extendedPdu); /* extendedPdu (4 bytes) */ Stream_Write_UINT32(s, extraFlags1); /* extraFlags1 (4 bytes) */ - Stream_Write_UINT32(s, - 0); /* extraFlags2 (4 bytes), must be set to zero, reserved for future use */ - Stream_Write_UINT32(s, - SpecialTypeDeviceCap); /* SpecialTypeDeviceCap (4 bytes) */ + Stream_Write_UINT32( + s, 0); /* extraFlags2 (4 bytes), must be set to zero, reserved for future use */ + Stream_Write_UINT32(s, SpecialTypeDeviceCap); /* SpecialTypeDeviceCap (4 bytes) */ return CHANNEL_RC_OK; } @@ -388,8 +369,8 @@ static UINT rdpdr_server_write_general_capability_set(RdpdrServerContext* * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_read_printer_capability_set(RdpdrServerContext* - context, wStream* s, RDPDR_CAPABILITY_HEADER* header) +static UINT rdpdr_server_read_printer_capability_set(RdpdrServerContext* context, wStream* s, + RDPDR_CAPABILITY_HEADER* header) { return CHANNEL_RC_OK; } @@ -399,8 +380,7 @@ static UINT rdpdr_server_read_printer_capability_set(RdpdrServerContext* * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_write_printer_capability_set(RdpdrServerContext* - context, wStream* s) +static UINT rdpdr_server_write_printer_capability_set(RdpdrServerContext* context, wStream* s) { RDPDR_CAPABILITY_HEADER header; header.CapabilityType = CAP_PRINTER_TYPE; @@ -421,8 +401,8 @@ static UINT rdpdr_server_write_printer_capability_set(RdpdrServerContext* * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_read_port_capability_set(RdpdrServerContext* context, - wStream* s, RDPDR_CAPABILITY_HEADER* header) +static UINT rdpdr_server_read_port_capability_set(RdpdrServerContext* context, wStream* s, + RDPDR_CAPABILITY_HEADER* header) { return CHANNEL_RC_OK; } @@ -432,8 +412,7 @@ static UINT rdpdr_server_read_port_capability_set(RdpdrServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_write_port_capability_set(RdpdrServerContext* context, - wStream* s) +static UINT rdpdr_server_write_port_capability_set(RdpdrServerContext* context, wStream* s) { RDPDR_CAPABILITY_HEADER header; header.CapabilityType = CAP_PORT_TYPE; @@ -454,8 +433,8 @@ static UINT rdpdr_server_write_port_capability_set(RdpdrServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_read_drive_capability_set(RdpdrServerContext* context, - wStream* s, RDPDR_CAPABILITY_HEADER* header) +static UINT rdpdr_server_read_drive_capability_set(RdpdrServerContext* context, wStream* s, + RDPDR_CAPABILITY_HEADER* header) { return CHANNEL_RC_OK; } @@ -465,8 +444,7 @@ static UINT rdpdr_server_read_drive_capability_set(RdpdrServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_write_drive_capability_set(RdpdrServerContext* context, - wStream* s) +static UINT rdpdr_server_write_drive_capability_set(RdpdrServerContext* context, wStream* s) { RDPDR_CAPABILITY_HEADER header; header.CapabilityType = CAP_DRIVE_TYPE; @@ -487,8 +465,8 @@ static UINT rdpdr_server_write_drive_capability_set(RdpdrServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_read_smartcard_capability_set(RdpdrServerContext* - context, wStream* s, RDPDR_CAPABILITY_HEADER* header) +static UINT rdpdr_server_read_smartcard_capability_set(RdpdrServerContext* context, wStream* s, + RDPDR_CAPABILITY_HEADER* header) { return CHANNEL_RC_OK; } @@ -498,8 +476,7 @@ static UINT rdpdr_server_read_smartcard_capability_set(RdpdrServerContext* * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_write_smartcard_capability_set( - RdpdrServerContext* context, wStream* s) +static UINT rdpdr_server_write_smartcard_capability_set(RdpdrServerContext* context, wStream* s) { RDPDR_CAPABILITY_HEADER header; header.CapabilityType = CAP_SMARTCARD_TYPE; @@ -520,8 +497,7 @@ static UINT rdpdr_server_write_smartcard_capability_set( * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_send_core_capability_request(RdpdrServerContext* - context) +static UINT rdpdr_server_send_core_capability_request(RdpdrServerContext* context) { wStream* s; BOOL status; @@ -555,14 +531,14 @@ static UINT rdpdr_server_send_core_capability_request(RdpdrServerContext* } Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */ - Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */ - Stream_Write_UINT16(s, numCapabilities); /* numCapabilities (2 bytes) */ - Stream_Write_UINT16(s, 0); /* Padding (2 bytes) */ + Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */ + Stream_Write_UINT16(s, numCapabilities); /* numCapabilities (2 bytes) */ + Stream_Write_UINT16(s, 0); /* Padding (2 bytes) */ if ((error = rdpdr_server_write_general_capability_set(context, s))) { - WLog_ERR(TAG, - "rdpdr_server_write_general_capability_set failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rdpdr_server_write_general_capability_set failed with error %" PRIu32 "!", + error); goto out; } @@ -570,7 +546,7 @@ static UINT rdpdr_server_send_core_capability_request(RdpdrServerContext* { if ((error = rdpdr_server_write_drive_capability_set(context, s))) { - WLog_ERR(TAG, "rdpdr_server_write_drive_capability_set failed with error %"PRIu32"!", + WLog_ERR(TAG, "rdpdr_server_write_drive_capability_set failed with error %" PRIu32 "!", error); goto out; } @@ -580,7 +556,7 @@ static UINT rdpdr_server_send_core_capability_request(RdpdrServerContext* { if ((error = rdpdr_server_write_port_capability_set(context, s))) { - WLog_ERR(TAG, "rdpdr_server_write_port_capability_set failed with error %"PRIu32"!", + WLog_ERR(TAG, "rdpdr_server_write_port_capability_set failed with error %" PRIu32 "!", error); goto out; } @@ -591,7 +567,8 @@ static UINT rdpdr_server_send_core_capability_request(RdpdrServerContext* if ((error = rdpdr_server_write_printer_capability_set(context, s))) { WLog_ERR(TAG, - "rdpdr_server_write_printer_capability_set failed with error %"PRIu32"!", error); + "rdpdr_server_write_printer_capability_set failed with error %" PRIu32 "!", + error); goto out; } } @@ -601,15 +578,16 @@ static UINT rdpdr_server_send_core_capability_request(RdpdrServerContext* if ((error = rdpdr_server_write_smartcard_capability_set(context, s))) { WLog_ERR(TAG, - "rdpdr_server_write_printer_capability_set failed with error %"PRIu32"!", error); + "rdpdr_server_write_printer_capability_set failed with error %" PRIu32 "!", + error); goto out; } } Stream_SealLength(s); winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), Stream_Length(s)); - status = WTSVirtualChannelWrite(context->priv->ChannelHandle, - (PCHAR) Stream_Buffer(s), Stream_Length(s), &written); + status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR)Stream_Buffer(s), + Stream_Length(s), &written); Stream_Free(s, TRUE); return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; out: @@ -622,8 +600,8 @@ out: * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_receive_core_capability_response( - RdpdrServerContext* context, wStream* s, RDPDR_HEADER* header) +static UINT rdpdr_server_receive_core_capability_response(RdpdrServerContext* context, wStream* s, + RDPDR_HEADER* header) { int i; UINT status; @@ -637,13 +615,13 @@ static UINT rdpdr_server_receive_core_capability_response( } Stream_Read_UINT16(s, numCapabilities); /* numCapabilities (2 bytes) */ - Stream_Seek_UINT16(s); /* Padding (2 bytes) */ + Stream_Seek_UINT16(s); /* Padding (2 bytes) */ for (i = 0; i < numCapabilities; i++) { if ((status = rdpdr_server_read_capability_set_header(s, &capabilityHeader))) { - WLog_ERR(TAG, "rdpdr_server_read_capability_set_header failed with error %"PRIu32"!", + WLog_ERR(TAG, "rdpdr_server_read_capability_set_header failed with error %" PRIu32 "!", status); return status; } @@ -651,10 +629,12 @@ static UINT rdpdr_server_receive_core_capability_response( switch (capabilityHeader.CapabilityType) { case CAP_GENERAL_TYPE: - if ((status = rdpdr_server_read_general_capability_set(context, s, - &capabilityHeader))) + if ((status = + rdpdr_server_read_general_capability_set(context, s, &capabilityHeader))) { - WLog_ERR(TAG, "rdpdr_server_read_general_capability_set failed with error %"PRIu32"!", + WLog_ERR(TAG, + "rdpdr_server_read_general_capability_set failed with error %" PRIu32 + "!", status); return status; } @@ -662,10 +642,12 @@ static UINT rdpdr_server_receive_core_capability_response( break; case CAP_PRINTER_TYPE: - if ((status = rdpdr_server_read_printer_capability_set(context, s, - &capabilityHeader))) + if ((status = + rdpdr_server_read_printer_capability_set(context, s, &capabilityHeader))) { - WLog_ERR(TAG, "rdpdr_server_read_printer_capability_set failed with error %"PRIu32"!", + WLog_ERR(TAG, + "rdpdr_server_read_printer_capability_set failed with error %" PRIu32 + "!", status); return status; } @@ -673,10 +655,10 @@ static UINT rdpdr_server_receive_core_capability_response( break; case CAP_PORT_TYPE: - if ((status = rdpdr_server_read_port_capability_set(context, s, - &capabilityHeader))) + if ((status = rdpdr_server_read_port_capability_set(context, s, &capabilityHeader))) { - WLog_ERR(TAG, "rdpdr_server_read_port_capability_set failed with error %"PRIu32"!", + WLog_ERR(TAG, + "rdpdr_server_read_port_capability_set failed with error %" PRIu32 "!", status); return status; } @@ -684,10 +666,12 @@ static UINT rdpdr_server_receive_core_capability_response( break; case CAP_DRIVE_TYPE: - if ((status = rdpdr_server_read_drive_capability_set(context, s, - &capabilityHeader))) + if ((status = + rdpdr_server_read_drive_capability_set(context, s, &capabilityHeader))) { - WLog_ERR(TAG, "rdpdr_server_read_drive_capability_set failed with error %"PRIu32"!", + WLog_ERR(TAG, + "rdpdr_server_read_drive_capability_set failed with error %" PRIu32 + "!", status); return status; } @@ -695,20 +679,22 @@ static UINT rdpdr_server_receive_core_capability_response( break; case CAP_SMARTCARD_TYPE: - if ((status = rdpdr_server_read_smartcard_capability_set(context, s, - &capabilityHeader))) + if ((status = + rdpdr_server_read_smartcard_capability_set(context, s, &capabilityHeader))) { WLog_ERR(TAG, - "rdpdr_server_read_smartcard_capability_set failed with error %"PRIu32"!", status); + "rdpdr_server_read_smartcard_capability_set failed with error %" PRIu32 + "!", + status); return status; } break; default: - WLog_DBG(TAG, "Unknown capabilityType %"PRIu16"", capabilityHeader.CapabilityType); - Stream_Seek(s, capabilityHeader.CapabilityLength - - RDPDR_CAPABILITY_HEADER_LENGTH); + WLog_DBG(TAG, "Unknown capabilityType %" PRIu16 "", + capabilityHeader.CapabilityType); + Stream_Seek(s, capabilityHeader.CapabilityLength - RDPDR_CAPABILITY_HEADER_LENGTH); return ERROR_INVALID_DATA; break; } @@ -739,17 +725,15 @@ static UINT rdpdr_server_send_client_id_confirm(RdpdrServerContext* context) return CHANNEL_RC_NO_MEMORY; } - Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */ - Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */ - Stream_Write_UINT16(s, - context->priv->VersionMajor); /* VersionMajor (2 bytes) */ - Stream_Write_UINT16(s, - context->priv->VersionMinor); /* VersionMinor (2 bytes) */ - Stream_Write_UINT32(s, context->priv->ClientId); /* ClientId (4 bytes) */ + Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */ + Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */ + Stream_Write_UINT16(s, context->priv->VersionMajor); /* VersionMajor (2 bytes) */ + Stream_Write_UINT16(s, context->priv->VersionMinor); /* VersionMinor (2 bytes) */ + Stream_Write_UINT32(s, context->priv->ClientId); /* ClientId (4 bytes) */ Stream_SealLength(s); winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), Stream_Length(s)); - status = WTSVirtualChannelWrite(context->priv->ChannelHandle, - (PCHAR) Stream_Buffer(s), Stream_Length(s), &written); + status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR)Stream_Buffer(s), + Stream_Length(s), &written); Stream_Free(s, TRUE); return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; } @@ -759,10 +743,10 @@ static UINT rdpdr_server_send_client_id_confirm(RdpdrServerContext* context) * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_receive_device_list_announce_request( - RdpdrServerContext* context, wStream* s, RDPDR_HEADER* header) +static UINT rdpdr_server_receive_device_list_announce_request(RdpdrServerContext* context, + wStream* s, RDPDR_HEADER* header) { - int i; + UINT32 i; UINT32 DeviceCount; UINT32 DeviceType; UINT32 DeviceId; @@ -776,7 +760,7 @@ static UINT rdpdr_server_receive_device_list_announce_request( } Stream_Read_UINT32(s, DeviceCount); /* DeviceCount (4 bytes) */ - WLog_DBG(TAG, "DeviceCount: %"PRIu32"", DeviceCount); + WLog_DBG(TAG, "DeviceCount: %" PRIu32 "", DeviceCount); for (i = 0; i < DeviceCount; i++) { @@ -788,9 +772,9 @@ static UINT rdpdr_server_receive_device_list_announce_request( return ERROR_INVALID_DATA; } - Stream_Read_UINT32(s, DeviceType); /* DeviceType (4 bytes) */ - Stream_Read_UINT32(s, DeviceId); /* DeviceId (4 bytes) */ - Stream_Read(s, PreferredDosName, 8); /* PreferredDosName (8 bytes) */ + Stream_Read_UINT32(s, DeviceType); /* DeviceType (4 bytes) */ + Stream_Read_UINT32(s, DeviceId); /* DeviceId (4 bytes) */ + Stream_Read(s, PreferredDosName, 8); /* PreferredDosName (8 bytes) */ Stream_Read_UINT32(s, DeviceDataLength); /* DeviceDataLength (4 bytes) */ if (Stream_GetRemainingLength(s) < DeviceDataLength) @@ -799,8 +783,8 @@ static UINT rdpdr_server_receive_device_list_announce_request( return ERROR_INVALID_DATA; } - WLog_DBG(TAG, "Device %d Name: %s Id: 0x%08"PRIX32" DataLength: %"PRIu32"", - i, PreferredDosName, DeviceId, DeviceDataLength); + WLog_DBG(TAG, "Device %d Name: %s Id: 0x%08" PRIX32 " DataLength: %" PRIu32 "", i, + PreferredDosName, DeviceId, DeviceDataLength); switch (DeviceType) { @@ -852,10 +836,10 @@ static UINT rdpdr_server_receive_device_list_announce_request( * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_receive_device_list_remove_request( - RdpdrServerContext* context, wStream* s, RDPDR_HEADER* header) +static UINT rdpdr_server_receive_device_list_remove_request(RdpdrServerContext* context, wStream* s, + RDPDR_HEADER* header) { - int i; + UINT32 i; UINT32 DeviceCount; UINT32 DeviceType; UINT32 DeviceId; @@ -867,7 +851,7 @@ static UINT rdpdr_server_receive_device_list_remove_request( } Stream_Read_UINT32(s, DeviceCount); /* DeviceCount (4 bytes) */ - WLog_DBG(TAG, "DeviceCount: %"PRIu32"", DeviceCount); + WLog_DBG(TAG, "DeviceCount: %" PRIu32 "", DeviceCount); for (i = 0; i < DeviceCount; i++) { @@ -878,7 +862,7 @@ static UINT rdpdr_server_receive_device_list_remove_request( } Stream_Read_UINT32(s, DeviceId); /* DeviceId (4 bytes) */ - WLog_DBG(TAG, "Device %d Id: 0x%08"PRIX32"", i, DeviceId); + WLog_DBG(TAG, "Device %d Id: 0x%08" PRIX32 "", i, DeviceId); DeviceType = 0; /* TODO: Save the device type on the announce request. */ switch (DeviceType) @@ -929,8 +913,8 @@ static UINT rdpdr_server_receive_device_list_remove_request( * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_receive_device_io_completion(RdpdrServerContext* - context, wStream* s, RDPDR_HEADER* header) +static UINT rdpdr_server_receive_device_io_completion(RdpdrServerContext* context, wStream* s, + RDPDR_HEADER* header) { UINT32 deviceId; UINT32 completionId; @@ -947,13 +931,13 @@ static UINT rdpdr_server_receive_device_io_completion(RdpdrServerContext* Stream_Read_UINT32(s, deviceId); Stream_Read_UINT32(s, completionId); Stream_Read_UINT32(s, ioStatus); - WLog_DBG(TAG, "deviceId=%"PRIu32", completionId=0x%"PRIx32", ioStatus=0x%"PRIx32"", deviceId, - completionId, ioStatus); + WLog_DBG(TAG, "deviceId=%" PRIu32 ", completionId=0x%" PRIx32 ", ioStatus=0x%" PRIx32 "", + deviceId, completionId, ioStatus); irp = rdpdr_server_dequeue_irp(context, completionId); if (!irp) { - WLog_ERR(TAG, "IRP not found for completionId=0x%"PRIx32"", completionId); + WLog_ERR(TAG, "IRP not found for completionId=0x%" PRIx32 "", completionId); return ERROR_INTERNAL_ERROR; } @@ -989,11 +973,11 @@ static UINT rdpdr_server_send_user_logged_on(RdpdrServerContext* context) } Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */ - Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */ + Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */ Stream_SealLength(s); winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), Stream_Length(s)); - status = WTSVirtualChannelWrite(context->priv->ChannelHandle, - (PCHAR) Stream_Buffer(s), Stream_Length(s), &written); + status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR)Stream_Buffer(s), + Stream_Length(s), &written); Stream_Free(s, TRUE); return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; } @@ -1003,11 +987,10 @@ static UINT rdpdr_server_send_user_logged_on(RdpdrServerContext* context) * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s, - RDPDR_HEADER* header) +static UINT rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s, RDPDR_HEADER* header) { UINT error = CHANNEL_RC_OK; - WLog_DBG(TAG, "RdpdrServerReceivePdu: Component: 0x%04"PRIX16" PacketId: 0x%04"PRIX16"", + WLog_DBG(TAG, "RdpdrServerReceivePdu: Component: 0x%04" PRIX16 " PacketId: 0x%04" PRIX16 "", header->Component, header->PacketId); winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), Stream_Length(s)); @@ -1018,7 +1001,9 @@ static UINT rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s, case PAKID_CORE_CLIENTID_CONFIRM: if ((error = rdpdr_server_receive_announce_response(context, s, header))) { - WLog_ERR(TAG, "rdpdr_server_receive_announce_response failed with error %"PRIu32"!", + WLog_ERR(TAG, + "rdpdr_server_receive_announce_response failed with error %" PRIu32 + "!", error); return error; } @@ -1028,7 +1013,9 @@ static UINT rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s, case PAKID_CORE_CLIENT_NAME: if ((error = rdpdr_server_receive_client_name_request(context, s, header))) { - WLog_ERR(TAG, "rdpdr_server_receive_client_name_request failed with error %"PRIu32"!", + WLog_ERR(TAG, + "rdpdr_server_receive_client_name_request failed with error %" PRIu32 + "!", error); return error; } @@ -1036,13 +1023,16 @@ static UINT rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s, if ((error = rdpdr_server_send_core_capability_request(context))) { WLog_ERR(TAG, - "rdpdr_server_send_core_capability_request failed with error %"PRIu32"!", error); + "rdpdr_server_send_core_capability_request failed with error %" PRIu32 + "!", + error); return error; } if ((error = rdpdr_server_send_client_id_confirm(context))) { - WLog_ERR(TAG, "rdpdr_server_send_client_id_confirm failed with error %"PRIu32"!", + WLog_ERR(TAG, + "rdpdr_server_send_client_id_confirm failed with error %" PRIu32 "!", error); return error; } @@ -1052,26 +1042,31 @@ static UINT rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s, case PAKID_CORE_CLIENT_CAPABILITY: if ((error = rdpdr_server_receive_core_capability_response(context, s, header))) { - WLog_ERR(TAG, - "rdpdr_server_receive_core_capability_response failed with error %"PRIu32"!", error); + WLog_ERR( + TAG, + "rdpdr_server_receive_core_capability_response failed with error %" PRIu32 + "!", + error); return error; } if (context->priv->UserLoggedOnPdu) if ((error = rdpdr_server_send_user_logged_on(context))) { - WLog_ERR(TAG, "rdpdr_server_send_user_logged_on failed with error %"PRIu32"!", error); + WLog_ERR(TAG, + "rdpdr_server_send_user_logged_on failed with error %" PRIu32 "!", + error); return error; } break; case PAKID_CORE_DEVICELIST_ANNOUNCE: - if ((error = rdpdr_server_receive_device_list_announce_request(context, s, - header))) + if ((error = rdpdr_server_receive_device_list_announce_request(context, s, header))) { WLog_ERR(TAG, - "rdpdr_server_receive_device_list_announce_request failed with error %"PRIu32"!", + "rdpdr_server_receive_device_list_announce_request failed with error " + "%" PRIu32 "!", error); return error; } @@ -1088,18 +1083,21 @@ static UINT rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s, if ((error = rdpdr_server_receive_device_io_completion(context, s, header))) { WLog_ERR(TAG, - "rdpdr_server_receive_device_io_completion failed with error %"PRIu32"!", error); + "rdpdr_server_receive_device_io_completion failed with error %" PRIu32 + "!", + error); return error; } break; case PAKID_CORE_DEVICELIST_REMOVE: - if ((error = rdpdr_server_receive_device_list_remove_request(context, s, - header))) + if ((error = rdpdr_server_receive_device_list_remove_request(context, s, header))) { WLog_ERR(TAG, - "rdpdr_server_receive_device_io_completion failed with error %"PRIu32"!", error); + "rdpdr_server_receive_device_io_completion failed with error %" PRIu32 + "!", + error); return error; } @@ -1125,7 +1123,7 @@ static UINT rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s, } else { - WLog_WARN(TAG, "Unknown RDPDR_HEADER.Component: 0x%04"PRIX16"", header->Component); + WLog_WARN(TAG, "Unknown RDPDR_HEADER.Component: 0x%04" PRIX16 "", header->Component); return ERROR_INVALID_DATA; } @@ -1144,7 +1142,7 @@ static DWORD WINAPI rdpdr_server_thread(LPVOID arg) DWORD BytesReturned; RdpdrServerContext* context; UINT error; - context = (RdpdrServerContext*) arg; + context = (RdpdrServerContext*)arg; buffer = NULL; BytesReturned = 0; ChannelEvent = NULL; @@ -1157,8 +1155,8 @@ static DWORD WINAPI rdpdr_server_thread(LPVOID arg) goto out; } - if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, - &buffer, &BytesReturned) == TRUE) + if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, + &BytesReturned) == TRUE) { if (BytesReturned == sizeof(HANDLE)) CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); @@ -1172,8 +1170,7 @@ static DWORD WINAPI rdpdr_server_thread(LPVOID arg) if ((error = rdpdr_server_send_announce_request(context))) { - WLog_ERR(TAG, "rdpdr_server_send_announce_request failed with error %"PRIu32"!", - error); + WLog_ERR(TAG, "rdpdr_server_send_announce_request failed with error %" PRIu32 "!", error); goto out_stream; } @@ -1185,7 +1182,7 @@ static DWORD WINAPI rdpdr_server_thread(LPVOID arg) if (status == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", error); goto out_stream; } @@ -1194,15 +1191,15 @@ static DWORD WINAPI rdpdr_server_thread(LPVOID arg) if (status == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error); goto out_stream; } if (status == WAIT_OBJECT_0) break; - if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, - (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned)) + if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, (PCHAR)Stream_Buffer(s), + Stream_Capacity(s), &BytesReturned)) { WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); error = ERROR_INTERNAL_ERROR; @@ -1217,11 +1214,11 @@ static DWORD WINAPI rdpdr_server_thread(LPVOID arg) while (Stream_GetRemainingLength(s) >= RDPDR_HEADER_LENGTH) { Stream_Read_UINT16(s, header.Component); /* Component (2 bytes) */ - Stream_Read_UINT16(s, header.PacketId); /* PacketId (2 bytes) */ + Stream_Read_UINT16(s, header.PacketId); /* PacketId (2 bytes) */ if ((error = rdpdr_server_receive_pdu(context, s, &header))) { - WLog_ERR(TAG, "rdpdr_server_receive_pdu failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rdpdr_server_receive_pdu failed with error %" PRIu32 "!", error); goto out_stream; } } @@ -1233,8 +1230,7 @@ out_stream: out: if (error && context->rdpcontext) - setChannelError(context->rdpcontext, error, - "rdpdr_server_thread reported an error"); + setChannelError(context->rdpcontext, error, "rdpdr_server_thread reported an error"); ExitThread(error); return error; @@ -1247,8 +1243,8 @@ out: */ static UINT rdpdr_server_start(RdpdrServerContext* context) { - context->priv->ChannelHandle = WTSVirtualChannelOpen(context->vcm, - WTS_CURRENT_SESSION, "rdpdr"); + context->priv->ChannelHandle = + WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "rdpdr"); if (!context->priv->ChannelHandle) { @@ -1262,8 +1258,8 @@ static UINT rdpdr_server_start(RdpdrServerContext* context) return ERROR_INTERNAL_ERROR; } - if (!(context->priv->Thread = CreateThread(NULL, 0, - rdpdr_server_thread, (void*) context, 0, NULL))) + if (!(context->priv->Thread = + CreateThread(NULL, 0, rdpdr_server_thread, (void*)context, 0, NULL))) { WLog_ERR(TAG, "CreateThread failed!"); CloseHandle(context->priv->StopEvent); @@ -1290,7 +1286,7 @@ static UINT rdpdr_server_stop(RdpdrServerContext* context) if (WaitForSingleObject(context->priv->Thread, INFINITE) == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error); return error; } @@ -1303,21 +1299,17 @@ static UINT rdpdr_server_stop(RdpdrServerContext* context) return CHANNEL_RC_OK; } -static void rdpdr_server_write_device_iorequest( - wStream* s, - UINT32 deviceId, - UINT32 fileId, - UINT32 completionId, - UINT32 majorFunction, - UINT32 minorFunction) +static void rdpdr_server_write_device_iorequest(wStream* s, UINT32 deviceId, UINT32 fileId, + UINT32 completionId, UINT32 majorFunction, + UINT32 minorFunction) { - Stream_Write_UINT16(s, RDPDR_CTYP_CORE); /* Component (2 bytes) */ + Stream_Write_UINT16(s, RDPDR_CTYP_CORE); /* Component (2 bytes) */ Stream_Write_UINT16(s, PAKID_CORE_DEVICE_IOREQUEST); /* PacketId (2 bytes) */ - Stream_Write_UINT32(s, deviceId); /* DeviceId (4 bytes) */ - Stream_Write_UINT32(s, fileId); /* FileId (4 bytes) */ - Stream_Write_UINT32(s, completionId); /* CompletionId (4 bytes) */ - Stream_Write_UINT32(s, majorFunction); /* MajorFunction (4 bytes) */ - Stream_Write_UINT32(s, minorFunction); /* MinorFunction (4 bytes) */ + Stream_Write_UINT32(s, deviceId); /* DeviceId (4 bytes) */ + Stream_Write_UINT32(s, fileId); /* FileId (4 bytes) */ + Stream_Write_UINT32(s, completionId); /* CompletionId (4 bytes) */ + Stream_Write_UINT32(s, majorFunction); /* MajorFunction (4 bytes) */ + Stream_Write_UINT32(s, minorFunction); /* MinorFunction (4 bytes) */ } /** @@ -1326,7 +1318,7 @@ static void rdpdr_server_write_device_iorequest( * @return 0 on success, otherwise a Win32 error code */ static UINT rdpdr_server_read_file_directory_information(wStream* s, - FILE_DIRECTORY_INFORMATION* fdi) + FILE_DIRECTORY_INFORMATION* fdi) { UINT32 fileNameLength; ZeroMemory(fdi, sizeof(FILE_DIRECTORY_INFORMATION)); @@ -1338,15 +1330,15 @@ static UINT rdpdr_server_read_file_directory_information(wStream* s, } Stream_Read_UINT32(s, fdi->NextEntryOffset); /* NextEntryOffset (4 bytes) */ - Stream_Read_UINT32(s, fdi->FileIndex); /* FileIndex (4 bytes) */ - Stream_Read_UINT64(s, fdi->CreationTime); /* CreationTime (8 bytes) */ - Stream_Read_UINT64(s, fdi->LastAccessTime); /* LastAccessTime (8 bytes) */ - Stream_Read_UINT64(s, fdi->LastWriteTime); /* LastWriteTime (8 bytes) */ - Stream_Read_UINT64(s, fdi->ChangeTime); /* ChangeTime (8 bytes) */ - Stream_Read_UINT64(s, fdi->EndOfFile); /* EndOfFile (8 bytes) */ - Stream_Read_UINT64(s, fdi->AllocationSize); /* AllocationSize (8 bytes) */ - Stream_Read_UINT32(s, fdi->FileAttributes); /* FileAttributes (4 bytes) */ - Stream_Read_UINT32(s, fileNameLength); /* FileNameLength (4 bytes) */ + Stream_Read_UINT32(s, fdi->FileIndex); /* FileIndex (4 bytes) */ + Stream_Read_UINT64(s, fdi->CreationTime); /* CreationTime (8 bytes) */ + Stream_Read_UINT64(s, fdi->LastAccessTime); /* LastAccessTime (8 bytes) */ + Stream_Read_UINT64(s, fdi->LastWriteTime); /* LastWriteTime (8 bytes) */ + Stream_Read_UINT64(s, fdi->ChangeTime); /* ChangeTime (8 bytes) */ + Stream_Read_UINT64(s, fdi->EndOfFile); /* EndOfFile (8 bytes) */ + Stream_Read_UINT64(s, fdi->AllocationSize); /* AllocationSize (8 bytes) */ + Stream_Read_UINT32(s, fdi->FileAttributes); /* FileAttributes (4 bytes) */ + Stream_Read_UINT32(s, fileNameLength); /* FileNameLength (4 bytes) */ if (Stream_GetRemainingLength(s) < fileNameLength) { @@ -1354,8 +1346,8 @@ static UINT rdpdr_server_read_file_directory_information(wStream* s, return ERROR_INVALID_DATA; } - WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) Stream_Pointer(s), fileNameLength / 2, - fdi->FileName, sizeof(fdi->FileName), NULL, NULL); + WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)Stream_Pointer(s), fileNameLength / 2, fdi->FileName, + sizeof(fdi->FileName), NULL, NULL); Stream_Seek(s, fileNameLength); return CHANNEL_RC_OK; } @@ -1365,21 +1357,19 @@ static UINT rdpdr_server_read_file_directory_information(wStream* s, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_send_device_create_request( - RdpdrServerContext* context, - UINT32 deviceId, - UINT32 completionId, - const char* path, - UINT32 desiredAccess, - UINT32 createOptions, - UINT32 createDisposition) +static UINT rdpdr_server_send_device_create_request(RdpdrServerContext* context, UINT32 deviceId, + UINT32 completionId, const char* path, + UINT32 desiredAccess, UINT32 createOptions, + UINT32 createDisposition) { UINT32 pathLength; ULONG written; BOOL status; wStream* s; WLog_DBG(TAG, - "RdpdrServerSendDeviceCreateRequest: deviceId=%"PRIu32", path=%s, desiredAccess=0x%"PRIx32" createOptions=0x%"PRIx32" createDisposition=0x%"PRIx32"", + "RdpdrServerSendDeviceCreateRequest: deviceId=%" PRIu32 + ", path=%s, desiredAccess=0x%" PRIx32 " createOptions=0x%" PRIx32 + " createDisposition=0x%" PRIx32 "", deviceId, path, desiredAccess, createOptions, createDisposition); /* Compute the required Unicode size. */ pathLength = (strlen(path) + 1) * sizeof(WCHAR); @@ -1391,23 +1381,21 @@ static UINT rdpdr_server_send_device_create_request( return CHANNEL_RC_NO_MEMORY; } - rdpdr_server_write_device_iorequest(s, deviceId, 0, completionId, IRP_MJ_CREATE, - 0); + rdpdr_server_write_device_iorequest(s, deviceId, 0, completionId, IRP_MJ_CREATE, 0); Stream_Write_UINT32(s, desiredAccess); /* DesiredAccess (4 bytes) */ - Stream_Write_UINT32(s, 0); /* AllocationSize (8 bytes) */ + Stream_Write_UINT32(s, 0); /* AllocationSize (8 bytes) */ Stream_Write_UINT32(s, 0); - Stream_Write_UINT32(s, 0); /* FileAttributes (4 bytes) */ - Stream_Write_UINT32(s, 3); /* SharedAccess (4 bytes) */ + Stream_Write_UINT32(s, 0); /* FileAttributes (4 bytes) */ + Stream_Write_UINT32(s, 3); /* SharedAccess (4 bytes) */ Stream_Write_UINT32(s, createDisposition); /* CreateDisposition (4 bytes) */ - Stream_Write_UINT32(s, createOptions); /* CreateOptions (4 bytes) */ - Stream_Write_UINT32(s, pathLength); /* PathLength (4 bytes) */ + Stream_Write_UINT32(s, createOptions); /* CreateOptions (4 bytes) */ + Stream_Write_UINT32(s, pathLength); /* PathLength (4 bytes) */ /* Convert the path to Unicode. */ - MultiByteToWideChar(CP_ACP, 0, path, -1, (LPWSTR) Stream_Pointer(s), - pathLength); + MultiByteToWideChar(CP_ACP, 0, path, -1, (LPWSTR)Stream_Pointer(s), pathLength); Stream_Seek(s, pathLength); Stream_SealLength(s); - status = WTSVirtualChannelWrite(context->priv->ChannelHandle, - (PCHAR) Stream_Buffer(s), Stream_Length(s), &written); + status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR)Stream_Buffer(s), + Stream_Length(s), &written); Stream_Free(s, TRUE); return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; } @@ -1417,16 +1405,13 @@ static UINT rdpdr_server_send_device_create_request( * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_send_device_close_request( - RdpdrServerContext* context, - UINT32 deviceId, - UINT32 fileId, - UINT32 completionId) +static UINT rdpdr_server_send_device_close_request(RdpdrServerContext* context, UINT32 deviceId, + UINT32 fileId, UINT32 completionId) { ULONG written; BOOL status; wStream* s; - WLog_DBG(TAG, "RdpdrServerSendDeviceCloseRequest: deviceId=%"PRIu32", fileId=%"PRIu32"", + WLog_DBG(TAG, "RdpdrServerSendDeviceCloseRequest: deviceId=%" PRIu32 ", fileId=%" PRIu32 "", deviceId, fileId); s = Stream_New(NULL, 128); @@ -1436,12 +1421,11 @@ static UINT rdpdr_server_send_device_close_request( return CHANNEL_RC_NO_MEMORY; } - rdpdr_server_write_device_iorequest(s, deviceId, fileId, completionId, - IRP_MJ_CLOSE, 0); + rdpdr_server_write_device_iorequest(s, deviceId, fileId, completionId, IRP_MJ_CLOSE, 0); Stream_Zero(s, 32); /* Padding (32 bytes) */ Stream_SealLength(s); - status = WTSVirtualChannelWrite(context->priv->ChannelHandle, - (PCHAR) Stream_Buffer(s), Stream_Length(s), &written); + status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR)Stream_Buffer(s), + Stream_Length(s), &written); Stream_Free(s, TRUE); return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; } @@ -1451,19 +1435,16 @@ static UINT rdpdr_server_send_device_close_request( * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_send_device_read_request( - RdpdrServerContext* context, - UINT32 deviceId, - UINT32 fileId, - UINT32 completionId, - UINT32 length, - UINT32 offset) +static UINT rdpdr_server_send_device_read_request(RdpdrServerContext* context, UINT32 deviceId, + UINT32 fileId, UINT32 completionId, UINT32 length, + UINT32 offset) { ULONG written; BOOL status; wStream* s; WLog_DBG(TAG, - "RdpdrServerSendDeviceReadRequest: deviceId=%"PRIu32", fileId=%"PRIu32", length=%"PRIu32", offset=%"PRIu32"", + "RdpdrServerSendDeviceReadRequest: deviceId=%" PRIu32 ", fileId=%" PRIu32 + ", length=%" PRIu32 ", offset=%" PRIu32 "", deviceId, fileId, length, offset); s = Stream_New(NULL, 128); @@ -1473,15 +1454,14 @@ static UINT rdpdr_server_send_device_read_request( return CHANNEL_RC_NO_MEMORY; } - rdpdr_server_write_device_iorequest(s, deviceId, fileId, completionId, - IRP_MJ_READ, 0); + rdpdr_server_write_device_iorequest(s, deviceId, fileId, completionId, IRP_MJ_READ, 0); Stream_Write_UINT32(s, length); /* Length (4 bytes) */ Stream_Write_UINT32(s, offset); /* Offset (8 bytes) */ Stream_Write_UINT32(s, 0); Stream_Zero(s, 20); /* Padding (20 bytes) */ Stream_SealLength(s); - status = WTSVirtualChannelWrite(context->priv->ChannelHandle, - (PCHAR) Stream_Buffer(s), Stream_Length(s), &written); + status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR)Stream_Buffer(s), + Stream_Length(s), &written); Stream_Free(s, TRUE); return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; } @@ -1491,20 +1471,16 @@ static UINT rdpdr_server_send_device_read_request( * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_send_device_write_request( - RdpdrServerContext* context, - UINT32 deviceId, - UINT32 fileId, - UINT32 completionId, - const char* data, - UINT32 length, - UINT32 offset) +static UINT rdpdr_server_send_device_write_request(RdpdrServerContext* context, UINT32 deviceId, + UINT32 fileId, UINT32 completionId, + const char* data, UINT32 length, UINT32 offset) { ULONG written; BOOL status; wStream* s; WLog_DBG(TAG, - "RdpdrServerSendDeviceWriteRequest: deviceId=%"PRIu32", fileId=%"PRIu32", length=%"PRIu32", offset=%"PRIu32"", + "RdpdrServerSendDeviceWriteRequest: deviceId=%" PRIu32 ", fileId=%" PRIu32 + ", length=%" PRIu32 ", offset=%" PRIu32 "", deviceId, fileId, length, offset); s = Stream_New(NULL, 64 + length); @@ -1514,16 +1490,15 @@ static UINT rdpdr_server_send_device_write_request( return CHANNEL_RC_NO_MEMORY; } - rdpdr_server_write_device_iorequest(s, deviceId, fileId, completionId, - IRP_MJ_WRITE, 0); + rdpdr_server_write_device_iorequest(s, deviceId, fileId, completionId, IRP_MJ_WRITE, 0); Stream_Write_UINT32(s, length); /* Length (4 bytes) */ Stream_Write_UINT32(s, offset); /* Offset (8 bytes) */ Stream_Write_UINT32(s, 0); - Stream_Zero(s, 20); /* Padding (20 bytes) */ + Stream_Zero(s, 20); /* Padding (20 bytes) */ Stream_Write(s, data, length); /* WriteData (variable) */ Stream_SealLength(s); - status = WTSVirtualChannelWrite(context->priv->ChannelHandle, - (PCHAR) Stream_Buffer(s), Stream_Length(s), &written); + status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR)Stream_Buffer(s), + Stream_Length(s), &written); Stream_Free(s, TRUE); return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; } @@ -1533,19 +1508,17 @@ static UINT rdpdr_server_send_device_write_request( * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_send_device_query_directory_request( - RdpdrServerContext* context, - UINT32 deviceId, - UINT32 fileId, - UINT32 completionId, - const char* path) +static UINT rdpdr_server_send_device_query_directory_request(RdpdrServerContext* context, + UINT32 deviceId, UINT32 fileId, + UINT32 completionId, const char* path) { UINT32 pathLength; ULONG written; BOOL status; wStream* s; WLog_DBG(TAG, - "RdpdrServerSendDeviceQueryDirectoryRequest: deviceId=%"PRIu32", fileId=%"PRIu32", path=%s", + "RdpdrServerSendDeviceQueryDirectoryRequest: deviceId=%" PRIu32 ", fileId=%" PRIu32 + ", path=%s", deviceId, fileId, path); /* Compute the required Unicode size. */ pathLength = path ? (strlen(path) + 1) * sizeof(WCHAR) : 0; @@ -1557,25 +1530,23 @@ static UINT rdpdr_server_send_device_query_directory_request( return CHANNEL_RC_NO_MEMORY; } - rdpdr_server_write_device_iorequest(s, deviceId, fileId, completionId, - IRP_MJ_DIRECTORY_CONTROL, IRP_MN_QUERY_DIRECTORY); - Stream_Write_UINT32(s, - FileDirectoryInformation); /* FsInformationClass (4 bytes) */ - Stream_Write_UINT8(s, path ? 1 : 0); /* InitialQuery (1 byte) */ - Stream_Write_UINT32(s, pathLength); /* PathLength (4 bytes) */ - Stream_Zero(s, 23); /* Padding (23 bytes) */ + rdpdr_server_write_device_iorequest(s, deviceId, fileId, completionId, IRP_MJ_DIRECTORY_CONTROL, + IRP_MN_QUERY_DIRECTORY); + Stream_Write_UINT32(s, FileDirectoryInformation); /* FsInformationClass (4 bytes) */ + Stream_Write_UINT8(s, path ? 1 : 0); /* InitialQuery (1 byte) */ + Stream_Write_UINT32(s, pathLength); /* PathLength (4 bytes) */ + Stream_Zero(s, 23); /* Padding (23 bytes) */ /* Convert the path to Unicode. */ if (pathLength > 0) { - MultiByteToWideChar(CP_ACP, 0, path, -1, (LPWSTR) Stream_Pointer(s), - pathLength); + MultiByteToWideChar(CP_ACP, 0, path, -1, (LPWSTR)Stream_Pointer(s), pathLength); Stream_Seek(s, pathLength); } Stream_SealLength(s); - status = WTSVirtualChannelWrite(context->priv->ChannelHandle, - (PCHAR) Stream_Buffer(s), Stream_Length(s), &written); + status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR)Stream_Buffer(s), + Stream_Length(s), &written); Stream_Free(s, TRUE); return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; } @@ -1585,19 +1556,17 @@ static UINT rdpdr_server_send_device_query_directory_request( * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_send_device_file_rename_request( - RdpdrServerContext* context, - UINT32 deviceId, - UINT32 fileId, - UINT32 completionId, - const char* path) +static UINT rdpdr_server_send_device_file_rename_request(RdpdrServerContext* context, + UINT32 deviceId, UINT32 fileId, + UINT32 completionId, const char* path) { UINT32 pathLength; ULONG written; BOOL status; wStream* s; WLog_DBG(TAG, - "RdpdrServerSendDeviceFileNameRequest: deviceId=%"PRIu32", fileId=%"PRIu32", path=%s", + "RdpdrServerSendDeviceFileNameRequest: deviceId=%" PRIu32 ", fileId=%" PRIu32 + ", path=%s", deviceId, fileId, path); /* Compute the required Unicode size. */ pathLength = path ? (strlen(path) + 1) * sizeof(WCHAR) : 0; @@ -1609,28 +1578,26 @@ static UINT rdpdr_server_send_device_file_rename_request( return CHANNEL_RC_NO_MEMORY; } - rdpdr_server_write_device_iorequest(s, deviceId, fileId, completionId, - IRP_MJ_SET_INFORMATION, 0); - Stream_Write_UINT32(s, - FileRenameInformation); /* FsInformationClass (4 bytes) */ - Stream_Write_UINT32(s, pathLength + 6); /* Length (4 bytes) */ - Stream_Zero(s, 24); /* Padding (24 bytes) */ + rdpdr_server_write_device_iorequest(s, deviceId, fileId, completionId, IRP_MJ_SET_INFORMATION, + 0); + Stream_Write_UINT32(s, FileRenameInformation); /* FsInformationClass (4 bytes) */ + Stream_Write_UINT32(s, pathLength + 6); /* Length (4 bytes) */ + Stream_Zero(s, 24); /* Padding (24 bytes) */ /* RDP_FILE_RENAME_INFORMATION */ - Stream_Write_UINT8(s, 0); /* ReplaceIfExists (1 byte) */ - Stream_Write_UINT8(s, 0); /* RootDirectory (1 byte) */ + Stream_Write_UINT8(s, 0); /* ReplaceIfExists (1 byte) */ + Stream_Write_UINT8(s, 0); /* RootDirectory (1 byte) */ Stream_Write_UINT32(s, pathLength); /* FileNameLength (4 bytes) */ /* Convert the path to Unicode. */ if (pathLength > 0) { - MultiByteToWideChar(CP_ACP, 0, path, -1, (LPWSTR) Stream_Pointer(s), - pathLength); + MultiByteToWideChar(CP_ACP, 0, path, -1, (LPWSTR)Stream_Pointer(s), pathLength); Stream_Seek(s, pathLength); } Stream_SealLength(s); - status = WTSVirtualChannelWrite(context->priv->ChannelHandle, - (PCHAR) Stream_Buffer(s), Stream_Length(s), &written); + status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR)Stream_Buffer(s), + Stream_Length(s), &written); Stream_Free(s, TRUE); return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; } @@ -1655,12 +1622,13 @@ static void rdpdr_server_convert_slashes(char* path, int size) * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_drive_create_directory_callback2( - RdpdrServerContext* context, wStream* s, RDPDR_IRP* irp, UINT32 deviceId, - UINT32 completionId, UINT32 ioStatus) +static UINT rdpdr_server_drive_create_directory_callback2(RdpdrServerContext* context, wStream* s, + RDPDR_IRP* irp, UINT32 deviceId, + UINT32 completionId, UINT32 ioStatus) { WLog_DBG(TAG, - "RdpdrServerDriveCreateDirectoryCallback2: deviceId=%"PRIu32", completionId=%"PRIu32", ioStatus=0x%"PRIx32"", + "RdpdrServerDriveCreateDirectoryCallback2: deviceId=%" PRIu32 ", completionId=%" PRIu32 + ", ioStatus=0x%" PRIx32 "", deviceId, completionId, ioStatus); /* Invoke the create directory completion routine. */ context->OnDriveCreateDirectoryComplete(context, irp->CallbackData, ioStatus); @@ -1674,14 +1642,15 @@ static UINT rdpdr_server_drive_create_directory_callback2( * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_drive_create_directory_callback1( - RdpdrServerContext* context, wStream* s, RDPDR_IRP* irp, UINT32 deviceId, - UINT32 completionId, UINT32 ioStatus) +static UINT rdpdr_server_drive_create_directory_callback1(RdpdrServerContext* context, wStream* s, + RDPDR_IRP* irp, UINT32 deviceId, + UINT32 completionId, UINT32 ioStatus) { UINT32 fileId; UINT8 information; WLog_DBG(TAG, - "RdpdrServerDriveCreateDirectoryCallback1: deviceId=%"PRIu32", completionId=%"PRIu32", ioStatus=0x%"PRIx32"", + "RdpdrServerDriveCreateDirectoryCallback1: deviceId=%" PRIu32 ", completionId=%" PRIu32 + ", ioStatus=0x%" PRIx32 "", deviceId, completionId, ioStatus); if (ioStatus != STATUS_SUCCESS) @@ -1699,7 +1668,7 @@ static UINT rdpdr_server_drive_create_directory_callback1( return ERROR_INVALID_DATA; } - Stream_Read_UINT32(s, fileId); /* FileId (4 bytes) */ + Stream_Read_UINT32(s, fileId); /* FileId (4 bytes) */ Stream_Read_UINT8(s, information); /* Information (1 byte) */ /* Setup the IRP. */ irp->CompletionId = context->priv->NextCompletionId++; @@ -1715,8 +1684,7 @@ static UINT rdpdr_server_drive_create_directory_callback1( } /* Send a request to close the file */ - return rdpdr_server_send_device_close_request(context, deviceId, fileId, - irp->CompletionId); + return rdpdr_server_send_device_close_request(context, deviceId, fileId, irp->CompletionId); } /** @@ -1724,8 +1692,8 @@ static UINT rdpdr_server_drive_create_directory_callback1( * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_drive_create_directory(RdpdrServerContext* context, - void* callbackData, UINT32 deviceId, const char* path) +static UINT rdpdr_server_drive_create_directory(RdpdrServerContext* context, void* callbackData, + UINT32 deviceId, const char* path) { RDPDR_IRP* irp; irp = rdpdr_server_irp_new(); @@ -1751,10 +1719,9 @@ static UINT rdpdr_server_drive_create_directory(RdpdrServerContext* context, } /* Send a request to open the file. */ - return rdpdr_server_send_device_create_request(context, deviceId, - irp->CompletionId, irp->PathName, - FILE_READ_DATA | SYNCHRONIZE, - FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, FILE_CREATE); + return rdpdr_server_send_device_create_request( + context, deviceId, irp->CompletionId, irp->PathName, FILE_READ_DATA | SYNCHRONIZE, + FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, FILE_CREATE); } /************************************************* @@ -1766,12 +1733,13 @@ static UINT rdpdr_server_drive_create_directory(RdpdrServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_drive_delete_directory_callback2( - RdpdrServerContext* context, wStream* s, RDPDR_IRP* irp, UINT32 deviceId, - UINT32 completionId, UINT32 ioStatus) +static UINT rdpdr_server_drive_delete_directory_callback2(RdpdrServerContext* context, wStream* s, + RDPDR_IRP* irp, UINT32 deviceId, + UINT32 completionId, UINT32 ioStatus) { WLog_DBG(TAG, - "RdpdrServerDriveDeleteDirectoryCallback2: deviceId=%"PRIu32", completionId=%"PRIu32", ioStatus=0x%"PRIx32"", + "RdpdrServerDriveDeleteDirectoryCallback2: deviceId=%" PRIu32 ", completionId=%" PRIu32 + ", ioStatus=0x%" PRIx32 "", deviceId, completionId, ioStatus); /* Invoke the delete directory completion routine. */ context->OnDriveDeleteDirectoryComplete(context, irp->CallbackData, ioStatus); @@ -1785,14 +1753,15 @@ static UINT rdpdr_server_drive_delete_directory_callback2( * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_drive_delete_directory_callback1( - RdpdrServerContext* context, wStream* s, RDPDR_IRP* irp, UINT32 deviceId, - UINT32 completionId, UINT32 ioStatus) +static UINT rdpdr_server_drive_delete_directory_callback1(RdpdrServerContext* context, wStream* s, + RDPDR_IRP* irp, UINT32 deviceId, + UINT32 completionId, UINT32 ioStatus) { UINT32 fileId; UINT8 information; WLog_DBG(TAG, - "RdpdrServerDriveDeleteDirectoryCallback1: deviceId=%"PRIu32", completionId=%"PRIu32", ioStatus=0x%"PRIx32"", + "RdpdrServerDriveDeleteDirectoryCallback1: deviceId=%" PRIu32 ", completionId=%" PRIu32 + ", ioStatus=0x%" PRIx32 "", deviceId, completionId, ioStatus); if (ioStatus != STATUS_SUCCESS) @@ -1810,7 +1779,7 @@ static UINT rdpdr_server_drive_delete_directory_callback1( return ERROR_INVALID_DATA; } - Stream_Read_UINT32(s, fileId); /* FileId (4 bytes) */ + Stream_Read_UINT32(s, fileId); /* FileId (4 bytes) */ Stream_Read_UINT8(s, information); /* Information (1 byte) */ /* Setup the IRP. */ irp->CompletionId = context->priv->NextCompletionId++; @@ -1826,8 +1795,7 @@ static UINT rdpdr_server_drive_delete_directory_callback1( } /* Send a request to close the file */ - return rdpdr_server_send_device_close_request(context, deviceId, fileId, - irp->CompletionId); + return rdpdr_server_send_device_close_request(context, deviceId, fileId, irp->CompletionId); } /** @@ -1835,8 +1803,8 @@ static UINT rdpdr_server_drive_delete_directory_callback1( * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_drive_delete_directory(RdpdrServerContext* context, - void* callbackData, UINT32 deviceId, const char* path) +static UINT rdpdr_server_drive_delete_directory(RdpdrServerContext* context, void* callbackData, + UINT32 deviceId, const char* path) { RDPDR_IRP* irp; irp = rdpdr_server_irp_new(); @@ -1862,10 +1830,9 @@ static UINT rdpdr_server_drive_delete_directory(RdpdrServerContext* context, } /* Send a request to open the file. */ - return rdpdr_server_send_device_create_request(context, deviceId, - irp->CompletionId, irp->PathName, - DELETE | SYNCHRONIZE, FILE_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE | - FILE_SYNCHRONOUS_IO_NONALERT, FILE_OPEN); + return rdpdr_server_send_device_create_request( + context, deviceId, irp->CompletionId, irp->PathName, DELETE | SYNCHRONIZE, + FILE_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE | FILE_SYNCHRONOUS_IO_NONALERT, FILE_OPEN); } /************************************************* @@ -1877,15 +1844,16 @@ static UINT rdpdr_server_drive_delete_directory(RdpdrServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_drive_query_directory_callback2( - RdpdrServerContext* context, wStream* s, RDPDR_IRP* irp, UINT32 deviceId, - UINT32 completionId, UINT32 ioStatus) +static UINT rdpdr_server_drive_query_directory_callback2(RdpdrServerContext* context, wStream* s, + RDPDR_IRP* irp, UINT32 deviceId, + UINT32 completionId, UINT32 ioStatus) { UINT error; UINT32 length; FILE_DIRECTORY_INFORMATION fdi; WLog_DBG(TAG, - "RdpdrServerDriveQueryDirectoryCallback2: deviceId=%"PRIu32", completionId=%"PRIu32", ioStatus=0x%"PRIx32"", + "RdpdrServerDriveQueryDirectoryCallback2: deviceId=%" PRIu32 ", completionId=%" PRIu32 + ", ioStatus=0x%" PRIx32 "", deviceId, completionId, ioStatus); if (Stream_GetRemainingLength(s) < 4) @@ -1901,7 +1869,8 @@ static UINT rdpdr_server_drive_query_directory_callback2( if ((error = rdpdr_server_read_file_directory_information(s, &fdi))) { WLog_ERR(TAG, - "rdpdr_server_read_file_directory_information failed with error %"PRIu32"!", error); + "rdpdr_server_read_file_directory_information failed with error %" PRIu32 "!", + error); return error; } } @@ -1933,14 +1902,13 @@ static UINT rdpdr_server_drive_query_directory_callback2( } /* Send a request to query the directory. */ - return rdpdr_server_send_device_query_directory_request(context, irp->DeviceId, - irp->FileId, irp->CompletionId, NULL); + return rdpdr_server_send_device_query_directory_request(context, irp->DeviceId, irp->FileId, + irp->CompletionId, NULL); } else { /* Invoke the query directory completion routine. */ - context->OnDriveQueryDirectoryComplete(context, irp->CallbackData, ioStatus, - NULL); + context->OnDriveQueryDirectoryComplete(context, irp->CallbackData, ioStatus, NULL); /* Destroy the IRP. */ rdpdr_server_irp_free(irp); } @@ -1953,20 +1921,20 @@ static UINT rdpdr_server_drive_query_directory_callback2( * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_drive_query_directory_callback1( - RdpdrServerContext* context, wStream* s, RDPDR_IRP* irp, UINT32 deviceId, - UINT32 completionId, UINT32 ioStatus) +static UINT rdpdr_server_drive_query_directory_callback1(RdpdrServerContext* context, wStream* s, + RDPDR_IRP* irp, UINT32 deviceId, + UINT32 completionId, UINT32 ioStatus) { UINT32 fileId; WLog_DBG(TAG, - "RdpdrServerDriveQueryDirectoryCallback1: deviceId=%"PRIu32", completionId=%"PRIu32", ioStatus=0x%"PRIx32"", + "RdpdrServerDriveQueryDirectoryCallback1: deviceId=%" PRIu32 ", completionId=%" PRIu32 + ", ioStatus=0x%" PRIx32 "", deviceId, completionId, ioStatus); if (ioStatus != STATUS_SUCCESS) { /* Invoke the query directory completion routine. */ - context->OnDriveQueryDirectoryComplete(context, irp->CallbackData, ioStatus, - NULL); + context->OnDriveQueryDirectoryComplete(context, irp->CallbackData, ioStatus, NULL); /* Destroy the IRP. */ rdpdr_server_irp_free(irp); return CHANNEL_RC_OK; @@ -1994,8 +1962,8 @@ static UINT rdpdr_server_drive_query_directory_callback1( } /* Send a request to query the directory. */ - return rdpdr_server_send_device_query_directory_request(context, deviceId, - fileId, irp->CompletionId, irp->PathName); + return rdpdr_server_send_device_query_directory_request(context, deviceId, fileId, + irp->CompletionId, irp->PathName); } /** @@ -2003,8 +1971,8 @@ static UINT rdpdr_server_drive_query_directory_callback1( * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_drive_query_directory(RdpdrServerContext* context, - void* callbackData, UINT32 deviceId, const char* path) +static UINT rdpdr_server_drive_query_directory(RdpdrServerContext* context, void* callbackData, + UINT32 deviceId, const char* path) { RDPDR_IRP* irp; irp = rdpdr_server_irp_new(); @@ -2030,10 +1998,9 @@ static UINT rdpdr_server_drive_query_directory(RdpdrServerContext* context, } /* Send a request to open the directory. */ - return rdpdr_server_send_device_create_request(context, deviceId, - irp->CompletionId, irp->PathName, - FILE_READ_DATA | SYNCHRONIZE, - FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, FILE_OPEN); + return rdpdr_server_send_device_create_request( + context, deviceId, irp->CompletionId, irp->PathName, FILE_READ_DATA | SYNCHRONIZE, + FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, FILE_OPEN); } /************************************************* @@ -2045,14 +2012,15 @@ static UINT rdpdr_server_drive_query_directory(RdpdrServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_drive_open_file_callback(RdpdrServerContext* context, - wStream* s, RDPDR_IRP* irp, UINT32 deviceId, UINT32 completionId, - UINT32 ioStatus) +static UINT rdpdr_server_drive_open_file_callback(RdpdrServerContext* context, wStream* s, + RDPDR_IRP* irp, UINT32 deviceId, + UINT32 completionId, UINT32 ioStatus) { UINT32 fileId; UINT8 information; WLog_DBG(TAG, - "RdpdrServerDriveOpenFileCallback: deviceId=%"PRIu32", completionId=%"PRIu32", ioStatus=0x%"PRIx32"", + "RdpdrServerDriveOpenFileCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32 + ", ioStatus=0x%" PRIx32 "", deviceId, completionId, ioStatus); if (Stream_GetRemainingLength(s) < 5) @@ -2061,11 +2029,10 @@ static UINT rdpdr_server_drive_open_file_callback(RdpdrServerContext* context, return ERROR_INVALID_DATA; } - Stream_Read_UINT32(s, fileId); /* FileId (4 bytes) */ + Stream_Read_UINT32(s, fileId); /* FileId (4 bytes) */ Stream_Read_UINT8(s, information); /* Information (1 byte) */ /* Invoke the open file completion routine. */ - context->OnDriveOpenFileComplete(context, irp->CallbackData, ioStatus, deviceId, - fileId); + context->OnDriveOpenFileComplete(context, irp->CallbackData, ioStatus, deviceId, fileId); /* Destroy the IRP. */ rdpdr_server_irp_free(irp); return CHANNEL_RC_OK; @@ -2076,9 +2043,9 @@ static UINT rdpdr_server_drive_open_file_callback(RdpdrServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_drive_open_file(RdpdrServerContext* context, - void* callbackData, UINT32 deviceId, const char* path, UINT32 desiredAccess, - UINT32 createDisposition) +static UINT rdpdr_server_drive_open_file(RdpdrServerContext* context, void* callbackData, + UINT32 deviceId, const char* path, UINT32 desiredAccess, + UINT32 createDisposition) { RDPDR_IRP* irp; irp = rdpdr_server_irp_new(); @@ -2104,9 +2071,9 @@ static UINT rdpdr_server_drive_open_file(RdpdrServerContext* context, } /* Send a request to open the file. */ - return rdpdr_server_send_device_create_request(context, deviceId, - irp->CompletionId, irp->PathName, - desiredAccess | SYNCHRONIZE, FILE_SYNCHRONOUS_IO_NONALERT, createDisposition); + return rdpdr_server_send_device_create_request(context, deviceId, irp->CompletionId, + irp->PathName, desiredAccess | SYNCHRONIZE, + FILE_SYNCHRONOUS_IO_NONALERT, createDisposition); } /************************************************* @@ -2118,14 +2085,15 @@ static UINT rdpdr_server_drive_open_file(RdpdrServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_drive_read_file_callback(RdpdrServerContext* context, - wStream* s, RDPDR_IRP* irp, UINT32 deviceId, UINT32 completionId, - UINT32 ioStatus) +static UINT rdpdr_server_drive_read_file_callback(RdpdrServerContext* context, wStream* s, + RDPDR_IRP* irp, UINT32 deviceId, + UINT32 completionId, UINT32 ioStatus) { UINT32 length; char* buffer = NULL; WLog_DBG(TAG, - "RdpdrServerDriveReadFileCallback: deviceId=%"PRIu32", completionId=%"PRIu32", ioStatus=0x%"PRIx32"", + "RdpdrServerDriveReadFileCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32 + ", ioStatus=0x%" PRIx32 "", deviceId, completionId, ioStatus); if (Stream_GetRemainingLength(s) < 4) @@ -2144,13 +2112,12 @@ static UINT rdpdr_server_drive_read_file_callback(RdpdrServerContext* context, if (length > 0) { - buffer = (char*) Stream_Pointer(s); + buffer = (char*)Stream_Pointer(s); Stream_Seek(s, length); } /* Invoke the read file completion routine. */ - context->OnDriveReadFileComplete(context, irp->CallbackData, ioStatus, buffer, - length); + context->OnDriveReadFileComplete(context, irp->CallbackData, ioStatus, buffer, length); /* Destroy the IRP. */ rdpdr_server_irp_free(irp); return CHANNEL_RC_OK; @@ -2161,9 +2128,9 @@ static UINT rdpdr_server_drive_read_file_callback(RdpdrServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_drive_read_file(RdpdrServerContext* context, - void* callbackData, UINT32 deviceId, UINT32 fileId, UINT32 length, - UINT32 offset) +static UINT rdpdr_server_drive_read_file(RdpdrServerContext* context, void* callbackData, + UINT32 deviceId, UINT32 fileId, UINT32 length, + UINT32 offset) { RDPDR_IRP* irp; irp = rdpdr_server_irp_new(); @@ -2188,8 +2155,8 @@ static UINT rdpdr_server_drive_read_file(RdpdrServerContext* context, } /* Send a request to open the directory. */ - return rdpdr_server_send_device_read_request(context, deviceId, fileId, - irp->CompletionId, length, offset); + return rdpdr_server_send_device_read_request(context, deviceId, fileId, irp->CompletionId, + length, offset); } /************************************************* @@ -2201,13 +2168,14 @@ static UINT rdpdr_server_drive_read_file(RdpdrServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_drive_write_file_callback(RdpdrServerContext* context, - wStream* s, RDPDR_IRP* irp, UINT32 deviceId, UINT32 completionId, - UINT32 ioStatus) +static UINT rdpdr_server_drive_write_file_callback(RdpdrServerContext* context, wStream* s, + RDPDR_IRP* irp, UINT32 deviceId, + UINT32 completionId, UINT32 ioStatus) { UINT32 length; WLog_DBG(TAG, - "RdpdrServerDriveWriteFileCallback: deviceId=%"PRIu32", completionId=%"PRIu32", ioStatus=0x%"PRIx32"", + "RdpdrServerDriveWriteFileCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32 + ", ioStatus=0x%" PRIx32 "", deviceId, completionId, ioStatus); if (Stream_GetRemainingLength(s) < 5) @@ -2217,7 +2185,7 @@ static UINT rdpdr_server_drive_write_file_callback(RdpdrServerContext* context, } Stream_Read_UINT32(s, length); /* Length (4 bytes) */ - Stream_Seek(s, 1); /* Padding (1 byte) */ + Stream_Seek(s, 1); /* Padding (1 byte) */ if (Stream_GetRemainingLength(s) < length) { @@ -2237,9 +2205,9 @@ static UINT rdpdr_server_drive_write_file_callback(RdpdrServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_drive_write_file(RdpdrServerContext* context, - void* callbackData, UINT32 deviceId, UINT32 fileId, const char* buffer, - UINT32 length, UINT32 offset) +static UINT rdpdr_server_drive_write_file(RdpdrServerContext* context, void* callbackData, + UINT32 deviceId, UINT32 fileId, const char* buffer, + UINT32 length, UINT32 offset) { RDPDR_IRP* irp; irp = rdpdr_server_irp_new(); @@ -2264,8 +2232,8 @@ static UINT rdpdr_server_drive_write_file(RdpdrServerContext* context, } /* Send a request to open the directory. */ - return rdpdr_server_send_device_write_request(context, deviceId, fileId, - irp->CompletionId, buffer, length, offset); + return rdpdr_server_send_device_write_request(context, deviceId, fileId, irp->CompletionId, + buffer, length, offset); } /************************************************* @@ -2277,12 +2245,13 @@ static UINT rdpdr_server_drive_write_file(RdpdrServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_drive_close_file_callback(RdpdrServerContext* context, - wStream* s, RDPDR_IRP* irp, UINT32 deviceId, UINT32 completionId, - UINT32 ioStatus) +static UINT rdpdr_server_drive_close_file_callback(RdpdrServerContext* context, wStream* s, + RDPDR_IRP* irp, UINT32 deviceId, + UINT32 completionId, UINT32 ioStatus) { WLog_DBG(TAG, - "RdpdrServerDriveCloseFileCallback: deviceId=%"PRIu32", completionId=%"PRIu32", ioStatus=0x%"PRIx32"", + "RdpdrServerDriveCloseFileCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32 + ", ioStatus=0x%" PRIx32 "", deviceId, completionId, ioStatus); /* Invoke the close file completion routine. */ context->OnDriveCloseFileComplete(context, irp->CallbackData, ioStatus); @@ -2296,8 +2265,8 @@ static UINT rdpdr_server_drive_close_file_callback(RdpdrServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_drive_close_file(RdpdrServerContext* context, - void* callbackData, UINT32 deviceId, UINT32 fileId) +static UINT rdpdr_server_drive_close_file(RdpdrServerContext* context, void* callbackData, + UINT32 deviceId, UINT32 fileId) { RDPDR_IRP* irp; irp = rdpdr_server_irp_new(); @@ -2322,8 +2291,7 @@ static UINT rdpdr_server_drive_close_file(RdpdrServerContext* context, } /* Send a request to open the directory. */ - return rdpdr_server_send_device_close_request(context, deviceId, fileId, - irp->CompletionId); + return rdpdr_server_send_device_close_request(context, deviceId, fileId, irp->CompletionId); } /************************************************* @@ -2335,12 +2303,13 @@ static UINT rdpdr_server_drive_close_file(RdpdrServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_drive_delete_file_callback2(RdpdrServerContext* - context, wStream* s, RDPDR_IRP* irp, UINT32 deviceId, UINT32 completionId, - UINT32 ioStatus) +static UINT rdpdr_server_drive_delete_file_callback2(RdpdrServerContext* context, wStream* s, + RDPDR_IRP* irp, UINT32 deviceId, + UINT32 completionId, UINT32 ioStatus) { WLog_DBG(TAG, - "RdpdrServerDriveDeleteFileCallback2: deviceId=%"PRIu32", completionId=%"PRIu32", ioStatus=0x%"PRIx32"", + "RdpdrServerDriveDeleteFileCallback2: deviceId=%" PRIu32 ", completionId=%" PRIu32 + ", ioStatus=0x%" PRIx32 "", deviceId, completionId, ioStatus); /* Invoke the delete file completion routine. */ context->OnDriveDeleteFileComplete(context, irp->CallbackData, ioStatus); @@ -2354,14 +2323,15 @@ static UINT rdpdr_server_drive_delete_file_callback2(RdpdrServerContext* * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_drive_delete_file_callback1(RdpdrServerContext* - context, wStream* s, RDPDR_IRP* irp, UINT32 deviceId, UINT32 completionId, - UINT32 ioStatus) +static UINT rdpdr_server_drive_delete_file_callback1(RdpdrServerContext* context, wStream* s, + RDPDR_IRP* irp, UINT32 deviceId, + UINT32 completionId, UINT32 ioStatus) { UINT32 fileId; UINT8 information; WLog_DBG(TAG, - "RdpdrServerDriveDeleteFileCallback1: deviceId=%"PRIu32", completionId=%"PRIu32", ioStatus=0x%"PRIx32"", + "RdpdrServerDriveDeleteFileCallback1: deviceId=%" PRIu32 ", completionId=%" PRIu32 + ", ioStatus=0x%" PRIx32 "", deviceId, completionId, ioStatus); if (ioStatus != STATUS_SUCCESS) @@ -2379,7 +2349,7 @@ static UINT rdpdr_server_drive_delete_file_callback1(RdpdrServerContext* return ERROR_INVALID_DATA; } - Stream_Read_UINT32(s, fileId); /* FileId (4 bytes) */ + Stream_Read_UINT32(s, fileId); /* FileId (4 bytes) */ Stream_Read_UINT8(s, information); /* Information (1 byte) */ /* Setup the IRP. */ irp->CompletionId = context->priv->NextCompletionId++; @@ -2395,8 +2365,7 @@ static UINT rdpdr_server_drive_delete_file_callback1(RdpdrServerContext* } /* Send a request to close the file */ - return rdpdr_server_send_device_close_request(context, deviceId, fileId, - irp->CompletionId); + return rdpdr_server_send_device_close_request(context, deviceId, fileId, irp->CompletionId); } /** @@ -2404,8 +2373,8 @@ static UINT rdpdr_server_drive_delete_file_callback1(RdpdrServerContext* * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_drive_delete_file(RdpdrServerContext* context, - void* callbackData, UINT32 deviceId, const char* path) +static UINT rdpdr_server_drive_delete_file(RdpdrServerContext* context, void* callbackData, + UINT32 deviceId, const char* path) { RDPDR_IRP* irp; irp = rdpdr_server_irp_new(); @@ -2431,10 +2400,9 @@ static UINT rdpdr_server_drive_delete_file(RdpdrServerContext* context, } /* Send a request to open the file. */ - return rdpdr_server_send_device_create_request(context, deviceId, - irp->CompletionId, irp->PathName, - FILE_READ_DATA | SYNCHRONIZE, - FILE_DELETE_ON_CLOSE | FILE_SYNCHRONOUS_IO_NONALERT, FILE_OPEN); + return rdpdr_server_send_device_create_request( + context, deviceId, irp->CompletionId, irp->PathName, FILE_READ_DATA | SYNCHRONIZE, + FILE_DELETE_ON_CLOSE | FILE_SYNCHRONOUS_IO_NONALERT, FILE_OPEN); } /************************************************* @@ -2446,12 +2414,13 @@ static UINT rdpdr_server_drive_delete_file(RdpdrServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_drive_rename_file_callback3(RdpdrServerContext* - context, wStream* s, RDPDR_IRP* irp, UINT32 deviceId, UINT32 completionId, - UINT32 ioStatus) +static UINT rdpdr_server_drive_rename_file_callback3(RdpdrServerContext* context, wStream* s, + RDPDR_IRP* irp, UINT32 deviceId, + UINT32 completionId, UINT32 ioStatus) { WLog_DBG(TAG, - "RdpdrServerDriveRenameFileCallback3: deviceId=%"PRIu32", completionId=%"PRIu32", ioStatus=0x%"PRIx32"", + "RdpdrServerDriveRenameFileCallback3: deviceId=%" PRIu32 ", completionId=%" PRIu32 + ", ioStatus=0x%" PRIx32 "", deviceId, completionId, ioStatus); /* Destroy the IRP. */ rdpdr_server_irp_free(irp); @@ -2463,13 +2432,14 @@ static UINT rdpdr_server_drive_rename_file_callback3(RdpdrServerContext* * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_drive_rename_file_callback2(RdpdrServerContext* - context, wStream* s, RDPDR_IRP* irp, UINT32 deviceId, UINT32 completionId, - UINT32 ioStatus) +static UINT rdpdr_server_drive_rename_file_callback2(RdpdrServerContext* context, wStream* s, + RDPDR_IRP* irp, UINT32 deviceId, + UINT32 completionId, UINT32 ioStatus) { UINT32 length; WLog_DBG(TAG, - "RdpdrServerDriveRenameFileCallback2: deviceId=%"PRIu32", completionId=%"PRIu32", ioStatus=0x%"PRIx32"", + "RdpdrServerDriveRenameFileCallback2: deviceId=%" PRIu32 ", completionId=%" PRIu32 + ", ioStatus=0x%" PRIx32 "", deviceId, completionId, ioStatus); if (Stream_GetRemainingLength(s) < 5) @@ -2479,7 +2449,7 @@ static UINT rdpdr_server_drive_rename_file_callback2(RdpdrServerContext* } Stream_Read_UINT32(s, length); /* Length (4 bytes) */ - Stream_Seek(s, 1); /* Padding (1 byte) */ + Stream_Seek(s, 1); /* Padding (1 byte) */ /* Invoke the rename file completion routine. */ context->OnDriveRenameFileComplete(context, irp->CallbackData, ioStatus); /* Setup the IRP. */ @@ -2496,7 +2466,7 @@ static UINT rdpdr_server_drive_rename_file_callback2(RdpdrServerContext* /* Send a request to close the file */ return rdpdr_server_send_device_close_request(context, deviceId, irp->FileId, - irp->CompletionId); + irp->CompletionId); } /** @@ -2504,14 +2474,15 @@ static UINT rdpdr_server_drive_rename_file_callback2(RdpdrServerContext* * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_drive_rename_file_callback1(RdpdrServerContext* - context, wStream* s, RDPDR_IRP* irp, UINT32 deviceId, UINT32 completionId, - UINT32 ioStatus) +static UINT rdpdr_server_drive_rename_file_callback1(RdpdrServerContext* context, wStream* s, + RDPDR_IRP* irp, UINT32 deviceId, + UINT32 completionId, UINT32 ioStatus) { UINT32 fileId; UINT8 information; WLog_DBG(TAG, - "RdpdrServerDriveRenameFileCallback1: deviceId=%"PRIu32", completionId=%"PRIu32", ioStatus=0x%"PRIx32"", + "RdpdrServerDriveRenameFileCallback1: deviceId=%" PRIu32 ", completionId=%" PRIu32 + ", ioStatus=0x%" PRIx32 "", deviceId, completionId, ioStatus); if (ioStatus != STATUS_SUCCESS) @@ -2529,7 +2500,7 @@ static UINT rdpdr_server_drive_rename_file_callback1(RdpdrServerContext* return ERROR_INVALID_DATA; } - Stream_Read_UINT32(s, fileId); /* FileId (4 bytes) */ + Stream_Read_UINT32(s, fileId); /* FileId (4 bytes) */ Stream_Read_UINT8(s, information); /* Information (1 byte) */ /* Setup the IRP. */ irp->CompletionId = context->priv->NextCompletionId++; @@ -2546,7 +2517,7 @@ static UINT rdpdr_server_drive_rename_file_callback1(RdpdrServerContext* /* Send a request to rename the file */ return rdpdr_server_send_device_file_rename_request(context, deviceId, fileId, - irp->CompletionId, irp->ExtraBuffer); + irp->CompletionId, irp->ExtraBuffer); } /** @@ -2554,8 +2525,9 @@ static UINT rdpdr_server_drive_rename_file_callback1(RdpdrServerContext* * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_server_drive_rename_file(RdpdrServerContext* context, - void* callbackData, UINT32 deviceId, const char* oldPath, const char* newPath) +static UINT rdpdr_server_drive_rename_file(RdpdrServerContext* context, void* callbackData, + UINT32 deviceId, const char* oldPath, + const char* newPath) { RDPDR_IRP* irp; irp = rdpdr_server_irp_new(); @@ -2583,15 +2555,15 @@ static UINT rdpdr_server_drive_rename_file(RdpdrServerContext* context, } /* Send a request to open the file. */ - return rdpdr_server_send_device_create_request(context, deviceId, - irp->CompletionId, irp->PathName, - FILE_READ_DATA | SYNCHRONIZE, FILE_SYNCHRONOUS_IO_NONALERT, FILE_OPEN); + return rdpdr_server_send_device_create_request(context, deviceId, irp->CompletionId, + irp->PathName, FILE_READ_DATA | SYNCHRONIZE, + FILE_SYNCHRONOUS_IO_NONALERT, FILE_OPEN); } RdpdrServerContext* rdpdr_server_context_new(HANDLE vcm) { RdpdrServerContext* context; - context = (RdpdrServerContext*) calloc(1, sizeof(RdpdrServerContext)); + context = (RdpdrServerContext*)calloc(1, sizeof(RdpdrServerContext)); if (context) { @@ -2607,7 +2579,7 @@ RdpdrServerContext* rdpdr_server_context_new(HANDLE vcm) context->DriveCloseFile = rdpdr_server_drive_close_file; context->DriveDeleteFile = rdpdr_server_drive_delete_file; context->DriveRenameFile = rdpdr_server_drive_rename_file; - context->priv = (RdpdrServerPrivate*) calloc(1, sizeof(RdpdrServerPrivate)); + context->priv = (RdpdrServerPrivate*)calloc(1, sizeof(RdpdrServerPrivate)); if (!context->priv) { @@ -2652,4 +2624,3 @@ void rdpdr_server_context_free(RdpdrServerContext* context) free(context); } } - diff --git a/channels/rdpdr/server/rdpdr_main.h b/channels/rdpdr/server/rdpdr_main.h index 035ff7d..f3f54cc 100644 --- a/channels/rdpdr/server/rdpdr_main.h +++ b/channels/rdpdr/server/rdpdr_main.h @@ -48,7 +48,7 @@ struct _rdpdr_server_private UINT32 NextCompletionId; }; -#define RDPDR_HEADER_LENGTH 4 +#define RDPDR_HEADER_LENGTH 4 struct _RDPDR_HEADER { @@ -57,14 +57,14 @@ struct _RDPDR_HEADER }; typedef struct _RDPDR_HEADER RDPDR_HEADER; -#define RDPDR_VERSION_MAJOR 0x0001 +#define RDPDR_VERSION_MAJOR 0x0001 -#define RDPDR_VERSION_MINOR_RDP50 0x0002 -#define RDPDR_VERSION_MINOR_RDP51 0x0005 -#define RDPDR_VERSION_MINOR_RDP52 0x000A -#define RDPDR_VERSION_MINOR_RDP6X 0x000C +#define RDPDR_VERSION_MINOR_RDP50 0x0002 +#define RDPDR_VERSION_MINOR_RDP51 0x0005 +#define RDPDR_VERSION_MINOR_RDP52 0x000A +#define RDPDR_VERSION_MINOR_RDP6X 0x000C -#define RDPDR_CAPABILITY_HEADER_LENGTH 8 +#define RDPDR_CAPABILITY_HEADER_LENGTH 8 struct _RDPDR_CAPABILITY_HEADER { @@ -81,8 +81,10 @@ struct _RDPDR_IRP UINT32 FileId; char PathName[256]; char ExtraBuffer[256]; - void *CallbackData; - UINT (*Callback)(RdpdrServerContext* context, wStream* s, struct _RDPDR_IRP* irp, UINT32 deviceId, UINT32 completionId, UINT32 ioStatus); + void* CallbackData; + UINT(*Callback) + (RdpdrServerContext* context, wStream* s, struct _RDPDR_IRP* irp, UINT32 deviceId, + UINT32 completionId, UINT32 ioStatus); }; typedef struct _RDPDR_IRP RDPDR_IRP; diff --git a/channels/rdpei/client/rdpei_main.c b/channels/rdpei/client/rdpei_main.c index f668159..7da9ae7 100644 --- a/channels/rdpei/client/rdpei_main.c +++ b/channels/rdpei/client/rdpei_main.c @@ -62,7 +62,7 @@ * http://msdn.microsoft.com/en-us/library/hh454910/ */ -#define MAX_CONTACTS 512 +#define MAX_CONTACTS 512 struct _RDPEI_CHANNEL_CALLBACK { @@ -101,11 +101,6 @@ struct _RDPEI_PLUGIN RDPINPUT_CONTACT_DATA contacts[MAX_CONTACTS]; RDPINPUT_CONTACT_POINT* contactPoints; - HANDLE event; - HANDLE stopEvent; - HANDLE thread; - - CRITICAL_SECTION lock; rdpContext* rdpcontext; }; typedef struct _RDPEI_PLUGIN RDPEI_PLUGIN; @@ -115,34 +110,46 @@ typedef struct _RDPEI_PLUGIN RDPEI_PLUGIN; * * @return 0 on success, otherwise a Win32 error code */ -UINT rdpei_send_frame(RdpeiClientContext* context); +static UINT rdpei_send_frame(RdpeiClientContext* context); -const char* RDPEI_EVENTID_STRINGS[] = +#ifdef WITH_DEBUG_RDPEI +static const char* rdpei_eventid_string(UINT16 event) { - "", - "EVENTID_SC_READY", - "EVENTID_CS_READY", - "EVENTID_TOUCH", - "EVENTID_SUSPEND_TOUCH", - "EVENTID_RESUME_TOUCH", - "EVENTID_DISMISS_HOVERING_CONTACT" -}; + switch (event) + { + case EVENTID_SC_READY: + return "EVENTID_SC_READY"; + case EVENTID_CS_READY: + return "EVENTID_CS_READY"; + case EVENTID_TOUCH: + return "EVENTID_TOUCH"; + case EVENTID_SUSPEND_TOUCH: + return "EVENTID_SUSPEND_TOUCH"; + case EVENTID_RESUME_TOUCH: + return "EVENTID_RESUME_TOUCH"; + case EVENTID_DISMISS_HOVERING_CONTACT: + return "EVENTID_DISMISS_HOVERING_CONTACT"; + default: + return "EVENTID_UNKNOWN"; + } +} +#endif /** * Function description * * @return 0 on success, otherwise a Win32 error code */ -UINT rdpei_add_frame(RdpeiClientContext* context) +static UINT rdpei_add_frame(RdpeiClientContext* context) { int i; RDPINPUT_CONTACT_DATA* contact; - RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*) context->handle; + RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*)context->handle; rdpei->frame.contactCount = 0; for (i = 0; i < rdpei->maxTouchContacts; i++) { - contact = (RDPINPUT_CONTACT_DATA*) & (rdpei->contactPoints[i].data); + contact = (RDPINPUT_CONTACT_DATA*)&(rdpei->contactPoints[i].data); if (rdpei->contactPoints[i].dirty) { @@ -169,91 +176,25 @@ UINT rdpei_add_frame(RdpeiClientContext* context) return CHANNEL_RC_OK; } -static DWORD WINAPI rdpei_schedule_thread(LPVOID arg) -{ - DWORD status; - RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*) arg; - RdpeiClientContext* context = (RdpeiClientContext*) rdpei->iface.pInterface; - HANDLE hdl[] = {rdpei->event, rdpei->stopEvent}; - UINT error = CHANNEL_RC_OK; - - if (!rdpei) - { - error = ERROR_INVALID_PARAMETER; - goto out; - } - - if (!context) - { - error = ERROR_INVALID_PARAMETER; - goto out; - } - - while (1) - { - status = WaitForMultipleObjects(2, hdl, FALSE, 20); - - if (status == WAIT_FAILED) - { - error = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"!", error); - break; - } - - if (status == WAIT_OBJECT_0 + 1) - break; - - EnterCriticalSection(&rdpei->lock); - - if ((error = rdpei_add_frame(context))) - { - WLog_ERR(TAG, "rdpei_add_frame failed with error %"PRIu32"!", error); - break; - } - - if (rdpei->frame.contactCount > 0) - { - if ((error = rdpei_send_frame(context))) - { - WLog_ERR(TAG, "rdpei_send_frame failed with error %"PRIu32"!", error); - break; - } - } - - if (status == WAIT_OBJECT_0) - ResetEvent(rdpei->event); - - LeaveCriticalSection(&rdpei->lock); - } - -out: - - if (error && rdpei && rdpei->rdpcontext) - setChannelError(rdpei->rdpcontext, error, - "rdpei_schedule_thread reported an error"); - - ExitThread(error); - return error; -} - /** * Function description * * @return 0 on success, otherwise a Win32 error code */ -UINT rdpei_send_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s, - UINT16 eventId, UINT32 pduLength) +static UINT rdpei_send_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s, UINT16 eventId, + UINT32 pduLength) { UINT status; Stream_SetPosition(s, 0); - Stream_Write_UINT16(s, eventId); /* eventId (2 bytes) */ + Stream_Write_UINT16(s, eventId); /* eventId (2 bytes) */ Stream_Write_UINT32(s, pduLength); /* pduLength (4 bytes) */ Stream_SetPosition(s, Stream_Length(s)); - status = callback->channel->Write(callback->channel, (UINT32) Stream_Length(s), - Stream_Buffer(s), NULL); + status = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s), + NULL); #ifdef WITH_DEBUG_RDPEI - WLog_DBG(TAG, "rdpei_send_pdu: eventId: %"PRIu16" (%s) length: %"PRIu32" status: %"PRIu32"", - eventId, RDPEI_EVENTID_STRINGS[eventId], pduLength, status); + WLog_DBG(TAG, + "rdpei_send_pdu: eventId: %" PRIu16 " (%s) length: %" PRIu32 " status: %" PRIu32 "", + eventId, rdpei_eventid_string(eventId), pduLength, status); #endif return status; } @@ -263,16 +204,16 @@ UINT rdpei_send_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s, * * @return 0 on success, otherwise a Win32 error code */ -UINT rdpei_send_cs_ready_pdu(RDPEI_CHANNEL_CALLBACK* callback) +static UINT rdpei_send_cs_ready_pdu(RDPEI_CHANNEL_CALLBACK* callback) { UINT status; wStream* s; UINT32 flags; UINT32 pduLength; - RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*) callback->plugin; + RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*)callback->plugin; flags = 0; flags |= READY_FLAGS_SHOW_TOUCH_VISUALS; - //flags |= READY_FLAGS_DISABLE_TIMESTAMP_INJECTION; + // flags |= READY_FLAGS_DISABLE_TIMESTAMP_INJECTION; pduLength = RDPINPUT_HEADER_LENGTH + 10; s = Stream_New(NULL, pduLength); @@ -283,17 +224,16 @@ UINT rdpei_send_cs_ready_pdu(RDPEI_CHANNEL_CALLBACK* callback) } Stream_Seek(s, RDPINPUT_HEADER_LENGTH); - Stream_Write_UINT32(s, flags); /* flags (4 bytes) */ - Stream_Write_UINT32(s, RDPINPUT_PROTOCOL_V10); /* protocolVersion (4 bytes) */ - Stream_Write_UINT16(s, - rdpei->maxTouchContacts); /* maxTouchContacts (2 bytes) */ + Stream_Write_UINT32(s, flags); /* flags (4 bytes) */ + Stream_Write_UINT32(s, RDPINPUT_PROTOCOL_V10); /* protocolVersion (4 bytes) */ + Stream_Write_UINT16(s, rdpei->maxTouchContacts); /* maxTouchContacts (2 bytes) */ Stream_SealLength(s); status = rdpei_send_pdu(callback, s, EVENTID_CS_READY, pduLength); Stream_Free(s, TRUE); return status; } -void rdpei_print_contact_flags(UINT32 contactFlags) +static void rdpei_print_contact_flags(UINT32 contactFlags) { if (contactFlags & CONTACT_FLAG_DOWN) WLog_DBG(TAG, " CONTACT_FLAG_DOWN"); @@ -319,14 +259,14 @@ void rdpei_print_contact_flags(UINT32 contactFlags) * * @return 0 on success, otherwise a Win32 error code */ -UINT rdpei_write_touch_frame(wStream* s, RDPINPUT_TOUCH_FRAME* frame) +static UINT rdpei_write_touch_frame(wStream* s, RDPINPUT_TOUCH_FRAME* frame) { UINT32 index; int rectSize = 2; RDPINPUT_CONTACT_DATA* contact; #ifdef WITH_DEBUG_RDPEI - WLog_DBG(TAG, "contactCount: %"PRIu32"", frame->contactCount); - WLog_DBG(TAG, "frameOffset: 0x%016"PRIX64"", frame->frameOffset); + WLog_DBG(TAG, "contactCount: %" PRIu32 "", frame->contactCount); + WLog_DBG(TAG, "frameOffset: 0x%016" PRIX64 "", frame->frameOffset); #endif rdpei_write_2byte_unsigned(s, frame->contactCount); /* contactCount (TWO_BYTE_UNSIGNED_INTEGER) */ @@ -334,10 +274,10 @@ UINT rdpei_write_touch_frame(wStream* s, RDPINPUT_TOUCH_FRAME* frame) * the time offset from the previous frame (in microseconds). * If this is the first frame being transmitted then this field MUST be set to zero. */ - rdpei_write_8byte_unsigned(s, - frame->frameOffset * 1000); /* frameOffset (EIGHT_BYTE_UNSIGNED_INTEGER) */ + rdpei_write_8byte_unsigned(s, frame->frameOffset * + 1000); /* frameOffset (EIGHT_BYTE_UNSIGNED_INTEGER) */ - if (!Stream_EnsureRemainingCapacity(s, (size_t) frame->contactCount * 64)) + if (!Stream_EnsureRemainingCapacity(s, (size_t)frame->contactCount * 64)) { WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); return CHANNEL_RC_NO_MEMORY; @@ -352,11 +292,13 @@ UINT rdpei_write_touch_frame(wStream* s, RDPINPUT_TOUCH_FRAME* frame) contact->contactRectRight = contact->x + rectSize; contact->contactRectBottom = contact->y + rectSize; #ifdef WITH_DEBUG_RDPEI - WLog_DBG(TAG, "contact[%"PRIu32"].contactId: %"PRIu32"", index, contact->contactId); - WLog_DBG(TAG, "contact[%"PRIu32"].fieldsPresent: %"PRIu32"", index, contact->fieldsPresent); - WLog_DBG(TAG, "contact[%"PRIu32"].x: %"PRId32"", index, contact->x); - WLog_DBG(TAG, "contact[%"PRIu32"].y: %"PRId32"", index, contact->y); - WLog_DBG(TAG, "contact[%"PRIu32"].contactFlags: 0x%08"PRIX32"", index, contact->contactFlags); + WLog_DBG(TAG, "contact[%" PRIu32 "].contactId: %" PRIu32 "", index, contact->contactId); + WLog_DBG(TAG, "contact[%" PRIu32 "].fieldsPresent: %" PRIu32 "", index, + contact->fieldsPresent); + WLog_DBG(TAG, "contact[%" PRIu32 "].x: %" PRId32 "", index, contact->x); + WLog_DBG(TAG, "contact[%" PRIu32 "].y: %" PRId32 "", index, contact->y); + WLog_DBG(TAG, "contact[%" PRIu32 "].contactFlags: 0x%08" PRIX32 "", index, + contact->contactFlags); rdpei_print_contact_flags(contact->contactFlags); #endif Stream_Write_UINT8(s, contact->contactId); /* contactId (1 byte) */ @@ -400,8 +342,8 @@ UINT rdpei_write_touch_frame(wStream* s, RDPINPUT_TOUCH_FRAME* frame) * * @return 0 on success, otherwise a Win32 error code */ -UINT rdpei_send_touch_event_pdu(RDPEI_CHANNEL_CALLBACK* callback, - RDPINPUT_TOUCH_FRAME* frame) +static UINT rdpei_send_touch_event_pdu(RDPEI_CHANNEL_CALLBACK* callback, + RDPINPUT_TOUCH_FRAME* frame) { UINT status; wStream* s; @@ -420,13 +362,13 @@ UINT rdpei_send_touch_event_pdu(RDPEI_CHANNEL_CALLBACK* callback, * the time that has elapsed (in milliseconds) from when the oldest touch frame * was generated to when it was encoded for transmission by the client. */ - rdpei_write_4byte_unsigned(s, - (UINT32) frame->frameOffset); /* encodeTime (FOUR_BYTE_UNSIGNED_INTEGER) */ - rdpei_write_2byte_unsigned(s, 1); /* (frameCount) TWO_BYTE_UNSIGNED_INTEGER */ + rdpei_write_4byte_unsigned( + s, (UINT32)frame->frameOffset); /* encodeTime (FOUR_BYTE_UNSIGNED_INTEGER) */ + rdpei_write_2byte_unsigned(s, 1); /* (frameCount) TWO_BYTE_UNSIGNED_INTEGER */ if ((status = rdpei_write_touch_frame(s, frame))) { - WLog_ERR(TAG, "rdpei_write_touch_frame failed with error %"PRIu32"!", status); + WLog_ERR(TAG, "rdpei_write_touch_frame failed with error %" PRIu32 "!", status); Stream_Free(s, TRUE); return status; } @@ -443,7 +385,7 @@ UINT rdpei_send_touch_event_pdu(RDPEI_CHANNEL_CALLBACK* callback, * * @return 0 on success, otherwise a Win32 error code */ -UINT rdpei_recv_sc_ready_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s) +static UINT rdpei_recv_sc_ready_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s) { UINT32 protocolVersion; Stream_Read_UINT32(s, protocolVersion); /* protocolVersion (4 bytes) */ @@ -464,14 +406,14 @@ UINT rdpei_recv_sc_ready_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s) * * @return 0 on success, otherwise a Win32 error code */ -UINT rdpei_recv_suspend_touch_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s) +static UINT rdpei_recv_suspend_touch_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s) { - RdpeiClientContext* rdpei = (RdpeiClientContext*) callback->plugin->pInterface; + RdpeiClientContext* rdpei = (RdpeiClientContext*)callback->plugin->pInterface; UINT error = CHANNEL_RC_OK; IFCALLRET(rdpei->SuspendTouch, error, rdpei); if (error) - WLog_ERR(TAG, "rdpei->SuspendTouch failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rdpei->SuspendTouch failed with error %" PRIu32 "!", error); return error; } @@ -481,14 +423,14 @@ UINT rdpei_recv_suspend_touch_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s) * * @return 0 on success, otherwise a Win32 error code */ -UINT rdpei_recv_resume_touch_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s) +static UINT rdpei_recv_resume_touch_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s) { - RdpeiClientContext* rdpei = (RdpeiClientContext*) callback->plugin->pInterface; + RdpeiClientContext* rdpei = (RdpeiClientContext*)callback->plugin->pInterface; UINT error = CHANNEL_RC_OK; IFCALLRET(rdpei->ResumeTouch, error, rdpei); if (error) - WLog_ERR(TAG, "rdpei->ResumeTouch failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rdpei->ResumeTouch failed with error %" PRIu32 "!", error); return error; } @@ -498,16 +440,19 @@ UINT rdpei_recv_resume_touch_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s) * * @return 0 on success, otherwise a Win32 error code */ -UINT rdpei_recv_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s) +static UINT rdpei_recv_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s) { UINT16 eventId; UINT32 pduLength; UINT error; - Stream_Read_UINT16(s, eventId); /* eventId (2 bytes) */ + if (Stream_GetRemainingLength(s) < 6) + return ERROR_INVALID_DATA; + + Stream_Read_UINT16(s, eventId); /* eventId (2 bytes) */ Stream_Read_UINT32(s, pduLength); /* pduLength (4 bytes) */ #ifdef WITH_DEBUG_RDPEI - WLog_DBG(TAG, "rdpei_recv_pdu: eventId: %"PRIu16" (%s) length: %"PRIu32"", - eventId, RDPEI_EVENTID_STRINGS[eventId], pduLength); + WLog_DBG(TAG, "rdpei_recv_pdu: eventId: %" PRIu16 " (%s) length: %" PRIu32 "", eventId, + rdpei_eventid_string(eventId), pduLength); #endif switch (eventId) @@ -515,13 +460,13 @@ UINT rdpei_recv_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s) case EVENTID_SC_READY: if ((error = rdpei_recv_sc_ready_pdu(callback, s))) { - WLog_ERR(TAG, "rdpei_recv_sc_ready_pdu failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rdpei_recv_sc_ready_pdu failed with error %" PRIu32 "!", error); return error; } if ((error = rdpei_send_cs_ready_pdu(callback))) { - WLog_ERR(TAG, "rdpei_send_cs_ready_pdu failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rdpei_send_cs_ready_pdu failed with error %" PRIu32 "!", error); return error; } @@ -530,7 +475,7 @@ UINT rdpei_recv_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s) case EVENTID_SUSPEND_TOUCH: if ((error = rdpei_recv_suspend_touch_pdu(callback, s))) { - WLog_ERR(TAG, "rdpei_recv_suspend_touch_pdu failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rdpei_recv_suspend_touch_pdu failed with error %" PRIu32 "!", error); return error; } @@ -539,7 +484,7 @@ UINT rdpei_recv_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s) case EVENTID_RESUME_TOUCH: if ((error = rdpei_recv_resume_touch_pdu(callback, s))) { - WLog_ERR(TAG, "rdpei_recv_resume_touch_pdu failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rdpei_recv_resume_touch_pdu failed with error %" PRIu32 "!", error); return error; } @@ -557,11 +502,10 @@ UINT rdpei_recv_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s) * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpei_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, - wStream* data) +static UINT rdpei_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data) { - RDPEI_CHANNEL_CALLBACK* callback = (RDPEI_CHANNEL_CALLBACK*) pChannelCallback; - return rdpei_recv_pdu(callback, data); + RDPEI_CHANNEL_CALLBACK* callback = (RDPEI_CHANNEL_CALLBACK*)pChannelCallback; + return rdpei_recv_pdu(callback, data); } /** @@ -571,7 +515,7 @@ static UINT rdpei_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, */ static UINT rdpei_on_close(IWTSVirtualChannelCallback* pChannelCallback) { - RDPEI_CHANNEL_CALLBACK* callback = (RDPEI_CHANNEL_CALLBACK*) pChannelCallback; + RDPEI_CHANNEL_CALLBACK* callback = (RDPEI_CHANNEL_CALLBACK*)pChannelCallback; free(callback); return CHANNEL_RC_OK; } @@ -581,15 +525,13 @@ static UINT rdpei_on_close(IWTSVirtualChannelCallback* pChannelCallback) * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpei_on_new_channel_connection(IWTSListenerCallback* - pListenerCallback, - IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept, - IWTSVirtualChannelCallback** ppCallback) +static UINT rdpei_on_new_channel_connection(IWTSListenerCallback* pListenerCallback, + IWTSVirtualChannel* pChannel, BYTE* Data, + BOOL* pbAccept, IWTSVirtualChannelCallback** ppCallback) { RDPEI_CHANNEL_CALLBACK* callback; - RDPEI_LISTENER_CALLBACK* listener_callback = (RDPEI_LISTENER_CALLBACK*) - pListenerCallback; - callback = (RDPEI_CHANNEL_CALLBACK*) calloc(1, sizeof(RDPEI_CHANNEL_CALLBACK)); + RDPEI_LISTENER_CALLBACK* listener_callback = (RDPEI_LISTENER_CALLBACK*)pListenerCallback; + callback = (RDPEI_CHANNEL_CALLBACK*)calloc(1, sizeof(RDPEI_CHANNEL_CALLBACK)); if (!callback) { @@ -603,7 +545,7 @@ static UINT rdpei_on_new_channel_connection(IWTSListenerCallback* callback->channel_mgr = listener_callback->channel_mgr; callback->channel = pChannel; listener_callback->channel_callback = callback; - *ppCallback = (IWTSVirtualChannelCallback*) callback; + *ppCallback = (IWTSVirtualChannelCallback*)callback; return CHANNEL_RC_OK; } @@ -612,13 +554,11 @@ static UINT rdpei_on_new_channel_connection(IWTSListenerCallback* * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpei_plugin_initialize(IWTSPlugin* pPlugin, - IWTSVirtualChannelManager* pChannelMgr) +static UINT rdpei_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr) { UINT error; - RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*) pPlugin; - rdpei->listener_callback = (RDPEI_LISTENER_CALLBACK*) calloc(1 , - sizeof(RDPEI_LISTENER_CALLBACK)); + RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*)pPlugin; + rdpei->listener_callback = (RDPEI_LISTENER_CALLBACK*)calloc(1, sizeof(RDPEI_LISTENER_CALLBACK)); if (!rdpei->listener_callback) { @@ -626,44 +566,21 @@ static UINT rdpei_plugin_initialize(IWTSPlugin* pPlugin, return CHANNEL_RC_NO_MEMORY; } - rdpei->listener_callback->iface.OnNewChannelConnection = - rdpei_on_new_channel_connection; + rdpei->listener_callback->iface.OnNewChannelConnection = rdpei_on_new_channel_connection; rdpei->listener_callback->plugin = pPlugin; rdpei->listener_callback->channel_mgr = pChannelMgr; if ((error = pChannelMgr->CreateListener(pChannelMgr, RDPEI_DVC_CHANNEL_NAME, 0, - (IWTSListenerCallback*) rdpei->listener_callback, &(rdpei->listener)))) + &rdpei->listener_callback->iface, &(rdpei->listener)))) { - WLog_ERR(TAG, "ChannelMgr->CreateListener failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "ChannelMgr->CreateListener failed with error %" PRIu32 "!", error); goto error_out; } rdpei->listener->pInterface = rdpei->iface.pInterface; - InitializeCriticalSection(&rdpei->lock); - - if (!(rdpei->event = CreateEvent(NULL, TRUE, FALSE, NULL))) - { - WLog_ERR(TAG, "CreateEvent failed!"); - goto error_out; - } - - if (!(rdpei->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) - { - WLog_ERR(TAG, "CreateEvent failed!"); - goto error_out; - } - - if (!(rdpei->thread = CreateThread(NULL, 0, - rdpei_schedule_thread, (void*) rdpei, 0, NULL))) - { - WLog_ERR(TAG, "CreateThread failed!"); - goto error_out; - } return error; error_out: - CloseHandle(rdpei->stopEvent); - CloseHandle(rdpei->event); free(rdpei->listener_callback); return error; } @@ -675,27 +592,19 @@ error_out: */ static UINT rdpei_plugin_terminated(IWTSPlugin* pPlugin) { - RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*) pPlugin; - UINT error; + RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*)pPlugin; if (!pPlugin) return ERROR_INVALID_PARAMETER; - SetEvent(rdpei->stopEvent); - EnterCriticalSection(&rdpei->lock); - - if (WaitForSingleObject(rdpei->thread, INFINITE) == WAIT_FAILED) + if (rdpei && rdpei->listener_callback) { - error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); - return error; + IWTSVirtualChannelManager* mgr = rdpei->listener_callback->channel_mgr; + if (mgr) + IFCALL(mgr->DestroyListener, mgr, rdpei->listener); } - - CloseHandle(rdpei->stopEvent); - CloseHandle(rdpei->event); - CloseHandle(rdpei->thread); - DeleteCriticalSection(&rdpei->lock); free(rdpei->listener_callback); + free(rdpei->contactPoints); free(rdpei->context); free(rdpei); return CHANNEL_RC_OK; @@ -705,9 +614,9 @@ static UINT rdpei_plugin_terminated(IWTSPlugin* pPlugin) * Channel Client Interface */ -int rdpei_get_version(RdpeiClientContext* context) +static int rdpei_get_version(RdpeiClientContext* context) { - RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*) context->handle; + RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*)context->handle; return rdpei->version; } @@ -719,7 +628,7 @@ int rdpei_get_version(RdpeiClientContext* context) UINT rdpei_send_frame(RdpeiClientContext* context) { UINT64 currentTime; - RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*) context->handle; + RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*)context->handle; RDPEI_CHANNEL_CALLBACK* callback = rdpei->listener_callback->channel_callback; UINT error; currentTime = GetTickCount64(); @@ -737,7 +646,7 @@ UINT rdpei_send_frame(RdpeiClientContext* context) if ((error = rdpei_send_touch_event_pdu(callback, &rdpei->frame))) { - WLog_ERR(TAG, "rdpei_send_touch_event_pdu failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rdpei_send_touch_event_pdu failed with error %" PRIu32 "!", error); return error; } @@ -751,18 +660,32 @@ UINT rdpei_send_frame(RdpeiClientContext* context) * * @return 0 on success, otherwise a Win32 error code */ -UINT rdpei_add_contact(RdpeiClientContext* context, - RDPINPUT_CONTACT_DATA* contact) +static UINT rdpei_add_contact(RdpeiClientContext* context, const RDPINPUT_CONTACT_DATA* contact) { + UINT error; RDPINPUT_CONTACT_POINT* contactPoint; - RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*) context->handle; - EnterCriticalSection(&rdpei->lock); - contactPoint = (RDPINPUT_CONTACT_POINT*) - &rdpei->contactPoints[contact->contactId]; + RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*)context->handle; + + contactPoint = (RDPINPUT_CONTACT_POINT*)&rdpei->contactPoints[contact->contactId]; CopyMemory(&(contactPoint->data), contact, sizeof(RDPINPUT_CONTACT_DATA)); contactPoint->dirty = TRUE; - SetEvent(rdpei->event); - LeaveCriticalSection(&rdpei->lock); + + error = rdpei_add_frame(context); + if (error != CHANNEL_RC_OK) + { + WLog_ERR(TAG, "rdpei_add_frame failed with error %" PRIu32 "!", error); + return error; + } + + if (rdpei->frame.contactCount > 0) + { + error = rdpei_send_frame(context); + if (error != CHANNEL_RC_OK) + { + WLog_ERR(TAG, "rdpei_send_frame failed with error %" PRIu32 "!", error); + return error; + } + } return CHANNEL_RC_OK; } @@ -771,21 +694,21 @@ UINT rdpei_add_contact(RdpeiClientContext* context, * * @return 0 on success, otherwise a Win32 error code */ -UINT rdpei_touch_begin(RdpeiClientContext* context, int externalId, int x, - int y, int* contactId) +static UINT rdpei_touch_begin(RdpeiClientContext* context, int externalId, int x, int y, + int* contactId) { unsigned int i; - int contactIdlocal = -1; + INT64 contactIdlocal = -1; RDPINPUT_CONTACT_DATA contact; RDPINPUT_CONTACT_POINT* contactPoint = NULL; - RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*) context->handle; - UINT error = CHANNEL_RC_OK; + RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*)context->handle; + UINT error = CHANNEL_RC_OK; /* Create a new contact point in an empty slot */ for (i = 0; i < rdpei->maxTouchContacts; i++) { - contactPoint = (RDPINPUT_CONTACT_POINT*) &rdpei->contactPoints[i]; + contactPoint = (RDPINPUT_CONTACT_POINT*)&rdpei->contactPoints[i]; if (!contactPoint->active) { @@ -805,7 +728,7 @@ UINT rdpei_touch_begin(RdpeiClientContext* context, int externalId, int x, contactPoint->lastY = y; contact.x = x; contact.y = y; - contact.contactId = (UINT32) contactIdlocal; + contact.contactId = (UINT32)contactIdlocal; contact.contactFlags |= CONTACT_FLAG_DOWN; contact.contactFlags |= CONTACT_FLAG_INRANGE; contact.contactFlags |= CONTACT_FLAG_INCONTACT; @@ -821,19 +744,19 @@ UINT rdpei_touch_begin(RdpeiClientContext* context, int externalId, int x, * * @return 0 on success, otherwise a Win32 error code */ -UINT rdpei_touch_update(RdpeiClientContext* context, int externalId, int x, - int y, int* contactId) +static UINT rdpei_touch_update(RdpeiClientContext* context, int externalId, int x, int y, + int* contactId) { unsigned int i; int contactIdlocal = -1; RDPINPUT_CONTACT_DATA contact; RDPINPUT_CONTACT_POINT* contactPoint = NULL; - RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*) context->handle; + RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*)context->handle; UINT error = CHANNEL_RC_OK; for (i = 0; i < rdpei->maxTouchContacts; i++) { - contactPoint = (RDPINPUT_CONTACT_POINT*) &rdpei->contactPoints[i]; + contactPoint = (RDPINPUT_CONTACT_POINT*)&rdpei->contactPoints[i]; if (!contactPoint->active) continue; @@ -852,7 +775,7 @@ UINT rdpei_touch_update(RdpeiClientContext* context, int externalId, int x, contactPoint->lastY = y; contact.x = x; contact.y = y; - contact.contactId = (UINT32) contactIdlocal; + contact.contactId = (UINT32)contactIdlocal; contact.contactFlags |= CONTACT_FLAG_UPDATE; contact.contactFlags |= CONTACT_FLAG_INRANGE; contact.contactFlags |= CONTACT_FLAG_INCONTACT; @@ -868,20 +791,20 @@ UINT rdpei_touch_update(RdpeiClientContext* context, int externalId, int x, * * @return 0 on success, otherwise a Win32 error code */ -UINT rdpei_touch_end(RdpeiClientContext* context, int externalId, int x, int y, - int* contactId) +static UINT rdpei_touch_end(RdpeiClientContext* context, int externalId, int x, int y, + int* contactId) { unsigned int i; int contactIdlocal = -1; int tempvalue; RDPINPUT_CONTACT_DATA contact; RDPINPUT_CONTACT_POINT* contactPoint = NULL; - RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*) context->handle; + RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*)context->handle; UINT error; for (i = 0; i < rdpei->maxTouchContacts; i++) { - contactPoint = (RDPINPUT_CONTACT_POINT*) &rdpei->contactPoints[i]; + contactPoint = (RDPINPUT_CONTACT_POINT*)&rdpei->contactPoints[i]; if (!contactPoint->active) continue; @@ -901,19 +824,19 @@ UINT rdpei_touch_end(RdpeiClientContext* context, int externalId, int x, int y, { if ((error = context->TouchUpdate(context, externalId, x, y, &tempvalue))) { - WLog_ERR(TAG, "context->TouchUpdate failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "context->TouchUpdate failed with error %" PRIu32 "!", error); return error; } } contact.x = x; contact.y = y; - contact.contactId = (UINT32) contactIdlocal; + contact.contactId = (UINT32)contactIdlocal; contact.contactFlags |= CONTACT_FLAG_UP; if ((error = context->AddContact(context, &contact))) { - WLog_ERR(TAG, "context->AddContact failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "context->AddContact failed with error %" PRIu32 "!", error); return error; } @@ -929,9 +852,9 @@ UINT rdpei_touch_end(RdpeiClientContext* context, int externalId, int x, int y, } #ifdef BUILTIN_CHANNELS -#define DVCPluginEntry rdpei_DVCPluginEntry +#define DVCPluginEntry rdpei_DVCPluginEntry #else -#define DVCPluginEntry FREERDP_API DVCPluginEntry +#define DVCPluginEntry FREERDP_API DVCPluginEntry #endif /** @@ -944,12 +867,12 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) UINT error; RDPEI_PLUGIN* rdpei = NULL; RdpeiClientContext* context = NULL; - rdpei = (RDPEI_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "rdpei"); + rdpei = (RDPEI_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "rdpei"); if (!rdpei) { size_t size; - rdpei = (RDPEI_PLUGIN*) calloc(1, sizeof(RDPEI_PLUGIN)); + rdpei = (RDPEI_PLUGIN*)calloc(1, sizeof(RDPEI_PLUGIN)); if (!rdpei) { @@ -964,12 +887,13 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) rdpei->version = 1; rdpei->currentFrameTime = 0; rdpei->previousFrameTime = 0; - rdpei->frame.contacts = (RDPINPUT_CONTACT_DATA*) rdpei->contacts; + rdpei->frame.contacts = (RDPINPUT_CONTACT_DATA*)rdpei->contacts; rdpei->maxTouchContacts = 10; size = rdpei->maxTouchContacts * sizeof(RDPINPUT_CONTACT_POINT); - rdpei->contactPoints = (RDPINPUT_CONTACT_POINT*) calloc(1, size); - rdpei->rdpcontext = ((freerdp*)((rdpSettings*) pEntryPoints->GetRdpSettings( - pEntryPoints))->instance)->context; + rdpei->contactPoints = (RDPINPUT_CONTACT_POINT*)calloc(1, size); + rdpei->rdpcontext = + ((freerdp*)((rdpSettings*)pEntryPoints->GetRdpSettings(pEntryPoints))->instance) + ->context; if (!rdpei->contactPoints) { @@ -978,7 +902,7 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) goto error_out; } - context = (RdpeiClientContext*) calloc(1, sizeof(RdpeiClientContext)); + context = (RdpeiClientContext*)calloc(1, sizeof(RdpeiClientContext)); if (!context) { @@ -987,18 +911,17 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) goto error_out; } - context->handle = (void*) rdpei; + context->handle = (void*)rdpei; context->GetVersion = rdpei_get_version; context->AddContact = rdpei_add_contact; context->TouchBegin = rdpei_touch_begin; context->TouchUpdate = rdpei_touch_update; context->TouchEnd = rdpei_touch_end; - rdpei->iface.pInterface = (void*) context; + rdpei->iface.pInterface = (void*)context; - if ((error = pEntryPoints->RegisterPlugin(pEntryPoints, "rdpei", - (IWTSPlugin*) rdpei))) + if ((error = pEntryPoints->RegisterPlugin(pEntryPoints, "rdpei", (IWTSPlugin*)rdpei))) { - WLog_ERR(TAG, "EntryPoints->RegisterPlugin failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "EntryPoints->RegisterPlugin failed with error %" PRIu32 "!", error); error = CHANNEL_RC_NO_MEMORY; goto error_out; } diff --git a/channels/rdpei/client/rdpei_main.h b/channels/rdpei/client/rdpei_main.h index 4dc4998..ed557b2 100644 --- a/channels/rdpei/client/rdpei_main.h +++ b/channels/rdpei/client/rdpei_main.h @@ -34,10 +34,10 @@ #define TAG CHANNELS_TAG("rdpei.client") -#define RDPINPUT_CONTACT_STATE_INITIAL 0x0000 -#define RDPINPUT_CONTACT_STATE_ENGAGED 0x0001 -#define RDPINPUT_CONTACT_STATE_HOVERING 0x0002 -#define RDPINPUT_CONTACT_STATE_OUT_OF_RANGE 0x0003 +#define RDPINPUT_CONTACT_STATE_INITIAL 0x0000 +#define RDPINPUT_CONTACT_STATE_ENGAGED 0x0001 +#define RDPINPUT_CONTACT_STATE_HOVERING 0x0002 +#define RDPINPUT_CONTACT_STATE_OUT_OF_RANGE 0x0003 /** * Touch Contact State Transitions @@ -84,8 +84,10 @@ typedef struct _RDPINPUT_CONTACT_POINT RDPINPUT_CONTACT_POINT; #ifdef WITH_DEBUG_DVC #define DEBUG_DVC(...) WLog_DBG(TAG, __VA_ARGS__) #else -#define DEBUG_DVC(...) do { } while (0) +#define DEBUG_DVC(...) \ + do \ + { \ + } while (0) #endif #endif /* FREERDP_CHANNEL_RDPEI_CLIENT_MAIN_H */ - diff --git a/channels/rdpei/rdpei_common.c b/channels/rdpei/rdpei_common.c index 41a2ec3..7628b32 100644 --- a/channels/rdpei/rdpei_common.c +++ b/channels/rdpei/rdpei_common.c @@ -199,18 +199,18 @@ BOOL rdpei_write_4byte_unsigned(wStream* s, UINT32 value) { BYTE byte; - if (value <= 0x3F) + if (value <= 0x3FUL) { Stream_Write_UINT8(s, value); } - else if (value <= 0x3FFF) + else if (value <= 0x3FFFUL) { byte = (value >> 8) & 0x3F; Stream_Write_UINT8(s, byte | 0x40); byte = (value & 0xFF); Stream_Write_UINT8(s, byte); } - else if (value <= 0x3FFFFF) + else if (value <= 0x3FFFFFUL) { byte = (value >> 16) & 0x3F; Stream_Write_UINT8(s, byte | 0x80); @@ -219,7 +219,7 @@ BOOL rdpei_write_4byte_unsigned(wStream* s, UINT32 value) byte = (value & 0xFF); Stream_Write_UINT8(s, byte); } - else if (value <= 0x3FFFFF) + else if (value <= 0x3FFFFFFFUL) { byte = (value >> 24) & 0x3F; Stream_Write_UINT8(s, byte | 0xC0); @@ -306,7 +306,7 @@ BOOL rdpei_write_4byte_signed(wStream* s, INT32 value) value *= -1; } - if (value <= 0x1F) + if (value <= 0x1FL) { byte = value & 0x1F; @@ -315,7 +315,7 @@ BOOL rdpei_write_4byte_signed(wStream* s, INT32 value) Stream_Write_UINT8(s, byte); } - else if (value <= 0x1FFF) + else if (value <= 0x1FFFL) { byte = (value >> 8) & 0x1F; @@ -326,7 +326,7 @@ BOOL rdpei_write_4byte_signed(wStream* s, INT32 value) byte = (value & 0xFF); Stream_Write_UINT8(s, byte); } - else if (value <= 0x1FFFFF) + else if (value <= 0x1FFFFFL) { byte = (value >> 16) & 0x1F; @@ -339,7 +339,7 @@ BOOL rdpei_write_4byte_signed(wStream* s, INT32 value) byte = (value & 0xFF); Stream_Write_UINT8(s, byte); } - else if (value <= 0x1FFFFF) + else if (value <= 0x1FFFFFFFL) { byte = (value >> 24) & 0x1F; @@ -408,7 +408,7 @@ BOOL rdpei_read_8byte_unsigned(wStream* s, UINT64* value) break; case 4: - *value = ((UINT64) (byte & 0x1F)) << 32; + *value = ((UINT64)(byte & 0x1F)) << 32; Stream_Read_UINT8(s, byte); *value |= (byte << 24); Stream_Read_UINT8(s, byte); @@ -420,9 +420,9 @@ BOOL rdpei_read_8byte_unsigned(wStream* s, UINT64* value) break; case 5: - *value = ((UINT64) (byte & 0x1F)) << 40; + *value = ((UINT64)(byte & 0x1F)) << 40; Stream_Read_UINT8(s, byte); - *value |= (((UINT64) byte) << 32); + *value |= (((UINT64)byte) << 32); Stream_Read_UINT8(s, byte); *value |= (byte << 24); Stream_Read_UINT8(s, byte); @@ -434,11 +434,11 @@ BOOL rdpei_read_8byte_unsigned(wStream* s, UINT64* value) break; case 6: - *value = ((UINT64) (byte & 0x1F)) << 48; + *value = ((UINT64)(byte & 0x1F)) << 48; Stream_Read_UINT8(s, byte); - *value |= (((UINT64) byte) << 40); + *value |= (((UINT64)byte) << 40); Stream_Read_UINT8(s, byte); - *value |= (((UINT64) byte) << 32); + *value |= (((UINT64)byte) << 32); Stream_Read_UINT8(s, byte); *value |= (byte << 24); Stream_Read_UINT8(s, byte); @@ -450,13 +450,13 @@ BOOL rdpei_read_8byte_unsigned(wStream* s, UINT64* value) break; case 7: - *value = ((UINT64) (byte & 0x1F)) << 56; + *value = ((UINT64)(byte & 0x1F)) << 56; Stream_Read_UINT8(s, byte); - *value |= (((UINT64) byte) << 48); + *value |= (((UINT64)byte) << 48); Stream_Read_UINT8(s, byte); - *value |= (((UINT64) byte) << 40); + *value |= (((UINT64)byte) << 40); Stream_Read_UINT8(s, byte); - *value |= (((UINT64) byte) << 32); + *value |= (((UINT64)byte) << 32); Stream_Read_UINT8(s, byte); *value |= (byte << 24); Stream_Read_UINT8(s, byte); @@ -478,12 +478,12 @@ BOOL rdpei_write_8byte_unsigned(wStream* s, UINT64 value) { BYTE byte; - if (value <= 0x1F) + if (value <= 0x1FULL) { byte = value & 0x1F; Stream_Write_UINT8(s, byte); } - else if (value <= 0x1FFF) + else if (value <= 0x1FFFULL) { byte = (value >> 8) & 0x1F; byte |= (1 << 5); @@ -491,7 +491,7 @@ BOOL rdpei_write_8byte_unsigned(wStream* s, UINT64 value) byte = (value & 0xFF); Stream_Write_UINT8(s, byte); } - else if (value <= 0x1FFFFF) + else if (value <= 0x1FFFFFULL) { byte = (value >> 16) & 0x1F; byte |= (2 << 5); @@ -501,7 +501,7 @@ BOOL rdpei_write_8byte_unsigned(wStream* s, UINT64 value) byte = (value & 0xFF); Stream_Write_UINT8(s, byte); } - else if (value <= 0x1FFFFF) + else if (value <= 0x1FFFFFULL) { byte = (value >> 24) & 0x1F; byte |= (3 << 5); @@ -513,7 +513,7 @@ BOOL rdpei_write_8byte_unsigned(wStream* s, UINT64 value) byte = (value & 0xFF); Stream_Write_UINT8(s, byte); } - else if (value <= 0x1FFFFFFF) + else if (value <= 0x1FFFFFFFULL) { byte = (value >> 32) & 0x1F; byte |= (4 << 5); @@ -527,7 +527,7 @@ BOOL rdpei_write_8byte_unsigned(wStream* s, UINT64 value) byte = (value & 0xFF); Stream_Write_UINT8(s, byte); } - else if (value <= 0x1FFFFFFFFF) + else if (value <= 0x1FFFFFFFFFULL) { byte = (value >> 40) & 0x1F; byte |= (5 << 5); @@ -543,7 +543,7 @@ BOOL rdpei_write_8byte_unsigned(wStream* s, UINT64 value) byte = (value & 0xFF); Stream_Write_UINT8(s, byte); } - else if (value <= 0x1FFFFFFFFFFF) + else if (value <= 0x1FFFFFFFFFFFULL) { byte = (value >> 48) & 0x1F; byte |= (6 << 5); @@ -561,7 +561,7 @@ BOOL rdpei_write_8byte_unsigned(wStream* s, UINT64 value) byte = (value & 0xFF); Stream_Write_UINT8(s, byte); } - else if (value <= 0x1FFFFFFFFFFFFF) + else if (value <= 0x1FFFFFFFFFFFFFFFULL) { byte = (value >> 56) & 0x1F; byte |= (7 << 5); @@ -589,7 +589,7 @@ BOOL rdpei_write_8byte_unsigned(wStream* s, UINT64 value) return TRUE; } -void touch_event_reset(RDPINPUT_TOUCH_EVENT *event) +void touch_event_reset(RDPINPUT_TOUCH_EVENT* event) { int i; @@ -601,8 +601,7 @@ void touch_event_reset(RDPINPUT_TOUCH_EVENT *event) event->frameCount = 0; } - -void touch_frame_reset(RDPINPUT_TOUCH_FRAME *frame) +void touch_frame_reset(RDPINPUT_TOUCH_FRAME* frame) { free(frame->contacts); frame->contacts = NULL; diff --git a/channels/rdpei/rdpei_common.h b/channels/rdpei/rdpei_common.h index 34d1edd..610767a 100644 --- a/channels/rdpei/rdpei_common.h +++ b/channels/rdpei/rdpei_common.h @@ -26,7 +26,8 @@ #include /** @brief input event ids */ -enum { +enum +{ EVENTID_SC_READY = 0x0001, EVENTID_CS_READY = 0x0002, EVENTID_TOUCH = 0x0003, @@ -46,8 +47,7 @@ BOOL rdpei_write_4byte_signed(wStream* s, INT32 value); BOOL rdpei_read_8byte_unsigned(wStream* s, UINT64* value); BOOL rdpei_write_8byte_unsigned(wStream* s, UINT64 value); -void touch_event_reset(RDPINPUT_TOUCH_EVENT *event); -void touch_frame_reset(RDPINPUT_TOUCH_FRAME *frame); +void touch_event_reset(RDPINPUT_TOUCH_EVENT* event); +void touch_frame_reset(RDPINPUT_TOUCH_FRAME* frame); #endif /* FREERDP_CHANNEL_RDPEI_COMMON_H */ - diff --git a/channels/rdpei/server/rdpei_main.c b/channels/rdpei/server/rdpei_main.c index a475584..81b93ce 100644 --- a/channels/rdpei/server/rdpei_main.c +++ b/channels/rdpei/server/rdpei_main.c @@ -34,7 +34,8 @@ #include /** @brief */ -enum RdpEiState { +enum RdpEiState +{ STATE_INITIAL, STATE_WAITING_CLIENT_READY, STATE_WAITING_FRAME, @@ -48,8 +49,8 @@ struct _rdpei_server_private UINT32 expectedBytes; BOOL waitingHeaders; - wStream *inputStream; - wStream *outputStream; + wStream* inputStream; + wStream* outputStream; UINT16 currentMsgType; @@ -58,11 +59,10 @@ struct _rdpei_server_private enum RdpEiState automataState; }; - RdpeiServerContext* rdpei_server_context_new(HANDLE vcm) { - RdpeiServerContext *ret = calloc(1, sizeof(*ret)); - RdpeiServerPrivate *priv; + RdpeiServerContext* ret = calloc(1, sizeof(*ret)); + RdpeiServerPrivate* priv; if (!ret) return NULL; @@ -97,22 +97,27 @@ out_free: * * @return 0 on success, otherwise a Win32 error code */ -UINT rdpei_server_init(RdpeiServerContext *context) +UINT rdpei_server_init(RdpeiServerContext* context) { - void *buffer = NULL; + void* buffer = NULL; DWORD bytesReturned; - RdpeiServerPrivate *priv = context->priv; + RdpeiServerPrivate* priv = context->priv; - priv->channelHandle = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, RDPEI_DVC_CHANNEL_NAME, WTS_CHANNEL_OPTION_DYNAMIC); + priv->channelHandle = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, RDPEI_DVC_CHANNEL_NAME, + WTS_CHANNEL_OPTION_DYNAMIC); if (!priv->channelHandle) { WLog_ERR(TAG, "WTSVirtualChannelOpenEx failed!"); return CHANNEL_RC_INITIALIZATION_ERROR; } - if (!WTSVirtualChannelQuery(priv->channelHandle, WTSVirtualEventHandle, &buffer, &bytesReturned) || (bytesReturned != sizeof(HANDLE))) + if (!WTSVirtualChannelQuery(priv->channelHandle, WTSVirtualEventHandle, &buffer, + &bytesReturned) || + (bytesReturned != sizeof(HANDLE))) { - WLog_ERR(TAG, "WTSVirtualChannelQuery failed or invalid invalid returned size(%"PRIu32")!", bytesReturned); + WLog_ERR(TAG, + "WTSVirtualChannelQuery failed or invalid invalid returned size(%" PRIu32 ")!", + bytesReturned); if (buffer) WTSFreeMemory(buffer); goto out_close; @@ -127,10 +132,9 @@ out_close: return CHANNEL_RC_INITIALIZATION_ERROR; } - -void rdpei_server_context_reset(RdpeiServerContext *context) +void rdpei_server_context_reset(RdpeiServerContext* context) { - RdpeiServerPrivate *priv = context->priv; + RdpeiServerPrivate* priv = context->priv; priv->channelHandle = INVALID_HANDLE_VALUE; priv->expectedBytes = RDPINPUT_HEADER_LENGTH; @@ -141,7 +145,7 @@ void rdpei_server_context_reset(RdpeiServerContext *context) void rdpei_server_context_free(RdpeiServerContext* context) { - RdpeiServerPrivate *priv = context->priv; + RdpeiServerPrivate* priv = context->priv; if (priv->channelHandle != INVALID_HANDLE_VALUE) WTSVirtualChannelClose(priv->channelHandle); Stream_Free(priv->inputStream, TRUE); @@ -149,18 +153,17 @@ void rdpei_server_context_free(RdpeiServerContext* context) free(context); } -HANDLE rdpei_server_get_event_handle(RdpeiServerContext *context) +HANDLE rdpei_server_get_event_handle(RdpeiServerContext* context) { return context->priv->eventHandle; } - /** * Function description * * @return 0 on success, otherwise a Win32 error code */ -static UINT read_cs_ready_message(RdpeiServerContext *context, wStream *s) +static UINT read_cs_ready_message(RdpeiServerContext* context, wStream* s) { UINT error = CHANNEL_RC_OK; if (Stream_GetRemainingLength(s) < 10) @@ -175,17 +178,17 @@ static UINT read_cs_ready_message(RdpeiServerContext *context, wStream *s) switch (context->clientVersion) { - case RDPINPUT_PROTOCOL_V10: - case RDPINPUT_PROTOCOL_V101: - break; - default: - WLog_ERR(TAG, "unhandled RPDEI protocol version 0x%"PRIx32"", context->clientVersion); - break; + case RDPINPUT_PROTOCOL_V10: + case RDPINPUT_PROTOCOL_V101: + break; + default: + WLog_ERR(TAG, "unhandled RPDEI protocol version 0x%" PRIx32 "", context->clientVersion); + break; } IFCALLRET(context->onClientReady, error, context); if (error) - WLog_ERR(TAG, "context->onClientReady failed with error %"PRIu32"", error); + WLog_ERR(TAG, "context->onClientReady failed with error %" PRIu32 "", error); return error; } @@ -195,7 +198,8 @@ static UINT read_cs_ready_message(RdpeiServerContext *context, wStream *s) * * @return 0 on success, otherwise a Win32 error code */ -static UINT read_touch_contact_data(RdpeiServerContext *context, wStream *s, RDPINPUT_CONTACT_DATA *contactData) +static UINT read_touch_contact_data(RdpeiServerContext* context, wStream* s, + RDPINPUT_CONTACT_DATA* contactData) { if (Stream_GetRemainingLength(s) < 1) { @@ -205,9 +209,9 @@ static UINT read_touch_contact_data(RdpeiServerContext *context, wStream *s, RDP Stream_Read_UINT8(s, contactData->contactId); if (!rdpei_read_2byte_unsigned(s, &contactData->fieldsPresent) || - !rdpei_read_4byte_signed(s, &contactData->x) || - !rdpei_read_4byte_signed(s, &contactData->y) || - !rdpei_read_4byte_unsigned(s, &contactData->contactFlags)) + !rdpei_read_4byte_signed(s, &contactData->x) || + !rdpei_read_4byte_signed(s, &contactData->y) || + !rdpei_read_4byte_unsigned(s, &contactData->contactFlags)) { WLog_ERR(TAG, "rdpei_read_ failed!"); return ERROR_INTERNAL_ERROR; @@ -216,9 +220,9 @@ static UINT read_touch_contact_data(RdpeiServerContext *context, wStream *s, RDP if (contactData->fieldsPresent & CONTACT_DATA_CONTACTRECT_PRESENT) { if (!rdpei_read_2byte_signed(s, &contactData->contactRectLeft) || - !rdpei_read_2byte_signed(s, &contactData->contactRectTop) || - !rdpei_read_2byte_signed(s, &contactData->contactRectRight) || - !rdpei_read_2byte_signed(s, &contactData->contactRectBottom)) + !rdpei_read_2byte_signed(s, &contactData->contactRectTop) || + !rdpei_read_2byte_signed(s, &contactData->contactRectRight) || + !rdpei_read_2byte_signed(s, &contactData->contactRectBottom)) { WLog_ERR(TAG, "rdpei_read_ failed!"); return ERROR_INTERNAL_ERROR; @@ -226,15 +230,14 @@ static UINT read_touch_contact_data(RdpeiServerContext *context, wStream *s, RDP } if ((contactData->fieldsPresent & CONTACT_DATA_ORIENTATION_PRESENT) && - !rdpei_read_4byte_unsigned(s, &contactData->orientation)) + !rdpei_read_4byte_unsigned(s, &contactData->orientation)) { WLog_ERR(TAG, "rdpei_read_ failed!"); return ERROR_INTERNAL_ERROR; } - if ((contactData->fieldsPresent & CONTACT_DATA_PRESSURE_PRESENT) && - !rdpei_read_4byte_unsigned(s, &contactData->pressure)) + !rdpei_read_4byte_unsigned(s, &contactData->pressure)) { WLog_ERR(TAG, "rdpei_read_ failed!"); return ERROR_INTERNAL_ERROR; @@ -248,13 +251,14 @@ static UINT read_touch_contact_data(RdpeiServerContext *context, wStream *s, RDP * * @return 0 on success, otherwise a Win32 error code */ -static UINT read_touch_frame(RdpeiServerContext *context, wStream *s, RDPINPUT_TOUCH_FRAME *frame) +static UINT read_touch_frame(RdpeiServerContext* context, wStream* s, RDPINPUT_TOUCH_FRAME* frame) { - int i; - RDPINPUT_CONTACT_DATA *contact; + UINT32 i; + RDPINPUT_CONTACT_DATA* contact; UINT error; - if (!rdpei_read_2byte_unsigned(s, &frame->contactCount) || !rdpei_read_8byte_unsigned(s, &frame->frameOffset)) + if (!rdpei_read_2byte_unsigned(s, &frame->contactCount) || + !rdpei_read_8byte_unsigned(s, &frame->frameOffset)) { WLog_ERR(TAG, "rdpei_read_ failed!"); return ERROR_INTERNAL_ERROR; @@ -271,7 +275,7 @@ static UINT read_touch_frame(RdpeiServerContext *context, wStream *s, RDPINPUT_T { if ((error = read_touch_contact_data(context, s, contact))) { - WLog_ERR(TAG, "read_touch_contact_data failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "read_touch_contact_data failed with error %" PRIu32 "!", error); frame->contactCount = i; touch_frame_reset(frame); return error; @@ -285,15 +289,16 @@ static UINT read_touch_frame(RdpeiServerContext *context, wStream *s, RDPINPUT_T * * @return 0 on success, otherwise a Win32 error code */ -static UINT read_touch_event(RdpeiServerContext *context, wStream *s) +static UINT read_touch_event(RdpeiServerContext* context, wStream* s) { UINT32 frameCount; - int i; - RDPINPUT_TOUCH_EVENT *event = &context->priv->touchEvent; - RDPINPUT_TOUCH_FRAME *frame; + UINT32 i; + RDPINPUT_TOUCH_EVENT* event = &context->priv->touchEvent; + RDPINPUT_TOUCH_FRAME* frame; UINT error = CHANNEL_RC_OK; - if (!rdpei_read_4byte_unsigned(s, &event->encodeTime) || !rdpei_read_2byte_unsigned(s, &frameCount)) + if (!rdpei_read_4byte_unsigned(s, &event->encodeTime) || + !rdpei_read_2byte_unsigned(s, &frameCount)) { WLog_ERR(TAG, "rdpei_read_ failed!"); return ERROR_INTERNAL_ERROR; @@ -311,29 +316,28 @@ static UINT read_touch_event(RdpeiServerContext *context, wStream *s) { if ((error = read_touch_frame(context, s, frame))) { - WLog_ERR(TAG, "read_touch_contact_data failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "read_touch_contact_data failed with error %" PRIu32 "!", error); event->frameCount = i; goto out_cleanup; } } - IFCALLRET(context->onTouchEvent, error, context, event); if (error) - WLog_ERR(TAG, "context->onTouchEvent failed with error %"PRIu32"", error); + WLog_ERR(TAG, "context->onTouchEvent failed with error %" PRIu32 "", error); out_cleanup: touch_event_reset(event); return error; } - /** * Function description * * @return 0 on success, otherwise a Win32 error code */ -static UINT read_dismiss_hovering_contact(RdpeiServerContext *context, wStream *s) { +static UINT read_dismiss_hovering_contact(RdpeiServerContext* context, wStream* s) +{ BYTE contactId; UINT error = CHANNEL_RC_OK; @@ -347,24 +351,25 @@ static UINT read_dismiss_hovering_contact(RdpeiServerContext *context, wStream * IFCALLRET(context->onTouchReleased, error, context, contactId); if (error) - WLog_ERR(TAG, "context->onTouchReleased failed with error %"PRIu32"", error); + WLog_ERR(TAG, "context->onTouchReleased failed with error %" PRIu32 "", error); return error; } - /** * Function description * * @return 0 on success, otherwise a Win32 error code */ -UINT rdpei_server_handle_messages(RdpeiServerContext *context) { +UINT rdpei_server_handle_messages(RdpeiServerContext* context) +{ DWORD bytesReturned; - RdpeiServerPrivate *priv = context->priv; - wStream *s = priv->inputStream; + RdpeiServerPrivate* priv = context->priv; + wStream* s = priv->inputStream; UINT error = CHANNEL_RC_OK; - if (!WTSVirtualChannelRead(priv->channelHandle, 0, (PCHAR)Stream_Pointer(s), priv->expectedBytes, &bytesReturned)) + if (!WTSVirtualChannelRead(priv->channelHandle, 0, (PCHAR)Stream_Pointer(s), + priv->expectedBytes, &bytesReturned)) { if (GetLastError() == ERROR_NO_DATA) return ERROR_READ_FAULT; @@ -391,7 +396,7 @@ UINT rdpei_server_handle_messages(RdpeiServerContext *context) { if (pduLen < RDPINPUT_HEADER_LENGTH) { - WLog_ERR(TAG, "invalid pduLength %"PRIu32"", pduLen); + WLog_ERR(TAG, "invalid pduLength %" PRIu32 "", pduLen); return ERROR_INVALID_DATA; } priv->expectedBytes = pduLen - RDPINPUT_HEADER_LENGTH; @@ -411,36 +416,37 @@ UINT rdpei_server_handle_messages(RdpeiServerContext *context) { /* when here we have the header + the body */ switch (priv->currentMsgType) { - case EVENTID_CS_READY: - if (priv->automataState != STATE_WAITING_CLIENT_READY) - { - WLog_ERR(TAG, "not expecting a CS_READY packet in this state(%d)", priv->automataState); - return ERROR_INVALID_STATE; - } + case EVENTID_CS_READY: + if (priv->automataState != STATE_WAITING_CLIENT_READY) + { + WLog_ERR(TAG, "not expecting a CS_READY packet in this state(%d)", + priv->automataState); + return ERROR_INVALID_STATE; + } - if ((error = read_cs_ready_message(context, s))) - { - WLog_ERR(TAG, "read_cs_ready_message failed with error %"PRIu32"", error); - return error; - } - break; + if ((error = read_cs_ready_message(context, s))) + { + WLog_ERR(TAG, "read_cs_ready_message failed with error %" PRIu32 "", error); + return error; + } + break; - case EVENTID_TOUCH: - if ((error = read_touch_event(context, s))) - { - WLog_ERR(TAG, "read_touch_event failed with error %"PRIu32"", error); - return error; - } - break; - case EVENTID_DISMISS_HOVERING_CONTACT: - if ((error = read_dismiss_hovering_contact(context, s))) - { - WLog_ERR(TAG, "read_dismiss_hovering_contact failed with error %"PRIu32"", error); - return error; - } - break; - default: - WLog_ERR(TAG, "unexpected message type 0x%"PRIx16"", priv->currentMsgType); + case EVENTID_TOUCH: + if ((error = read_touch_event(context, s))) + { + WLog_ERR(TAG, "read_touch_event failed with error %" PRIu32 "", error); + return error; + } + break; + case EVENTID_DISMISS_HOVERING_CONTACT: + if ((error = read_dismiss_hovering_contact(context, s))) + { + WLog_ERR(TAG, "read_dismiss_hovering_contact failed with error %" PRIu32 "", error); + return error; + } + break; + default: + WLog_ERR(TAG, "unexpected message type 0x%" PRIx16 "", priv->currentMsgType); } Stream_SetPosition(s, 0); @@ -449,16 +455,15 @@ UINT rdpei_server_handle_messages(RdpeiServerContext *context) { return error; } - /** * Function description * * @return 0 on success, otherwise a Win32 error code */ -UINT rdpei_server_send_sc_ready(RdpeiServerContext *context, UINT32 version) +UINT rdpei_server_send_sc_ready(RdpeiServerContext* context, UINT32 version) { ULONG written; - RdpeiServerPrivate *priv = context->priv; + RdpeiServerPrivate* priv = context->priv; if (priv->automataState != STATE_INITIAL) { @@ -479,7 +484,7 @@ UINT rdpei_server_send_sc_ready(RdpeiServerContext *context, UINT32 version) Stream_Write_UINT32(priv->outputStream, version); if (!WTSVirtualChannelWrite(priv->channelHandle, (PCHAR)Stream_Buffer(priv->outputStream), - Stream_GetPosition(priv->outputStream), &written)) + Stream_GetPosition(priv->outputStream), &written)) { WLog_ERR(TAG, "WTSVirtualChannelWrite failed!"); return ERROR_INTERNAL_ERROR; @@ -494,21 +499,21 @@ UINT rdpei_server_send_sc_ready(RdpeiServerContext *context, UINT32 version) * * @return 0 on success, otherwise a Win32 error code */ -UINT rdpei_server_suspend(RdpeiServerContext *context) +UINT rdpei_server_suspend(RdpeiServerContext* context) { ULONG written; - RdpeiServerPrivate *priv = context->priv; + RdpeiServerPrivate* priv = context->priv; switch (priv->automataState) { - case STATE_SUSPENDED: - WLog_ERR(TAG, "already suspended"); - return CHANNEL_RC_OK; - case STATE_WAITING_FRAME: - break; - default: - WLog_ERR(TAG, "called from unexpected state %d", priv->automataState); - return ERROR_INVALID_STATE; + case STATE_SUSPENDED: + WLog_ERR(TAG, "already suspended"); + return CHANNEL_RC_OK; + case STATE_WAITING_FRAME: + break; + default: + WLog_ERR(TAG, "called from unexpected state %d", priv->automataState); + return ERROR_INVALID_STATE; } Stream_SetPosition(priv->outputStream, 0); @@ -522,7 +527,7 @@ UINT rdpei_server_suspend(RdpeiServerContext *context) Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH); if (!WTSVirtualChannelWrite(priv->channelHandle, (PCHAR)Stream_Buffer(priv->outputStream), - Stream_GetPosition(priv->outputStream), &written)) + Stream_GetPosition(priv->outputStream), &written)) { WLog_ERR(TAG, "WTSVirtualChannelWrite failed!"); return ERROR_INTERNAL_ERROR; @@ -532,27 +537,26 @@ UINT rdpei_server_suspend(RdpeiServerContext *context) return CHANNEL_RC_OK; } - /** * Function description * * @return 0 on success, otherwise a Win32 error code */ -UINT rdpei_server_resume(RdpeiServerContext *context) +UINT rdpei_server_resume(RdpeiServerContext* context) { ULONG written; - RdpeiServerPrivate *priv = context->priv; + RdpeiServerPrivate* priv = context->priv; switch (priv->automataState) { - case STATE_WAITING_FRAME: - WLog_ERR(TAG, "not suspended"); - return CHANNEL_RC_OK; - case STATE_SUSPENDED: - break; - default: - WLog_ERR(TAG, "called from unexpected state %d", priv->automataState); - return ERROR_INVALID_STATE; + case STATE_WAITING_FRAME: + WLog_ERR(TAG, "not suspended"); + return CHANNEL_RC_OK; + case STATE_SUSPENDED: + break; + default: + WLog_ERR(TAG, "called from unexpected state %d", priv->automataState); + return ERROR_INVALID_STATE; } Stream_SetPosition(priv->outputStream, 0); @@ -566,7 +570,7 @@ UINT rdpei_server_resume(RdpeiServerContext *context) Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH); if (!WTSVirtualChannelWrite(priv->channelHandle, (PCHAR)Stream_Buffer(priv->outputStream), - Stream_GetPosition(priv->outputStream), &written)) + Stream_GetPosition(priv->outputStream), &written)) { WLog_ERR(TAG, "WTSVirtualChannelWrite failed!"); return ERROR_INTERNAL_ERROR; @@ -575,4 +579,3 @@ UINT rdpei_server_resume(RdpeiServerContext *context) priv->automataState = STATE_WAITING_FRAME; return CHANNEL_RC_OK; } - diff --git a/channels/rdpei/server/rdpei_main.h b/channels/rdpei/server/rdpei_main.h index f6505f5..cf3e3cb 100644 --- a/channels/rdpei/server/rdpei_main.h +++ b/channels/rdpei/server/rdpei_main.h @@ -29,7 +29,4 @@ #define TAG CHANNELS_TAG("rdpei.server") - - #endif /* FREERDP_CHANNEL_RDPEI_SERVER_MAIN_H */ - diff --git a/channels/rdpgfx/client/rdpgfx_codec.c b/channels/rdpgfx/client/rdpgfx_codec.c index d2dfbb3..d89278c 100644 --- a/channels/rdpgfx/client/rdpgfx_codec.c +++ b/channels/rdpgfx/client/rdpgfx_codec.c @@ -39,8 +39,7 @@ * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_read_h264_metablock(RDPGFX_PLUGIN* gfx, wStream* s, - RDPGFX_H264_METABLOCK* meta) +static UINT rdpgfx_read_h264_metablock(RDPGFX_PLUGIN* gfx, wStream* s, RDPGFX_H264_METABLOCK* meta) { UINT32 index; RECTANGLE_16* regionRect; @@ -63,7 +62,7 @@ static UINT rdpgfx_read_h264_metablock(RDPGFX_PLUGIN* gfx, wStream* s, goto error_out; } - meta->regionRects = (RECTANGLE_16*) calloc(meta->numRegionRects, sizeof(RECTANGLE_16)); + meta->regionRects = (RECTANGLE_16*)calloc(meta->numRegionRects, sizeof(RECTANGLE_16)); if (!meta->regionRects) { @@ -72,8 +71,8 @@ static UINT rdpgfx_read_h264_metablock(RDPGFX_PLUGIN* gfx, wStream* s, goto error_out; } - meta->quantQualityVals = (RDPGFX_H264_QUANT_QUALITY*) calloc(meta->numRegionRects, sizeof( - RDPGFX_H264_QUANT_QUALITY)); + meta->quantQualityVals = + (RDPGFX_H264_QUANT_QUALITY*)calloc(meta->numRegionRects, sizeof(RDPGFX_H264_QUANT_QUALITY)); if (!meta->quantQualityVals) { @@ -82,7 +81,7 @@ static UINT rdpgfx_read_h264_metablock(RDPGFX_PLUGIN* gfx, wStream* s, goto error_out; } - WLog_DBG(TAG, "H264_METABLOCK: numRegionRects: %"PRIu32"", meta->numRegionRects); + WLog_DBG(TAG, "H264_METABLOCK: numRegionRects: %" PRIu32 "", meta->numRegionRects); for (index = 0; index < meta->numRegionRects; index++) { @@ -90,12 +89,13 @@ static UINT rdpgfx_read_h264_metablock(RDPGFX_PLUGIN* gfx, wStream* s, if ((error = rdpgfx_read_rect16(s, regionRect))) { - WLog_ERR(TAG, "rdpgfx_read_rect16 failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rdpgfx_read_rect16 failed with error %" PRIu32 "!", error); goto error_out; } WLog_DBG(TAG, - "regionRects[%"PRIu32"]: left: %"PRIu16" top: %"PRIu16" right: %"PRIu16" bottom: %"PRIu16"", + "regionRects[%" PRIu32 "]: left: %" PRIu16 " top: %" PRIu16 " right: %" PRIu16 + " bottom: %" PRIu16 "", index, regionRect->left, regionRect->top, regionRect->right, regionRect->bottom); } @@ -109,14 +109,16 @@ static UINT rdpgfx_read_h264_metablock(RDPGFX_PLUGIN* gfx, wStream* s, for (index = 0; index < meta->numRegionRects; index++) { quantQualityVal = &(meta->quantQualityVals[index]); - Stream_Read_UINT8(s, quantQualityVal->qpVal); /* qpVal (1 byte) */ + Stream_Read_UINT8(s, quantQualityVal->qpVal); /* qpVal (1 byte) */ Stream_Read_UINT8(s, quantQualityVal->qualityVal); /* qualityVal (1 byte) */ quantQualityVal->qp = quantQualityVal->qpVal & 0x3F; quantQualityVal->r = (quantQualityVal->qpVal >> 6) & 1; quantQualityVal->p = (quantQualityVal->qpVal >> 7) & 1; WLog_DBG(TAG, - "quantQualityVals[%"PRIu32"]: qp: %"PRIu8" r: %"PRIu8" p: %"PRIu8" qualityVal: %"PRIu8"", - index, quantQualityVal->qp, quantQualityVal->r, quantQualityVal->p, quantQualityVal->qualityVal); + "quantQualityVals[%" PRIu32 "]: qp: %" PRIu8 " r: %" PRIu8 " p: %" PRIu8 + " qualityVal: %" PRIu8 "", + index, quantQualityVal->qp, quantQualityVal->r, quantQualityVal->p, + quantQualityVal->qualityVal); } return CHANNEL_RC_OK; @@ -138,7 +140,7 @@ static UINT rdpgfx_decode_AVC420(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd UINT error; wStream* s; RDPGFX_AVC420_BITMAP_STREAM h264; - RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface; s = Stream_New(cmd->data, cmd->length); if (!s) @@ -150,21 +152,21 @@ static UINT rdpgfx_decode_AVC420(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd if ((error = rdpgfx_read_h264_metablock(gfx, s, &(h264.meta)))) { Stream_Free(s, FALSE); - WLog_ERR(TAG, "rdpgfx_read_h264_metablock failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rdpgfx_read_h264_metablock failed with error %" PRIu32 "!", error); return error; } h264.data = Stream_Pointer(s); - h264.length = (UINT32) Stream_GetRemainingLength(s); + h264.length = (UINT32)Stream_GetRemainingLength(s); Stream_Free(s, FALSE); - cmd->extra = (void*) &h264; + cmd->extra = (void*)&h264; if (context) { IFCALLRET(context->SurfaceCommand, error, context, cmd); if (error) - WLog_ERR(TAG, "context->SurfaceCommand failed with error %"PRIu32"", error); + WLog_ERR(TAG, "context->SurfaceCommand failed with error %" PRIu32 "", error); } free(h264.meta.regionRects); @@ -184,7 +186,7 @@ static UINT rdpgfx_decode_AVC444(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd size_t pos1, pos2; wStream* s; RDPGFX_AVC444_BITMAP_STREAM h264 = { 0 }; - RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface; s = Stream_New(cmd->data, cmd->length); if (!s) @@ -213,7 +215,7 @@ static UINT rdpgfx_decode_AVC444(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd if ((error = rdpgfx_read_h264_metablock(gfx, s, &(h264.bitstream[0].meta)))) { - WLog_ERR(TAG, "rdpgfx_read_h264_metablock failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rdpgfx_read_h264_metablock failed with error %" PRIu32 "!", error); goto fail; } @@ -235,7 +237,7 @@ static UINT rdpgfx_decode_AVC444(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd if ((error = rdpgfx_read_h264_metablock(gfx, s, &(h264.bitstream[1].meta)))) { - WLog_ERR(TAG, "rdpgfx_read_h264_metablock failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rdpgfx_read_h264_metablock failed with error %" PRIu32 "!", error); goto fail; } @@ -243,19 +245,16 @@ 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; + cmd->extra = (void*)&h264; if (context) { IFCALLRET(context->SurfaceCommand, error, context, cmd); if (error) - WLog_ERR(TAG, "context->SurfaceCommand failed with error %"PRIu32"", error); + WLog_ERR(TAG, "context->SurfaceCommand failed with error %" PRIu32 "", error); } fail: @@ -275,21 +274,21 @@ fail: UINT rdpgfx_decode(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd) { UINT error = CHANNEL_RC_OK; - RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface; PROFILER_ENTER(context->SurfaceProfiler) switch (cmd->codecId) { case RDPGFX_CODECID_AVC420: if ((error = rdpgfx_decode_AVC420(gfx, cmd))) - WLog_ERR(TAG, "rdpgfx_decode_AVC420 failed with error %"PRIu32"", error); + WLog_ERR(TAG, "rdpgfx_decode_AVC420 failed with error %" PRIu32 "", error); break; case RDPGFX_CODECID_AVC444: case RDPGFX_CODECID_AVC444v2: if ((error = rdpgfx_decode_AVC444(gfx, cmd))) - WLog_ERR(TAG, "rdpgfx_decode_AVC444 failed with error %"PRIu32"", error); + WLog_ERR(TAG, "rdpgfx_decode_AVC444 failed with error %" PRIu32 "", error); break; @@ -299,7 +298,7 @@ UINT rdpgfx_decode(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd) IFCALLRET(context->SurfaceCommand, error, context, cmd); if (error) - WLog_ERR(TAG, "context->SurfaceCommand failed with error %"PRIu32"", error); + WLog_ERR(TAG, "context->SurfaceCommand failed with error %" PRIu32 "", error); } break; diff --git a/channels/rdpgfx/client/rdpgfx_main.c b/channels/rdpgfx/client/rdpgfx_main.c index 0090db0..6ca75bd 100644 --- a/channels/rdpgfx/client/rdpgfx_main.c +++ b/channels/rdpgfx/client/rdpgfx_main.c @@ -47,106 +47,285 @@ #define TAG CHANNELS_TAG("rdpgfx.client") +static void free_surfaces(RdpgfxClientContext* context, wHashTable* SurfaceTable) +{ + UINT error = 0; + ULONG_PTR* pKeys = NULL; + int count; + int index; + + count = HashTable_GetKeys(SurfaceTable, &pKeys); + + for (index = 0; index < count; index++) + { + RDPGFX_DELETE_SURFACE_PDU pdu; + pdu.surfaceId = ((UINT16)pKeys[index]) - 1; + + if (context) + { + IFCALLRET(context->DeleteSurface, error, context, &pdu); + + if (error) + { + WLog_ERR(TAG, "context->DeleteSurface failed with error %" PRIu32 "", error); + } + } + } + + free(pKeys); +} + +static void evict_cache_slots(RdpgfxClientContext* context, UINT16 MaxCacheSlots, void** CacheSlots) +{ + UINT16 index; + + for (index = 0; index < MaxCacheSlots; index++) + { + if (CacheSlots[index]) + { + RDPGFX_EVICT_CACHE_ENTRY_PDU pdu; + pdu.cacheSlot = (UINT16)index + 1; + + if (context && context->EvictCacheEntry) + { + context->EvictCacheEntry(context, &pdu); + } + + CacheSlots[index] = NULL; + } + } +} + /** * Function description * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_send_caps_advertise_pdu(RDPGFX_CHANNEL_CALLBACK* callback) +static UINT rdpgfx_send_caps_advertise_pdu(RdpgfxClientContext* context, + const RDPGFX_CAPS_ADVERTISE_PDU* pdu) { - UINT error; - wStream* s; + UINT error = CHANNEL_RC_OK; UINT16 index; - RDPGFX_PLUGIN* gfx; RDPGFX_HEADER header; RDPGFX_CAPSET* capsSet; - RDPGFX_CAPSET capsSets[RDPGFX_NUMBER_CAPSETS]; - RDPGFX_CAPS_ADVERTISE_PDU pdu; - gfx = (RDPGFX_PLUGIN*) callback->plugin; + RDPGFX_PLUGIN* gfx; + RDPGFX_CHANNEL_CALLBACK* callback; + wStream* s; + gfx = (RDPGFX_PLUGIN*)context->handle; + + if (!gfx || !gfx->listener_callback) + return ERROR_BAD_ARGUMENTS; + + callback = gfx->listener_callback->channel_callback; + header.flags = 0; header.cmdId = RDPGFX_CMDID_CAPSADVERTISE; + header.pduLength = RDPGFX_HEADER_SIZE + 2; + + for (index = 0; index < pdu->capsSetCount; index++) + { + capsSet = &(pdu->capsSets[index]); + header.pduLength += RDPGFX_CAPSET_BASE_SIZE + capsSet->length; + } + + DEBUG_RDPGFX(gfx->log, "SendCapsAdvertisePdu %" PRIu16 "", pdu->capsSetCount); + s = Stream_New(NULL, header.pduLength); + + if (!s) + { + WLog_ERR(TAG, "Stream_New failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + if ((error = rdpgfx_write_header(s, &header))) + goto fail; + + /* RDPGFX_CAPS_ADVERTISE_PDU */ + Stream_Write_UINT16(s, pdu->capsSetCount); /* capsSetCount (2 bytes) */ + + for (index = 0; index < pdu->capsSetCount; index++) + { + capsSet = &(pdu->capsSets[index]); + Stream_Write_UINT32(s, capsSet->version); /* version (4 bytes) */ + Stream_Write_UINT32(s, capsSet->length); /* capsDataLength (4 bytes) */ + Stream_Write_UINT32(s, capsSet->flags); /* capsData (4 bytes) */ + Stream_Zero(s, capsSet->length - 4); + } + + Stream_SealLength(s); + error = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s), + NULL); +fail: + Stream_Free(s, TRUE); + return error; +} + +static BOOL rdpgfx_is_capability_filtered(RDPGFX_PLUGIN* gfx, UINT32 caps) +{ + const UINT32 filter = gfx->capsFilter; + const UINT32 capList[] = { + RDPGFX_CAPVERSION_8, RDPGFX_CAPVERSION_81, RDPGFX_CAPVERSION_10, + RDPGFX_CAPVERSION_101, RDPGFX_CAPVERSION_102, RDPGFX_CAPVERSION_103, + RDPGFX_CAPVERSION_104, RDPGFX_CAPVERSION_105, RDPGFX_CAPVERSION_106 + }; + UINT32 x; + + for (x = 0; x < ARRAYSIZE(capList); x++) + { + if (caps == capList[x]) + return (filter & (1 << x)) != 0; + } + + return TRUE; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpgfx_send_supported_caps(RDPGFX_CHANNEL_CALLBACK* callback) +{ + RDPGFX_PLUGIN* gfx; + RdpgfxClientContext* context; + RDPGFX_CAPSET* capsSet; + RDPGFX_CAPSET capsSets[RDPGFX_NUMBER_CAPSETS] = { 0 }; + RDPGFX_CAPS_ADVERTISE_PDU pdu; + + if (!callback) + return ERROR_BAD_ARGUMENTS; + + gfx = (RDPGFX_PLUGIN*)callback->plugin; + + if (!gfx) + return ERROR_BAD_CONFIGURATION; + + context = (RdpgfxClientContext*)gfx->iface.pInterface; + + if (!context) + return ERROR_BAD_CONFIGURATION; + pdu.capsSetCount = 0; - pdu.capsSets = (RDPGFX_CAPSET*) capsSets; - capsSet = &capsSets[pdu.capsSetCount++]; - capsSet->version = RDPGFX_CAPVERSION_8; - capsSet->flags = 0; + pdu.capsSets = (RDPGFX_CAPSET*)capsSets; - if (gfx->ThinClient) - capsSet->flags |= RDPGFX_CAPS_FLAG_THINCLIENT; + if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_8)) + { + capsSet = &capsSets[pdu.capsSetCount++]; + capsSet->version = RDPGFX_CAPVERSION_8; + capsSet->length = 4; + capsSet->flags = 0; - /* in CAPVERSION_8 the spec says that we should not have both - * thinclient and smallcache (and thinclient implies a small cache) - */ - if (gfx->SmallCache && !gfx->ThinClient) - capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE; + if (gfx->ThinClient) + capsSet->flags |= RDPGFX_CAPS_FLAG_THINCLIENT; - capsSet = &capsSets[pdu.capsSetCount++]; - capsSet->version = RDPGFX_CAPVERSION_81; - capsSet->flags = 0; + /* in CAPVERSION_8 the spec says that we should not have both + * thinclient and smallcache (and thinclient implies a small cache) + */ + if (gfx->SmallCache && !gfx->ThinClient) + capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE; + } - if (gfx->ThinClient) - capsSet->flags |= RDPGFX_CAPS_FLAG_THINCLIENT; + if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_81)) + { + capsSet = &capsSets[pdu.capsSetCount++]; + capsSet->version = RDPGFX_CAPVERSION_81; + capsSet->length = 4; + capsSet->flags = 0; + + if (gfx->ThinClient) + capsSet->flags |= RDPGFX_CAPS_FLAG_THINCLIENT; - if (gfx->SmallCache) - capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE; + if (gfx->SmallCache) + capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE; #ifdef WITH_GFX_H264 - if (gfx->H264) - capsSet->flags |= RDPGFX_CAPS_FLAG_AVC420_ENABLED; + + if (gfx->H264) + capsSet->flags |= RDPGFX_CAPS_FLAG_AVC420_ENABLED; + #endif + } if (!gfx->H264 || gfx->AVC444) { - capsSet = &capsSets[pdu.capsSetCount++]; - capsSet->version = RDPGFX_CAPVERSION_10; - capsSet->flags = 0; + UINT32 caps10Flags = 0; if (gfx->SmallCache) - capsSet->flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE; + caps10Flags |= RDPGFX_CAPS_FLAG_SMALL_CACHE; #ifdef WITH_GFX_H264 + if (!gfx->AVC444) - capsSet->flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED; + caps10Flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED; + #else - capsSet->flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED; + caps10Flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED; #endif - capsSets[pdu.capsSetCount] = *capsSet; - capsSets[pdu.capsSetCount++].version = RDPGFX_CAPVERSION_102; - capsSets[pdu.capsSetCount] = *capsSet; - capsSets[pdu.capsSetCount++].version = RDPGFX_CAPVERSION_103; - } + if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_10)) + { + capsSet = &capsSets[pdu.capsSetCount++]; + capsSet->version = RDPGFX_CAPVERSION_10; + capsSet->length = 4; + capsSet->flags = caps10Flags; + } - header.pduLength = RDPGFX_HEADER_SIZE + 2 + (pdu.capsSetCount * RDPGFX_CAPSET_SIZE); - WLog_Print(gfx->log, WLOG_DEBUG, "SendCapsAdvertisePdu %"PRIu16"", pdu.capsSetCount); - s = Stream_New(NULL, header.pduLength); + if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_101)) + { + capsSet = &capsSets[pdu.capsSetCount++]; + capsSet->version = RDPGFX_CAPVERSION_101; + capsSet->length = 0x10; + capsSet->flags = 0; + } - if (!s) - { - WLog_ERR(TAG, "Stream_New failed!"); - return CHANNEL_RC_NO_MEMORY; - } + if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_102)) + { + capsSet = &capsSets[pdu.capsSetCount++]; + capsSet->version = RDPGFX_CAPVERSION_102; + capsSet->length = 0x4; + capsSet->flags = caps10Flags; + } - if ((error = rdpgfx_write_header(s, &header))) - goto fail; + if (gfx->ThinClient) + { + if ((caps10Flags & RDPGFX_CAPS_FLAG_AVC_DISABLED) == 0) + caps10Flags |= RDPGFX_CAPS_FLAG_AVC_THINCLIENT; + } - /* RDPGFX_CAPS_ADVERTISE_PDU */ - Stream_Write_UINT16(s, pdu.capsSetCount); /* capsSetCount (2 bytes) */ + if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_103)) + { + capsSet = &capsSets[pdu.capsSetCount++]; + capsSet->version = RDPGFX_CAPVERSION_103; + capsSet->length = 0x4; + capsSet->flags = caps10Flags & ~RDPGFX_CAPS_FLAG_SMALL_CACHE; + } - for (index = 0; index < pdu.capsSetCount; index++) - { - capsSet = &(pdu.capsSets[index]); - Stream_Write_UINT32(s, capsSet->version); /* version (4 bytes) */ - Stream_Write_UINT32(s, 4); /* capsDataLength (4 bytes) */ - Stream_Write_UINT32(s, capsSet->flags); /* capsData (4 bytes) */ + if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_104)) + { + capsSet = &capsSets[pdu.capsSetCount++]; + capsSet->version = RDPGFX_CAPVERSION_104; + capsSet->length = 0x4; + capsSet->flags = caps10Flags; + } + + if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_105)) + { + capsSet = &capsSets[pdu.capsSetCount++]; + capsSet->version = RDPGFX_CAPVERSION_105; + capsSet->length = 0x4; + capsSet->flags = caps10Flags; + } + + if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_106)) + { + capsSet = &capsSets[pdu.capsSetCount++]; + capsSet->version = RDPGFX_CAPVERSION_106; + capsSet->length = 0x4; + capsSet->flags = caps10Flags; + } } - Stream_SealLength(s); - error = callback->channel->Write(callback->channel, (UINT32) Stream_Length(s), - Stream_Buffer(s), NULL); -fail: - Stream_Free(s, TRUE); - return error; + return IFCALLRESULT(ERROR_BAD_CONFIGURATION, context->CapsAdvertise, context, &pdu); } /** @@ -154,14 +333,12 @@ fail: * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_recv_caps_confirm_pdu(RDPGFX_CHANNEL_CALLBACK* callback, - wStream* s) +static UINT rdpgfx_recv_caps_confirm_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) { RDPGFX_CAPSET capsSet; - UINT32 capsDataLength; RDPGFX_CAPS_CONFIRM_PDU pdu; - RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; - + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin; + RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface; pdu.capsSet = &capsSet; if (Stream_GetRemainingLength(s) < 12) @@ -171,14 +348,16 @@ static UINT rdpgfx_recv_caps_confirm_pdu(RDPGFX_CHANNEL_CALLBACK* callback, } Stream_Read_UINT32(s, capsSet.version); /* version (4 bytes) */ - Stream_Read_UINT32(s, capsDataLength); /* capsDataLength (4 bytes) */ - Stream_Read_UINT32(s, capsSet.flags); /* capsData (4 bytes) */ - + Stream_Read_UINT32(s, capsSet.length); /* capsDataLength (4 bytes) */ + Stream_Read_UINT32(s, capsSet.flags); /* capsData (4 bytes) */ gfx->ConnectionCaps = capsSet; + DEBUG_RDPGFX(gfx->log, "RecvCapsConfirmPdu: version: 0x%08" PRIX32 " flags: 0x%08" PRIX32 "", + capsSet.version, capsSet.flags); - WLog_Print(gfx->log, WLOG_DEBUG, "RecvCapsConfirmPdu: version: 0x%08"PRIX32" flags: 0x%08"PRIX32"", - capsSet.version, capsSet.flags); - return CHANNEL_RC_OK; + if (!context) + return ERROR_BAD_CONFIGURATION; + + return IFCALLRESULT(CHANNEL_RC_OK, context->CapsConfirm, context, &pdu); } /** @@ -186,20 +365,34 @@ static UINT rdpgfx_recv_caps_confirm_pdu(RDPGFX_CHANNEL_CALLBACK* callback, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_send_frame_acknowledge_pdu(RDPGFX_CHANNEL_CALLBACK* callback, - RDPGFX_FRAME_ACKNOWLEDGE_PDU* pdu) +static UINT rdpgfx_send_frame_acknowledge_pdu(RdpgfxClientContext* context, + const RDPGFX_FRAME_ACKNOWLEDGE_PDU* pdu) { UINT error; wStream* s; RDPGFX_HEADER header; - RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; + RDPGFX_PLUGIN* gfx; + RDPGFX_CHANNEL_CALLBACK* callback; + + if (!context || !pdu) + return ERROR_BAD_ARGUMENTS; + + gfx = (RDPGFX_PLUGIN*)context->handle; + + if (!gfx || !gfx->listener_callback) + return ERROR_BAD_CONFIGURATION; + + callback = gfx->listener_callback->channel_callback; + + if (!callback) + return ERROR_BAD_CONFIGURATION; header.flags = 0; header.cmdId = RDPGFX_CMDID_FRAMEACKNOWLEDGE; header.pduLength = RDPGFX_HEADER_SIZE + 12; - WLog_Print(gfx->log, WLOG_DEBUG, "SendFrameAcknowledgePdu: %"PRIu32"", pdu->frameId); - + DEBUG_RDPGFX(gfx->log, "SendFrameAcknowledgePdu: %" PRIu32 "", pdu->frameId); s = Stream_New(NULL, header.pduLength); + if (!s) { WLog_ERR(TAG, "Stream_New failed!"); @@ -210,31 +403,48 @@ static UINT rdpgfx_send_frame_acknowledge_pdu(RDPGFX_CHANNEL_CALLBACK* callback, goto fail; /* RDPGFX_FRAME_ACKNOWLEDGE_PDU */ - Stream_Write_UINT32(s, pdu->queueDepth); /* queueDepth (4 bytes) */ - Stream_Write_UINT32(s, pdu->frameId); /* frameId (4 bytes) */ - Stream_Write_UINT32(s, - pdu->totalFramesDecoded); /* totalFramesDecoded (4 bytes) */ - error = callback->channel->Write(callback->channel, (UINT32) Stream_Length(s), - Stream_Buffer(s), NULL); + Stream_Write_UINT32(s, pdu->queueDepth); /* queueDepth (4 bytes) */ + Stream_Write_UINT32(s, pdu->frameId); /* frameId (4 bytes) */ + Stream_Write_UINT32(s, pdu->totalFramesDecoded); /* totalFramesDecoded (4 bytes) */ + error = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s), + NULL); + + if (error == CHANNEL_RC_OK) /* frame successfully acked */ + gfx->UnacknowledgedFrames--; + fail: Stream_Free(s, TRUE); return error; } -static UINT rdpgfx_send_qoe_frame_acknowledge_pdu(RDPGFX_CHANNEL_CALLBACK* callback, +static UINT rdpgfx_send_qoe_frame_acknowledge_pdu(RdpgfxClientContext* context, const RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU* pdu) { UINT error; wStream* s; RDPGFX_HEADER header; - RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; - + RDPGFX_CHANNEL_CALLBACK* callback; + RDPGFX_PLUGIN* gfx; header.flags = 0; header.cmdId = RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE; header.pduLength = RDPGFX_HEADER_SIZE + 12; - WLog_Print(gfx->log, WLOG_DEBUG, "SendQoeFrameAcknowledgePdu: %"PRIu32"", pdu->frameId); + if (!context || !pdu) + return ERROR_BAD_ARGUMENTS; + + gfx = (RDPGFX_PLUGIN*)context->handle; + + if (!gfx || !gfx->listener_callback) + return ERROR_BAD_CONFIGURATION; + + callback = gfx->listener_callback->channel_callback; + + if (!callback) + return ERROR_BAD_CONFIGURATION; + + DEBUG_RDPGFX(gfx->log, "SendQoeFrameAcknowledgePdu: %" PRIu32 "", pdu->frameId); s = Stream_New(NULL, header.pduLength); + if (!s) { WLog_ERR(TAG, "Stream_New failed!"); @@ -249,9 +459,78 @@ static UINT rdpgfx_send_qoe_frame_acknowledge_pdu(RDPGFX_CHANNEL_CALLBACK* callb Stream_Write_UINT32(s, pdu->timestamp); Stream_Write_UINT16(s, pdu->timeDiffSE); Stream_Write_UINT16(s, pdu->timeDiffEDR); + error = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s), + NULL); +fail: + Stream_Free(s, TRUE); + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpgfx_send_cache_import_offer_pdu(RdpgfxClientContext* context, + const RDPGFX_CACHE_IMPORT_OFFER_PDU* pdu) +{ + UINT16 index; + UINT error = CHANNEL_RC_OK; + wStream* s; + RDPGFX_PLUGIN* gfx; + RDPGFX_CHANNEL_CALLBACK* callback; + RDPGFX_HEADER header; + RDPGFX_CACHE_ENTRY_METADATA* cacheEntries; + + if (!context || !pdu) + return ERROR_BAD_ARGUMENTS; + + gfx = (RDPGFX_PLUGIN*)context->handle; + + if (!gfx || !gfx->listener_callback) + return ERROR_BAD_CONFIGURATION; + + callback = gfx->listener_callback->channel_callback; + + if (!callback) + return ERROR_BAD_CONFIGURATION; + + header.flags = 0; + header.cmdId = RDPGFX_CMDID_CACHEIMPORTOFFER; + header.pduLength = RDPGFX_HEADER_SIZE + 2 + pdu->cacheEntriesCount * 12; + DEBUG_RDPGFX(gfx->log, "SendCacheImportOfferPdu: cacheEntriesCount: %" PRIu16 "", + pdu->cacheEntriesCount); + s = Stream_New(NULL, header.pduLength); + + if (!s) + { + WLog_ERR(TAG, "Stream_New failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + if ((error = rdpgfx_write_header(s, &header))) + goto fail; + + if (pdu->cacheEntriesCount <= 0) + { + WLog_ERR(TAG, "Invalid cacheEntriesCount: %" PRIu16 "", pdu->cacheEntriesCount); + error = ERROR_INVALID_DATA; + goto fail; + } + + /* cacheEntriesCount (2 bytes) */ + Stream_Write_UINT16(s, pdu->cacheEntriesCount); + + for (index = 0; index < pdu->cacheEntriesCount; index++) + { + cacheEntries = &(pdu->cacheEntries[index]); + Stream_Write_UINT64(s, cacheEntries->cacheKey); /* cacheKey (8 bytes) */ + Stream_Write_UINT32(s, cacheEntries->bitmapLength); /* bitmapLength (4 bytes) */ + } + + error = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s), + NULL); - error = callback->channel->Write(callback->channel, (UINT32) Stream_Length(s), - Stream_Buffer(s), NULL); fail: Stream_Free(s, TRUE); return error; @@ -262,15 +541,14 @@ fail: * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_recv_reset_graphics_pdu(RDPGFX_CHANNEL_CALLBACK* callback, - wStream* s) +static UINT rdpgfx_recv_reset_graphics_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) { int pad; UINT32 index; MONITOR_DEF* monitor; RDPGFX_RESET_GRAPHICS_PDU pdu; - RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; - RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin; + RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface; UINT error = CHANNEL_RC_OK; GraphicsResetEventArgs graphicsReset; @@ -280,8 +558,8 @@ static UINT rdpgfx_recv_reset_graphics_pdu(RDPGFX_CHANNEL_CALLBACK* callback, return ERROR_INVALID_DATA; } - Stream_Read_UINT32(s, pdu.width); /* width (4 bytes) */ - Stream_Read_UINT32(s, pdu.height); /* height (4 bytes) */ + Stream_Read_UINT32(s, pdu.width); /* width (4 bytes) */ + Stream_Read_UINT32(s, pdu.height); /* height (4 bytes) */ Stream_Read_UINT32(s, pdu.monitorCount); /* monitorCount (4 bytes) */ if (Stream_GetRemainingLength(s) < (pdu.monitorCount * 20)) @@ -290,7 +568,8 @@ static UINT rdpgfx_recv_reset_graphics_pdu(RDPGFX_CHANNEL_CALLBACK* callback, return ERROR_INVALID_DATA; } - pdu.monitorDefArray = (MONITOR_DEF*) calloc(pdu.monitorCount, sizeof(MONITOR_DEF)); + pdu.monitorDefArray = (MONITOR_DEF*)calloc(pdu.monitorCount, sizeof(MONITOR_DEF)); + if (!pdu.monitorDefArray) { WLog_Print(gfx->log, WLOG_ERROR, "calloc failed!"); @@ -300,16 +579,16 @@ static UINT rdpgfx_recv_reset_graphics_pdu(RDPGFX_CHANNEL_CALLBACK* callback, for (index = 0; index < pdu.monitorCount; index++) { monitor = &(pdu.monitorDefArray[index]); - Stream_Read_UINT32(s, monitor->left); /* left (4 bytes) */ - Stream_Read_UINT32(s, monitor->top); /* top (4 bytes) */ - Stream_Read_UINT32(s, monitor->right); /* right (4 bytes) */ + Stream_Read_UINT32(s, monitor->left); /* left (4 bytes) */ + Stream_Read_UINT32(s, monitor->top); /* top (4 bytes) */ + Stream_Read_UINT32(s, monitor->right); /* right (4 bytes) */ Stream_Read_UINT32(s, monitor->bottom); /* bottom (4 bytes) */ - Stream_Read_UINT32(s, monitor->flags); /* flags (4 bytes) */ + Stream_Read_UINT32(s, monitor->flags); /* flags (4 bytes) */ } pad = 340 - (RDPGFX_HEADER_SIZE + 12 + (pdu.monitorCount * 20)); - if (Stream_GetRemainingLength(s) < (size_t) pad) + if (Stream_GetRemainingLength(s) < (size_t)pad) { WLog_Print(gfx->log, WLOG_ERROR, "Stream_GetRemainingLength failed!"); free(pdu.monitorDefArray); @@ -317,15 +596,17 @@ static UINT rdpgfx_recv_reset_graphics_pdu(RDPGFX_CHANNEL_CALLBACK* callback, } Stream_Seek(s, pad); /* pad (total size is 340 bytes) */ - WLog_Print(gfx->log, WLOG_DEBUG, "RecvResetGraphicsPdu: width: %"PRIu32" height: %"PRIu32" count: %"PRIu32"", - pdu.width, pdu.height, pdu.monitorCount); + DEBUG_RDPGFX(gfx->log, + "RecvResetGraphicsPdu: width: %" PRIu32 " height: %" PRIu32 " count: %" PRIu32 "", + pdu.width, pdu.height, pdu.monitorCount); for (index = 0; index < pdu.monitorCount; index++) { monitor = &(pdu.monitorDefArray[index]); - WLog_Print(gfx->log, WLOG_DEBUG, - "RecvResetGraphicsPdu: monitor left:%"PRIi32" top:%"PRIi32" right:%"PRIi32" left:%"PRIi32" flags:0x%"PRIx32"", - monitor->left, monitor->top, monitor->right, monitor->bottom, monitor->flags); + DEBUG_RDPGFX(gfx->log, + "RecvResetGraphicsPdu: monitor left:%" PRIi32 " top:%" PRIi32 " right:%" PRIi32 + " bottom:%" PRIi32 " flags:0x%" PRIx32 "", + monitor->left, monitor->top, monitor->right, monitor->bottom, monitor->flags); } if (context) @@ -333,15 +614,15 @@ static UINT rdpgfx_recv_reset_graphics_pdu(RDPGFX_CHANNEL_CALLBACK* callback, IFCALLRET(context->ResetGraphics, error, context, &pdu); if (error) - WLog_Print(gfx->log, WLOG_ERROR, "context->ResetGraphics failed with error %"PRIu32"", error); + WLog_Print(gfx->log, WLOG_ERROR, "context->ResetGraphics failed with error %" PRIu32 "", + error); } /* some listeners may be interested (namely the display channel) */ - EventArgsInit(&graphicsReset, "xfreerdp"); + EventArgsInit(&graphicsReset, "libfreerdp"); graphicsReset.width = pdu.width; graphicsReset.height = pdu.height; PubSub_OnGraphicsReset(gfx->rdpcontext->pubSub, gfx->rdpcontext, &graphicsReset); - free(pdu.monitorDefArray); return error; } @@ -351,12 +632,11 @@ static UINT rdpgfx_recv_reset_graphics_pdu(RDPGFX_CHANNEL_CALLBACK* callback, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_recv_evict_cache_entry_pdu(RDPGFX_CHANNEL_CALLBACK* callback, - wStream* s) +static UINT rdpgfx_recv_evict_cache_entry_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) { RDPGFX_EVICT_CACHE_ENTRY_PDU pdu; - RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; - RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin; + RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface; UINT error = CHANNEL_RC_OK; if (Stream_GetRemainingLength(s) < 2) @@ -366,14 +646,16 @@ static UINT rdpgfx_recv_evict_cache_entry_pdu(RDPGFX_CHANNEL_CALLBACK* callback, } Stream_Read_UINT16(s, pdu.cacheSlot); /* cacheSlot (2 bytes) */ - WLog_Print(gfx->log, WLOG_DEBUG, "RecvEvictCacheEntryPdu: cacheSlot: %"PRIu16"", pdu.cacheSlot); + WLog_Print(gfx->log, WLOG_DEBUG, "RecvEvictCacheEntryPdu: cacheSlot: %" PRIu16 "", + pdu.cacheSlot); if (context) { IFCALLRET(context->EvictCacheEntry, error, context, &pdu); if (error) - WLog_Print(gfx->log, WLOG_ERROR, "context->EvictCacheEntry failed with error %"PRIu32"", error); + WLog_Print(gfx->log, WLOG_ERROR, + "context->EvictCacheEntry failed with error %" PRIu32 "", error); } return error; @@ -384,13 +666,12 @@ static UINT rdpgfx_recv_evict_cache_entry_pdu(RDPGFX_CHANNEL_CALLBACK* callback, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_recv_cache_import_reply_pdu(RDPGFX_CHANNEL_CALLBACK* callback, - wStream* s) +static UINT rdpgfx_recv_cache_import_reply_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) { UINT16 index; RDPGFX_CACHE_IMPORT_REPLY_PDU pdu; - RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; - RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin; + RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface; UINT error = CHANNEL_RC_OK; if (Stream_GetRemainingLength(s) < 2) @@ -407,7 +688,8 @@ static UINT rdpgfx_recv_cache_import_reply_pdu(RDPGFX_CHANNEL_CALLBACK* callback return ERROR_INVALID_DATA; } - pdu.cacheSlots = (UINT16*) calloc(pdu.importedEntriesCount, sizeof(UINT16)); + pdu.cacheSlots = (UINT16*)calloc(pdu.importedEntriesCount, sizeof(UINT16)); + if (!pdu.cacheSlots) { WLog_Print(gfx->log, WLOG_ERROR, "calloc failed!"); @@ -419,15 +701,16 @@ static UINT rdpgfx_recv_cache_import_reply_pdu(RDPGFX_CHANNEL_CALLBACK* callback Stream_Read_UINT16(s, pdu.cacheSlots[index]); /* cacheSlot (2 bytes) */ } - WLog_Print(gfx->log, WLOG_DEBUG, "RecvCacheImportReplyPdu: importedEntriesCount: %"PRIu16"", - pdu.importedEntriesCount); + DEBUG_RDPGFX(gfx->log, "RecvCacheImportReplyPdu: importedEntriesCount: %" PRIu16 "", + pdu.importedEntriesCount); if (context) { IFCALLRET(context->CacheImportReply, error, context, &pdu); if (error) - WLog_Print(gfx->log, WLOG_ERROR, "context->CacheImportReply failed with error %"PRIu32"", error); + WLog_Print(gfx->log, WLOG_ERROR, + "context->CacheImportReply failed with error %" PRIu32 "", error); } free(pdu.cacheSlots); @@ -439,12 +722,11 @@ static UINT rdpgfx_recv_cache_import_reply_pdu(RDPGFX_CHANNEL_CALLBACK* callback * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_recv_create_surface_pdu(RDPGFX_CHANNEL_CALLBACK* callback, - wStream* s) +static UINT rdpgfx_recv_create_surface_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) { RDPGFX_CREATE_SURFACE_PDU pdu; - RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; - RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin; + RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface; UINT error = CHANNEL_RC_OK; if (Stream_GetRemainingLength(s) < 7) @@ -453,20 +735,22 @@ static UINT rdpgfx_recv_create_surface_pdu(RDPGFX_CHANNEL_CALLBACK* callback, return ERROR_INVALID_DATA; } - Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */ - Stream_Read_UINT16(s, pdu.width); /* width (2 bytes) */ - Stream_Read_UINT16(s, pdu.height); /* height (2 bytes) */ + Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */ + Stream_Read_UINT16(s, pdu.width); /* width (2 bytes) */ + Stream_Read_UINT16(s, pdu.height); /* height (2 bytes) */ Stream_Read_UINT8(s, pdu.pixelFormat); /* RDPGFX_PIXELFORMAT (1 byte) */ - WLog_Print(gfx->log, WLOG_DEBUG, - "RecvCreateSurfacePdu: surfaceId: %"PRIu16" width: %"PRIu16" height: %"PRIu16" pixelFormat: 0x%02"PRIX8"", - pdu.surfaceId, pdu.width, pdu.height, pdu.pixelFormat); + DEBUG_RDPGFX(gfx->log, + "RecvCreateSurfacePdu: surfaceId: %" PRIu16 " width: %" PRIu16 " height: %" PRIu16 + " pixelFormat: 0x%02" PRIX8 "", + pdu.surfaceId, pdu.width, pdu.height, pdu.pixelFormat); if (context) { IFCALLRET(context->CreateSurface, error, context, &pdu); if (error) - WLog_Print(gfx->log, WLOG_ERROR, "context->CreateSurface failed with error %"PRIu32"", error); + WLog_Print(gfx->log, WLOG_ERROR, "context->CreateSurface failed with error %" PRIu32 "", + error); } return error; @@ -477,12 +761,11 @@ static UINT rdpgfx_recv_create_surface_pdu(RDPGFX_CHANNEL_CALLBACK* callback, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_recv_delete_surface_pdu(RDPGFX_CHANNEL_CALLBACK* callback, - wStream* s) +static UINT rdpgfx_recv_delete_surface_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) { RDPGFX_DELETE_SURFACE_PDU pdu; - RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; - RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin; + RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface; UINT error = CHANNEL_RC_OK; if (Stream_GetRemainingLength(s) < 2) @@ -492,14 +775,15 @@ static UINT rdpgfx_recv_delete_surface_pdu(RDPGFX_CHANNEL_CALLBACK* callback, } Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */ - WLog_Print(gfx->log, WLOG_DEBUG, "RecvDeleteSurfacePdu: surfaceId: %"PRIu16"", pdu.surfaceId); + DEBUG_RDPGFX(gfx->log, "RecvDeleteSurfacePdu: surfaceId: %" PRIu16 "", pdu.surfaceId); if (context) { IFCALLRET(context->DeleteSurface, error, context, &pdu); if (error) - WLog_Print(gfx->log, WLOG_ERROR, "context->DeleteSurface failed with error %"PRIu32"", error); + WLog_Print(gfx->log, WLOG_ERROR, "context->DeleteSurface failed with error %" PRIu32 "", + error); } return error; @@ -510,12 +794,11 @@ static UINT rdpgfx_recv_delete_surface_pdu(RDPGFX_CHANNEL_CALLBACK* callback, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_recv_start_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback, - wStream* s) +static UINT rdpgfx_recv_start_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) { RDPGFX_START_FRAME_PDU pdu; - RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; - RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin; + RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface; UINT error = CHANNEL_RC_OK; if (Stream_GetRemainingLength(s) < RDPGFX_START_FRAME_PDU_SIZE) @@ -525,17 +808,18 @@ static UINT rdpgfx_recv_start_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback, } Stream_Read_UINT32(s, pdu.timestamp); /* timestamp (4 bytes) */ - Stream_Read_UINT32(s, pdu.frameId); /* frameId (4 bytes) */ - WLog_Print(gfx->log, WLOG_DEBUG, "RecvStartFramePdu: frameId: %"PRIu32" timestamp: 0x%08"PRIX32"", - pdu.frameId, pdu.timestamp); + Stream_Read_UINT32(s, pdu.frameId); /* frameId (4 bytes) */ + DEBUG_RDPGFX(gfx->log, "RecvStartFramePdu: frameId: %" PRIu32 " timestamp: 0x%08" PRIX32 "", + pdu.frameId, pdu.timestamp); + gfx->StartDecodingTime = GetTickCount64(); - gfx->StartDecodingTime = GetTickCountPrecise(); if (context) { IFCALLRET(context->StartFrame, error, context, &pdu); if (error) - WLog_Print(gfx->log, WLOG_ERROR, "context->StartFrame failed with error %"PRIu32"", error); + WLog_Print(gfx->log, WLOG_ERROR, "context->StartFrame failed with error %" PRIu32 "", + error); } gfx->UnacknowledgedFrames++; @@ -547,13 +831,12 @@ static UINT rdpgfx_recv_start_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_recv_end_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback, - wStream* s) +static UINT rdpgfx_recv_end_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) { RDPGFX_END_FRAME_PDU pdu; RDPGFX_FRAME_ACKNOWLEDGE_PDU ack; - RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; - RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin; + RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface; UINT error = CHANNEL_RC_OK; if (Stream_GetRemainingLength(s) < RDPGFX_END_FRAME_PDU_SIZE) @@ -563,7 +846,7 @@ static UINT rdpgfx_recv_end_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback, } Stream_Read_UINT32(s, pdu.frameId); /* frameId (4 bytes) */ - WLog_Print(gfx->log, WLOG_DEBUG, "RecvEndFramePdu: frameId: %"PRIu32"", pdu.frameId); + DEBUG_RDPGFX(gfx->log, "RecvEndFramePdu: frameId: %" PRIu32 "", pdu.frameId); if (context) { @@ -571,13 +854,17 @@ static UINT rdpgfx_recv_end_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback, if (error) { - WLog_Print(gfx->log, WLOG_ERROR, "context->EndFrame failed with error %"PRIu32"", error); + WLog_Print(gfx->log, WLOG_ERROR, "context->EndFrame failed with error %" PRIu32 "", + error); return error; } } - gfx->UnacknowledgedFrames--; gfx->TotalDecodedFrames++; + + if (!gfx->sendFrameAcks) + return error; + ack.frameId = pdu.frameId; ack.totalFramesDecoded = gfx->TotalDecodedFrames; @@ -586,40 +873,52 @@ static UINT rdpgfx_recv_end_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback, ack.queueDepth = SUSPEND_FRAME_ACKNOWLEDGEMENT; if (gfx->TotalDecodedFrames == 1) - if ((error = rdpgfx_send_frame_acknowledge_pdu(callback, &ack))) - WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_send_frame_acknowledge_pdu failed with error %"PRIu32"", error); + if ((error = rdpgfx_send_frame_acknowledge_pdu(context, &ack))) + WLog_Print(gfx->log, WLOG_ERROR, + "rdpgfx_send_frame_acknowledge_pdu failed with error %" PRIu32 "", + error); } else { ack.queueDepth = QUEUE_DEPTH_UNAVAILABLE; - if ((error = rdpgfx_send_frame_acknowledge_pdu(callback, &ack))) - WLog_Print(gfx->log, WLOG_DEBUG, "rdpgfx_send_frame_acknowledge_pdu failed with error %"PRIu32"", error); + if ((error = rdpgfx_send_frame_acknowledge_pdu(context, &ack))) + WLog_Print(gfx->log, WLOG_ERROR, + "rdpgfx_send_frame_acknowledge_pdu failed with error %" PRIu32 "", error); } - switch(gfx->ConnectionCaps.version) + switch (gfx->ConnectionCaps.version) { - case RDPGFX_CAPVERSION_10: - case RDPGFX_CAPVERSION_102: - case RDPGFX_CAPVERSION_103: - if (gfx->SendQoeAck) - { - RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU qoe; - UINT32 diff = (GetTickCountPrecise() - gfx->StartDecodingTime); - - if (diff > 65000) - diff = 0; - - qoe.frameId = pdu.frameId; - qoe.timestamp = gfx->StartDecodingTime; - qoe.timeDiffSE = diff; - qoe.timeDiffEDR = 1; - if ((error = rdpgfx_send_qoe_frame_acknowledge_pdu(callback, &qoe))) - WLog_Print(gfx->log, WLOG_DEBUG, "rdpgfx_send_frame_acknowledge_pdu failed with error %"PRIu32"", error); - } - break; - default: - break; + case RDPGFX_CAPVERSION_10: + case RDPGFX_CAPVERSION_102: + case RDPGFX_CAPVERSION_103: + case RDPGFX_CAPVERSION_104: + case RDPGFX_CAPVERSION_105: + case RDPGFX_CAPVERSION_106: + if (gfx->SendQoeAck) + { + RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU qoe; + UINT64 diff = (GetTickCount64() - gfx->StartDecodingTime); + + if (diff > 65000) + diff = 0; + + qoe.frameId = pdu.frameId; + qoe.timestamp = gfx->StartDecodingTime; + qoe.timeDiffSE = diff; + qoe.timeDiffEDR = 1; + + if ((error = rdpgfx_send_qoe_frame_acknowledge_pdu(context, &qoe))) + WLog_Print(gfx->log, WLOG_ERROR, + "rdpgfx_send_qoe_frame_acknowledge_pdu failed with error %" PRIu32 + "", + error); + } + + break; + + default: + break; } return error; @@ -630,12 +929,11 @@ static UINT rdpgfx_recv_end_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_recv_wire_to_surface_1_pdu(RDPGFX_CHANNEL_CALLBACK* callback, - wStream* s) +static UINT rdpgfx_recv_wire_to_surface_1_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) { RDPGFX_SURFACE_COMMAND cmd; RDPGFX_WIRE_TO_SURFACE_PDU_1 pdu; - RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin; UINT error; if (Stream_GetRemainingLength(s) < RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE) @@ -644,13 +942,13 @@ static UINT rdpgfx_recv_wire_to_surface_1_pdu(RDPGFX_CHANNEL_CALLBACK* callback, return ERROR_INVALID_DATA; } - Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */ - Stream_Read_UINT16(s, pdu.codecId); /* codecId (2 bytes) */ + Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */ + Stream_Read_UINT16(s, pdu.codecId); /* codecId (2 bytes) */ Stream_Read_UINT8(s, pdu.pixelFormat); /* pixelFormat (1 byte) */ if ((error = rdpgfx_read_rect16(s, &(pdu.destRect)))) /* destRect (8 bytes) */ { - WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_read_rect16 failed with error %"PRIu32"", error); + WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_read_rect16 failed with error %" PRIu32 "", error); return error; } @@ -664,14 +962,15 @@ static UINT rdpgfx_recv_wire_to_surface_1_pdu(RDPGFX_CHANNEL_CALLBACK* callback, pdu.bitmapData = Stream_Pointer(s); Stream_Seek(s, pdu.bitmapDataLength); - WLog_Print(gfx->log, WLOG_DEBUG, - "RecvWireToSurface1Pdu: surfaceId: %"PRIu16" codecId: %s (0x%04"PRIX16") pixelFormat: 0x%02"PRIX8" " - "destRect: left: %"PRIu16" top: %"PRIu16" right: %"PRIu16" bottom: %"PRIu16" bitmapDataLength: %"PRIu32"", - pdu.surfaceId, rdpgfx_get_codec_id_string(pdu.codecId), - pdu.codecId, pdu.pixelFormat, - pdu.destRect.left, pdu.destRect.top, - pdu.destRect.right, pdu.destRect.bottom, - pdu.bitmapDataLength); + + DEBUG_RDPGFX(gfx->log, + "RecvWireToSurface1Pdu: surfaceId: %" PRIu16 " codecId: %s (0x%04" PRIX16 + ") pixelFormat: 0x%02" PRIX8 " " + "destRect: left: %" PRIu16 " top: %" PRIu16 " right: %" PRIu16 " bottom: %" PRIu16 + " bitmapDataLength: %" PRIu32 "", + pdu.surfaceId, rdpgfx_get_codec_id_string(pdu.codecId), pdu.codecId, + pdu.pixelFormat, pdu.destRect.left, pdu.destRect.top, pdu.destRect.right, + pdu.destRect.bottom, pdu.bitmapDataLength); cmd.surfaceId = pdu.surfaceId; cmd.codecId = pdu.codecId; cmd.contextId = 0; @@ -701,7 +1000,7 @@ static UINT rdpgfx_recv_wire_to_surface_1_pdu(RDPGFX_CHANNEL_CALLBACK* callback, cmd.extra = NULL; if ((error = rdpgfx_decode(gfx, &cmd))) - WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_decode failed with error %"PRIu32"!", error); + WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_decode failed with error %" PRIu32 "!", error); return error; } @@ -711,13 +1010,12 @@ static UINT rdpgfx_recv_wire_to_surface_1_pdu(RDPGFX_CHANNEL_CALLBACK* callback, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_recv_wire_to_surface_2_pdu(RDPGFX_CHANNEL_CALLBACK* callback, - wStream* s) +static UINT rdpgfx_recv_wire_to_surface_2_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) { RDPGFX_SURFACE_COMMAND cmd; RDPGFX_WIRE_TO_SURFACE_PDU_2 pdu; - RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; - RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin; + RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface; UINT error = CHANNEL_RC_OK; if (Stream_GetRemainingLength(s) < RDPGFX_WIRE_TO_SURFACE_PDU_2_SIZE) @@ -726,21 +1024,38 @@ static UINT rdpgfx_recv_wire_to_surface_2_pdu(RDPGFX_CHANNEL_CALLBACK* callback, return ERROR_INVALID_DATA; } - Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */ - Stream_Read_UINT16(s, pdu.codecId); /* codecId (2 bytes) */ - Stream_Read_UINT32(s, pdu.codecContextId); /* codecContextId (4 bytes) */ - Stream_Read_UINT8(s, pdu.pixelFormat); /* pixelFormat (1 byte) */ + Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */ + Stream_Read_UINT16(s, pdu.codecId); /* codecId (2 bytes) */ + Stream_Read_UINT32(s, pdu.codecContextId); /* codecContextId (4 bytes) */ + Stream_Read_UINT8(s, pdu.pixelFormat); /* pixelFormat (1 byte) */ Stream_Read_UINT32(s, pdu.bitmapDataLength); /* bitmapDataLength (4 bytes) */ pdu.bitmapData = Stream_Pointer(s); Stream_Seek(s, pdu.bitmapDataLength); - WLog_Print(gfx->log, WLOG_DEBUG, "RecvWireToSurface2Pdu: surfaceId: %"PRIu16" codecId: %s (0x%04"PRIX16") " - "codecContextId: %"PRIu32" pixelFormat: 0x%02"PRIX8" bitmapDataLength: %"PRIu32"", - pdu.surfaceId, rdpgfx_get_codec_id_string(pdu.codecId), pdu.codecId, - pdu.codecContextId, pdu.pixelFormat, pdu.bitmapDataLength); + DEBUG_RDPGFX(gfx->log, + "RecvWireToSurface2Pdu: surfaceId: %" PRIu16 " codecId: %s (0x%04" PRIX16 ") " + "codecContextId: %" PRIu32 " pixelFormat: 0x%02" PRIX8 + " bitmapDataLength: %" PRIu32 "", + pdu.surfaceId, rdpgfx_get_codec_id_string(pdu.codecId), pdu.codecId, + pdu.codecContextId, pdu.pixelFormat, pdu.bitmapDataLength); + cmd.surfaceId = pdu.surfaceId; cmd.codecId = pdu.codecId; cmd.contextId = pdu.codecContextId; - cmd.format = pdu.pixelFormat; + + switch (pdu.pixelFormat) + { + case GFX_PIXEL_FORMAT_XRGB_8888: + cmd.format = PIXEL_FORMAT_BGRX32; + break; + + case GFX_PIXEL_FORMAT_ARGB_8888: + cmd.format = PIXEL_FORMAT_BGRA32; + break; + + default: + return ERROR_INVALID_DATA; + } + cmd.left = 0; cmd.top = 0; cmd.right = 0; @@ -756,7 +1071,8 @@ static UINT rdpgfx_recv_wire_to_surface_2_pdu(RDPGFX_CHANNEL_CALLBACK* callback, IFCALLRET(context->SurfaceCommand, error, context, &cmd); if (error) - WLog_Print(gfx->log, WLOG_ERROR, "context->SurfaceCommand failed with error %"PRIu32"", error); + WLog_Print(gfx->log, WLOG_ERROR, + "context->SurfaceCommand failed with error %" PRIu32 "", error); } return error; @@ -767,12 +1083,11 @@ static UINT rdpgfx_recv_wire_to_surface_2_pdu(RDPGFX_CHANNEL_CALLBACK* callback, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_recv_delete_encoding_context_pdu(RDPGFX_CHANNEL_CALLBACK* - callback, wStream* s) +static UINT rdpgfx_recv_delete_encoding_context_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) { RDPGFX_DELETE_ENCODING_CONTEXT_PDU pdu; - RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; - RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin; + RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface; UINT error = CHANNEL_RC_OK; if (Stream_GetRemainingLength(s) < 6) @@ -781,17 +1096,20 @@ static UINT rdpgfx_recv_delete_encoding_context_pdu(RDPGFX_CHANNEL_CALLBACK* return ERROR_INVALID_DATA; } - Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */ + Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */ Stream_Read_UINT32(s, pdu.codecContextId); /* codecContextId (4 bytes) */ - WLog_Print(gfx->log, WLOG_DEBUG, "RecvDeleteEncodingContextPdu: surfaceId: %"PRIu16" codecContextId: %"PRIu32"", - pdu.surfaceId, pdu.codecContextId); + + DEBUG_RDPGFX(gfx->log, + "RecvDeleteEncodingContextPdu: surfaceId: %" PRIu16 " codecContextId: %" PRIu32 "", + pdu.surfaceId, pdu.codecContextId); if (context) { IFCALLRET(context->DeleteEncodingContext, error, context, &pdu); if (error) - WLog_Print(gfx->log, WLOG_ERROR, "context->DeleteEncodingContext failed with error %"PRIu32"", error); + WLog_Print(gfx->log, WLOG_ERROR, + "context->DeleteEncodingContext failed with error %" PRIu32 "", error); } return error; @@ -807,8 +1125,8 @@ static UINT rdpgfx_recv_solid_fill_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStrea UINT16 index; RECTANGLE_16* fillRect; RDPGFX_SOLID_FILL_PDU pdu; - RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; - RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin; + RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface; UINT error; if (Stream_GetRemainingLength(s) < 8) @@ -821,7 +1139,8 @@ static UINT rdpgfx_recv_solid_fill_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStrea if ((error = rdpgfx_read_color32(s, &(pdu.fillPixel)))) /* fillPixel (4 bytes) */ { - WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_read_color32 failed with error %"PRIu32"!", error); + WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_read_color32 failed with error %" PRIu32 "!", + error); return error; } @@ -833,7 +1152,8 @@ static UINT rdpgfx_recv_solid_fill_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStrea return ERROR_INVALID_DATA; } - pdu.fillRects = (RECTANGLE_16*) calloc(pdu.fillRectCount, sizeof(RECTANGLE_16)); + pdu.fillRects = (RECTANGLE_16*)calloc(pdu.fillRectCount, sizeof(RECTANGLE_16)); + if (!pdu.fillRects) { WLog_Print(gfx->log, WLOG_ERROR, "calloc failed!"); @@ -846,21 +1166,22 @@ static UINT rdpgfx_recv_solid_fill_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStrea if ((error = rdpgfx_read_rect16(s, fillRect))) { - WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_read_rect16 failed with error %"PRIu32"!", error); + WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_read_rect16 failed with error %" PRIu32 "!", + error); free(pdu.fillRects); return error; } } - - WLog_Print(gfx->log, WLOG_DEBUG, "RecvSolidFillPdu: surfaceId: %"PRIu16" fillRectCount: %"PRIu16"", - pdu.surfaceId, pdu.fillRectCount); + DEBUG_RDPGFX(gfx->log, "RecvSolidFillPdu: surfaceId: %" PRIu16 " fillRectCount: %" PRIu16 "", + pdu.surfaceId, pdu.fillRectCount); if (context) { IFCALLRET(context->SolidFill, error, context, &pdu); if (error) - WLog_Print(gfx->log, WLOG_ERROR, "context->SolidFill failed with error %"PRIu32"", error); + WLog_Print(gfx->log, WLOG_ERROR, "context->SolidFill failed with error %" PRIu32 "", + error); } free(pdu.fillRects); @@ -872,14 +1193,13 @@ static UINT rdpgfx_recv_solid_fill_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStrea * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_recv_surface_to_surface_pdu(RDPGFX_CHANNEL_CALLBACK* - callback, wStream* s) +static UINT rdpgfx_recv_surface_to_surface_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) { UINT16 index; RDPGFX_POINT16* destPt; RDPGFX_SURFACE_TO_SURFACE_PDU pdu; - RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; - RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin; + RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface; UINT error; if (Stream_GetRemainingLength(s) < 14) @@ -888,12 +1208,13 @@ static UINT rdpgfx_recv_surface_to_surface_pdu(RDPGFX_CHANNEL_CALLBACK* return ERROR_INVALID_DATA; } - Stream_Read_UINT16(s, pdu.surfaceIdSrc); /* surfaceIdSrc (2 bytes) */ + Stream_Read_UINT16(s, pdu.surfaceIdSrc); /* surfaceIdSrc (2 bytes) */ Stream_Read_UINT16(s, pdu.surfaceIdDest); /* surfaceIdDest (2 bytes) */ if ((error = rdpgfx_read_rect16(s, &(pdu.rectSrc)))) /* rectSrc (8 bytes ) */ { - WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_read_rect16 failed with error %"PRIu32"!", error); + WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_read_rect16 failed with error %" PRIu32 "!", + error); return error; } @@ -905,7 +1226,8 @@ static UINT rdpgfx_recv_surface_to_surface_pdu(RDPGFX_CHANNEL_CALLBACK* return ERROR_INVALID_DATA; } - pdu.destPts = (RDPGFX_POINT16*) calloc(pdu.destPtsCount, sizeof(RDPGFX_POINT16)); + pdu.destPts = (RDPGFX_POINT16*)calloc(pdu.destPtsCount, sizeof(RDPGFX_POINT16)); + if (!pdu.destPts) { WLog_Print(gfx->log, WLOG_ERROR, "calloc failed!"); @@ -918,24 +1240,27 @@ static UINT rdpgfx_recv_surface_to_surface_pdu(RDPGFX_CHANNEL_CALLBACK* if ((error = rdpgfx_read_point16(s, destPt))) { - WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_read_point16 failed with error %"PRIu32"!", error); + WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_read_point16 failed with error %" PRIu32 "!", + error); free(pdu.destPts); return error; } } - WLog_Print(gfx->log, WLOG_DEBUG, "RecvSurfaceToSurfacePdu: surfaceIdSrc: %"PRIu16" surfaceIdDest: %"PRIu16" " - "left: %"PRIu16" top: %"PRIu16" right: %"PRIu16" bottom: %"PRIu16" destPtsCount: %"PRIu16"", - pdu.surfaceIdSrc, pdu.surfaceIdDest, - pdu.rectSrc.left, pdu.rectSrc.top, pdu.rectSrc.right, pdu.rectSrc.bottom, - pdu.destPtsCount); + DEBUG_RDPGFX(gfx->log, + "RecvSurfaceToSurfacePdu: surfaceIdSrc: %" PRIu16 " surfaceIdDest: %" PRIu16 " " + "left: %" PRIu16 " top: %" PRIu16 " right: %" PRIu16 " bottom: %" PRIu16 + " destPtsCount: %" PRIu16 "", + pdu.surfaceIdSrc, pdu.surfaceIdDest, pdu.rectSrc.left, pdu.rectSrc.top, + pdu.rectSrc.right, pdu.rectSrc.bottom, pdu.destPtsCount); if (context) { IFCALLRET(context->SurfaceToSurface, error, context, &pdu); if (error) - WLog_Print(gfx->log, WLOG_ERROR, "context->SurfaceToSurface failed with error %"PRIu32"", error); + WLog_Print(gfx->log, WLOG_ERROR, + "context->SurfaceToSurface failed with error %" PRIu32 "", error); } free(pdu.destPts); @@ -947,12 +1272,11 @@ static UINT rdpgfx_recv_surface_to_surface_pdu(RDPGFX_CHANNEL_CALLBACK* * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_recv_surface_to_cache_pdu(RDPGFX_CHANNEL_CALLBACK* callback, - wStream* s) +static UINT rdpgfx_recv_surface_to_cache_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) { RDPGFX_SURFACE_TO_CACHE_PDU pdu; - RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; - RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin; + RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface; UINT error; if (Stream_GetRemainingLength(s) < 20) @@ -962,28 +1286,30 @@ static UINT rdpgfx_recv_surface_to_cache_pdu(RDPGFX_CHANNEL_CALLBACK* callback, } Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */ - Stream_Read_UINT64(s, pdu.cacheKey); /* cacheKey (8 bytes) */ + Stream_Read_UINT64(s, pdu.cacheKey); /* cacheKey (8 bytes) */ Stream_Read_UINT16(s, pdu.cacheSlot); /* cacheSlot (2 bytes) */ if ((error = rdpgfx_read_rect16(s, &(pdu.rectSrc)))) /* rectSrc (8 bytes ) */ { - WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_read_rect16 failed with error %"PRIu32"!", error); + WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_read_rect16 failed with error %" PRIu32 "!", + error); return error; } - WLog_Print(gfx->log, WLOG_DEBUG, - "RecvSurfaceToCachePdu: surfaceId: %"PRIu16" cacheKey: 0x%016"PRIX64" cacheSlot: %"PRIu16" " - "left: %"PRIu16" top: %"PRIu16" right: %"PRIu16" bottom: %"PRIu16"", - pdu.surfaceId, pdu.cacheKey, pdu.cacheSlot, - pdu.rectSrc.left, pdu.rectSrc.top, - pdu.rectSrc.right, pdu.rectSrc.bottom); + DEBUG_RDPGFX(gfx->log, + "RecvSurfaceToCachePdu: surfaceId: %" PRIu16 " cacheKey: 0x%016" PRIX64 + " cacheSlot: %" PRIu16 " " + "left: %" PRIu16 " top: %" PRIu16 " right: %" PRIu16 " bottom: %" PRIu16 "", + pdu.surfaceId, pdu.cacheKey, pdu.cacheSlot, pdu.rectSrc.left, pdu.rectSrc.top, + pdu.rectSrc.right, pdu.rectSrc.bottom); if (context) { IFCALLRET(context->SurfaceToCache, error, context, &pdu); if (error) - WLog_Print(gfx->log, WLOG_ERROR, "context->SurfaceToCache failed with error %"PRIu32"", error); + WLog_Print(gfx->log, WLOG_ERROR, + "context->SurfaceToCache failed with error %" PRIu32 "", error); } return error; @@ -994,14 +1320,13 @@ static UINT rdpgfx_recv_surface_to_cache_pdu(RDPGFX_CHANNEL_CALLBACK* callback, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_recv_cache_to_surface_pdu(RDPGFX_CHANNEL_CALLBACK* callback, - wStream* s) +static UINT rdpgfx_recv_cache_to_surface_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) { UINT16 index; RDPGFX_POINT16* destPt; RDPGFX_CACHE_TO_SURFACE_PDU pdu; - RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; - RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin; + RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface; UINT error = CHANNEL_RC_OK; if (Stream_GetRemainingLength(s) < 6) @@ -1010,8 +1335,8 @@ static UINT rdpgfx_recv_cache_to_surface_pdu(RDPGFX_CHANNEL_CALLBACK* callback, return ERROR_INVALID_DATA; } - Stream_Read_UINT16(s, pdu.cacheSlot); /* cacheSlot (2 bytes) */ - Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */ + Stream_Read_UINT16(s, pdu.cacheSlot); /* cacheSlot (2 bytes) */ + Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */ Stream_Read_UINT16(s, pdu.destPtsCount); /* destPtsCount (2 bytes) */ if (Stream_GetRemainingLength(s) < (size_t)(pdu.destPtsCount * 4)) @@ -1020,7 +1345,8 @@ static UINT rdpgfx_recv_cache_to_surface_pdu(RDPGFX_CHANNEL_CALLBACK* callback, return ERROR_INVALID_DATA; } - pdu.destPts = (RDPGFX_POINT16*) calloc(pdu.destPtsCount, sizeof(RDPGFX_POINT16)); + pdu.destPts = (RDPGFX_POINT16*)calloc(pdu.destPtsCount, sizeof(RDPGFX_POINT16)); + if (!pdu.destPts) { WLog_Print(gfx->log, WLOG_ERROR, "calloc failed!"); @@ -1033,22 +1359,25 @@ static UINT rdpgfx_recv_cache_to_surface_pdu(RDPGFX_CHANNEL_CALLBACK* callback, if ((error = rdpgfx_read_point16(s, destPt))) { - WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_read_point16 failed with error %"PRIu32"", error); + WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_read_point16 failed with error %" PRIu32 "", + error); free(pdu.destPts); return error; } } - WLog_Print(gfx->log, WLOG_DEBUG, - "RdpGfxRecvCacheToSurfacePdu: cacheSlot: %"PRIu16" surfaceId: %"PRIu16" destPtsCount: %"PRIu16"", - pdu.cacheSlot, pdu.surfaceId, pdu.destPtsCount); + DEBUG_RDPGFX(gfx->log, + "RdpGfxRecvCacheToSurfacePdu: cacheSlot: %" PRIu16 " surfaceId: %" PRIu16 + " destPtsCount: %" PRIu16 "", + pdu.cacheSlot, pdu.surfaceId, pdu.destPtsCount); if (context) { IFCALLRET(context->CacheToSurface, error, context, &pdu); if (error) - WLog_Print(gfx->log, WLOG_ERROR, "context->CacheToSurface failed with error %"PRIu32"", error); + WLog_Print(gfx->log, WLOG_ERROR, + "context->CacheToSurface failed with error %" PRIu32 "", error); } free(pdu.destPts); @@ -1060,12 +1389,11 @@ static UINT rdpgfx_recv_cache_to_surface_pdu(RDPGFX_CHANNEL_CALLBACK* callback, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_recv_map_surface_to_output_pdu(RDPGFX_CHANNEL_CALLBACK* - callback, wStream* s) +static UINT rdpgfx_recv_map_surface_to_output_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) { RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU pdu; - RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; - RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin; + RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface; UINT error = CHANNEL_RC_OK; if (Stream_GetRemainingLength(s) < 12) @@ -1074,20 +1402,60 @@ static UINT rdpgfx_recv_map_surface_to_output_pdu(RDPGFX_CHANNEL_CALLBACK* return ERROR_INVALID_DATA; } - Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */ - Stream_Read_UINT16(s, pdu.reserved); /* reserved (2 bytes) */ + Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */ + Stream_Read_UINT16(s, pdu.reserved); /* reserved (2 bytes) */ Stream_Read_UINT32(s, pdu.outputOriginX); /* outputOriginX (4 bytes) */ Stream_Read_UINT32(s, pdu.outputOriginY); /* outputOriginY (4 bytes) */ - WLog_Print(gfx->log, WLOG_DEBUG, - "RecvMapSurfaceToOutputPdu: surfaceId: %"PRIu16" outputOriginX: %"PRIu32" outputOriginY: %"PRIu32"", - pdu.surfaceId, pdu.outputOriginX, pdu.outputOriginY); + DEBUG_RDPGFX(gfx->log, + "RecvMapSurfaceToOutputPdu: surfaceId: %" PRIu16 " outputOriginX: %" PRIu32 + " outputOriginY: %" PRIu32 "", + pdu.surfaceId, pdu.outputOriginX, pdu.outputOriginY); if (context) { IFCALLRET(context->MapSurfaceToOutput, error, context, &pdu); if (error) - WLog_Print(gfx->log, WLOG_ERROR, "context->MapSurfaceToOutput failed with error %"PRIu32"", error); + WLog_Print(gfx->log, WLOG_ERROR, + "context->MapSurfaceToOutput failed with error %" PRIu32 "", error); + } + + return error; +} + +static UINT rdpgfx_recv_map_surface_to_scaled_output_pdu(RDPGFX_CHANNEL_CALLBACK* callback, + wStream* s) +{ + RDPGFX_MAP_SURFACE_TO_SCALED_OUTPUT_PDU pdu; + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin; + RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface; + UINT error = CHANNEL_RC_OK; + + if (Stream_GetRemainingLength(s) < 20) + { + WLog_Print(gfx->log, WLOG_ERROR, "not enough data!"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */ + Stream_Read_UINT16(s, pdu.reserved); /* reserved (2 bytes) */ + Stream_Read_UINT32(s, pdu.outputOriginX); /* outputOriginX (4 bytes) */ + Stream_Read_UINT32(s, pdu.outputOriginY); /* outputOriginY (4 bytes) */ + Stream_Read_UINT32(s, pdu.targetWidth); /* targetWidth (4 bytes) */ + Stream_Read_UINT32(s, pdu.targetHeight); /* targetHeight (4 bytes) */ + DEBUG_RDPGFX(gfx->log, + "RecvMapSurfaceToScaledOutputPdu: surfaceId: %" PRIu16 " outputOriginX: %" PRIu32 + " outputOriginY: %" PRIu32 " targetWidth: %" PRIu32 " targetHeight: %" PRIu32, + pdu.surfaceId, pdu.outputOriginX, pdu.outputOriginY, pdu.targetWidth, + pdu.targetHeight); + + if (context) + { + IFCALLRET(context->MapSurfaceToScaledOutput, error, context, &pdu); + + if (error) + WLog_Print(gfx->log, WLOG_ERROR, + "context->MapSurfaceToScaledOutput failed with error %" PRIu32 "", error); } return error; @@ -1098,12 +1466,11 @@ static UINT rdpgfx_recv_map_surface_to_output_pdu(RDPGFX_CHANNEL_CALLBACK* * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_recv_map_surface_to_window_pdu(RDPGFX_CHANNEL_CALLBACK* callback, - wStream* s) +static UINT rdpgfx_recv_map_surface_to_window_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) { RDPGFX_MAP_SURFACE_TO_WINDOW_PDU pdu; - RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; - RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin; + RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface; UINT error = CHANNEL_RC_OK; if (Stream_GetRemainingLength(s) < 18) @@ -1112,20 +1479,61 @@ static UINT rdpgfx_recv_map_surface_to_window_pdu(RDPGFX_CHANNEL_CALLBACK* callb return ERROR_INVALID_DATA; } - Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */ - Stream_Read_UINT64(s, pdu.windowId); /* windowId (8 bytes) */ - Stream_Read_UINT32(s, pdu.mappedWidth); /* mappedWidth (4 bytes) */ + Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */ + Stream_Read_UINT64(s, pdu.windowId); /* windowId (8 bytes) */ + Stream_Read_UINT32(s, pdu.mappedWidth); /* mappedWidth (4 bytes) */ Stream_Read_UINT32(s, pdu.mappedHeight); /* mappedHeight (4 bytes) */ - WLog_Print(gfx->log, WLOG_DEBUG, - "RecvMapSurfaceToWindowPdu: surfaceId: %"PRIu16" windowId: 0x%016"PRIX64" mappedWidth: %"PRIu32" mappedHeight: %"PRIu32"", - pdu.surfaceId, pdu.windowId, pdu.mappedWidth, pdu.mappedHeight); + DEBUG_RDPGFX(gfx->log, + "RecvMapSurfaceToWindowPdu: surfaceId: %" PRIu16 " windowId: 0x%016" PRIX64 + " mappedWidth: %" PRIu32 " mappedHeight: %" PRIu32 "", + pdu.surfaceId, pdu.windowId, pdu.mappedWidth, pdu.mappedHeight); if (context && context->MapSurfaceToWindow) { IFCALLRET(context->MapSurfaceToWindow, error, context, &pdu); if (error) - WLog_Print(gfx->log, WLOG_ERROR, "context->MapSurfaceToWindow failed with error %"PRIu32"", error); + WLog_Print(gfx->log, WLOG_ERROR, + "context->MapSurfaceToWindow failed with error %" PRIu32 "", error); + } + + return error; +} + +static UINT rdpgfx_recv_map_surface_to_scaled_window_pdu(RDPGFX_CHANNEL_CALLBACK* callback, + wStream* s) +{ + RDPGFX_MAP_SURFACE_TO_SCALED_WINDOW_PDU pdu; + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin; + RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface; + UINT error = CHANNEL_RC_OK; + + if (Stream_GetRemainingLength(s) < 26) + { + WLog_Print(gfx->log, WLOG_ERROR, "not enough data!"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT16(s, pdu.surfaceId); /* surfaceId (2 bytes) */ + Stream_Read_UINT64(s, pdu.windowId); /* windowId (8 bytes) */ + Stream_Read_UINT32(s, pdu.mappedWidth); /* mappedWidth (4 bytes) */ + Stream_Read_UINT32(s, pdu.mappedHeight); /* mappedHeight (4 bytes) */ + Stream_Read_UINT32(s, pdu.targetWidth); /* targetWidth (4 bytes) */ + Stream_Read_UINT32(s, pdu.targetHeight); /* targetHeight (4 bytes) */ + DEBUG_RDPGFX(gfx->log, + "RecvMapSurfaceToScaledWindowPdu: surfaceId: %" PRIu16 " windowId: 0x%016" PRIX64 + " mappedWidth: %" PRIu32 " mappedHeight: %" PRIu32 " targetWidth: %" PRIu32 + " targetHeight: %" PRIu32 "", + pdu.surfaceId, pdu.windowId, pdu.mappedWidth, pdu.mappedHeight, pdu.targetWidth, + pdu.targetHeight); + + if (context && context->MapSurfaceToScaledWindow) + { + IFCALLRET(context->MapSurfaceToScaledWindow, error, context, &pdu); + + if (error) + WLog_Print(gfx->log, WLOG_ERROR, + "context->MapSurfaceToScaledWindow failed with error %" PRIu32 "", error); } return error; @@ -1141,129 +1549,166 @@ static UINT rdpgfx_recv_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) size_t beg, end; RDPGFX_HEADER header; UINT error; - RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; - + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin; beg = Stream_GetPosition(s); if ((error = rdpgfx_read_header(s, &header))) { - WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_read_header failed with error %"PRIu32"!", error); + WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_read_header failed with error %" PRIu32 "!", + error); return error; } - WLog_Print(gfx->log, WLOG_DEBUG, "cmdId: %s (0x%04"PRIX16") flags: 0x%04"PRIX16" pduLength: %"PRIu32"", - rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId, header.flags, - header.pduLength); + DEBUG_RDPGFX( + gfx->log, "cmdId: %s (0x%04" PRIX16 ") flags: 0x%04" PRIX16 " pduLength: %" PRIu32 "", + rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId, header.flags, header.pduLength); switch (header.cmdId) { case RDPGFX_CMDID_WIRETOSURFACE_1: if ((error = rdpgfx_recv_wire_to_surface_1_pdu(callback, s))) - WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_wire_to_surface_1_pdu failed with error %"PRIu32"!", - error); + WLog_Print(gfx->log, WLOG_ERROR, + "rdpgfx_recv_wire_to_surface_1_pdu failed with error %" PRIu32 "!", + error); break; case RDPGFX_CMDID_WIRETOSURFACE_2: if ((error = rdpgfx_recv_wire_to_surface_2_pdu(callback, s))) - WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_wire_to_surface_2_pdu failed with error %"PRIu32"!", - error); + WLog_Print(gfx->log, WLOG_ERROR, + "rdpgfx_recv_wire_to_surface_2_pdu failed with error %" PRIu32 "!", + error); break; case RDPGFX_CMDID_DELETEENCODINGCONTEXT: if ((error = rdpgfx_recv_delete_encoding_context_pdu(callback, s))) - WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_delete_encoding_context_pdu failed with error %"PRIu32"!", - error); + WLog_Print(gfx->log, WLOG_ERROR, + "rdpgfx_recv_delete_encoding_context_pdu failed with error %" PRIu32 "!", + error); break; case RDPGFX_CMDID_SOLIDFILL: if ((error = rdpgfx_recv_solid_fill_pdu(callback, s))) - WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_solid_fill_pdu failed with error %"PRIu32"!", error); + WLog_Print(gfx->log, WLOG_ERROR, + "rdpgfx_recv_solid_fill_pdu failed with error %" PRIu32 "!", error); break; case RDPGFX_CMDID_SURFACETOSURFACE: if ((error = rdpgfx_recv_surface_to_surface_pdu(callback, s))) - WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_surface_to_surface_pdu failed with error %"PRIu32"!", - error); + WLog_Print(gfx->log, WLOG_ERROR, + "rdpgfx_recv_surface_to_surface_pdu failed with error %" PRIu32 "!", + error); break; case RDPGFX_CMDID_SURFACETOCACHE: if ((error = rdpgfx_recv_surface_to_cache_pdu(callback, s))) - WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_surface_to_cache_pdu failed with error %"PRIu32"!", error); + WLog_Print(gfx->log, WLOG_ERROR, + "rdpgfx_recv_surface_to_cache_pdu failed with error %" PRIu32 "!", + error); break; case RDPGFX_CMDID_CACHETOSURFACE: if ((error = rdpgfx_recv_cache_to_surface_pdu(callback, s))) - WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_cache_to_surface_pdu failed with error %"PRIu32"!", error); + WLog_Print(gfx->log, WLOG_ERROR, + "rdpgfx_recv_cache_to_surface_pdu failed with error %" PRIu32 "!", + error); break; case RDPGFX_CMDID_EVICTCACHEENTRY: if ((error = rdpgfx_recv_evict_cache_entry_pdu(callback, s))) - WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_evict_cache_entry_pdu failed with error %"PRIu32"!", - error); + WLog_Print(gfx->log, WLOG_ERROR, + "rdpgfx_recv_evict_cache_entry_pdu failed with error %" PRIu32 "!", + error); break; case RDPGFX_CMDID_CREATESURFACE: if ((error = rdpgfx_recv_create_surface_pdu(callback, s))) - WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_create_surface_pdu failed with error %"PRIu32"!", error); + WLog_Print(gfx->log, WLOG_ERROR, + "rdpgfx_recv_create_surface_pdu failed with error %" PRIu32 "!", error); break; case RDPGFX_CMDID_DELETESURFACE: if ((error = rdpgfx_recv_delete_surface_pdu(callback, s))) - WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_delete_surface_pdu failed with error %"PRIu32"!", error); + WLog_Print(gfx->log, WLOG_ERROR, + "rdpgfx_recv_delete_surface_pdu failed with error %" PRIu32 "!", error); break; case RDPGFX_CMDID_STARTFRAME: if ((error = rdpgfx_recv_start_frame_pdu(callback, s))) - WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_start_frame_pdu failed with error %"PRIu32"!", error); + WLog_Print(gfx->log, WLOG_ERROR, + "rdpgfx_recv_start_frame_pdu failed with error %" PRIu32 "!", error); break; case RDPGFX_CMDID_ENDFRAME: if ((error = rdpgfx_recv_end_frame_pdu(callback, s))) - WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_end_frame_pdu failed with error %"PRIu32"!", error); + WLog_Print(gfx->log, WLOG_ERROR, + "rdpgfx_recv_end_frame_pdu failed with error %" PRIu32 "!", error); break; case RDPGFX_CMDID_RESETGRAPHICS: if ((error = rdpgfx_recv_reset_graphics_pdu(callback, s))) - WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_reset_graphics_pdu failed with error %"PRIu32"!", error); + WLog_Print(gfx->log, WLOG_ERROR, + "rdpgfx_recv_reset_graphics_pdu failed with error %" PRIu32 "!", error); break; case RDPGFX_CMDID_MAPSURFACETOOUTPUT: if ((error = rdpgfx_recv_map_surface_to_output_pdu(callback, s))) - WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_map_surface_to_output_pdu failed with error %"PRIu32"!", - error); + WLog_Print(gfx->log, WLOG_ERROR, + "rdpgfx_recv_map_surface_to_output_pdu failed with error %" PRIu32 "!", + error); break; case RDPGFX_CMDID_CACHEIMPORTREPLY: if ((error = rdpgfx_recv_cache_import_reply_pdu(callback, s))) - WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_cache_import_reply_pdu failed with error %"PRIu32"!", - error); + WLog_Print(gfx->log, WLOG_ERROR, + "rdpgfx_recv_cache_import_reply_pdu failed with error %" PRIu32 "!", + error); break; case RDPGFX_CMDID_CAPSCONFIRM: if ((error = rdpgfx_recv_caps_confirm_pdu(callback, s))) - WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_caps_confirm_pdu failed with error %"PRIu32"!", error); + WLog_Print(gfx->log, WLOG_ERROR, + "rdpgfx_recv_caps_confirm_pdu failed with error %" PRIu32 "!", error); break; case RDPGFX_CMDID_MAPSURFACETOWINDOW: if ((error = rdpgfx_recv_map_surface_to_window_pdu(callback, s))) - WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_map_surface_to_window_pdu failed with error %"PRIu32"!", - error); + WLog_Print(gfx->log, WLOG_ERROR, + "rdpgfx_recv_map_surface_to_window_pdu failed with error %" PRIu32 "!", + error); + + break; + + case RDPGFX_CMDID_MAPSURFACETOSCALEDWINDOW: + if ((error = rdpgfx_recv_map_surface_to_scaled_window_pdu(callback, s))) + WLog_Print(gfx->log, WLOG_ERROR, + "rdpgfx_recv_map_surface_to_scaled_window_pdu failed with error %" PRIu32 + "!", + error); + + break; + + case RDPGFX_CMDID_MAPSURFACETOSCALEDOUTPUT: + if ((error = rdpgfx_recv_map_surface_to_scaled_output_pdu(callback, s))) + WLog_Print(gfx->log, WLOG_ERROR, + "rdpgfx_recv_map_surface_to_scaled_output_pdu failed with error %" PRIu32 + "!", + error); break; @@ -1274,8 +1719,8 @@ static UINT rdpgfx_recv_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) if (error) { - WLog_Print(gfx->log, WLOG_ERROR, "Error while parsing GFX cmdId: %s (0x%04"PRIX16")", - rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId); + WLog_Print(gfx->log, WLOG_ERROR, "Error while processing GFX cmdId: %s (0x%04" PRIX16 ")", + rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId); return error; } @@ -1283,8 +1728,9 @@ static UINT rdpgfx_recv_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) if (end != (beg + header.pduLength)) { - WLog_Print(gfx->log, WLOG_ERROR, "Unexpected gfx pdu end: Actual: %d, Expected: %"PRIu32"", - end, (beg + header.pduLength)); + WLog_Print(gfx->log, WLOG_ERROR, + "Unexpected gfx pdu end: Actual: %d, Expected: %" PRIu32 "", end, + (beg + header.pduLength)); Stream_SetPosition(s, (beg + header.pduLength)); } @@ -1296,18 +1742,17 @@ static UINT rdpgfx_recv_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s) * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_on_data_received(IWTSVirtualChannelCallback* - pChannelCallback, wStream* data) +static UINT rdpgfx_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data) { wStream* s; int status = 0; UINT32 DstSize = 0; BYTE* pDstData = NULL; - RDPGFX_CHANNEL_CALLBACK* callback = (RDPGFX_CHANNEL_CALLBACK*) pChannelCallback; - RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; + RDPGFX_CHANNEL_CALLBACK* callback = (RDPGFX_CHANNEL_CALLBACK*)pChannelCallback; + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin; UINT error = CHANNEL_RC_OK; status = zgfx_decompress(gfx->zgfx, Stream_Pointer(data), Stream_GetRemainingLength(data), - &pDstData, &DstSize, 0); + &pDstData, &DstSize, 0); if (status < 0) { @@ -1316,6 +1761,7 @@ static UINT rdpgfx_on_data_received(IWTSVirtualChannelCallback* } s = Stream_New(pDstData, DstSize); + if (!s) { WLog_Print(gfx->log, WLOG_ERROR, "calloc failed!"); @@ -1326,7 +1772,8 @@ static UINT rdpgfx_on_data_received(IWTSVirtualChannelCallback* { if ((error = rdpgfx_recv_pdu(callback, s))) { - WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_pdu failed with error %"PRIu32"!", error); + WLog_Print(gfx->log, WLOG_ERROR, "rdpgfx_recv_pdu failed with error %" PRIu32 "!", + error); break; } } @@ -1342,9 +1789,26 @@ static UINT rdpgfx_on_data_received(IWTSVirtualChannelCallback* */ static UINT rdpgfx_on_open(IWTSVirtualChannelCallback* pChannelCallback) { - RDPGFX_CHANNEL_CALLBACK* callback = (RDPGFX_CHANNEL_CALLBACK*) pChannelCallback; - WLog_DBG(TAG, "OnOpen"); - return rdpgfx_send_caps_advertise_pdu(callback); + RDPGFX_CHANNEL_CALLBACK* callback = (RDPGFX_CHANNEL_CALLBACK*)pChannelCallback; + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin; + RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface; + UINT error = CHANNEL_RC_OK; + BOOL do_caps_advertise = TRUE; + gfx->sendFrameAcks = TRUE; + + if (context) + { + IFCALLRET(context->OnOpen, error, context, &do_caps_advertise, &gfx->sendFrameAcks); + + if (error) + WLog_Print(gfx->log, WLOG_ERROR, "context->OnOpen failed with error %" PRIu32 "", + error); + } + + if (do_caps_advertise) + error = rdpgfx_send_supported_caps(callback); + + return error; } /** @@ -1354,56 +1818,21 @@ static UINT rdpgfx_on_open(IWTSVirtualChannelCallback* pChannelCallback) */ static UINT rdpgfx_on_close(IWTSVirtualChannelCallback* pChannelCallback) { - int count; - int index; - ULONG_PTR* pKeys = NULL; - RDPGFX_CHANNEL_CALLBACK* callback = (RDPGFX_CHANNEL_CALLBACK*) pChannelCallback; - RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) callback->plugin; - RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; + RDPGFX_CHANNEL_CALLBACK* callback = (RDPGFX_CHANNEL_CALLBACK*)pChannelCallback; + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin; + RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface; + + DEBUG_RDPGFX(gfx->log, "OnClose"); + free_surfaces(context, gfx->SurfaceTable); + evict_cache_slots(context, gfx->MaxCacheSlots, gfx->CacheSlots); - WLog_Print(gfx->log, WLOG_DEBUG, "OnClose"); free(callback); gfx->UnacknowledgedFrames = 0; gfx->TotalDecodedFrames = 0; - if (gfx->zgfx) - { - zgfx_context_free(gfx->zgfx); - gfx->zgfx = zgfx_context_new(FALSE); - - if (!gfx->zgfx) - return CHANNEL_RC_NO_MEMORY; - } - - count = HashTable_GetKeys(gfx->SurfaceTable, &pKeys); - - for (index = 0; index < count; index++) + if (context) { - RDPGFX_DELETE_SURFACE_PDU pdu; - pdu.surfaceId = ((UINT16) pKeys[index]) - 1; - - if (context && context->DeleteSurface) - { - context->DeleteSurface(context, &pdu); - } - } - - free(pKeys); - - for (index = 0; index < gfx->MaxCacheSlot; index++) - { - if (gfx->CacheSlots[index]) - { - RDPGFX_EVICT_CACHE_ENTRY_PDU pdu; - pdu.cacheSlot = (UINT16) index; - - if (context && context->EvictCacheEntry) - { - context->EvictCacheEntry(context, &pdu); - } - - gfx->CacheSlots[index] = NULL; - } + IFCALL(context->OnClose, context); } return CHANNEL_RC_OK; @@ -1414,15 +1843,15 @@ static UINT rdpgfx_on_close(IWTSVirtualChannelCallback* pChannelCallback) * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_on_new_channel_connection(IWTSListenerCallback* - pListenerCallback, - IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept, - IWTSVirtualChannelCallback** ppCallback) +static UINT rdpgfx_on_new_channel_connection(IWTSListenerCallback* pListenerCallback, + IWTSVirtualChannel* pChannel, BYTE* Data, + BOOL* pbAccept, + IWTSVirtualChannelCallback** ppCallback) { RDPGFX_CHANNEL_CALLBACK* callback; RDPGFX_LISTENER_CALLBACK* listener_callback = (RDPGFX_LISTENER_CALLBACK*)pListenerCallback; + callback = (RDPGFX_CHANNEL_CALLBACK*)calloc(1, sizeof(RDPGFX_CHANNEL_CALLBACK)); - callback = (RDPGFX_CHANNEL_CALLBACK*) calloc(1, sizeof(RDPGFX_CHANNEL_CALLBACK)); if (!callback) { WLog_ERR(TAG, "calloc failed!"); @@ -1436,7 +1865,7 @@ static UINT rdpgfx_on_new_channel_connection(IWTSListenerCallback* callback->channel_mgr = listener_callback->channel_mgr; callback->channel = pChannel; listener_callback->channel_callback = callback; - *ppCallback = (IWTSVirtualChannelCallback*) callback; + *ppCallback = (IWTSVirtualChannelCallback*)callback; return CHANNEL_RC_OK; } @@ -1445,13 +1874,12 @@ static UINT rdpgfx_on_new_channel_connection(IWTSListenerCallback* * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_plugin_initialize(IWTSPlugin* pPlugin, - IWTSVirtualChannelManager* pChannelMgr) +static UINT rdpgfx_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr) { UINT error; - RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) pPlugin; + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)pPlugin; + gfx->listener_callback = (RDPGFX_LISTENER_CALLBACK*)calloc(1, sizeof(RDPGFX_LISTENER_CALLBACK)); - gfx->listener_callback = (RDPGFX_LISTENER_CALLBACK*) calloc(1, sizeof(RDPGFX_LISTENER_CALLBACK)); if (!gfx->listener_callback) { WLog_Print(gfx->log, WLOG_ERROR, "calloc failed!"); @@ -1462,9 +1890,9 @@ static UINT rdpgfx_plugin_initialize(IWTSPlugin* pPlugin, gfx->listener_callback->plugin = pPlugin; gfx->listener_callback->channel_mgr = pChannelMgr; error = pChannelMgr->CreateListener(pChannelMgr, RDPGFX_DVC_CHANNEL_NAME, 0, - (IWTSListenerCallback*) gfx->listener_callback, &(gfx->listener)); + &gfx->listener_callback->iface, &(gfx->listener)); gfx->listener->pInterface = gfx->iface.pInterface; - WLog_Print(gfx->log, WLOG_DEBUG, "Initialize"); + DEBUG_RDPGFX(gfx->log, "Initialize"); return error; } @@ -1475,77 +1903,16 @@ static UINT rdpgfx_plugin_initialize(IWTSPlugin* pPlugin, */ static UINT rdpgfx_plugin_terminated(IWTSPlugin* pPlugin) { - int count; - int index; - ULONG_PTR* pKeys = NULL; - RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) pPlugin; - RdpgfxClientContext* context = (RdpgfxClientContext*) gfx->iface.pInterface; - UINT error = CHANNEL_RC_OK; - WLog_Print(gfx->log, WLOG_DEBUG, "Terminated"); - - if (gfx->listener_callback) + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)pPlugin; + RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface; + DEBUG_RDPGFX(gfx->log, "Terminated"); + if (gfx && gfx->listener_callback) { - free(gfx->listener_callback); - gfx->listener_callback = NULL; - } - - if (gfx->zgfx) - { - zgfx_context_free(gfx->zgfx); - gfx->zgfx = NULL; - } - - count = HashTable_GetKeys(gfx->SurfaceTable, &pKeys); - - for (index = 0; index < count; index++) - { - RDPGFX_DELETE_SURFACE_PDU pdu; - pdu.surfaceId = ((UINT16) pKeys[index]) - 1; - - if (context) - { - IFCALLRET(context->DeleteSurface, error, context, &pdu); - - if (error) - { - WLog_Print(gfx->log, WLOG_ERROR, "context->DeleteSurface failed with error %"PRIu32"", error); - free(pKeys); - free(context); - free(gfx); - return error; - } - } - } - - free(pKeys); - HashTable_Free(gfx->SurfaceTable); - - for (index = 0; index < gfx->MaxCacheSlot; index++) - { - if (gfx->CacheSlots[index]) - { - RDPGFX_EVICT_CACHE_ENTRY_PDU pdu; - pdu.cacheSlot = (UINT16) index; - - if (context) - { - IFCALLRET(context->EvictCacheEntry, error, context, &pdu); - - if (error) - { - WLog_Print(gfx->log, WLOG_ERROR, "context->EvictCacheEntry failed with error %"PRIu32"", error); - free(context); - free(gfx); - return error; - } - } - - gfx->CacheSlots[index] = NULL; - } + IWTSVirtualChannelManager* mgr = gfx->listener_callback->channel_mgr; + if (mgr) + IFCALL(mgr->DestroyListener, mgr, gfx->listener); } - - free(context); - free(gfx); + rdpgfx_client_context_free(context); return CHANNEL_RC_OK; } @@ -1554,17 +1921,16 @@ static UINT rdpgfx_plugin_terminated(IWTSPlugin* pPlugin) * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_set_surface_data(RdpgfxClientContext* context, - UINT16 surfaceId, void* pData) +static UINT rdpgfx_set_surface_data(RdpgfxClientContext* context, UINT16 surfaceId, void* pData) { ULONG_PTR key; - RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) context->handle; - key = ((ULONG_PTR) surfaceId) + 1; + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)context->handle; + key = ((ULONG_PTR)surfaceId) + 1; if (pData) - HashTable_Add(gfx->SurfaceTable, (void*) key, pData); + HashTable_Add(gfx->SurfaceTable, (void*)key, pData); else - HashTable_Remove(gfx->SurfaceTable, (void*) key); + HashTable_Remove(gfx->SurfaceTable, (void*)key); return CHANNEL_RC_OK; } @@ -1574,14 +1940,14 @@ static UINT rdpgfx_set_surface_data(RdpgfxClientContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_get_surface_ids(RdpgfxClientContext* context, - UINT16** ppSurfaceIds, UINT16* count_out) +static UINT rdpgfx_get_surface_ids(RdpgfxClientContext* context, UINT16** ppSurfaceIds, + UINT16* count_out) { int count; int index; UINT16* pSurfaceIds; ULONG_PTR* pKeys = NULL; - RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) context->handle; + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)context->handle; count = HashTable_GetKeys(gfx->SurfaceTable, &pKeys); if (count < 1) @@ -1590,7 +1956,7 @@ static UINT rdpgfx_get_surface_ids(RdpgfxClientContext* context, return CHANNEL_RC_OK; } - pSurfaceIds = (UINT16*) calloc(count, sizeof(UINT16)); + pSurfaceIds = (UINT16*)calloc(count, sizeof(UINT16)); if (!pSurfaceIds) { @@ -1610,14 +1976,13 @@ static UINT rdpgfx_get_surface_ids(RdpgfxClientContext* context, return CHANNEL_RC_OK; } -static void* rdpgfx_get_surface_data(RdpgfxClientContext* context, - UINT16 surfaceId) +static void* rdpgfx_get_surface_data(RdpgfxClientContext* context, UINT16 surfaceId) { ULONG_PTR key; void* pData = NULL; - RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) context->handle; - key = ((ULONG_PTR) surfaceId) + 1; - pData = HashTable_GetItemValue(gfx->SurfaceTable, (void*) key); + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)context->handle; + key = ((ULONG_PTR)surfaceId) + 1; + pData = HashTable_GetItemValue(gfx->SurfaceTable, (void*)key); return pData; } @@ -1626,44 +1991,155 @@ static void* rdpgfx_get_surface_data(RdpgfxClientContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_set_cache_slot_data(RdpgfxClientContext* context, - UINT16 cacheSlot, void* pData) +static UINT rdpgfx_set_cache_slot_data(RdpgfxClientContext* context, UINT16 cacheSlot, void* pData) { - RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) context->handle; + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)context->handle; - if (cacheSlot >= gfx->MaxCacheSlot) + /* Microsoft uses 1-based indexing for the egfx bitmap cache ! */ + if (cacheSlot == 0 || cacheSlot > gfx->MaxCacheSlots) { - WLog_ERR(TAG, "%s: invalid cache slot %"PRIu16" maxAllowed=%"PRIu16"", __FUNCTION__, - cacheSlot, gfx->MaxCacheSlot); + WLog_ERR(TAG, "%s: invalid cache slot %" PRIu16 ", must be between 1 and %" PRIu16 "", + __FUNCTION__, cacheSlot, gfx->MaxCacheSlots); return ERROR_INVALID_INDEX; } - gfx->CacheSlots[cacheSlot] = pData; + gfx->CacheSlots[cacheSlot - 1] = pData; return CHANNEL_RC_OK; } static void* rdpgfx_get_cache_slot_data(RdpgfxClientContext* context, UINT16 cacheSlot) { void* pData = NULL; - RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*) context->handle; + RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)context->handle; - if (cacheSlot >= gfx->MaxCacheSlot) + /* Microsoft uses 1-based indexing for the egfx bitmap cache ! */ + if (cacheSlot == 0 || cacheSlot > gfx->MaxCacheSlots) { - WLog_ERR(TAG, "%s: invalid cache slot %"PRIu16" maxAllowed=%"PRIu16"", __FUNCTION__, - cacheSlot, gfx->MaxCacheSlot); + WLog_ERR(TAG, "%s: invalid cache slot %" PRIu16 ", must be between 1 and %" PRIu16 "", + __FUNCTION__, cacheSlot, gfx->MaxCacheSlots); return NULL; } - pData = gfx->CacheSlots[cacheSlot]; + pData = gfx->CacheSlots[cacheSlot - 1]; return pData; } #ifdef BUILTIN_CHANNELS -#define DVCPluginEntry rdpgfx_DVCPluginEntry +#define DVCPluginEntry rdpgfx_DVCPluginEntry #else -#define DVCPluginEntry FREERDP_API DVCPluginEntry +#define DVCPluginEntry FREERDP_API DVCPluginEntry #endif +RdpgfxClientContext* rdpgfx_client_context_new(rdpSettings* settings) +{ + RDPGFX_PLUGIN* gfx; + RdpgfxClientContext* context; + + gfx = (RDPGFX_PLUGIN*)calloc(1, sizeof(RDPGFX_PLUGIN)); + + if (!gfx) + { + WLog_ERR(TAG, "calloc failed!"); + return NULL; + } + + gfx->log = WLog_Get(TAG); + + if (!gfx->log) + { + free(gfx); + WLog_ERR(TAG, "Failed to acquire reference to WLog %s", TAG); + return NULL; + } + + gfx->settings = settings; + gfx->rdpcontext = ((freerdp*)gfx->settings->instance)->context; + gfx->SurfaceTable = HashTable_New(TRUE); + + if (!gfx->SurfaceTable) + { + free(gfx); + WLog_ERR(TAG, "HashTable_New failed!"); + return NULL; + } + + gfx->ThinClient = gfx->settings->GfxThinClient; + gfx->SmallCache = gfx->settings->GfxSmallCache; + gfx->Progressive = gfx->settings->GfxProgressive; + gfx->ProgressiveV2 = gfx->settings->GfxProgressiveV2; + gfx->H264 = gfx->settings->GfxH264; + gfx->AVC444 = gfx->settings->GfxAVC444; + gfx->SendQoeAck = gfx->settings->GfxSendQoeAck; + gfx->capsFilter = gfx->settings->GfxCapsFilter; + + if (gfx->H264) + gfx->SmallCache = TRUE; + + gfx->MaxCacheSlots = gfx->SmallCache ? 4096 : 25600; + context = (RdpgfxClientContext*)calloc(1, sizeof(RdpgfxClientContext)); + + if (!context) + { + free(gfx); + WLog_ERR(TAG, "calloc failed!"); + return NULL; + } + + context->handle = (void*)gfx; + context->GetSurfaceIds = rdpgfx_get_surface_ids; + context->SetSurfaceData = rdpgfx_set_surface_data; + context->GetSurfaceData = rdpgfx_get_surface_data; + context->SetCacheSlotData = rdpgfx_set_cache_slot_data; + context->GetCacheSlotData = rdpgfx_get_cache_slot_data; + context->CapsAdvertise = rdpgfx_send_caps_advertise_pdu; + context->FrameAcknowledge = rdpgfx_send_frame_acknowledge_pdu; + context->CacheImportOffer = rdpgfx_send_cache_import_offer_pdu; + context->QoeFrameAcknowledge = rdpgfx_send_qoe_frame_acknowledge_pdu; + + gfx->iface.pInterface = (void*)context; + gfx->zgfx = zgfx_context_new(FALSE); + + if (!gfx->zgfx) + { + free(gfx); + free(context); + WLog_ERR(TAG, "zgfx_context_new failed!"); + return NULL; + } + + return context; +} + +void rdpgfx_client_context_free(RdpgfxClientContext* context) +{ + + RDPGFX_PLUGIN* gfx; + + if (!context) + return; + + gfx = (RDPGFX_PLUGIN*)context->handle; + + free_surfaces(context, gfx->SurfaceTable); + evict_cache_slots(context, gfx->MaxCacheSlots, gfx->CacheSlots); + + if (gfx->listener_callback) + { + free(gfx->listener_callback); + gfx->listener_callback = NULL; + } + + if (gfx->zgfx) + { + zgfx_context_free(gfx->zgfx); + gfx->zgfx = NULL; + } + + HashTable_Free(gfx->SurfaceTable); + free(context); + free(gfx); +} + /** * Function description * @@ -1674,80 +2150,27 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) UINT error = CHANNEL_RC_OK; RDPGFX_PLUGIN* gfx; RdpgfxClientContext* context; - gfx = (RDPGFX_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "rdpgfx"); + gfx = (RDPGFX_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "rdpgfx"); if (!gfx) { - gfx = (RDPGFX_PLUGIN*) calloc(1, sizeof(RDPGFX_PLUGIN)); + context = + rdpgfx_client_context_new((rdpSettings*)pEntryPoints->GetRdpSettings(pEntryPoints)); - if (!gfx) + if (!context) { - WLog_ERR(TAG, "calloc failed!"); + WLog_ERR(TAG, "rdpgfx_client_context_new failed!"); return CHANNEL_RC_NO_MEMORY; } - gfx->log = WLog_Get(TAG); - if (!gfx->log) - { - free(gfx); - WLog_ERR(TAG, "Failed to acquire reference to WLog %s", TAG); - return ERROR_INTERNAL_ERROR; - } + gfx = (RDPGFX_PLUGIN*)context->handle; - gfx->settings = (rdpSettings*) pEntryPoints->GetRdpSettings(pEntryPoints); gfx->iface.Initialize = rdpgfx_plugin_initialize; gfx->iface.Connected = NULL; gfx->iface.Disconnected = NULL; gfx->iface.Terminated = rdpgfx_plugin_terminated; - gfx->rdpcontext = ((freerdp *)gfx->settings->instance)->context; - - gfx->SurfaceTable = HashTable_New(TRUE); - if (!gfx->SurfaceTable) - { - free(gfx); - WLog_ERR(TAG, "HashTable_New failed!"); - return CHANNEL_RC_NO_MEMORY; - } - - gfx->ThinClient = gfx->settings->GfxThinClient; - gfx->SmallCache = gfx->settings->GfxSmallCache; - gfx->Progressive = gfx->settings->GfxProgressive; - gfx->ProgressiveV2 = gfx->settings->GfxProgressiveV2; - gfx->H264 = gfx->settings->GfxH264; - gfx->AVC444 = gfx->settings->GfxAVC444; - gfx->SendQoeAck = gfx->settings->GfxSendQoeAck; - - if (gfx->H264) - gfx->SmallCache = TRUE; - - gfx->MaxCacheSlot = gfx->SmallCache ? 4096 : 25600; - - context = (RdpgfxClientContext *)calloc(1, sizeof(RdpgfxClientContext)); - if (!context) - { - free(gfx); - WLog_ERR(TAG, "calloc failed!"); - return CHANNEL_RC_NO_MEMORY; - } - - context->handle = (void*) gfx; - context->GetSurfaceIds = rdpgfx_get_surface_ids; - context->SetSurfaceData = rdpgfx_set_surface_data; - context->GetSurfaceData = rdpgfx_get_surface_data; - context->SetCacheSlotData = rdpgfx_set_cache_slot_data; - context->GetCacheSlotData = rdpgfx_get_cache_slot_data; - gfx->iface.pInterface = (void*) context; - gfx->zgfx = zgfx_context_new(FALSE); - - if (!gfx->zgfx) - { - free(gfx); - free(context); - WLog_ERR(TAG, "zgfx_context_new failed!"); - return CHANNEL_RC_NO_MEMORY; - } - error = pEntryPoints->RegisterPlugin(pEntryPoints, "rdpgfx", (IWTSPlugin*) gfx); + error = pEntryPoints->RegisterPlugin(pEntryPoints, "rdpgfx", (IWTSPlugin*)gfx); } return error; diff --git a/channels/rdpgfx/client/rdpgfx_main.h b/channels/rdpgfx/client/rdpgfx_main.h index 7efe298..362f409 100644 --- a/channels/rdpgfx/client/rdpgfx_main.h +++ b/channels/rdpgfx/client/rdpgfx_main.h @@ -67,16 +67,18 @@ struct _RDPGFX_PLUGIN BOOL ProgressiveV2; BOOL H264; BOOL AVC444; + UINT32 capsFilter; ZGFX_CONTEXT* zgfx; UINT32 UnacknowledgedFrames; UINT32 TotalDecodedFrames; - UINT32 StartDecodingTime; + UINT64 StartDecodingTime; BOOL suspendFrameAcks; + BOOL sendFrameAcks; wHashTable* SurfaceTable; - UINT16 MaxCacheSlot; + UINT16 MaxCacheSlots; void* CacheSlots[25600]; rdpContext* rdpcontext; @@ -87,4 +89,3 @@ struct _RDPGFX_PLUGIN typedef struct _RDPGFX_PLUGIN RDPGFX_PLUGIN; #endif /* FREERDP_CHANNEL_RDPGFX_CLIENT_MAIN_H */ - diff --git a/channels/rdpgfx/rdpgfx_common.c b/channels/rdpgfx/rdpgfx_common.c index 2a6243b..e0a50a6 100644 --- a/channels/rdpgfx/rdpgfx_common.c +++ b/channels/rdpgfx/rdpgfx_common.c @@ -31,36 +31,35 @@ #include "rdpgfx_common.h" -static const char* RDPGFX_CMDID_STRINGS[] = -{ - "RDPGFX_CMDID_UNUSED_0000", - "RDPGFX_CMDID_WIRETOSURFACE_1", - "RDPGFX_CMDID_WIRETOSURFACE_2", - "RDPGFX_CMDID_DELETEENCODINGCONTEXT", - "RDPGFX_CMDID_SOLIDFILL", - "RDPGFX_CMDID_SURFACETOSURFACE", - "RDPGFX_CMDID_SURFACETOCACHE", - "RDPGFX_CMDID_CACHETOSURFACE", - "RDPGFX_CMDID_EVICTCACHEENTRY", - "RDPGFX_CMDID_CREATESURFACE", - "RDPGFX_CMDID_DELETESURFACE", - "RDPGFX_CMDID_STARTFRAME", - "RDPGFX_CMDID_ENDFRAME", - "RDPGFX_CMDID_FRAMEACKNOWLEDGE", - "RDPGFX_CMDID_RESETGRAPHICS", - "RDPGFX_CMDID_MAPSURFACETOOUTPUT", - "RDPGFX_CMDID_CACHEIMPORTOFFER", - "RDPGFX_CMDID_CACHEIMPORTREPLY", - "RDPGFX_CMDID_CAPSADVERTISE", - "RDPGFX_CMDID_CAPSCONFIRM", - "RDPGFX_CMDID_UNUSED_0014", - "RDPGFX_CMDID_MAPSURFACETOWINDOW", - "RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE" -}; +static const char* RDPGFX_CMDID_STRINGS[] = { "RDPGFX_CMDID_UNUSED_0000", + "RDPGFX_CMDID_WIRETOSURFACE_1", + "RDPGFX_CMDID_WIRETOSURFACE_2", + "RDPGFX_CMDID_DELETEENCODINGCONTEXT", + "RDPGFX_CMDID_SOLIDFILL", + "RDPGFX_CMDID_SURFACETOSURFACE", + "RDPGFX_CMDID_SURFACETOCACHE", + "RDPGFX_CMDID_CACHETOSURFACE", + "RDPGFX_CMDID_EVICTCACHEENTRY", + "RDPGFX_CMDID_CREATESURFACE", + "RDPGFX_CMDID_DELETESURFACE", + "RDPGFX_CMDID_STARTFRAME", + "RDPGFX_CMDID_ENDFRAME", + "RDPGFX_CMDID_FRAMEACKNOWLEDGE", + "RDPGFX_CMDID_RESETGRAPHICS", + "RDPGFX_CMDID_MAPSURFACETOOUTPUT", + "RDPGFX_CMDID_CACHEIMPORTOFFER", + "RDPGFX_CMDID_CACHEIMPORTREPLY", + "RDPGFX_CMDID_CAPSADVERTISE", + "RDPGFX_CMDID_CAPSCONFIRM", + "RDPGFX_CMDID_UNUSED_0014", + "RDPGFX_CMDID_MAPSURFACETOWINDOW", + "RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE", + "RDPGFX_CMDID_MAPSURFACETOSCALEDOUTPUT", + "RDPGFX_CMDID_MAPSURFACETOSCALEDWINDOW" }; const char* rdpgfx_get_cmd_id_string(UINT16 cmdId) { - if (cmdId <= RDPGFX_CMDID_MAPSURFACETOWINDOW) + if (cmdId <= RDPGFX_CMDID_MAPSURFACETOSCALEDWINDOW) return RDPGFX_CMDID_STRINGS[cmdId]; else return "RDPGFX_CMDID_UNKNOWN"; @@ -117,8 +116,8 @@ UINT rdpgfx_read_header(wStream* s, RDPGFX_HEADER* header) return CHANNEL_RC_NO_MEMORY; } - Stream_Read_UINT16(s, header->cmdId); /* cmdId (2 bytes) */ - Stream_Read_UINT16(s, header->flags); /* flags (2 bytes) */ + Stream_Read_UINT16(s, header->cmdId); /* cmdId (2 bytes) */ + Stream_Read_UINT16(s, header->flags); /* flags (2 bytes) */ Stream_Read_UINT32(s, header->pduLength); /* pduLength (4 bytes) */ return CHANNEL_RC_OK; } @@ -128,10 +127,10 @@ UINT rdpgfx_read_header(wStream* s, RDPGFX_HEADER* header) * * @return 0 on success, otherwise a Win32 error code */ -UINT rdpgfx_write_header(wStream* s, RDPGFX_HEADER* header) +UINT rdpgfx_write_header(wStream* s, const RDPGFX_HEADER* header) { - Stream_Write_UINT16(s, header->cmdId); /* cmdId (2 bytes) */ - Stream_Write_UINT16(s, header->flags); /* flags (2 bytes) */ + Stream_Write_UINT16(s, header->cmdId); /* cmdId (2 bytes) */ + Stream_Write_UINT16(s, header->flags); /* flags (2 bytes) */ Stream_Write_UINT32(s, header->pduLength); /* pduLength (4 bytes) */ return CHANNEL_RC_OK; } @@ -159,7 +158,7 @@ UINT rdpgfx_read_point16(wStream* s, RDPGFX_POINT16* pt16) * * @return 0 on success, otherwise a Win32 error code */ -UINT rdpgfx_write_point16(wStream* s, RDPGFX_POINT16* point16) +UINT rdpgfx_write_point16(wStream* s, const RDPGFX_POINT16* point16) { Stream_Write_UINT16(s, point16->x); /* x (2 bytes) */ Stream_Write_UINT16(s, point16->y); /* y (2 bytes) */ @@ -179,10 +178,14 @@ UINT rdpgfx_read_rect16(wStream* s, RECTANGLE_16* rect16) return ERROR_INVALID_DATA; } - Stream_Read_UINT16(s, rect16->left); /* left (2 bytes) */ - Stream_Read_UINT16(s, rect16->top); /* top (2 bytes) */ - Stream_Read_UINT16(s, rect16->right); /* right (2 bytes) */ + Stream_Read_UINT16(s, rect16->left); /* left (2 bytes) */ + Stream_Read_UINT16(s, rect16->top); /* top (2 bytes) */ + Stream_Read_UINT16(s, rect16->right); /* right (2 bytes) */ Stream_Read_UINT16(s, rect16->bottom); /* bottom (2 bytes) */ + if (rect16->left >= rect16->right) + return ERROR_INVALID_DATA; + if (rect16->top >= rect16->bottom) + return ERROR_INVALID_DATA; return CHANNEL_RC_OK; } @@ -191,11 +194,11 @@ UINT rdpgfx_read_rect16(wStream* s, RECTANGLE_16* rect16) * * @return 0 on success, otherwise a Win32 error code */ -UINT rdpgfx_write_rect16(wStream* s, RECTANGLE_16* rect16) +UINT rdpgfx_write_rect16(wStream* s, const RECTANGLE_16* rect16) { - Stream_Write_UINT16(s, rect16->left); /* left (2 bytes) */ - Stream_Write_UINT16(s, rect16->top); /* top (2 bytes) */ - Stream_Write_UINT16(s, rect16->right); /* right (2 bytes) */ + Stream_Write_UINT16(s, rect16->left); /* left (2 bytes) */ + Stream_Write_UINT16(s, rect16->top); /* top (2 bytes) */ + Stream_Write_UINT16(s, rect16->right); /* right (2 bytes) */ Stream_Write_UINT16(s, rect16->bottom); /* bottom (2 bytes) */ return CHANNEL_RC_OK; } @@ -213,9 +216,9 @@ UINT rdpgfx_read_color32(wStream* s, RDPGFX_COLOR32* color32) return ERROR_INVALID_DATA; } - Stream_Read_UINT8(s, color32->B); /* B (1 byte) */ - Stream_Read_UINT8(s, color32->G); /* G (1 byte) */ - Stream_Read_UINT8(s, color32->R); /* R (1 byte) */ + Stream_Read_UINT8(s, color32->B); /* B (1 byte) */ + Stream_Read_UINT8(s, color32->G); /* G (1 byte) */ + Stream_Read_UINT8(s, color32->R); /* R (1 byte) */ Stream_Read_UINT8(s, color32->XA); /* XA (1 byte) */ return CHANNEL_RC_OK; } @@ -225,11 +228,11 @@ UINT rdpgfx_read_color32(wStream* s, RDPGFX_COLOR32* color32) * * @return 0 on success, otherwise a Win32 error code */ -UINT rdpgfx_write_color32(wStream* s, RDPGFX_COLOR32* color32) +UINT rdpgfx_write_color32(wStream* s, const RDPGFX_COLOR32* color32) { - Stream_Write_UINT8(s, color32->B); /* B (1 byte) */ - Stream_Write_UINT8(s, color32->G); /* G (1 byte) */ - Stream_Write_UINT8(s, color32->R); /* R (1 byte) */ + Stream_Write_UINT8(s, color32->B); /* B (1 byte) */ + Stream_Write_UINT8(s, color32->G); /* G (1 byte) */ + Stream_Write_UINT8(s, color32->R); /* R (1 byte) */ Stream_Write_UINT8(s, color32->XA); /* XA (1 byte) */ return CHANNEL_RC_OK; } diff --git a/channels/rdpgfx/rdpgfx_common.h b/channels/rdpgfx/rdpgfx_common.h index d9d7270..664c9cc 100644 --- a/channels/rdpgfx/rdpgfx_common.h +++ b/channels/rdpgfx/rdpgfx_common.h @@ -32,16 +32,24 @@ FREERDP_LOCAL const char* rdpgfx_get_cmd_id_string(UINT16 cmdId); FREERDP_LOCAL const char* rdpgfx_get_codec_id_string(UINT16 codecId); FREERDP_LOCAL UINT rdpgfx_read_header(wStream* s, RDPGFX_HEADER* header); -FREERDP_LOCAL UINT rdpgfx_write_header(wStream* s, RDPGFX_HEADER* header); +FREERDP_LOCAL UINT rdpgfx_write_header(wStream* s, const RDPGFX_HEADER* header); FREERDP_LOCAL UINT rdpgfx_read_point16(wStream* s, RDPGFX_POINT16* pt16); -FREERDP_LOCAL UINT rdpgfx_write_point16(wStream* s, RDPGFX_POINT16* point16); +FREERDP_LOCAL UINT rdpgfx_write_point16(wStream* s, const RDPGFX_POINT16* point16); FREERDP_LOCAL UINT rdpgfx_read_rect16(wStream* s, RECTANGLE_16* rect16); -FREERDP_LOCAL UINT rdpgfx_write_rect16(wStream* s, RECTANGLE_16* rect16); +FREERDP_LOCAL UINT rdpgfx_write_rect16(wStream* s, const RECTANGLE_16* rect16); FREERDP_LOCAL UINT rdpgfx_read_color32(wStream* s, RDPGFX_COLOR32* color32); -FREERDP_LOCAL UINT rdpgfx_write_color32(wStream* s, RDPGFX_COLOR32* color32); +FREERDP_LOCAL UINT rdpgfx_write_color32(wStream* s, const RDPGFX_COLOR32* color32); -#endif /* FREERDP_CHANNEL_RDPGFX_COMMON_H */ +#ifdef WITH_DEBUG_RDPGFX +#define DEBUG_RDPGFX(_LOGGER, ...) WLog_Print(_LOGGER, WLOG_DEBUG, __VA_ARGS__) +#else +#define DEBUG_RDPGFX(_LOGGER, ...) \ + do \ + { \ + } while (0) +#endif +#endif /* FREERDP_CHANNEL_RDPGFX_COMMON_H */ diff --git a/channels/rdpgfx/server/rdpgfx_main.c b/channels/rdpgfx/server/rdpgfx_main.c index e3e645c..1a532bf 100644 --- a/channels/rdpgfx/server/rdpgfx_main.c +++ b/channels/rdpgfx/server/rdpgfx_main.c @@ -54,8 +54,7 @@ static INLINE UINT32 rdpgfx_pdu_length(UINT32 dataLen) return RDPGFX_HEADER_SIZE + dataLen; } -static INLINE UINT rdpgfx_server_packet_init_header(wStream* s, - UINT16 cmdId, UINT32 pduLength) +static INLINE UINT rdpgfx_server_packet_init_header(wStream* s, UINT16 cmdId, UINT32 pduLength) { RDPGFX_HEADER header; header.flags = 0; @@ -73,8 +72,7 @@ static INLINE UINT rdpgfx_server_packet_init_header(wStream* s, * @param s stream * @param start saved start pos of the packet in the stream */ -static INLINE void rdpgfx_server_packet_complete_header(wStream* s, - size_t start) +static INLINE void rdpgfx_server_packet_complete_header(wStream* s, size_t start) { size_t current = Stream_GetPosition(s); /* Fill actual length */ @@ -101,8 +99,7 @@ static UINT rdpgfx_server_packet_send(RdpgfxServerContext* context, wStream* s) /* Allocate new stream with enough capacity. Additional overhead is * descriptor (1 bytes) + segmentCount (2 bytes) + uncompressedSize (4 bytes) * + segmentCount * size (4 bytes) */ - fs = Stream_New(NULL, SrcSize + 7 - + (SrcSize / ZGFX_SEGMENTED_MAXSIZE + 1) * 4); + fs = Stream_New(NULL, SrcSize + 7 + (SrcSize / ZGFX_SEGMENTED_MAXSIZE + 1) * 4); if (!fs) { @@ -111,16 +108,14 @@ static UINT rdpgfx_server_packet_send(RdpgfxServerContext* context, wStream* s) goto out; } - if (zgfx_compress_to_stream(context->priv->zgfx, fs, pSrcData, - SrcSize, &flags) < 0) + if (zgfx_compress_to_stream(context->priv->zgfx, fs, pSrcData, SrcSize, &flags) < 0) { WLog_ERR(TAG, "zgfx_compress_to_stream failed!"); error = ERROR_INTERNAL_ERROR; goto out; } - if (!WTSVirtualChannelWrite(context->priv->rdpgfx_channel, - (PCHAR) Stream_Buffer(fs), + if (!WTSVirtualChannelWrite(context->priv->rdpgfx_channel, (PCHAR)Stream_Buffer(fs), Stream_GetPosition(fs), &written)) { WLog_ERR(TAG, "WTSVirtualChannelWrite failed!"); @@ -130,8 +125,8 @@ static UINT rdpgfx_server_packet_send(RdpgfxServerContext* context, wStream* s) if (written < Stream_GetPosition(fs)) { - WLog_WARN(TAG, "Unexpected bytes written: %"PRIu32"/%"PRIuz"", - written, Stream_GetPosition(fs)); + WLog_WARN(TAG, "Unexpected bytes written: %" PRIu32 "/%" PRIuz "", written, + Stream_GetPosition(fs)); } error = CHANNEL_RC_OK; @@ -168,7 +163,7 @@ static wStream* rdpgfx_server_single_packet_new(UINT16 cmdId, UINT32 dataLen) if ((error = rdpgfx_server_packet_init_header(s, cmdId, pduLength))) { - WLog_ERR(TAG, "Failed to init header with error %"PRIu32"!", error); + WLog_ERR(TAG, "Failed to init header with error %" PRIu32 "!", error); goto error; } @@ -186,8 +181,7 @@ error: * * @return 0 on success, otherwise a Win32 error code */ -static INLINE UINT rdpgfx_server_single_packet_send( - RdpgfxServerContext* context, wStream* s) +static INLINE UINT rdpgfx_server_single_packet_send(RdpgfxServerContext* context, wStream* s) { /* Fill actual length */ rdpgfx_server_packet_complete_header(s, 0); @@ -200,11 +194,11 @@ static INLINE UINT rdpgfx_server_single_packet_send( * @return 0 on success, otherwise a Win32 error code */ static UINT rdpgfx_send_caps_confirm_pdu(RdpgfxServerContext* context, - RDPGFX_CAPS_CONFIRM_PDU* capsConfirm) + const RDPGFX_CAPS_CONFIRM_PDU* capsConfirm) { RDPGFX_CAPSET* capsSet = capsConfirm->capsSet; - wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_CAPSCONFIRM, RDPGFX_CAPSET_SIZE); + wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_CAPSCONFIRM, + RDPGFX_CAPSET_BASE_SIZE + capsSet->length); if (!s) { @@ -213,8 +207,16 @@ static UINT rdpgfx_send_caps_confirm_pdu(RdpgfxServerContext* context, } Stream_Write_UINT32(s, capsSet->version); /* version (4 bytes) */ - Stream_Write_UINT32(s, 4); /* capsDataLength (4 bytes) */ - Stream_Write_UINT32(s, capsSet->flags); /* capsData (4 bytes) */ + Stream_Write_UINT32(s, capsSet->length); /* capsDataLength (4 bytes) */ + + if (capsSet->length >= 4) + { + Stream_Write_UINT32(s, capsSet->flags); /* capsData (4 bytes) */ + Stream_Zero(s, capsSet->length - 4); + } + else + Stream_Zero(s, capsSet->length); + return rdpgfx_server_single_packet_send(context, s); } @@ -224,7 +226,7 @@ static UINT rdpgfx_send_caps_confirm_pdu(RdpgfxServerContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT rdpgfx_send_reset_graphics_pdu(RdpgfxServerContext* context, - RDPGFX_RESET_GRAPHICS_PDU* pdu) + const RDPGFX_RESET_GRAPHICS_PDU* pdu) { UINT32 index; MONITOR_DEF* monitor; @@ -233,14 +235,13 @@ static UINT rdpgfx_send_reset_graphics_pdu(RdpgfxServerContext* context, /* Check monitorCount. This ensures total size within 340 bytes) */ if (pdu->monitorCount >= 16) { - WLog_ERR(TAG, "Monitor count MUST be less than or equal to 16: %"PRIu32"", + WLog_ERR(TAG, "Monitor count MUST be less than or equal to 16: %" PRIu32 "", pdu->monitorCount); return ERROR_INVALID_DATA; } - s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_RESETGRAPHICS, - RDPGFX_RESET_GRAPHICS_PDU_SIZE - RDPGFX_HEADER_SIZE); + s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_RESETGRAPHICS, + RDPGFX_RESET_GRAPHICS_PDU_SIZE - RDPGFX_HEADER_SIZE); if (!s) { @@ -248,18 +249,18 @@ static UINT rdpgfx_send_reset_graphics_pdu(RdpgfxServerContext* context, return CHANNEL_RC_NO_MEMORY; } - Stream_Write_UINT32(s, pdu->width); /* width (4 bytes) */ - Stream_Write_UINT32(s, pdu->height); /* height (4 bytes) */ + Stream_Write_UINT32(s, pdu->width); /* width (4 bytes) */ + Stream_Write_UINT32(s, pdu->height); /* height (4 bytes) */ Stream_Write_UINT32(s, pdu->monitorCount); /* monitorCount (4 bytes) */ for (index = 0; index < pdu->monitorCount; index++) { monitor = &(pdu->monitorDefArray[index]); - Stream_Write_UINT32(s, monitor->left); /* left (4 bytes) */ - Stream_Write_UINT32(s, monitor->top); /* top (4 bytes) */ - Stream_Write_UINT32(s, monitor->right); /* right (4 bytes) */ + Stream_Write_UINT32(s, monitor->left); /* left (4 bytes) */ + Stream_Write_UINT32(s, monitor->top); /* top (4 bytes) */ + Stream_Write_UINT32(s, monitor->right); /* right (4 bytes) */ Stream_Write_UINT32(s, monitor->bottom); /* bottom (4 bytes) */ - Stream_Write_UINT32(s, monitor->flags); /* flags (4 bytes) */ + Stream_Write_UINT32(s, monitor->flags); /* flags (4 bytes) */ } /* pad (total size must be 340 bytes) */ @@ -273,7 +274,7 @@ static UINT rdpgfx_send_reset_graphics_pdu(RdpgfxServerContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT rdpgfx_send_evict_cache_entry_pdu(RdpgfxServerContext* context, - RDPGFX_EVICT_CACHE_ENTRY_PDU* pdu) + const RDPGFX_EVICT_CACHE_ENTRY_PDU* pdu) { wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_EVICTCACHEENTRY, 2); @@ -293,12 +294,11 @@ static UINT rdpgfx_send_evict_cache_entry_pdu(RdpgfxServerContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT rdpgfx_send_cache_import_reply_pdu(RdpgfxServerContext* context, - RDPGFX_CACHE_IMPORT_REPLY_PDU* pdu) + const RDPGFX_CACHE_IMPORT_REPLY_PDU* pdu) { UINT16 index; - wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_CACHEIMPORTREPLY, - 2 + 2 * pdu->importedEntriesCount); + wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_CACHEIMPORTREPLY, + 2 + 2 * pdu->importedEntriesCount); if (!s) { @@ -323,7 +323,7 @@ static UINT rdpgfx_send_cache_import_reply_pdu(RdpgfxServerContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT rdpgfx_send_create_surface_pdu(RdpgfxServerContext* context, - RDPGFX_CREATE_SURFACE_PDU* pdu) + const RDPGFX_CREATE_SURFACE_PDU* pdu) { wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_CREATESURFACE, 7); @@ -333,9 +333,9 @@ static UINT rdpgfx_send_create_surface_pdu(RdpgfxServerContext* context, return CHANNEL_RC_NO_MEMORY; } - Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */ - Stream_Write_UINT16(s, pdu->width); /* width (2 bytes) */ - Stream_Write_UINT16(s, pdu->height); /* height (2 bytes) */ + Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */ + Stream_Write_UINT16(s, pdu->width); /* width (2 bytes) */ + Stream_Write_UINT16(s, pdu->height); /* height (2 bytes) */ Stream_Write_UINT8(s, pdu->pixelFormat); /* RDPGFX_PIXELFORMAT (1 byte) */ return rdpgfx_server_single_packet_send(context, s); } @@ -346,7 +346,7 @@ static UINT rdpgfx_send_create_surface_pdu(RdpgfxServerContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT rdpgfx_send_delete_surface_pdu(RdpgfxServerContext* context, - RDPGFX_DELETE_SURFACE_PDU* pdu) + const RDPGFX_DELETE_SURFACE_PDU* pdu) { wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_DELETESURFACE, 2); @@ -360,15 +360,13 @@ static UINT rdpgfx_send_delete_surface_pdu(RdpgfxServerContext* context, return rdpgfx_server_single_packet_send(context, s); } -static INLINE void rdpgfx_write_start_frame_pdu(wStream* s, - RDPGFX_START_FRAME_PDU* pdu) +static INLINE void rdpgfx_write_start_frame_pdu(wStream* s, const RDPGFX_START_FRAME_PDU* pdu) { Stream_Write_UINT32(s, pdu->timestamp); /* timestamp (4 bytes) */ - Stream_Write_UINT32(s, pdu->frameId); /* frameId (4 bytes) */ + Stream_Write_UINT32(s, pdu->frameId); /* frameId (4 bytes) */ } -static INLINE void rdpgfx_write_end_frame_pdu(wStream* s, - RDPGFX_END_FRAME_PDU* pdu) +static INLINE void rdpgfx_write_end_frame_pdu(wStream* s, const RDPGFX_END_FRAME_PDU* pdu) { Stream_Write_UINT32(s, pdu->frameId); /* frameId (4 bytes) */ } @@ -379,11 +377,10 @@ static INLINE void rdpgfx_write_end_frame_pdu(wStream* s, * @return 0 on success, otherwise a Win32 error code */ static UINT rdpgfx_send_start_frame_pdu(RdpgfxServerContext* context, - RDPGFX_START_FRAME_PDU* pdu) + const RDPGFX_START_FRAME_PDU* pdu) { - wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_STARTFRAME, - RDPGFX_START_FRAME_PDU_SIZE); + wStream* s = + rdpgfx_server_single_packet_new(RDPGFX_CMDID_STARTFRAME, RDPGFX_START_FRAME_PDU_SIZE); if (!s) { @@ -400,12 +397,9 @@ static UINT rdpgfx_send_start_frame_pdu(RdpgfxServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_send_end_frame_pdu(RdpgfxServerContext* context, - RDPGFX_END_FRAME_PDU* pdu) +static UINT rdpgfx_send_end_frame_pdu(RdpgfxServerContext* context, const RDPGFX_END_FRAME_PDU* pdu) { - wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_ENDFRAME, - RDPGFX_END_FRAME_PDU_SIZE); + wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_ENDFRAME, RDPGFX_END_FRAME_PDU_SIZE); if (!s) { @@ -423,14 +417,13 @@ static UINT rdpgfx_send_end_frame_pdu(RdpgfxServerContext* context, * * @return estimated size */ -static INLINE UINT32 rdpgfx_estimate_h264_avc420( - RDPGFX_AVC420_BITMAP_STREAM* havc420) +static INLINE UINT32 rdpgfx_estimate_h264_avc420(const RDPGFX_AVC420_BITMAP_STREAM* havc420) { /* H264 metadata + H264 stream. See rdpgfx_write_h264_avc420 */ return sizeof(UINT32) /* numRegionRects */ - + 10 /* regionRects + quantQualityVals */ - * havc420->meta.numRegionRects - + havc420->length; + + 10 /* regionRects + quantQualityVals */ + * havc420->meta.numRegionRects + + havc420->length; } /** @@ -439,8 +432,7 @@ static INLINE UINT32 rdpgfx_estimate_h264_avc420( * * @return estimated size */ -static INLINE UINT32 rdpgfx_estimate_surface_command(RDPGFX_SURFACE_COMMAND* - cmd) +static INLINE UINT32 rdpgfx_estimate_surface_command(const RDPGFX_SURFACE_COMMAND* cmd) { RDPGFX_AVC420_BITMAP_STREAM* havc420 = NULL; RDPGFX_AVC444_BITMAP_STREAM* havc444 = NULL; @@ -486,7 +478,7 @@ static INLINE UINT32 rdpgfx_estimate_surface_command(RDPGFX_SURFACE_COMMAND* * * @return 0 on success, otherwise a Win32 error code */ -static INLINE UINT16 rdpgfx_surface_command_cmdid(RDPGFX_SURFACE_COMMAND* cmd) +static INLINE UINT16 rdpgfx_surface_command_cmdid(const RDPGFX_SURFACE_COMMAND* cmd) { if (cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE || cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE_V2) @@ -502,7 +494,7 @@ static INLINE UINT16 rdpgfx_surface_command_cmdid(RDPGFX_SURFACE_COMMAND* cmd) * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_write_h264_metablock(wStream* s, RDPGFX_H264_METABLOCK* meta) +static UINT rdpgfx_write_h264_metablock(wStream* s, const RDPGFX_H264_METABLOCK* meta) { UINT32 index; RECTANGLE_16* regionRect; @@ -520,7 +512,7 @@ static UINT rdpgfx_write_h264_metablock(wStream* s, RDPGFX_H264_METABLOCK* meta) if ((error = rdpgfx_write_rect16(s, regionRect))) { - WLog_ERR(TAG, "rdpgfx_write_rect16 failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rdpgfx_write_rect16 failed with error %" PRIu32 "!", error); return error; } } @@ -528,9 +520,8 @@ static UINT rdpgfx_write_h264_metablock(wStream* s, RDPGFX_H264_METABLOCK* meta) for (index = 0; index < meta->numRegionRects; index++) { quantQualityVal = &(meta->quantQualityVals[index]); - Stream_Write_UINT8(s, quantQualityVal->qp - | (quantQualityVal->r << 6) - | (quantQualityVal->p << 7)); /* qpVal (1 byte) */ + Stream_Write_UINT8(s, quantQualityVal->qp | (quantQualityVal->r << 6) | + (quantQualityVal->p << 7)); /* qpVal (1 byte) */ /* qualityVal (1 byte) */ Stream_Write_UINT8(s, quantQualityVal->qualityVal); } @@ -544,15 +535,13 @@ static UINT rdpgfx_write_h264_metablock(wStream* s, RDPGFX_H264_METABLOCK* meta) * * @return 0 on success, otherwise a Win32 error code */ -static INLINE UINT rdpgfx_write_h264_avc420(wStream* s, - RDPGFX_AVC420_BITMAP_STREAM* havc420) +static INLINE UINT rdpgfx_write_h264_avc420(wStream* s, RDPGFX_AVC420_BITMAP_STREAM* havc420) { UINT error = CHANNEL_RC_OK; if ((error = rdpgfx_write_h264_metablock(s, &(havc420->meta)))) { - WLog_ERR(TAG, "rdpgfx_write_h264_metablock failed with error %"PRIu32"!", - error); + WLog_ERR(TAG, "rdpgfx_write_h264_metablock failed with error %" PRIu32 "!", error); return error; } @@ -570,8 +559,7 @@ static INLINE UINT rdpgfx_write_h264_avc420(wStream* s, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_write_surface_command(wStream* s, - RDPGFX_SURFACE_COMMAND* cmd) +static UINT rdpgfx_write_surface_command(wStream* s, const RDPGFX_SURFACE_COMMAND* cmd) { UINT error = CHANNEL_RC_OK; RDPGFX_AVC420_BITMAP_STREAM* havc420 = NULL; @@ -600,23 +588,23 @@ static UINT rdpgfx_write_surface_command(wStream* s, { /* Write RDPGFX_CMDID_WIRETOSURFACE_2 format for CAPROGRESSIVE */ Stream_Write_UINT16(s, cmd->surfaceId); /* surfaceId (2 bytes) */ - Stream_Write_UINT16(s, cmd->codecId); /* codecId (2 bytes) */ + Stream_Write_UINT16(s, cmd->codecId); /* codecId (2 bytes) */ Stream_Write_UINT32(s, cmd->contextId); /* codecContextId (4 bytes) */ - Stream_Write_UINT8(s, pixelFormat); /* pixelFormat (1 byte) */ - Stream_Write_UINT32(s, cmd->length); /* bitmapDataLength (4 bytes) */ + Stream_Write_UINT8(s, pixelFormat); /* pixelFormat (1 byte) */ + Stream_Write_UINT32(s, cmd->length); /* bitmapDataLength (4 bytes) */ Stream_Write(s, cmd->data, cmd->length); } else { /* Write RDPGFX_CMDID_WIRETOSURFACE_1 format for others */ Stream_Write_UINT16(s, cmd->surfaceId); /* surfaceId (2 bytes) */ - Stream_Write_UINT16(s, cmd->codecId); /* codecId (2 bytes) */ - Stream_Write_UINT8(s, pixelFormat); /* pixelFormat (1 byte) */ - Stream_Write_UINT16(s, cmd->left); /* left (2 bytes) */ - Stream_Write_UINT16(s, cmd->top); /* top (2 bytes) */ - Stream_Write_UINT16(s, cmd->right); /* right (2 bytes) */ - Stream_Write_UINT16(s, cmd->bottom); /* bottom (2 bytes) */ - Stream_Write_UINT32(s, cmd->length); /* bitmapDataLength (4 bytes) */ + Stream_Write_UINT16(s, cmd->codecId); /* codecId (2 bytes) */ + Stream_Write_UINT8(s, pixelFormat); /* pixelFormat (1 byte) */ + Stream_Write_UINT16(s, cmd->left); /* left (2 bytes) */ + Stream_Write_UINT16(s, cmd->top); /* top (2 bytes) */ + Stream_Write_UINT16(s, cmd->right); /* right (2 bytes) */ + Stream_Write_UINT16(s, cmd->bottom); /* bottom (2 bytes) */ + Stream_Write_UINT32(s, cmd->length); /* bitmapDataLength (4 bytes) */ bitmapDataStart = Stream_GetPosition(s); if (cmd->codecId == RDPGFX_CODECID_AVC420) @@ -630,10 +618,11 @@ static UINT rdpgfx_write_surface_command(wStream* s, return error; } } - else if ((cmd->codecId == RDPGFX_CODECID_AVC444) || (cmd->codecId == RDPGFX_CODECID_AVC444v2)) + else if ((cmd->codecId == RDPGFX_CODECID_AVC444) || + (cmd->codecId == RDPGFX_CODECID_AVC444v2)) { havc444 = (RDPGFX_AVC444_BITMAP_STREAM*)cmd->extra; - havc420 = &(havc444->bitstream[0]); /* avc420EncodedBitstreamInfo (4 bytes) */ + havc420 = &(havc444->bitstream[0]); /* avc420EncodedBitstreamInfo (4 bytes) */ Stream_Write_UINT32(s, havc444->cbAvc420EncodedBitstream1 | (havc444->LC << 30UL)); /* avc420EncodedBitstream1 */ error = rdpgfx_write_h264_avc420(s, havc420); @@ -680,13 +669,12 @@ static UINT rdpgfx_write_surface_command(wStream* s, * @return 0 on success, otherwise a Win32 error code */ static UINT rdpgfx_send_surface_command(RdpgfxServerContext* context, - RDPGFX_SURFACE_COMMAND* cmd) + const RDPGFX_SURFACE_COMMAND* cmd) { UINT error = CHANNEL_RC_OK; wStream* s; - s = rdpgfx_server_single_packet_new( - rdpgfx_surface_command_cmdid(cmd), - rdpgfx_estimate_surface_command(cmd)); + s = rdpgfx_server_single_packet_new(rdpgfx_surface_command_cmdid(cmd), + rdpgfx_estimate_surface_command(cmd)); if (!s) { @@ -717,8 +705,9 @@ error: * @return 0 on success, otherwise a Win32 error code */ static UINT rdpgfx_send_surface_frame_command(RdpgfxServerContext* context, - RDPGFX_SURFACE_COMMAND* cmd, RDPGFX_START_FRAME_PDU* startFrame, - RDPGFX_END_FRAME_PDU* endFrame) + const RDPGFX_SURFACE_COMMAND* cmd, + const RDPGFX_START_FRAME_PDU* startFrame, + const RDPGFX_END_FRAME_PDU* endFrame) { UINT error = CHANNEL_RC_OK; @@ -748,12 +737,11 @@ static UINT rdpgfx_send_surface_frame_command(RdpgfxServerContext* context, if (startFrame) { position = Stream_GetPosition(s); - error = rdpgfx_server_packet_init_header(s, - RDPGFX_CMDID_STARTFRAME, 0); + error = rdpgfx_server_packet_init_header(s, RDPGFX_CMDID_STARTFRAME, 0); if (error != CHANNEL_RC_OK) { - WLog_ERR(TAG, "Failed to init header with error %"PRIu32"!", error); + WLog_ERR(TAG, "Failed to init header with error %" PRIu32 "!", error); goto error; } @@ -763,13 +751,12 @@ static UINT rdpgfx_send_surface_frame_command(RdpgfxServerContext* context, /* Write RDPGFX_CMDID_WIRETOSURFACE_1 or RDPGFX_CMDID_WIRETOSURFACE_2 */ position = Stream_GetPosition(s); - error = rdpgfx_server_packet_init_header(s, - rdpgfx_surface_command_cmdid(cmd), - 0); // Actual length will be filled later + error = rdpgfx_server_packet_init_header(s, rdpgfx_surface_command_cmdid(cmd), + 0); // Actual length will be filled later if (error != CHANNEL_RC_OK) { - WLog_ERR(TAG, "Failed to init header with error %"PRIu32"!", error); + WLog_ERR(TAG, "Failed to init header with error %" PRIu32 "!", error); goto error; } @@ -787,12 +774,11 @@ static UINT rdpgfx_send_surface_frame_command(RdpgfxServerContext* context, if (endFrame) { position = Stream_GetPosition(s); - error = rdpgfx_server_packet_init_header(s, - RDPGFX_CMDID_ENDFRAME, 0); + error = rdpgfx_server_packet_init_header(s, RDPGFX_CMDID_ENDFRAME, 0); if (error != CHANNEL_RC_OK) { - WLog_ERR(TAG, "Failed to init header with error %"PRIu32"!", error); + WLog_ERR(TAG, "Failed to init header with error %" PRIu32 "!", error); goto error; } @@ -811,12 +797,10 @@ error: * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_send_delete_encoding_context_pdu(RdpgfxServerContext* - context, - RDPGFX_DELETE_ENCODING_CONTEXT_PDU* pdu) +static UINT rdpgfx_send_delete_encoding_context_pdu(RdpgfxServerContext* context, + const RDPGFX_DELETE_ENCODING_CONTEXT_PDU* pdu) { - wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_DELETEENCODINGCONTEXT, 6); + wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_DELETEENCODINGCONTEXT, 6); if (!s) { @@ -824,7 +808,7 @@ static UINT rdpgfx_send_delete_encoding_context_pdu(RdpgfxServerContext* return CHANNEL_RC_NO_MEMORY; } - Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */ + Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */ Stream_Write_UINT32(s, pdu->codecContextId); /* codecContextId (4 bytes) */ return rdpgfx_server_single_packet_send(context, s); } @@ -835,14 +819,13 @@ static UINT rdpgfx_send_delete_encoding_context_pdu(RdpgfxServerContext* * @return 0 on success, otherwise a Win32 error code */ static UINT rdpgfx_send_solid_fill_pdu(RdpgfxServerContext* context, - RDPGFX_SOLID_FILL_PDU* pdu) + const RDPGFX_SOLID_FILL_PDU* pdu) { UINT error = CHANNEL_RC_OK; UINT16 index; RECTANGLE_16* fillRect; - wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_SOLIDFILL, - 8 + 8 * pdu->fillRectCount); + wStream* s = + rdpgfx_server_single_packet_new(RDPGFX_CMDID_SOLIDFILL, 8 + 8 * pdu->fillRectCount); if (!s) { @@ -855,7 +838,7 @@ static UINT rdpgfx_send_solid_fill_pdu(RdpgfxServerContext* context, /* fillPixel (4 bytes) */ if ((error = rdpgfx_write_color32(s, &(pdu->fillPixel)))) { - WLog_ERR(TAG, "rdpgfx_write_color32 failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rdpgfx_write_color32 failed with error %" PRIu32 "!", error); goto error; } @@ -867,7 +850,7 @@ static UINT rdpgfx_send_solid_fill_pdu(RdpgfxServerContext* context, if ((error = rdpgfx_write_rect16(s, fillRect))) { - WLog_ERR(TAG, "rdpgfx_write_rect16 failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rdpgfx_write_rect16 failed with error %" PRIu32 "!", error); goto error; } } @@ -884,14 +867,13 @@ error: * @return 0 on success, otherwise a Win32 error code */ static UINT rdpgfx_send_surface_to_surface_pdu(RdpgfxServerContext* context, - RDPGFX_SURFACE_TO_SURFACE_PDU* pdu) + const RDPGFX_SURFACE_TO_SURFACE_PDU* pdu) { UINT error = CHANNEL_RC_OK; UINT16 index; RDPGFX_POINT16* destPt; - wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_SURFACETOSURFACE, - 14 + 4 * pdu->destPtsCount); + wStream* s = + rdpgfx_server_single_packet_new(RDPGFX_CMDID_SURFACETOSURFACE, 14 + 4 * pdu->destPtsCount); if (!s) { @@ -899,13 +881,13 @@ static UINT rdpgfx_send_surface_to_surface_pdu(RdpgfxServerContext* context, return CHANNEL_RC_NO_MEMORY; } - Stream_Write_UINT16(s, pdu->surfaceIdSrc); /* surfaceIdSrc (2 bytes) */ + Stream_Write_UINT16(s, pdu->surfaceIdSrc); /* surfaceIdSrc (2 bytes) */ Stream_Write_UINT16(s, pdu->surfaceIdDest); /* surfaceIdDest (2 bytes) */ /* rectSrc (8 bytes ) */ if ((error = rdpgfx_write_rect16(s, &(pdu->rectSrc)))) { - WLog_ERR(TAG, "rdpgfx_write_rect16 failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rdpgfx_write_rect16 failed with error %" PRIu32 "!", error); goto error; } @@ -917,7 +899,7 @@ static UINT rdpgfx_send_surface_to_surface_pdu(RdpgfxServerContext* context, if ((error = rdpgfx_write_point16(s, destPt))) { - WLog_ERR(TAG, "rdpgfx_write_point16 failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rdpgfx_write_point16 failed with error %" PRIu32 "!", error); goto error; } } @@ -934,11 +916,10 @@ error: * @return 0 on success, otherwise a Win32 error code */ static UINT rdpgfx_send_surface_to_cache_pdu(RdpgfxServerContext* context, - RDPGFX_SURFACE_TO_CACHE_PDU* pdu) + const RDPGFX_SURFACE_TO_CACHE_PDU* pdu) { UINT error = CHANNEL_RC_OK; - wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_SURFACETOCACHE, 20); + wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_SURFACETOCACHE, 20); if (!s) { @@ -947,13 +928,13 @@ static UINT rdpgfx_send_surface_to_cache_pdu(RdpgfxServerContext* context, } Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */ - Stream_Write_UINT64(s, pdu->cacheKey); /* cacheKey (8 bytes) */ + Stream_Write_UINT64(s, pdu->cacheKey); /* cacheKey (8 bytes) */ Stream_Write_UINT16(s, pdu->cacheSlot); /* cacheSlot (2 bytes) */ /* rectSrc (8 bytes ) */ if ((error = rdpgfx_write_rect16(s, &(pdu->rectSrc)))) { - WLog_ERR(TAG, "rdpgfx_write_rect16 failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rdpgfx_write_rect16 failed with error %" PRIu32 "!", error); goto error; } @@ -969,14 +950,13 @@ error: * @return 0 on success, otherwise a Win32 error code */ static UINT rdpgfx_send_cache_to_surface_pdu(RdpgfxServerContext* context, - RDPGFX_CACHE_TO_SURFACE_PDU* pdu) + const RDPGFX_CACHE_TO_SURFACE_PDU* pdu) { UINT error = CHANNEL_RC_OK; UINT16 index; RDPGFX_POINT16* destPt; - wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_CACHETOSURFACE, - 6 + 4 * pdu->destPtsCount); + wStream* s = + rdpgfx_server_single_packet_new(RDPGFX_CMDID_CACHETOSURFACE, 6 + 4 * pdu->destPtsCount); if (!s) { @@ -984,8 +964,8 @@ static UINT rdpgfx_send_cache_to_surface_pdu(RdpgfxServerContext* context, return CHANNEL_RC_NO_MEMORY; } - Stream_Write_UINT16(s, pdu->cacheSlot); /* cacheSlot (2 bytes) */ - Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */ + Stream_Write_UINT16(s, pdu->cacheSlot); /* cacheSlot (2 bytes) */ + Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */ Stream_Write_UINT16(s, pdu->destPtsCount); /* destPtsCount (2 bytes) */ for (index = 0; index < pdu->destPtsCount; index++) @@ -994,7 +974,7 @@ static UINT rdpgfx_send_cache_to_surface_pdu(RdpgfxServerContext* context, if ((error = rdpgfx_write_point16(s, destPt))) { - WLog_ERR(TAG, "rdpgfx_write_point16 failed with error %"PRIu32"", error); + WLog_ERR(TAG, "rdpgfx_write_point16 failed with error %" PRIu32 "", error); goto error; } } @@ -1011,10 +991,9 @@ error: * @return 0 on success, otherwise a Win32 error code */ static UINT rdpgfx_send_map_surface_to_output_pdu(RdpgfxServerContext* context, - RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU* pdu) + const RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU* pdu) { - wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_MAPSURFACETOOUTPUT, 12); + wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_MAPSURFACETOOUTPUT, 12); if (!s) { @@ -1022,8 +1001,8 @@ static UINT rdpgfx_send_map_surface_to_output_pdu(RdpgfxServerContext* context, return CHANNEL_RC_NO_MEMORY; } - Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */ - Stream_Write_UINT16(s, 0); /* reserved (2 bytes). Must be 0 */ + Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */ + Stream_Write_UINT16(s, 0); /* reserved (2 bytes). Must be 0 */ Stream_Write_UINT32(s, pdu->outputOriginX); /* outputOriginX (4 bytes) */ Stream_Write_UINT32(s, pdu->outputOriginY); /* outputOriginY (4 bytes) */ return rdpgfx_server_single_packet_send(context, s); @@ -1035,10 +1014,9 @@ static UINT rdpgfx_send_map_surface_to_output_pdu(RdpgfxServerContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT rdpgfx_send_map_surface_to_window_pdu(RdpgfxServerContext* context, - RDPGFX_MAP_SURFACE_TO_WINDOW_PDU* pdu) + const RDPGFX_MAP_SURFACE_TO_WINDOW_PDU* pdu) { - wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_MAPSURFACETOWINDOW, 18); + wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_MAPSURFACETOWINDOW, 18); if (!s) { @@ -1046,10 +1024,31 @@ static UINT rdpgfx_send_map_surface_to_window_pdu(RdpgfxServerContext* context, return CHANNEL_RC_NO_MEMORY; } - Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */ - Stream_Write_UINT64(s, pdu->windowId); /* windowId (8 bytes) */ - Stream_Write_UINT32(s, pdu->mappedWidth); /* mappedWidth (4 bytes) */ + Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */ + Stream_Write_UINT64(s, pdu->windowId); /* windowId (8 bytes) */ + Stream_Write_UINT32(s, pdu->mappedWidth); /* mappedWidth (4 bytes) */ + Stream_Write_UINT32(s, pdu->mappedHeight); /* mappedHeight (4 bytes) */ + return rdpgfx_server_single_packet_send(context, s); +} + +static UINT +rdpgfx_send_map_surface_to_scaled_window_pdu(RdpgfxServerContext* context, + const RDPGFX_MAP_SURFACE_TO_SCALED_WINDOW_PDU* pdu) +{ + wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_MAPSURFACETOSCALEDWINDOW, 26); + + if (!s) + { + WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */ + Stream_Write_UINT64(s, pdu->windowId); /* windowId (8 bytes) */ + Stream_Write_UINT32(s, pdu->mappedWidth); /* mappedWidth (4 bytes) */ Stream_Write_UINT32(s, pdu->mappedHeight); /* mappedHeight (4 bytes) */ + Stream_Write_UINT32(s, pdu->targetWidth); /* targetWidth (4 bytes) */ + Stream_Write_UINT32(s, pdu->targetHeight); /* targetHeight (4 bytes) */ return rdpgfx_server_single_packet_send(context, s); } @@ -1058,8 +1057,7 @@ static UINT rdpgfx_send_map_surface_to_window_pdu(RdpgfxServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_recv_frame_acknowledge_pdu(RdpgfxServerContext* context, - wStream* s) +static UINT rdpgfx_recv_frame_acknowledge_pdu(RdpgfxServerContext* context, wStream* s) { RDPGFX_FRAME_ACKNOWLEDGE_PDU pdu; UINT error = CHANNEL_RC_OK; @@ -1070,18 +1068,16 @@ static UINT rdpgfx_recv_frame_acknowledge_pdu(RdpgfxServerContext* context, return ERROR_INVALID_DATA; } - Stream_Read_UINT32(s, pdu.queueDepth); /* queueDepth (4 bytes) */ - Stream_Read_UINT32(s, pdu.frameId); /* frameId (4 bytes) */ - /* totalFramesDecoded (4 bytes) */ - Stream_Read_UINT32(s, pdu.totalFramesDecoded); + Stream_Read_UINT32(s, pdu.queueDepth); /* queueDepth (4 bytes) */ + Stream_Read_UINT32(s, pdu.frameId); /* frameId (4 bytes) */ + Stream_Read_UINT32(s, pdu.totalFramesDecoded); /* totalFramesDecoded (4 bytes) */ if (context) { IFCALLRET(context->FrameAcknowledge, error, context, &pdu); if (error) - WLog_ERR(TAG, "context->FrameAcknowledge failed with error %"PRIu32"", - error); + WLog_ERR(TAG, "context->FrameAcknowledge failed with error %" PRIu32 "", error); } return error; @@ -1092,11 +1088,10 @@ static UINT rdpgfx_recv_frame_acknowledge_pdu(RdpgfxServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_recv_cache_import_offer_pdu(RdpgfxServerContext* context, - wStream* s) +static UINT rdpgfx_recv_cache_import_offer_pdu(RdpgfxServerContext* context, wStream* s) { UINT16 index; - RDPGFX_CACHE_IMPORT_OFFER_PDU pdu; + RDPGFX_CACHE_IMPORT_OFFER_PDU pdu = { 0 }; RDPGFX_CACHE_ENTRY_METADATA* cacheEntries; UINT error = CHANNEL_RC_OK; @@ -1109,10 +1104,10 @@ static UINT rdpgfx_recv_cache_import_offer_pdu(RdpgfxServerContext* context, /* cacheEntriesCount (2 bytes) */ Stream_Read_UINT16(s, pdu.cacheEntriesCount); - if (pdu.cacheEntriesCount <= 0) + /* 2.2.2.16 RDPGFX_CACHE_IMPORT_OFFER_PDU */ + if (pdu.cacheEntriesCount >= 5462) { - /* According to the latest spec, capsSetCount <= 3 */ - WLog_ERR(TAG, "Invalid cacheEntriesCount: %"PRIu16"", pdu.cacheEntriesCount); + WLog_ERR(TAG, "Invalid cacheEntriesCount: %" PRIu16 "", pdu.cacheEntriesCount); return ERROR_INVALID_DATA; } @@ -1122,22 +1117,23 @@ static UINT rdpgfx_recv_cache_import_offer_pdu(RdpgfxServerContext* context, return ERROR_INVALID_DATA; } - pdu.cacheEntries = (RDPGFX_CACHE_ENTRY_METADATA*) - calloc(pdu.cacheEntriesCount, - sizeof(RDPGFX_CACHE_ENTRY_METADATA)); - - if (!pdu.cacheEntries) + if (pdu.cacheEntriesCount > 0) { - WLog_ERR(TAG, "calloc failed!"); - return CHANNEL_RC_NO_MEMORY; + pdu.cacheEntries = (RDPGFX_CACHE_ENTRY_METADATA*)calloc( + pdu.cacheEntriesCount, sizeof(RDPGFX_CACHE_ENTRY_METADATA)); + + if (!pdu.cacheEntries) + { + WLog_ERR(TAG, "calloc failed!"); + return CHANNEL_RC_NO_MEMORY; + } } for (index = 0; index < pdu.cacheEntriesCount; index++) { cacheEntries = &(pdu.cacheEntries[index]); - Stream_Read_UINT64(s, cacheEntries->cacheKey); /* cacheKey (8 bytes) */ - /* bitmapLength (4 bytes) */ - Stream_Read_UINT32(s, cacheEntries->bitmapLength); + Stream_Read_UINT64(s, cacheEntries->cacheKey); /* cacheKey (8 bytes) */ + Stream_Read_UINT32(s, cacheEntries->bitmapLength); /* bitmapLength (4 bytes) */ } if (context) @@ -1145,8 +1141,7 @@ static UINT rdpgfx_recv_cache_import_offer_pdu(RdpgfxServerContext* context, IFCALLRET(context->CacheImportOffer, error, context, &pdu); if (error) - WLog_ERR(TAG, "context->CacheImportOffer failed with error %"PRIu32"", - error); + WLog_ERR(TAG, "context->CacheImportOffer failed with error %" PRIu32 "", error); } free(pdu.cacheEntries); @@ -1158,14 +1153,15 @@ static UINT rdpgfx_recv_cache_import_offer_pdu(RdpgfxServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_recv_caps_advertise_pdu(RdpgfxServerContext* context, - wStream* s) +static UINT rdpgfx_recv_caps_advertise_pdu(RdpgfxServerContext* context, wStream* s) { UINT16 index; - RDPGFX_CAPSET* capsSets; - RDPGFX_CAPS_ADVERTISE_PDU pdu; - UINT error = CHANNEL_RC_OK; - UINT32 capsDataLength; + RDPGFX_CAPSET* capsSets = NULL; + RDPGFX_CAPS_ADVERTISE_PDU pdu = { 0 }; + UINT error = ERROR_INVALID_DATA; + + if (!context) + return ERROR_BAD_ARGUMENTS; if (Stream_GetRemainingLength(s) < 2) { @@ -1174,45 +1170,44 @@ static UINT rdpgfx_recv_caps_advertise_pdu(RdpgfxServerContext* context, } Stream_Read_UINT16(s, pdu.capsSetCount); /* capsSetCount (2 bytes) */ - - if (Stream_GetRemainingLength(s) < (pdu.capsSetCount * RDPGFX_CAPSET_SIZE)) + if (pdu.capsSetCount > 0) { - WLog_ERR(TAG, "not enough data!"); - return ERROR_INVALID_DATA; + capsSets = calloc(pdu.capsSetCount, (RDPGFX_CAPSET_BASE_SIZE + 4)); + if (!capsSets) + return ERROR_OUTOFMEMORY; } - capsSets = calloc(pdu.capsSetCount, RDPGFX_CAPSET_SIZE); - - if (!capsSets) - return ERROR_OUTOFMEMORY; - - pdu.capsSets = (RDPGFX_CAPSET*) capsSets; + pdu.capsSets = capsSets; for (index = 0; index < pdu.capsSetCount; index++) { RDPGFX_CAPSET* capsSet = &(pdu.capsSets[index]); + + if (Stream_GetRemainingLength(s) < 8) + goto fail; + Stream_Read_UINT32(s, capsSet->version); /* version (4 bytes) */ - Stream_Read_UINT32(s, capsDataLength); /* capsDataLength (4 bytes) */ + Stream_Read_UINT32(s, capsSet->length); /* capsDataLength (4 bytes) */ - if (capsDataLength != 4) + if (capsSet->length >= 4) { - WLog_ERR(TAG, "capsDataLength does not equal to 4: %"PRIu32"", - capsDataLength); - free(capsSets); - return ERROR_INVALID_DATA; + if (Stream_GetRemainingLength(s) < 4) + goto fail; + + Stream_Peek_UINT32(s, capsSet->flags); /* capsData (4 bytes) */ } - Stream_Read_UINT32(s, capsSet->flags); /* capsData (4 bytes) */ + if (!Stream_SafeSeek(s, capsSet->length)) + goto fail; } - if (context) - { - IFCALLRET(context->CapsAdvertise, error, context, &pdu); + error = ERROR_BAD_CONFIGURATION; + IFCALLRET(context->CapsAdvertise, error, context, &pdu); - if (error) - WLog_ERR(TAG, "context->CapsAdvertise failed with error %"PRIu32"", error); - } + if (error) + WLog_ERR(TAG, "context->CapsAdvertise failed with error %" PRIu32 "", error); +fail: free(capsSets); return error; } @@ -1222,8 +1217,7 @@ static UINT rdpgfx_recv_caps_advertise_pdu(RdpgfxServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpgfx_recv_qoe_frame_acknowledge_pdu(RdpgfxServerContext* context, - wStream* s) +static UINT rdpgfx_recv_qoe_frame_acknowledge_pdu(RdpgfxServerContext* context, wStream* s) { RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU pdu; UINT error = CHANNEL_RC_OK; @@ -1234,9 +1228,9 @@ static UINT rdpgfx_recv_qoe_frame_acknowledge_pdu(RdpgfxServerContext* context, return ERROR_INVALID_DATA; } - Stream_Read_UINT32(s, pdu.frameId); /* frameId (4 bytes) */ - Stream_Read_UINT32(s, pdu.timestamp); /* timestamp (4 bytes) */ - Stream_Read_UINT16(s, pdu.timeDiffSE); /* timeDiffSE (2 bytes) */ + Stream_Read_UINT32(s, pdu.frameId); /* frameId (4 bytes) */ + Stream_Read_UINT32(s, pdu.timestamp); /* timestamp (4 bytes) */ + Stream_Read_UINT16(s, pdu.timeDiffSE); /* timeDiffSE (2 bytes) */ Stream_Read_UINT16(s, pdu.timeDiffEDR); /* timeDiffEDR (2 bytes) */ if (context) @@ -1244,13 +1238,33 @@ static UINT rdpgfx_recv_qoe_frame_acknowledge_pdu(RdpgfxServerContext* context, IFCALLRET(context->QoeFrameAcknowledge, error, context, &pdu); if (error) - WLog_ERR(TAG, "context->QoeFrameAcknowledge failed with error %"PRIu32"", - error); + WLog_ERR(TAG, "context->QoeFrameAcknowledge failed with error %" PRIu32 "", error); } return error; } +static UINT +rdpgfx_send_map_surface_to_scaled_output_pdu(RdpgfxServerContext* context, + const RDPGFX_MAP_SURFACE_TO_SCALED_OUTPUT_PDU* pdu) +{ + wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_MAPSURFACETOSCALEDOUTPUT, 20); + + if (!s) + { + WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */ + Stream_Write_UINT16(s, 0); /* reserved (2 bytes). Must be 0 */ + Stream_Write_UINT32(s, pdu->outputOriginX); /* outputOriginX (4 bytes) */ + Stream_Write_UINT32(s, pdu->outputOriginY); /* outputOriginY (4 bytes) */ + Stream_Write_UINT32(s, pdu->targetWidth); /* targetWidth (4 bytes) */ + Stream_Write_UINT32(s, pdu->targetHeight); /* targetHeight (4 bytes) */ + return rdpgfx_server_single_packet_send(context, s); +} + /** * Function description * @@ -1265,41 +1279,50 @@ static UINT rdpgfx_server_receive_pdu(RdpgfxServerContext* context, wStream* s) if ((error = rdpgfx_read_header(s, &header))) { - WLog_ERR(TAG, "rdpgfx_read_header failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "rdpgfx_read_header failed with error %" PRIu32 "!", error); return error; } - WLog_DBG(TAG, "cmdId: %s (0x%04"PRIX16") flags: 0x%04"PRIX16" pduLength: %"PRIu32"", - rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId, - header.flags, header.pduLength); +#ifdef WITH_DEBUG_RDPGFX + WLog_DBG(TAG, "cmdId: %s (0x%04" PRIX16 ") flags: 0x%04" PRIX16 " pduLength: %" PRIu32 "", + rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId, header.flags, header.pduLength); +#endif switch (header.cmdId) { case RDPGFX_CMDID_FRAMEACKNOWLEDGE: if ((error = rdpgfx_recv_frame_acknowledge_pdu(context, s))) - WLog_ERR(TAG, "rdpgfx_recv_frame_acknowledge_pdu " - "failed with error %"PRIu32"!", error); + WLog_ERR(TAG, + "rdpgfx_recv_frame_acknowledge_pdu " + "failed with error %" PRIu32 "!", + error); break; case RDPGFX_CMDID_CACHEIMPORTOFFER: if ((error = rdpgfx_recv_cache_import_offer_pdu(context, s))) - WLog_ERR(TAG, "rdpgfx_recv_cache_import_offer_pdu " - "failed with error %"PRIu32"!", error); + WLog_ERR(TAG, + "rdpgfx_recv_cache_import_offer_pdu " + "failed with error %" PRIu32 "!", + error); break; case RDPGFX_CMDID_CAPSADVERTISE: if ((error = rdpgfx_recv_caps_advertise_pdu(context, s))) - WLog_ERR(TAG, "rdpgfx_recv_caps_advertise_pdu " - "failed with error %"PRIu32"!", error); + WLog_ERR(TAG, + "rdpgfx_recv_caps_advertise_pdu " + "failed with error %" PRIu32 "!", + error); break; case RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE: if ((error = rdpgfx_recv_qoe_frame_acknowledge_pdu(context, s))) - WLog_ERR(TAG, "rdpgfx_recv_qoe_frame_acknowledge_pdu " - "failed with error %"PRIu32"!", error); + WLog_ERR(TAG, + "rdpgfx_recv_qoe_frame_acknowledge_pdu " + "failed with error %" PRIu32 "!", + error); break; @@ -1310,7 +1333,7 @@ static UINT rdpgfx_server_receive_pdu(RdpgfxServerContext* context, wStream* s) if (error) { - WLog_ERR(TAG, "Error while parsing GFX cmdId: %s (0x%04"PRIX16")", + WLog_ERR(TAG, "Error while parsing GFX cmdId: %s (0x%04" PRIX16 ")", rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId); return error; } @@ -1319,8 +1342,8 @@ static UINT rdpgfx_server_receive_pdu(RdpgfxServerContext* context, wStream* s) if (end != (beg + header.pduLength)) { - WLog_ERR(TAG, "Unexpected gfx pdu end: Actual: %d, Expected: %"PRIu32"", - end, (beg + header.pduLength)); + WLog_ERR(TAG, "Unexpected gfx pdu end: Actual: %d, Expected: %" PRIu32 "", end, + (beg + header.pduLength)); Stream_SetPosition(s, (beg + header.pduLength)); } @@ -1329,7 +1352,7 @@ static UINT rdpgfx_server_receive_pdu(RdpgfxServerContext* context, wStream* s) static DWORD WINAPI rdpgfx_server_thread_func(LPVOID arg) { - RdpgfxServerContext* context = (RdpgfxServerContext*) arg; + RdpgfxServerContext* context = (RdpgfxServerContext*)arg; RdpgfxServerPrivate* priv = context->priv; DWORD status; DWORD nCount; @@ -1349,7 +1372,7 @@ static DWORD WINAPI rdpgfx_server_thread_func(LPVOID arg) if (status == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"", error); + WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error); break; } @@ -1359,15 +1382,13 @@ static DWORD WINAPI rdpgfx_server_thread_func(LPVOID arg) if ((error = rdpgfx_server_handle_messages(context))) { - WLog_ERR(TAG, "rdpgfx_server_handle_messages failed with error %"PRIu32"", - error); + WLog_ERR(TAG, "rdpgfx_server_handle_messages failed with error %" PRIu32 "", error); break; } } if (error && context->rdpcontext) - setChannelError(context->rdpcontext, error, - "rdpgfx_server_thread_func reported an error"); + setChannelError(context->rdpcontext, error, "rdpgfx_server_thread_func reported an error"); ExitThread(error); return error; @@ -1375,7 +1396,7 @@ static DWORD WINAPI rdpgfx_server_thread_func(LPVOID arg) static BOOL rdpgfx_server_open(RdpgfxServerContext* context) { - RdpgfxServerPrivate* priv = (RdpgfxServerPrivate*) context->priv; + RdpgfxServerPrivate* priv = (RdpgfxServerPrivate*)context->priv; void* buffer = NULL; if (!priv->isOpened) @@ -1384,19 +1405,17 @@ static BOOL rdpgfx_server_open(RdpgfxServerContext* context) DWORD BytesReturned = 0; priv->SessionId = WTS_CURRENT_SESSION; - if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, - WTSSessionId, (LPSTR*) &pSessionId, - &BytesReturned) == FALSE) + if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId, + (LPSTR*)&pSessionId, &BytesReturned) == FALSE) { WLog_ERR(TAG, "WTSQuerySessionInformationA failed!"); return FALSE; } - priv->SessionId = (DWORD) * pSessionId; + priv->SessionId = (DWORD)*pSessionId; WTSFreeMemory(pSessionId); - priv->rdpgfx_channel = WTSVirtualChannelOpenEx(priv->SessionId, - RDPGFX_DVC_CHANNEL_NAME, - WTS_CHANNEL_OPTION_DYNAMIC); + priv->rdpgfx_channel = WTSVirtualChannelOpenEx(priv->SessionId, RDPGFX_DVC_CHANNEL_NAME, + WTS_CHANNEL_OPTION_DYNAMIC); if (!priv->rdpgfx_channel) { @@ -1405,12 +1424,13 @@ static BOOL rdpgfx_server_open(RdpgfxServerContext* context) } /* Query for channel event handle */ - if (!WTSVirtualChannelQuery(priv->rdpgfx_channel, WTSVirtualEventHandle, - &buffer, &BytesReturned) - || (BytesReturned != sizeof(HANDLE))) + if (!WTSVirtualChannelQuery(priv->rdpgfx_channel, WTSVirtualEventHandle, &buffer, + &BytesReturned) || + (BytesReturned != sizeof(HANDLE))) { - WLog_ERR(TAG, "WTSVirtualChannelQuery failed " - "or invalid returned size(%"PRIu32")", + WLog_ERR(TAG, + "WTSVirtualChannelQuery failed " + "or invalid returned size(%" PRIu32 ")", BytesReturned); if (buffer) @@ -1436,9 +1456,8 @@ static BOOL rdpgfx_server_open(RdpgfxServerContext* context) goto out_zgfx; } - if (!(priv->thread = CreateThread(NULL, 0, - rdpgfx_server_thread_func, - (void*) context, 0, NULL))) + if (!(priv->thread = + CreateThread(NULL, 0, rdpgfx_server_thread_func, (void*)context, 0, NULL))) { WLog_ERR(TAG, "CreateThread failed!"); goto out_stopEvent; @@ -1467,7 +1486,7 @@ out_close: static BOOL rdpgfx_server_close(RdpgfxServerContext* context) { - RdpgfxServerPrivate* priv = (RdpgfxServerPrivate*) context->priv; + RdpgfxServerPrivate* priv = (RdpgfxServerPrivate*)context->priv; if (priv->ownThread && priv->thread) { @@ -1475,8 +1494,7 @@ static BOOL rdpgfx_server_close(RdpgfxServerContext* context) if (WaitForSingleObject(priv->thread, INFINITE) == WAIT_FAILED) { - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", - GetLastError()); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", GetLastError()); return FALSE; } @@ -1533,12 +1551,13 @@ RdpgfxServerContext* rdpgfx_server_context_new(HANDLE vcm) context->EvictCacheEntry = rdpgfx_send_evict_cache_entry_pdu; context->MapSurfaceToOutput = rdpgfx_send_map_surface_to_output_pdu; context->MapSurfaceToWindow = rdpgfx_send_map_surface_to_window_pdu; + context->MapSurfaceToScaledOutput = rdpgfx_send_map_surface_to_scaled_output_pdu; + context->MapSurfaceToScaledWindow = rdpgfx_send_map_surface_to_scaled_window_pdu; context->CapsAdvertise = NULL; context->CapsConfirm = rdpgfx_send_caps_confirm_pdu; context->FrameAcknowledge = NULL; context->QoeFrameAcknowledge = NULL; - context->priv = priv = (RdpgfxServerPrivate*) - calloc(1, sizeof(RdpgfxServerPrivate)); + context->priv = priv = (RdpgfxServerPrivate*)calloc(1, sizeof(RdpgfxServerPrivate)); if (!priv) { @@ -1558,7 +1577,7 @@ RdpgfxServerContext* rdpgfx_server_context_new(HANDLE vcm) priv->isOpened = FALSE; priv->isReady = FALSE; priv->ownThread = TRUE; - return (RdpgfxServerContext*) context; + return (RdpgfxServerContext*)context; out_free_priv: free(context->priv); out_free: @@ -1602,9 +1621,8 @@ UINT rdpgfx_server_handle_messages(RdpgfxServerContext* context) /* Check whether the dynamic channel is ready */ if (!priv->isReady) { - if (WTSVirtualChannelQuery(priv->rdpgfx_channel, - WTSVirtualChannelReady, - &buffer, &BytesReturned) == FALSE) + if (WTSVirtualChannelQuery(priv->rdpgfx_channel, WTSVirtualChannelReady, &buffer, + &BytesReturned) == FALSE) { if (GetLastError() == ERROR_NO_DATA) return ERROR_NO_DATA; @@ -1613,7 +1631,7 @@ UINT rdpgfx_server_handle_messages(RdpgfxServerContext* context) return ERROR_INTERNAL_ERROR; } - priv->isReady = *((BOOL*) buffer); + priv->isReady = *((BOOL*)buffer); WTSFreeMemory(buffer); } @@ -1622,8 +1640,7 @@ UINT rdpgfx_server_handle_messages(RdpgfxServerContext* context) { Stream_SetPosition(s, 0); - if (!WTSVirtualChannelRead(priv->rdpgfx_channel, - 0, NULL, 0, &BytesReturned)) + if (!WTSVirtualChannelRead(priv->rdpgfx_channel, 0, NULL, 0, &BytesReturned)) { if (GetLastError() == ERROR_NO_DATA) return ERROR_NO_DATA; @@ -1641,8 +1658,7 @@ UINT rdpgfx_server_handle_messages(RdpgfxServerContext* context) return CHANNEL_RC_NO_MEMORY; } - if (WTSVirtualChannelRead(priv->rdpgfx_channel, 0, - (PCHAR) Stream_Buffer(s), + if (WTSVirtualChannelRead(priv->rdpgfx_channel, 0, (PCHAR)Stream_Buffer(s), Stream_Capacity(s), &BytesReturned) == FALSE) { WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); @@ -1656,8 +1672,10 @@ UINT rdpgfx_server_handle_messages(RdpgfxServerContext* context) { if ((ret = rdpgfx_server_receive_pdu(context, s))) { - WLog_ERR(TAG, "rdpgfx_server_receive_pdu " - "failed with error %"PRIu32"!", ret); + WLog_ERR(TAG, + "rdpgfx_server_receive_pdu " + "failed with error %" PRIu32 "!", + ret); return ret; } } diff --git a/channels/rdpsnd/ChannelOptions.cmake b/channels/rdpsnd/ChannelOptions.cmake index 909da1d..948ba97 100644 --- a/channels/rdpsnd/ChannelOptions.cmake +++ b/channels/rdpsnd/ChannelOptions.cmake @@ -3,7 +3,7 @@ set(OPTION_DEFAULT OFF) set(OPTION_CLIENT_DEFAULT ON) set(OPTION_SERVER_DEFAULT ON) -define_channel_options(NAME "rdpsnd" TYPE "static" +define_channel_options(NAME "rdpsnd" TYPE "static;dynamic" DESCRIPTION "Audio Output Virtual Channel Extension" SPECIFICATIONS "[MS-RDPEA]" DEFAULT ${OPTION_DEFAULT}) diff --git a/channels/rdpsnd/client/CMakeLists.txt b/channels/rdpsnd/client/CMakeLists.txt index e66f23a..70f4aa2 100644 --- a/channels/rdpsnd/client/CMakeLists.txt +++ b/channels/rdpsnd/client/CMakeLists.txt @@ -21,7 +21,7 @@ set(${MODULE_PREFIX}_SRCS rdpsnd_main.c rdpsnd_main.h) -add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntryEx") +add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntryEx;DVCPluginEntry") target_link_libraries(${MODULE_NAME} winpr freerdp ${CMAKE_THREAD_LIBS_INIT} @@ -57,4 +57,8 @@ if(WITH_OPENSLES) add_channel_client_subsystem(${MODULE_PREFIX} ${CHANNEL_NAME} "opensles" "") endif() +if (WITH_SERVER) + add_channel_client_subsystem(${MODULE_PREFIX} ${CHANNEL_NAME} "proxy" "") +endif() + add_channel_client_subsystem(${MODULE_PREFIX} ${CHANNEL_NAME} "fake" "") diff --git a/channels/rdpsnd/client/alsa/rdpsnd_alsa.c b/channels/rdpsnd/client/alsa/rdpsnd_alsa.c index 65f298a..95e7a79 100644 --- a/channels/rdpsnd/client/alsa/rdpsnd_alsa.c +++ b/channels/rdpsnd/client/alsa/rdpsnd_alsa.c @@ -61,11 +61,11 @@ struct rdpsnd_alsa_plugin snd_pcm_uframes_t period_size; }; -#define SND_PCM_CHECK(_func, _status) \ - if (_status < 0) \ - { \ - WLog_ERR(TAG, "%s: %d\n", _func, _status); \ - return -1; \ +#define SND_PCM_CHECK(_func, _status) \ + if (_status < 0) \ + { \ + WLog_ERR(TAG, "%s: %d\n", _func, _status); \ + return -1; \ } static int rdpsnd_alsa_set_hw_params(rdpsndAlsaPlugin* alsa) @@ -78,7 +78,8 @@ static int rdpsnd_alsa_set_hw_params(rdpsndAlsaPlugin* alsa) status = snd_pcm_hw_params_any(alsa->pcm_handle, hw_params); SND_PCM_CHECK("snd_pcm_hw_params_any", status); /* Set interleaved read/write access */ - status = snd_pcm_hw_params_set_access(alsa->pcm_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); + status = + snd_pcm_hw_params_set_access(alsa->pcm_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); SND_PCM_CHECK("snd_pcm_hw_params_set_access", status); /* Set sample format */ status = snd_pcm_hw_params_set_format(alsa->pcm_handle, hw_params, alsa->format); @@ -111,7 +112,8 @@ static int rdpsnd_alsa_set_hw_params(rdpsndAlsaPlugin* alsa) * It is also possible for the buffer size to not be an integer multiple of the period size. */ int interrupts_per_sec_near = 50; - int bytes_per_sec = (alsa->actual_rate * alsa->aformat.wBitsPerSample / 8 * alsa->actual_channels); + int bytes_per_sec = + (alsa->actual_rate * alsa->aformat.wBitsPerSample / 8 * alsa->actual_channels); alsa->buffer_size = buffer_size_max; alsa->period_size = (bytes_per_sec / interrupts_per_sec_near); @@ -123,11 +125,12 @@ static int rdpsnd_alsa_set_hw_params(rdpsndAlsaPlugin* alsa) } /* Set buffer size */ - status = snd_pcm_hw_params_set_buffer_size_near(alsa->pcm_handle, hw_params, &alsa->buffer_size); + status = + snd_pcm_hw_params_set_buffer_size_near(alsa->pcm_handle, hw_params, &alsa->buffer_size); SND_PCM_CHECK("snd_pcm_hw_params_set_buffer_size_near", status); /* Set period size */ status = snd_pcm_hw_params_set_period_size_near(alsa->pcm_handle, hw_params, &alsa->period_size, - NULL); + NULL); SND_PCM_CHECK("snd_pcm_hw_params_set_period_size_near", status); status = snd_pcm_hw_params(alsa->pcm_handle, hw_params); SND_PCM_CHECK("snd_pcm_hw_params", status); @@ -144,10 +147,10 @@ static int rdpsnd_alsa_set_sw_params(rdpsndAlsaPlugin* alsa) status = snd_pcm_sw_params_current(alsa->pcm_handle, sw_params); SND_PCM_CHECK("snd_pcm_sw_params_current", status); status = snd_pcm_sw_params_set_avail_min(alsa->pcm_handle, sw_params, - (alsa->aformat.nChannels * alsa->actual_channels)); + (alsa->aformat.nChannels * alsa->actual_channels)); SND_PCM_CHECK("snd_pcm_sw_params_set_avail_min", status); status = snd_pcm_sw_params_set_start_threshold(alsa->pcm_handle, sw_params, - alsa->aformat.nBlockAlign); + alsa->aformat.nBlockAlign); SND_PCM_CHECK("snd_pcm_sw_params_set_start_threshold", status); status = snd_pcm_sw_params(alsa->pcm_handle, sw_params); SND_PCM_CHECK("snd_pcm_sw_params", status); @@ -183,7 +186,7 @@ static int rdpsnd_alsa_set_params(rdpsndAlsaPlugin* alsa) static BOOL rdpsnd_alsa_set_format(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format, UINT32 latency) { - rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device; + rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*)device; if (format) { @@ -291,7 +294,7 @@ static BOOL rdpsnd_alsa_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* for { int mode; int status; - rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device; + rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*)device; if (alsa->pcm_handle) return TRUE; @@ -306,13 +309,12 @@ static BOOL rdpsnd_alsa_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* for return FALSE; } - return rdpsnd_alsa_set_format(device, format, latency) && - rdpsnd_alsa_open_mixer(alsa); + return rdpsnd_alsa_set_format(device, format, latency) && rdpsnd_alsa_open_mixer(alsa); } static void rdpsnd_alsa_close(rdpsndDevicePlugin* device) { - rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device; + rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*)device; if (!alsa) return; @@ -322,7 +324,7 @@ static void rdpsnd_alsa_close(rdpsndDevicePlugin* device) static void rdpsnd_alsa_free(rdpsndDevicePlugin* device) { - rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device; + rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*)device; rdpsnd_alsa_pcm_close(alsa); rdpsnd_alsa_close_mixer(alsa); free(alsa->device_name); @@ -334,8 +336,7 @@ static BOOL rdpsnd_alsa_format_supported(rdpsndDevicePlugin* device, const AUDIO switch (format->wFormatTag) { case WAVE_FORMAT_PCM: - if (format->cbSize == 0 && - format->nSamplesPerSec <= 48000 && + if (format->cbSize == 0 && format->nSamplesPerSec <= 48000 && (format->wBitsPerSample == 8 || format->wBitsPerSample == 16) && (format->nChannels == 1 || format->nChannels == 2)) { @@ -358,8 +359,8 @@ static UINT32 rdpsnd_alsa_get_volume(rdpsndDevicePlugin* device) UINT16 dwVolumeLeft; UINT16 dwVolumeRight; snd_mixer_elem_t* elem; - rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device; - dwVolumeLeft = ((50 * 0xFFFF) / 100); /* 50% */ + rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*)device; + dwVolumeLeft = ((50 * 0xFFFF) / 100); /* 50% */ dwVolumeRight = ((50 * 0xFFFF) / 100); /* 50% */ if (!rdpsnd_alsa_open_mixer(alsa)) @@ -372,8 +373,10 @@ static UINT32 rdpsnd_alsa_get_volume(rdpsndDevicePlugin* device) snd_mixer_selem_get_playback_volume_range(elem, &volume_min, &volume_max); snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, &volume_left); snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, &volume_right); - dwVolumeLeft = (UINT16)(((volume_left * 0xFFFF) - volume_min) / (volume_max - volume_min)); - dwVolumeRight = (UINT16)(((volume_right * 0xFFFF) - volume_min) / (volume_max - volume_min)); + dwVolumeLeft = + (UINT16)(((volume_left * 0xFFFF) - volume_min) / (volume_max - volume_min)); + dwVolumeRight = + (UINT16)(((volume_right * 0xFFFF) - volume_min) / (volume_max - volume_min)); break; } } @@ -391,7 +394,7 @@ static BOOL rdpsnd_alsa_set_volume(rdpsndDevicePlugin* device, UINT32 value) long volume_left; long volume_right; snd_mixer_elem_t* elem; - rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device; + rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*)device; if (!rdpsnd_alsa_open_mixer(alsa)) return FALSE; @@ -407,8 +410,10 @@ static BOOL rdpsnd_alsa_set_volume(rdpsndDevicePlugin* device, UINT32 value) volume_left = volume_min + (left * (volume_max - volume_min)) / 0xFFFF; volume_right = volume_min + (right * (volume_max - volume_min)) / 0xFFFF; - if ((snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, volume_left) < 0) || - (snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, volume_right) < 0)) + if ((snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, volume_left) < + 0) || + (snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, + volume_right) < 0)) { WLog_ERR(TAG, "error setting the volume\n"); return FALSE; @@ -424,21 +429,21 @@ static UINT rdpsnd_alsa_play(rdpsndDevicePlugin* device, const BYTE* data, size_ UINT latency; size_t offset; int frame_size; - rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device; + rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*)device; offset = 0; frame_size = alsa->actual_channels * alsa->aformat.wBitsPerSample / 8; while (offset < size) { - snd_pcm_sframes_t status = snd_pcm_writei(alsa->pcm_handle, &data[offset], - (size - offset) / frame_size); + snd_pcm_sframes_t status = + snd_pcm_writei(alsa->pcm_handle, &data[offset], (size - offset) / frame_size); if (status < 0) status = snd_pcm_recover(alsa->pcm_handle, status, 0); if (status < 0) { - WLog_ERR(TAG, "status: %d\n", status); + WLog_ERR(TAG, "status: %d\n", status); rdpsnd_alsa_close(device); rdpsnd_alsa_open(device, NULL, alsa->latency); break; @@ -462,12 +467,6 @@ static UINT rdpsnd_alsa_play(rdpsndDevicePlugin* device, const BYTE* data, size_ return latency + alsa->latency; } -static COMMAND_LINE_ARGUMENT_A rdpsnd_alsa_args[] = -{ - { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "device" }, - { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } -}; - /** * Function description * @@ -478,10 +477,14 @@ static UINT rdpsnd_alsa_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV* int status; DWORD flags; COMMAND_LINE_ARGUMENT_A* arg; - rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device; - flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; - status = CommandLineParseArgumentsA(args->argc, args->argv, rdpsnd_alsa_args, flags, - alsa, NULL, NULL); + rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*)device; + COMMAND_LINE_ARGUMENT_A rdpsnd_alsa_args[] = { { "dev", COMMAND_LINE_VALUE_REQUIRED, "", + NULL, NULL, -1, NULL, "device" }, + { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } }; + flags = + COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; + status = CommandLineParseArgumentsA(args->argc, args->argv, rdpsnd_alsa_args, flags, alsa, NULL, + NULL); if (status < 0) { @@ -496,8 +499,7 @@ static UINT rdpsnd_alsa_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV* if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) continue; - CommandLineSwitchStart(arg) - CommandLineSwitchCase(arg, "dev") + CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "dev") { alsa->device_name = _strdup(arg->Value); @@ -505,16 +507,15 @@ static UINT rdpsnd_alsa_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV* return CHANNEL_RC_NO_MEMORY; } CommandLineSwitchEnd(arg) - } - while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); return CHANNEL_RC_OK; } #ifdef BUILTIN_CHANNELS -#define freerdp_rdpsnd_client_subsystem_entry alsa_freerdp_rdpsnd_client_subsystem_entry +#define freerdp_rdpsnd_client_subsystem_entry alsa_freerdp_rdpsnd_client_subsystem_entry #else -#define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry +#define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry #endif /** @@ -527,7 +528,7 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p ADDIN_ARGV* args; rdpsndAlsaPlugin* alsa; UINT error; - alsa = (rdpsndAlsaPlugin*) calloc(1, sizeof(rdpsndAlsaPlugin)); + alsa = (rdpsndAlsaPlugin*)calloc(1, sizeof(rdpsndAlsaPlugin)); if (!alsa) { @@ -546,9 +547,9 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p if (args->argc > 1) { - if ((error = rdpsnd_alsa_parse_addin_args((rdpsndDevicePlugin*) alsa, args))) + if ((error = rdpsnd_alsa_parse_addin_args((rdpsndDevicePlugin*)alsa, args))) { - WLog_ERR(TAG, "rdpsnd_alsa_parse_addin_args failed with error %"PRIu32"", error); + WLog_ERR(TAG, "rdpsnd_alsa_parse_addin_args failed with error %" PRIu32 "", error); goto error_parse_args; } } @@ -569,7 +570,7 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p alsa->actual_rate = 22050; alsa->format = SND_PCM_FORMAT_S16_LE; alsa->actual_channels = 2; - pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*) alsa); + pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*)alsa); return CHANNEL_RC_OK; error_strdup: free(alsa->device_name); diff --git a/channels/rdpsnd/client/fake/rdpsnd_fake.c b/channels/rdpsnd/client/fake/rdpsnd_fake.c index 51c184b..fe77cda 100644 --- a/channels/rdpsnd/client/fake/rdpsnd_fake.c +++ b/channels/rdpsnd/client/fake/rdpsnd_fake.c @@ -57,7 +57,7 @@ static BOOL rdpsnd_fake_set_volume(rdpsndDevicePlugin* device, UINT32 value) static void rdpsnd_fake_free(rdpsndDevicePlugin* device) { - rdpsndFakePlugin* fake = (rdpsndFakePlugin*) device; + rdpsndFakePlugin* fake = (rdpsndFakePlugin*)device; if (!fake) return; @@ -70,26 +70,11 @@ static BOOL rdpsnd_fake_format_supported(rdpsndDevicePlugin* device, const AUDIO return TRUE; } -static BOOL rdpsnd_fake_set_format(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format, - int latency) -{ - return TRUE; -} - static UINT rdpsnd_fake_play(rdpsndDevicePlugin* device, const BYTE* data, size_t size) { return CHANNEL_RC_OK; } -static void rdpsnd_fake_start(rdpsndDevicePlugin* device) -{ -} - -static COMMAND_LINE_ARGUMENT_A rdpsnd_fake_args[] = -{ - { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } -}; - /** * Function description * @@ -100,9 +85,11 @@ static UINT rdpsnd_fake_parse_addin_args(rdpsndFakePlugin* fake, ADDIN_ARGV* arg int status; DWORD flags; COMMAND_LINE_ARGUMENT_A* arg; - flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; - status = CommandLineParseArgumentsA(args->argc, args->argv, - rdpsnd_fake_args, flags, fake, NULL, NULL); + COMMAND_LINE_ARGUMENT_A rdpsnd_fake_args[] = { { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } }; + flags = + COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; + status = CommandLineParseArgumentsA(args->argc, args->argv, rdpsnd_fake_args, flags, fake, NULL, + NULL); if (status < 0) return ERROR_INVALID_DATA; @@ -114,18 +101,16 @@ static UINT rdpsnd_fake_parse_addin_args(rdpsndFakePlugin* fake, ADDIN_ARGV* arg if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) continue; - CommandLineSwitchStart(arg) - CommandLineSwitchEnd(arg) - } - while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + CommandLineSwitchStart(arg) CommandLineSwitchEnd(arg) + } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); return CHANNEL_RC_OK; } #ifdef BUILTIN_CHANNELS -#define freerdp_rdpsnd_client_subsystem_entry fake_freerdp_rdpsnd_client_subsystem_entry +#define freerdp_rdpsnd_client_subsystem_entry fake_freerdp_rdpsnd_client_subsystem_entry #else -#define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry +#define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry #endif /** @@ -137,8 +122,8 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p { ADDIN_ARGV* args; rdpsndFakePlugin* fake; - UINT ret; - fake = (rdpsndFakePlugin*) calloc(1, sizeof(rdpsndFakePlugin)); + UINT ret = CHANNEL_RC_OK; + fake = (rdpsndFakePlugin*)calloc(1, sizeof(rdpsndFakePlugin)); if (!fake) return CHANNEL_RC_NO_MEMORY; @@ -147,7 +132,6 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p fake->device.FormatSupported = rdpsnd_fake_format_supported; fake->device.SetVolume = rdpsnd_fake_set_volume; fake->device.Play = rdpsnd_fake_play; - fake->device.Start = rdpsnd_fake_start; fake->device.Close = rdpsnd_fake_close; fake->device.Free = rdpsnd_fake_free; args = pEntryPoints->args; @@ -163,9 +147,8 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p } } - ret = CHANNEL_RC_NO_MEMORY; pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, &fake->device); - return CHANNEL_RC_OK; + return ret; error: rdpsnd_fake_free(&fake->device); return ret; diff --git a/channels/rdpsnd/client/ios/TPCircularBuffer.c b/channels/rdpsnd/client/ios/TPCircularBuffer.c index 1c94027..b29f611 100644 --- a/channels/rdpsnd/client/ios/TPCircularBuffer.c +++ b/channels/rdpsnd/client/ios/TPCircularBuffer.c @@ -35,106 +35,119 @@ #include #include -#define reportResult(result,operation) (_reportResult((result),(operation),__FILE__,__LINE__)) -static inline bool _reportResult(kern_return_t result, const char *operation, const char* file, int line) { - if ( result != ERR_SUCCESS ) { - WLog_DBG(TAG, "%s:%d: %s: %s\n", file, line, operation, mach_error_string(result)); - return false; - } - return true; +#define reportResult(result, operation) (_reportResult((result), (operation), __FILE__, __LINE__)) +static inline bool _reportResult(kern_return_t result, const char* operation, const char* file, + int line) +{ + if (result != ERR_SUCCESS) + { + WLog_DBG(TAG, "%s:%d: %s: %s\n", file, line, operation, mach_error_string(result)); + return false; + } + return true; } -bool TPCircularBufferInit(TPCircularBuffer *buffer, int length) { - - // Keep trying until we get our buffer, needed to handle race conditions - int retries = 3; - while ( true ) { - - buffer->length = round_page(length); // We need whole page sizes - - // Temporarily allocate twice the length, so we have the contiguous address space to - // support a second instance of the buffer directly after - vm_address_t bufferAddress; - kern_return_t result = vm_allocate(mach_task_self(), - &bufferAddress, - buffer->length * 2, - VM_FLAGS_ANYWHERE); // allocate anywhere it'll fit - if ( result != ERR_SUCCESS ) { - if ( retries-- == 0 ) { - reportResult(result, "Buffer allocation"); - return false; - } - // Try again if we fail - continue; - } - - // Now replace the second half of the allocation with a virtual copy of the first half. Deallocate the second half... - result = vm_deallocate(mach_task_self(), - bufferAddress + buffer->length, - buffer->length); - if ( result != ERR_SUCCESS ) { - if ( retries-- == 0 ) { - reportResult(result, "Buffer deallocation"); - return false; - } - // If this fails somehow, deallocate the whole region and try again - vm_deallocate(mach_task_self(), bufferAddress, buffer->length); - continue; - } - - // Re-map the buffer to the address space immediately after the buffer - vm_address_t virtualAddress = bufferAddress + buffer->length; - vm_prot_t cur_prot, max_prot; - result = vm_remap(mach_task_self(), - &virtualAddress, // mirror target - buffer->length, // size of mirror - 0, // auto alignment - 0, // force remapping to virtualAddress - mach_task_self(), // same task - bufferAddress, // mirror source - 0, // MAP READ-WRITE, NOT COPY - &cur_prot, // unused protection struct - &max_prot, // unused protection struct - VM_INHERIT_DEFAULT); - if ( result != ERR_SUCCESS ) { - if ( retries-- == 0 ) { - reportResult(result, "Remap buffer memory"); - return false; - } - // If this remap failed, we hit a race condition, so deallocate and try again - vm_deallocate(mach_task_self(), bufferAddress, buffer->length); - continue; - } - - if ( virtualAddress != bufferAddress+buffer->length ) { - // If the memory is not contiguous, clean up both allocated buffers and try again - if ( retries-- == 0 ) { - WLog_DBG(TAG, "Couldn't map buffer memory to end of buffer"); - return false; - } - - vm_deallocate(mach_task_self(), virtualAddress, buffer->length); - vm_deallocate(mach_task_self(), bufferAddress, buffer->length); - continue; - } - - buffer->buffer = (void*)bufferAddress; - buffer->fillCount = 0; - buffer->head = buffer->tail = 0; - - return true; - } - return false; +bool TPCircularBufferInit(TPCircularBuffer* buffer, int length) +{ + + // Keep trying until we get our buffer, needed to handle race conditions + int retries = 3; + while (true) + { + + buffer->length = round_page(length); // We need whole page sizes + + // Temporarily allocate twice the length, so we have the contiguous address space to + // support a second instance of the buffer directly after + vm_address_t bufferAddress; + kern_return_t result = vm_allocate(mach_task_self(), &bufferAddress, buffer->length * 2, + VM_FLAGS_ANYWHERE); // allocate anywhere it'll fit + if (result != ERR_SUCCESS) + { + if (retries-- == 0) + { + reportResult(result, "Buffer allocation"); + return false; + } + // Try again if we fail + continue; + } + + // Now replace the second half of the allocation with a virtual copy of the first half. + // Deallocate the second half... + result = vm_deallocate(mach_task_self(), bufferAddress + buffer->length, buffer->length); + if (result != ERR_SUCCESS) + { + if (retries-- == 0) + { + reportResult(result, "Buffer deallocation"); + return false; + } + // If this fails somehow, deallocate the whole region and try again + vm_deallocate(mach_task_self(), bufferAddress, buffer->length); + continue; + } + + // Re-map the buffer to the address space immediately after the buffer + vm_address_t virtualAddress = bufferAddress + buffer->length; + vm_prot_t cur_prot, max_prot; + result = vm_remap(mach_task_self(), + &virtualAddress, // mirror target + buffer->length, // size of mirror + 0, // auto alignment + 0, // force remapping to virtualAddress + mach_task_self(), // same task + bufferAddress, // mirror source + 0, // MAP READ-WRITE, NOT COPY + &cur_prot, // unused protection struct + &max_prot, // unused protection struct + VM_INHERIT_DEFAULT); + if (result != ERR_SUCCESS) + { + if (retries-- == 0) + { + reportResult(result, "Remap buffer memory"); + return false; + } + // If this remap failed, we hit a race condition, so deallocate and try again + vm_deallocate(mach_task_self(), bufferAddress, buffer->length); + continue; + } + + if (virtualAddress != bufferAddress + buffer->length) + { + // If the memory is not contiguous, clean up both allocated buffers and try again + if (retries-- == 0) + { + WLog_DBG(TAG, "Couldn't map buffer memory to end of buffer"); + return false; + } + + vm_deallocate(mach_task_self(), virtualAddress, buffer->length); + vm_deallocate(mach_task_self(), bufferAddress, buffer->length); + continue; + } + + buffer->buffer = (void*)bufferAddress; + buffer->fillCount = 0; + buffer->head = buffer->tail = 0; + + return true; + } + return false; } -void TPCircularBufferCleanup(TPCircularBuffer *buffer) { - vm_deallocate(mach_task_self(), (vm_address_t)buffer->buffer, buffer->length * 2); - memset(buffer, 0, sizeof(TPCircularBuffer)); +void TPCircularBufferCleanup(TPCircularBuffer* buffer) +{ + vm_deallocate(mach_task_self(), (vm_address_t)buffer->buffer, buffer->length * 2); + memset(buffer, 0, sizeof(TPCircularBuffer)); } -void TPCircularBufferClear(TPCircularBuffer *buffer) { - int32_t fillCount; - if ( TPCircularBufferTail(buffer, &fillCount) ) { - TPCircularBufferConsume(buffer, fillCount); - } +void TPCircularBufferClear(TPCircularBuffer* buffer) +{ + int32_t fillCount; + if (TPCircularBufferTail(buffer, &fillCount)) + { + TPCircularBufferConsume(buffer, fillCount); + } } diff --git a/channels/rdpsnd/client/ios/TPCircularBuffer.h b/channels/rdpsnd/client/ios/TPCircularBuffer.h index cd2a4d8..d246efa 100644 --- a/channels/rdpsnd/client/ios/TPCircularBuffer.h +++ b/channels/rdpsnd/client/ios/TPCircularBuffer.h @@ -8,9 +8,10 @@ // // // This implementation makes use of a virtual memory mapping technique that inserts a virtual copy -// of the buffer memory directly after the buffer's end, negating the need for any buffer wrap-around -// logic. Clients can simply use the returned memory address as if it were contiguous space. -// +// of the buffer memory directly after the buffer's end, negating the need for any buffer +// wrap-around logic. Clients can simply use the returned memory address as if it were contiguous +// space. +// // The implementation is thread-safe in the case of a single producer and single consumer. // // Virtual memory technique originally proposed by Philip Howard (http://vrb.slashusr.org/), and @@ -47,146 +48,167 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif - -typedef struct { - void *buffer; - int32_t length; - int32_t tail; - int32_t head; - volatile int32_t fillCount; -} TPCircularBuffer; - -/*! - * Initialise buffer - * - * Note that the length is advisory only: Because of the way the - * memory mirroring technique works, the true buffer length will - * be multiples of the device page size (e.g. 4096 bytes) - * - * @param buffer Circular buffer - * @param length Length of buffer - */ -bool TPCircularBufferInit(TPCircularBuffer *buffer, int32_t length); - -/*! - * Cleanup buffer - * - * Releases buffer resources. - */ -void TPCircularBufferCleanup(TPCircularBuffer *buffer); - -/*! - * Clear buffer - * - * Resets buffer to original, empty state. - * - * This is safe for use by consumer while producer is accessing - * buffer. - */ -void TPCircularBufferClear(TPCircularBuffer *buffer); - -// Reading (consuming) - -/*! - * Access end of buffer - * - * This gives you a pointer to the end of the buffer, ready - * for reading, and the number of available bytes to read. - * - * @param buffer Circular buffer - * @param availableBytes On output, the number of bytes ready for reading - * @return Pointer to the first bytes ready for reading, or NULL if buffer is empty - */ -static __inline__ __attribute__((always_inline)) void* TPCircularBufferTail(TPCircularBuffer *buffer, int32_t* availableBytes) { - *availableBytes = buffer->fillCount; - if ( *availableBytes == 0 ) return NULL; - return (void*)((char*)buffer->buffer + buffer->tail); -} - -/*! - * Consume bytes in buffer - * - * This frees up the just-read bytes, ready for writing again. - * - * @param buffer Circular buffer - * @param amount Number of bytes to consume - */ -static __inline__ __attribute__((always_inline)) void TPCircularBufferConsume(TPCircularBuffer *buffer, int32_t amount) { - buffer->tail = (buffer->tail + amount) % buffer->length; - OSAtomicAdd32Barrier(-amount, &buffer->fillCount); - assert(buffer->fillCount >= 0); -} - -/*! - * Version of TPCircularBufferConsume without the memory barrier, for more optimal use in single-threaded contexts - */ -static __inline__ __attribute__((always_inline)) void TPCircularBufferConsumeNoBarrier(TPCircularBuffer *buffer, int32_t amount) { - buffer->tail = (buffer->tail + amount) % buffer->length; - buffer->fillCount -= amount; - assert(buffer->fillCount >= 0); -} -/*! - * Access front of buffer - * - * This gives you a pointer to the front of the buffer, ready - * for writing, and the number of available bytes to write. - * - * @param buffer Circular buffer - * @param availableBytes On output, the number of bytes ready for writing - * @return Pointer to the first bytes ready for writing, or NULL if buffer is full - */ -static __inline__ __attribute__((always_inline)) void* TPCircularBufferHead(TPCircularBuffer *buffer, int32_t* availableBytes) { - *availableBytes = (buffer->length - buffer->fillCount); - if ( *availableBytes == 0 ) return NULL; - return (void*)((char*)buffer->buffer + buffer->head); -} - -// Writing (producing) - -/*! - * Produce bytes in buffer - * - * This marks the given section of the buffer ready for reading. - * - * @param buffer Circular buffer - * @param amount Number of bytes to produce - */ -static __inline__ __attribute__((always_inline)) void TPCircularBufferProduce(TPCircularBuffer *buffer, int amount) { - buffer->head = (buffer->head + amount) % buffer->length; - OSAtomicAdd32Barrier(amount, &buffer->fillCount); - assert(buffer->fillCount <= buffer->length); -} - -/*! - * Version of TPCircularBufferProduce without the memory barrier, for more optimal use in single-threaded contexts - */ -static __inline__ __attribute__((always_inline)) void TPCircularBufferProduceNoBarrier(TPCircularBuffer *buffer, int amount) { - buffer->head = (buffer->head + amount) % buffer->length; - buffer->fillCount += amount; - assert(buffer->fillCount <= buffer->length); -} - -/*! - * Helper routine to copy bytes to buffer - * - * This copies the given bytes to the buffer, and marks them ready for writing. - * - * @param buffer Circular buffer - * @param src Source buffer - * @param len Number of bytes in source buffer - * @return true if bytes copied, false if there was insufficient space - */ -static __inline__ __attribute__((always_inline)) bool TPCircularBufferProduceBytes(TPCircularBuffer *buffer, const void* src, int32_t len) { - int32_t space; - void *ptr = TPCircularBufferHead(buffer, &space); - if ( space < len ) return false; - memcpy(ptr, src, len); - TPCircularBufferProduce(buffer, len); - return true; -} + typedef struct + { + void* buffer; + int32_t length; + int32_t tail; + int32_t head; + volatile int32_t fillCount; + } TPCircularBuffer; + + /*! + * Initialise buffer + * + * Note that the length is advisory only: Because of the way the + * memory mirroring technique works, the true buffer length will + * be multiples of the device page size (e.g. 4096 bytes) + * + * @param buffer Circular buffer + * @param length Length of buffer + */ + bool TPCircularBufferInit(TPCircularBuffer* buffer, int32_t length); + + /*! + * Cleanup buffer + * + * Releases buffer resources. + */ + void TPCircularBufferCleanup(TPCircularBuffer* buffer); + + /*! + * Clear buffer + * + * Resets buffer to original, empty state. + * + * This is safe for use by consumer while producer is accessing + * buffer. + */ + void TPCircularBufferClear(TPCircularBuffer* buffer); + + // Reading (consuming) + + /*! + * Access end of buffer + * + * This gives you a pointer to the end of the buffer, ready + * for reading, and the number of available bytes to read. + * + * @param buffer Circular buffer + * @param availableBytes On output, the number of bytes ready for reading + * @return Pointer to the first bytes ready for reading, or NULL if buffer is empty + */ + static __inline__ __attribute__((always_inline)) void* + TPCircularBufferTail(TPCircularBuffer* buffer, int32_t* availableBytes) + { + *availableBytes = buffer->fillCount; + if (*availableBytes == 0) + return NULL; + return (void*)((char*)buffer->buffer + buffer->tail); + } + + /*! + * Consume bytes in buffer + * + * This frees up the just-read bytes, ready for writing again. + * + * @param buffer Circular buffer + * @param amount Number of bytes to consume + */ + static __inline__ __attribute__((always_inline)) void + TPCircularBufferConsume(TPCircularBuffer* buffer, int32_t amount) + { + buffer->tail = (buffer->tail + amount) % buffer->length; + OSAtomicAdd32Barrier(-amount, &buffer->fillCount); + assert(buffer->fillCount >= 0); + } + + /*! + * Version of TPCircularBufferConsume without the memory barrier, for more optimal use in + * single-threaded contexts + */ + static __inline__ __attribute__((always_inline)) void + TPCircularBufferConsumeNoBarrier(TPCircularBuffer* buffer, int32_t amount) + { + buffer->tail = (buffer->tail + amount) % buffer->length; + buffer->fillCount -= amount; + assert(buffer->fillCount >= 0); + } + + /*! + * Access front of buffer + * + * This gives you a pointer to the front of the buffer, ready + * for writing, and the number of available bytes to write. + * + * @param buffer Circular buffer + * @param availableBytes On output, the number of bytes ready for writing + * @return Pointer to the first bytes ready for writing, or NULL if buffer is full + */ + static __inline__ __attribute__((always_inline)) void* + TPCircularBufferHead(TPCircularBuffer* buffer, int32_t* availableBytes) + { + *availableBytes = (buffer->length - buffer->fillCount); + if (*availableBytes == 0) + return NULL; + return (void*)((char*)buffer->buffer + buffer->head); + } + + // Writing (producing) + + /*! + * Produce bytes in buffer + * + * This marks the given section of the buffer ready for reading. + * + * @param buffer Circular buffer + * @param amount Number of bytes to produce + */ + static __inline__ __attribute__((always_inline)) void + TPCircularBufferProduce(TPCircularBuffer* buffer, int amount) + { + buffer->head = (buffer->head + amount) % buffer->length; + OSAtomicAdd32Barrier(amount, &buffer->fillCount); + assert(buffer->fillCount <= buffer->length); + } + + /*! + * Version of TPCircularBufferProduce without the memory barrier, for more optimal use in + * single-threaded contexts + */ + static __inline__ __attribute__((always_inline)) void + TPCircularBufferProduceNoBarrier(TPCircularBuffer* buffer, int amount) + { + buffer->head = (buffer->head + amount) % buffer->length; + buffer->fillCount += amount; + assert(buffer->fillCount <= buffer->length); + } + + /*! + * Helper routine to copy bytes to buffer + * + * This copies the given bytes to the buffer, and marks them ready for writing. + * + * @param buffer Circular buffer + * @param src Source buffer + * @param len Number of bytes in source buffer + * @return true if bytes copied, false if there was insufficient space + */ + static __inline__ __attribute__((always_inline)) bool + TPCircularBufferProduceBytes(TPCircularBuffer* buffer, const void* src, int32_t len) + { + int32_t space; + void* ptr = TPCircularBufferHead(buffer, &space); + if (space < len) + return false; + memcpy(ptr, src, len); + TPCircularBufferProduce(buffer, len); + return true; + } #ifdef __cplusplus } diff --git a/channels/rdpsnd/client/ios/rdpsnd_ios.c b/channels/rdpsnd/client/ios/rdpsnd_ios.c index 6431644..29feb97 100644 --- a/channels/rdpsnd/client/ios/rdpsnd_ios.c +++ b/channels/rdpsnd/client/ios/rdpsnd_ios.c @@ -33,8 +33,8 @@ #include "rdpsnd_main.h" #include "TPCircularBuffer.h" -#define INPUT_BUFFER_SIZE 32768 -#define CIRCULAR_BUFFER_SIZE (INPUT_BUFFER_SIZE * 4) +#define INPUT_BUFFER_SIZE 32768 +#define CIRCULAR_BUFFER_SIZE (INPUT_BUFFER_SIZE * 4) typedef struct rdpsnd_ios_plugin { @@ -47,14 +47,10 @@ typedef struct rdpsnd_ios_plugin #define THIS(__ptr) ((rdpsndIOSPlugin*)__ptr) -static OSStatus rdpsnd_ios_render_cb( - void* inRefCon, - AudioUnitRenderActionFlags __unused* ioActionFlags, - const AudioTimeStamp __unused* inTimeStamp, - UInt32 inBusNumber, - UInt32 __unused inNumberFrames, - AudioBufferList* ioData -) +static OSStatus rdpsnd_ios_render_cb(void* inRefCon, + AudioUnitRenderActionFlags __unused* ioActionFlags, + const AudioTimeStamp __unused* inTimeStamp, UInt32 inBusNumber, + UInt32 __unused inNumberFrames, AudioBufferList* ioData) { unsigned int i; @@ -182,22 +178,17 @@ static BOOL rdpsnd_ios_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in return FALSE; /* Set the format for the AudioUnit. */ - AudioStreamBasicDescription audioFormat = {0}; - audioFormat.mSampleRate = format->nSamplesPerSec; - audioFormat.mFormatID = kAudioFormatLinearPCM; - audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; - audioFormat.mFramesPerPacket = 1; /* imminent property of the Linear PCM */ + AudioStreamBasicDescription audioFormat = { 0 }; + audioFormat.mSampleRate = format->nSamplesPerSec; + audioFormat.mFormatID = kAudioFormatLinearPCM; + audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; + audioFormat.mFramesPerPacket = 1; /* imminent property of the Linear PCM */ audioFormat.mChannelsPerFrame = format->nChannels; - audioFormat.mBitsPerChannel = format->wBitsPerSample; - audioFormat.mBytesPerFrame = (format->wBitsPerSample * format->nChannels) / 8; - audioFormat.mBytesPerPacket = audioFormat.mBytesPerFrame * audioFormat.mFramesPerPacket; - status = AudioUnitSetProperty( - p->audio_unit, - kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Input, - 0, - &audioFormat, - sizeof(audioFormat)); + audioFormat.mBitsPerChannel = format->wBitsPerSample; + audioFormat.mBytesPerFrame = (format->wBitsPerSample * format->nChannels) / 8; + audioFormat.mBytesPerPacket = audioFormat.mBytesPerFrame * audioFormat.mFramesPerPacket; + status = AudioUnitSetProperty(p->audio_unit, kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, 0, &audioFormat, sizeof(audioFormat)); if (status != 0) { @@ -207,16 +198,12 @@ static BOOL rdpsnd_ios_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in } /* Set up the AudioUnit callback. */ - AURenderCallbackStruct callbackStruct = {0}; + AURenderCallbackStruct callbackStruct = { 0 }; callbackStruct.inputProc = rdpsnd_ios_render_cb; callbackStruct.inputProcRefCon = p; - status = AudioUnitSetProperty( - p->audio_unit, - kAudioUnitProperty_SetRenderCallback, - kAudioUnitScope_Input, - 0, - &callbackStruct, - sizeof(callbackStruct)); + status = + AudioUnitSetProperty(p->audio_unit, kAudioUnitProperty_SetRenderCallback, + kAudioUnitScope_Input, 0, &callbackStruct, sizeof(callbackStruct)); if (status != 0) { @@ -279,9 +266,9 @@ static void rdpsnd_ios_free(rdpsndDevicePlugin* device) } #ifdef BUILTIN_CHANNELS -#define freerdp_rdpsnd_client_subsystem_entry ios_freerdp_rdpsnd_client_subsystem_entry +#define freerdp_rdpsnd_client_subsystem_entry ios_freerdp_rdpsnd_client_subsystem_entry #else -#define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry +#define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry #endif /** @@ -291,7 +278,7 @@ static void rdpsnd_ios_free(rdpsndDevicePlugin* device) */ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pEntryPoints) { - rdpsndIOSPlugin* p = (rdpsndIOSPlugin*) calloc(1, sizeof(rdpsndIOSPlugin)); + rdpsndIOSPlugin* p = (rdpsndIOSPlugin*)calloc(1, sizeof(rdpsndIOSPlugin)); if (!p) return CHANNEL_RC_NO_MEMORY; diff --git a/channels/rdpsnd/client/mac/CMakeLists.txt b/channels/rdpsnd/client/mac/CMakeLists.txt index 63c4331..8b84656 100644 --- a/channels/rdpsnd/client/mac/CMakeLists.txt +++ b/channels/rdpsnd/client/mac/CMakeLists.txt @@ -19,12 +19,14 @@ define_channel_client_subsystem("rdpsnd" "mac" "") -FIND_LIBRARY(CORE_AUDIO CoreAudio) -FIND_LIBRARY(AUDIO_TOOL AudioToolbox) +find_library(COCOA_LIBRARY Cocoa REQUIRED) FIND_LIBRARY(CORE_FOUNDATION CoreFoundation) +FIND_LIBRARY(CORE_AUDIO CoreAudio REQUIRED) +FIND_LIBRARY(AUDIO_TOOL AudioToolbox REQUIRED) +FIND_LIBRARY(AV_FOUNDATION AVFoundation REQUIRED) set(${MODULE_PREFIX}_SRCS - rdpsnd_mac.c) + rdpsnd_mac.m) include_directories(..) include_directories(${MACAUDIO_INCLUDE_DIRS}) @@ -35,7 +37,9 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${AUDIO_TOOL} + ${AV_FOUNDATION} ${CORE_AUDIO} + ${COCOA_LIBRARY} ${CORE_FOUNDATION}) set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp winpr) diff --git a/channels/rdpsnd/client/mac/rdpsnd_mac.m b/channels/rdpsnd/client/mac/rdpsnd_mac.m new file mode 100644 index 0000000..ffdfb9f --- /dev/null +++ b/channels/rdpsnd/client/mac/rdpsnd_mac.m @@ -0,0 +1,373 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Audio Output Virtual Channel + * + * Copyright 2012 Laxmikant Rashinkar + * Copyright 2015 Thincast Technologies GmbH + * Copyright 2015 DI (FH) Martin Haimberger + * Copyright 2016 Inuvika Inc. + * Copyright 2016 David PHAM-VAN + * + * 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 "rdpsnd_main.h" + +struct rdpsnd_mac_plugin +{ + rdpsndDevicePlugin device; + + BOOL isOpen; + BOOL isPlaying; + + UINT32 latency; + AUDIO_FORMAT format; + + AVAudioEngine *engine; + AVAudioPlayerNode *player; + UINT64 diff; +}; +typedef struct rdpsnd_mac_plugin rdpsndMacPlugin; + +static BOOL rdpsnd_mac_set_format(rdpsndDevicePlugin *device, const AUDIO_FORMAT *format, + UINT32 latency) +{ + rdpsndMacPlugin *mac = (rdpsndMacPlugin *)device; + if (!mac || !format) + return FALSE; + + mac->latency = latency; + mac->format = *format; + + audio_format_print(WLog_Get(TAG), WLOG_DEBUG, format); + return TRUE; +} + +static char *FormatError(OSStatus st) +{ + switch (st) + { + case kAudioFileUnspecifiedError: + return "kAudioFileUnspecifiedError"; + + case kAudioFileUnsupportedFileTypeError: + return "kAudioFileUnsupportedFileTypeError"; + + case kAudioFileUnsupportedDataFormatError: + return "kAudioFileUnsupportedDataFormatError"; + + case kAudioFileUnsupportedPropertyError: + return "kAudioFileUnsupportedPropertyError"; + + case kAudioFileBadPropertySizeError: + return "kAudioFileBadPropertySizeError"; + + case kAudioFilePermissionsError: + return "kAudioFilePermissionsError"; + + case kAudioFileNotOptimizedError: + return "kAudioFileNotOptimizedError"; + + case kAudioFileInvalidChunkError: + return "kAudioFileInvalidChunkError"; + + case kAudioFileDoesNotAllow64BitDataSizeError: + return "kAudioFileDoesNotAllow64BitDataSizeError"; + + case kAudioFileInvalidPacketOffsetError: + return "kAudioFileInvalidPacketOffsetError"; + + case kAudioFileInvalidFileError: + return "kAudioFileInvalidFileError"; + + case kAudioFileOperationNotSupportedError: + return "kAudioFileOperationNotSupportedError"; + + case kAudioFileNotOpenError: + return "kAudioFileNotOpenError"; + + case kAudioFileEndOfFileError: + return "kAudioFileEndOfFileError"; + + case kAudioFilePositionError: + return "kAudioFilePositionError"; + + case kAudioFileFileNotFoundError: + return "kAudioFileFileNotFoundError"; + + default: + return "unknown error"; + } +} + +static void rdpsnd_mac_release(rdpsndMacPlugin *mac) +{ + if (mac->player) + [mac->player release]; + mac->player = NULL; + + if (mac->engine) + [mac->engine release]; + mac->engine = NULL; +} + +static BOOL rdpsnd_mac_open(rdpsndDevicePlugin *device, const AUDIO_FORMAT *format, UINT32 latency) +{ + AudioDeviceID outputDeviceID; + UInt32 propertySize; + OSStatus err; + NSError *error; + rdpsndMacPlugin *mac = (rdpsndMacPlugin *)device; + AudioObjectPropertyAddress propertyAddress = { kAudioHardwarePropertyDefaultSystemOutputDevice, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster }; + + if (mac->isOpen) + return TRUE; + + if (!rdpsnd_mac_set_format(device, format, latency)) + return FALSE; + + propertySize = sizeof(outputDeviceID); + err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, + &propertySize, &outputDeviceID); + if (err) + { + WLog_ERR(TAG, "AudioHardwareGetProperty: %s", FormatError(err)); + return FALSE; + } + + mac->engine = [[AVAudioEngine alloc] init]; + if (!mac->engine) + return FALSE; + + if (@available(macOS 10.15, *)) + { + /* Setting the output audio device on 10.15 or later breaks sound playback. Do not set for + * now until we find a proper fix for #5747 */ + } + else + { + err = AudioUnitSetProperty(mac->engine.outputNode.audioUnit, + kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, + 0, &outputDeviceID, sizeof(outputDeviceID)); + if (err) + { + rdpsnd_mac_release(mac); + WLog_ERR(TAG, "AudioUnitSetProperty: %s", FormatError(err)); + return FALSE; + } + } + + mac->player = [[AVAudioPlayerNode alloc] init]; + if (!mac->player) + { + rdpsnd_mac_release(mac); + WLog_ERR(TAG, "AVAudioPlayerNode::init() failed"); + return FALSE; + } + + [mac->engine attachNode:mac->player]; + + [mac->engine connect:mac->player to:mac->engine.mainMixerNode format:nil]; + + if (![mac->engine startAndReturnError:&error]) + { + device->Close(device); + WLog_ERR(TAG, "Failed to start audio player %s", [error.localizedDescription UTF8String]); + return FALSE; + } + + mac->isOpen = TRUE; + return TRUE; +} + +static void rdpsnd_mac_close(rdpsndDevicePlugin *device) +{ + rdpsndMacPlugin *mac = (rdpsndMacPlugin *)device; + + if (mac->isPlaying) + { + [mac->player stop]; + mac->isPlaying = FALSE; + } + + if (mac->isOpen) + { + [mac->engine stop]; + mac->isOpen = FALSE; + } + + rdpsnd_mac_release(mac); +} + +static void rdpsnd_mac_free(rdpsndDevicePlugin *device) +{ + rdpsndMacPlugin *mac = (rdpsndMacPlugin *)device; + device->Close(device); + free(mac); +} + +static BOOL rdpsnd_mac_format_supported(rdpsndDevicePlugin *device, const AUDIO_FORMAT *format) +{ + WINPR_UNUSED(device); + + switch (format->wFormatTag) + { + case WAVE_FORMAT_PCM: + if (format->wBitsPerSample != 16) + return FALSE; + return TRUE; + + default: + return FALSE; + } +} + +static BOOL rdpsnd_mac_set_volume(rdpsndDevicePlugin *device, UINT32 value) +{ + Float32 fVolume; + UINT16 volumeLeft; + UINT16 volumeRight; + rdpsndMacPlugin *mac = (rdpsndMacPlugin *)device; + + if (!mac->player) + return FALSE; + + volumeLeft = (value & 0xFFFF); + volumeRight = ((value >> 16) & 0xFFFF); + fVolume = ((float)volumeLeft) / 65535.0f; + + mac->player.volume = fVolume; + + return TRUE; +} + +static void rdpsnd_mac_start(rdpsndDevicePlugin *device) +{ + rdpsndMacPlugin *mac = (rdpsndMacPlugin *)device; + + if (!mac->isPlaying) + { + [mac->player play]; + + mac->isPlaying = TRUE; + mac->diff = 100; /* Initial latency, corrected after first sample is played. */ + } +} + +static UINT rdpsnd_mac_play(rdpsndDevicePlugin *device, const BYTE *data, size_t size) +{ + rdpsndMacPlugin *mac = (rdpsndMacPlugin *)device; + AVAudioPCMBuffer *buffer; + AVAudioFormat *format; + float *const *db; + size_t pos, step, x; + AVAudioFrameCount count; + UINT64 start = GetTickCount64(); + + if (!mac->isOpen) + return 0; + + step = 2 * mac->format.nChannels; + + count = size / step; + format = [[AVAudioFormat alloc] initWithCommonFormat:AVAudioPCMFormatFloat32 + sampleRate:mac->format.nSamplesPerSec + channels:mac->format.nChannels + interleaved:NO]; + if (!format) + { + WLog_WARN(TAG, "AVAudioFormat::init() failed"); + return 0; + } + buffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:format frameCapacity:count]; + if (!buffer) + { + [format release]; + WLog_WARN(TAG, "AVAudioPCMBuffer::init() failed"); + return 0; + } + + buffer.frameLength = buffer.frameCapacity; + db = buffer.floatChannelData; + + for (pos = 0; pos < count; pos++) + { + const BYTE *d = &data[pos * step]; + for (x = 0; x < mac->format.nChannels; x++) + { + const float val = (int16_t)((uint16_t)d[0] | ((uint16_t)d[1] << 8)) / 32768.0f; + db[x][pos] = val; + d += sizeof(int16_t); + } + } + + rdpsnd_mac_start(device); + + [mac->player scheduleBuffer:buffer + completionHandler:^{ + UINT64 stop = GetTickCount64(); + if (start > stop) + mac->diff = 0; + else + mac->diff = stop - start; + }]; + + return mac->diff > UINT_MAX ? UINT_MAX : mac->diff; +} + +#ifdef BUILTIN_CHANNELS +#define freerdp_rdpsnd_client_subsystem_entry mac_freerdp_rdpsnd_client_subsystem_entry +#else +#define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry +#endif + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pEntryPoints) +{ + rdpsndMacPlugin *mac; + mac = (rdpsndMacPlugin *)calloc(1, sizeof(rdpsndMacPlugin)); + + if (!mac) + return CHANNEL_RC_NO_MEMORY; + + mac->device.Open = rdpsnd_mac_open; + mac->device.FormatSupported = rdpsnd_mac_format_supported; + mac->device.SetVolume = rdpsnd_mac_set_volume; + mac->device.Play = rdpsnd_mac_play; + mac->device.Close = rdpsnd_mac_close; + mac->device.Free = rdpsnd_mac_free; + pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin *)mac); + return CHANNEL_RC_OK; +} diff --git a/channels/rdpsnd/client/opensles/opensl_io.c b/channels/rdpsnd/client/opensles/opensl_io.c index ffc24e1..61afc10 100644 --- a/channels/rdpsnd/client/opensles/opensl_io.c +++ b/channels/rdpsnd/client/opensles/opensl_io.c @@ -6,14 +6,14 @@ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * 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. + * Neither the name of the nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -32,7 +32,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "rdpsnd_main.h" #include "opensl_io.h" #define CONV16BIT 32768 -#define CONVMYFLT (1./32768.) +#define CONVMYFLT (1. / 32768.) static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void* context); @@ -42,22 +42,24 @@ static SLresult openSLCreateEngine(OPENSL_STREAM* p) SLresult result; // create engine result = slCreateEngine(&(p->engineObject), 0, NULL, 0, NULL, NULL); - DEBUG_SND("engineObject=%p", (void*) p->engineObject); + DEBUG_SND("engineObject=%p", (void*)p->engineObject); - if (result != SL_RESULT_SUCCESS) goto engine_end; + if (result != SL_RESULT_SUCCESS) + goto engine_end; // realize the engine result = (*p->engineObject)->Realize(p->engineObject, SL_BOOLEAN_FALSE); - DEBUG_SND("Realize=%"PRIu32"", result); + DEBUG_SND("Realize=%" PRIu32 "", result); - if (result != SL_RESULT_SUCCESS) goto engine_end; + if (result != SL_RESULT_SUCCESS) + goto engine_end; // get the engine interface, which is needed in order to create other objects - result = (*p->engineObject)->GetInterface(p->engineObject, SL_IID_ENGINE, - &(p->engineEngine)); - DEBUG_SND("engineEngine=%p", (void*) p->engineEngine); + result = (*p->engineObject)->GetInterface(p->engineObject, SL_IID_ENGINE, &(p->engineEngine)); + DEBUG_SND("engineEngine=%p", (void*)p->engineEngine); - if (result != SL_RESULT_SUCCESS) goto engine_end; + if (result != SL_RESULT_SUCCESS) + goto engine_end; engine_end: return result; @@ -68,18 +70,15 @@ static SLresult openSLPlayOpen(OPENSL_STREAM* p) { SLresult result; SLuint32 sr = p->sr; - SLuint32 channels = p->outchannels; + SLuint32 channels = p->outchannels; assert(p->engineObject); assert(p->engineEngine); if (channels) { // configure audio source - SLDataLocator_AndroidSimpleBufferQueue loc_bufq = - { - SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, - p->queuesize - }; + SLDataLocator_AndroidSimpleBufferQueue loc_bufq = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, + p->queuesize }; switch (sr) { @@ -135,90 +134,102 @@ static SLresult openSLPlayOpen(OPENSL_STREAM* p) return -1; } - const SLInterfaceID ids[] = {SL_IID_VOLUME}; - const SLboolean req[] = {SL_BOOLEAN_FALSE}; - result = (*p->engineEngine)->CreateOutputMix(p->engineEngine, - &(p->outputMixObject), 1, ids, req); - DEBUG_SND("engineEngine=%p", (void*) p->engineEngine); + const SLInterfaceID ids[] = { SL_IID_VOLUME }; + const SLboolean req[] = { SL_BOOLEAN_FALSE }; + result = (*p->engineEngine) + ->CreateOutputMix(p->engineEngine, &(p->outputMixObject), 1, ids, req); + DEBUG_SND("engineEngine=%p", (void*)p->engineEngine); assert(!result); - if (result != SL_RESULT_SUCCESS) goto end_openaudio; + if (result != SL_RESULT_SUCCESS) + goto end_openaudio; // realize the output mix result = (*p->outputMixObject)->Realize(p->outputMixObject, SL_BOOLEAN_FALSE); - DEBUG_SND("Realize=%"PRIu32"", result); + DEBUG_SND("Realize=%" PRIu32 "", result); assert(!result); - if (result != SL_RESULT_SUCCESS) goto end_openaudio; + if (result != SL_RESULT_SUCCESS) + goto end_openaudio; int speakers; if (channels > 1) speakers = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; - else speakers = SL_SPEAKER_FRONT_CENTER; - - SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, channels, sr, - SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16, - speakers, SL_BYTEORDER_LITTLEENDIAN - }; - SLDataSource audioSrc = {&loc_bufq, &format_pcm}; + else + speakers = SL_SPEAKER_FRONT_CENTER; + + SLDataFormat_PCM format_pcm = { SL_DATAFORMAT_PCM, + channels, + sr, + SL_PCMSAMPLEFORMAT_FIXED_16, + SL_PCMSAMPLEFORMAT_FIXED_16, + speakers, + SL_BYTEORDER_LITTLEENDIAN }; + SLDataSource audioSrc = { &loc_bufq, &format_pcm }; // configure audio sink - SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, p->outputMixObject}; - SLDataSink audioSnk = {&loc_outmix, NULL}; + SLDataLocator_OutputMix loc_outmix = { SL_DATALOCATOR_OUTPUTMIX, p->outputMixObject }; + SLDataSink audioSnk = { &loc_outmix, NULL }; // create audio player - const SLInterfaceID ids1[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_VOLUME}; - const SLboolean req1[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; - result = (*p->engineEngine)->CreateAudioPlayer(p->engineEngine, - &(p->bqPlayerObject), &audioSrc, &audioSnk, 2, ids1, req1); - DEBUG_SND("bqPlayerObject=%p", (void*) p->bqPlayerObject); + const SLInterfaceID ids1[] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_VOLUME }; + const SLboolean req1[] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE }; + result = (*p->engineEngine) + ->CreateAudioPlayer(p->engineEngine, &(p->bqPlayerObject), &audioSrc, + &audioSnk, 2, ids1, req1); + DEBUG_SND("bqPlayerObject=%p", (void*)p->bqPlayerObject); assert(!result); - if (result != SL_RESULT_SUCCESS) goto end_openaudio; + if (result != SL_RESULT_SUCCESS) + goto end_openaudio; // realize the player result = (*p->bqPlayerObject)->Realize(p->bqPlayerObject, SL_BOOLEAN_FALSE); - DEBUG_SND("Realize=%"PRIu32"", result); + DEBUG_SND("Realize=%" PRIu32 "", result); assert(!result); - if (result != SL_RESULT_SUCCESS) goto end_openaudio; + if (result != SL_RESULT_SUCCESS) + goto end_openaudio; // get the play interface - result = (*p->bqPlayerObject)->GetInterface(p->bqPlayerObject, SL_IID_PLAY, - &(p->bqPlayerPlay)); - DEBUG_SND("bqPlayerPlay=%p", (void*) p->bqPlayerPlay); + result = + (*p->bqPlayerObject)->GetInterface(p->bqPlayerObject, SL_IID_PLAY, &(p->bqPlayerPlay)); + DEBUG_SND("bqPlayerPlay=%p", (void*)p->bqPlayerPlay); assert(!result); - if (result != SL_RESULT_SUCCESS) goto end_openaudio; + if (result != SL_RESULT_SUCCESS) + goto end_openaudio; // get the volume interface - result = (*p->bqPlayerObject)->GetInterface(p->bqPlayerObject, SL_IID_VOLUME, - &(p->bqPlayerVolume)); - DEBUG_SND("bqPlayerVolume=%p", (void*) p->bqPlayerVolume); + result = (*p->bqPlayerObject) + ->GetInterface(p->bqPlayerObject, SL_IID_VOLUME, &(p->bqPlayerVolume)); + DEBUG_SND("bqPlayerVolume=%p", (void*)p->bqPlayerVolume); assert(!result); - if (result != SL_RESULT_SUCCESS) goto end_openaudio; + if (result != SL_RESULT_SUCCESS) + goto end_openaudio; // get the buffer queue interface - result = (*p->bqPlayerObject)->GetInterface(p->bqPlayerObject, - SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - &(p->bqPlayerBufferQueue)); - DEBUG_SND("bqPlayerBufferQueue=%p", (void*) p->bqPlayerBufferQueue); + result = (*p->bqPlayerObject) + ->GetInterface(p->bqPlayerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, + &(p->bqPlayerBufferQueue)); + DEBUG_SND("bqPlayerBufferQueue=%p", (void*)p->bqPlayerBufferQueue); assert(!result); - if (result != SL_RESULT_SUCCESS) goto end_openaudio; + if (result != SL_RESULT_SUCCESS) + goto end_openaudio; // register callback on the buffer queue - result = (*p->bqPlayerBufferQueue)->RegisterCallback(p->bqPlayerBufferQueue, - bqPlayerCallback, p); - DEBUG_SND("bqPlayerCallback=%p", (void*) p->bqPlayerCallback); + result = (*p->bqPlayerBufferQueue) + ->RegisterCallback(p->bqPlayerBufferQueue, bqPlayerCallback, p); + DEBUG_SND("bqPlayerCallback=%p", (void*)p->bqPlayerCallback); assert(!result); - if (result != SL_RESULT_SUCCESS) goto end_openaudio; + if (result != SL_RESULT_SUCCESS) + goto end_openaudio; // set the player's state to playing - result = (*p->bqPlayerPlay)->SetPlayState(p->bqPlayerPlay, - SL_PLAYSTATE_PLAYING); - DEBUG_SND("SetPlayState=%"PRIu32"", result); + result = (*p->bqPlayerPlay)->SetPlayState(p->bqPlayerPlay, SL_PLAYSTATE_PLAYING); + DEBUG_SND("SetPlayState=%" PRIu32 "", result); assert(!result); end_openaudio: assert(!result); @@ -258,13 +269,11 @@ static void openSLDestroyEngine(OPENSL_STREAM* p) } } - // open the android audio device for and/or output -OPENSL_STREAM* android_OpenAudioDevice(int sr, int outchannels, - int bufferframes) +OPENSL_STREAM* android_OpenAudioDevice(int sr, int outchannels, int bufferframes) { OPENSL_STREAM* p; - p = (OPENSL_STREAM*) calloc(1, sizeof(OPENSL_STREAM)); + p = (OPENSL_STREAM*)calloc(1, sizeof(OPENSL_STREAM)); if (!p) return NULL; @@ -313,7 +322,7 @@ void android_CloseAudioDevice(OPENSL_STREAM* p) // this callback handler is called every time a buffer finishes playing static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void* context) { - OPENSL_STREAM* p = (OPENSL_STREAM*) context; + OPENSL_STREAM* p = (OPENSL_STREAM*)context; assert(p); assert(p->queue); void* data = Queue_Dequeue(p->queue); @@ -328,8 +337,8 @@ int android_AudioOut(OPENSL_STREAM* p, const short* buffer, int size) assert(size > 0); /* Assure, that the queue is not full. */ - if (p->queuesize <= Queue_Count(p->queue) - && WaitForSingleObject(p->queue->event, INFINITE) == WAIT_FAILED) + if (p->queuesize <= Queue_Count(p->queue) && + WaitForSingleObject(p->queue->event, INFINITE) == WAIT_FAILED) { DEBUG_SND("WaitForSingleObject failed!"); return -1; @@ -345,8 +354,7 @@ int android_AudioOut(OPENSL_STREAM* p, const short* buffer, int size) memcpy(data, buffer, size * sizeof(short)); Queue_Enqueue(p->queue, data); - (*p->bqPlayerBufferQueue)->Enqueue(p->bqPlayerBufferQueue, - data, sizeof(short) * size); + (*p->bqPlayerBufferQueue)->Enqueue(p->bqPlayerBufferQueue, data, sizeof(short) * size); return size; } @@ -394,8 +402,7 @@ int android_GetOutputVolumeMax(OPENSL_STREAM* p) SLmillibel level; assert(p); assert(p->bqPlayerVolume); - SLresult rc = (*p->bqPlayerVolume)->GetMaxVolumeLevel(p->bqPlayerVolume, - &level); + SLresult rc = (*p->bqPlayerVolume)->GetMaxVolumeLevel(p->bqPlayerVolume, &level); if (SL_RESULT_SUCCESS != rc) return 0; @@ -403,7 +410,6 @@ int android_GetOutputVolumeMax(OPENSL_STREAM* p) return level; } - BOOL android_SetOutputVolume(OPENSL_STREAM* p, int level) { SLresult rc = (*p->bqPlayerVolume)->SetVolumeLevel(p->bqPlayerVolume, level); @@ -413,4 +419,3 @@ BOOL android_SetOutputVolume(OPENSL_STREAM* p, int level) return TRUE; } - diff --git a/channels/rdpsnd/client/opensles/opensl_io.h b/channels/rdpsnd/client/opensles/opensl_io.h index 0bb121a..57dc048 100644 --- a/channels/rdpsnd/client/opensles/opensl_io.h +++ b/channels/rdpsnd/client/opensles/opensl_io.h @@ -6,14 +6,14 @@ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of the nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * 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. + * Neither the name of the nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -38,72 +38,71 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -typedef struct opensl_stream -{ - // engine interfaces - SLObjectItf engineObject; - SLEngineItf engineEngine; + typedef struct opensl_stream + { + // engine interfaces + SLObjectItf engineObject; + SLEngineItf engineEngine; - // output mix interfaces - SLObjectItf outputMixObject; + // output mix interfaces + SLObjectItf outputMixObject; - // buffer queue player interfaces - SLObjectItf bqPlayerObject; - SLPlayItf bqPlayerPlay; - SLVolumeItf bqPlayerVolume; - SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue; - SLEffectSendItf bqPlayerEffectSend; + // buffer queue player interfaces + SLObjectItf bqPlayerObject; + SLPlayItf bqPlayerPlay; + SLVolumeItf bqPlayerVolume; + SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue; + SLEffectSendItf bqPlayerEffectSend; - unsigned int outchannels; - unsigned int sr; + unsigned int outchannels; + unsigned int sr; - unsigned int queuesize; - wQueue* queue; -} OPENSL_STREAM; + unsigned int queuesize; + wQueue* queue; + } OPENSL_STREAM; -/* -Open the audio device with a given sampling rate (sr), output channels and IO buffer size -in frames. Returns a handle to the OpenSL stream -*/ -FREERDP_LOCAL OPENSL_STREAM* android_OpenAudioDevice(int sr, int outchannels, - int bufferframes); -/* -Close the audio device -*/ -FREERDP_LOCAL void android_CloseAudioDevice(OPENSL_STREAM* p); -/* -Write a buffer to the OpenSL stream *p, of size samples. Returns the number of samples written. -*/ -FREERDP_LOCAL int android_AudioOut(OPENSL_STREAM* p, const short* buffer, - int size); -/* - * Set the volume input level. - */ -FREERDP_LOCAL void android_SetInputVolume(OPENSL_STREAM* p, int level); -/* - * Get the current output mute setting. - */ -FREERDP_LOCAL int android_GetOutputMute(OPENSL_STREAM* p); -/* - * Change the current output mute setting. - */ -FREERDP_LOCAL BOOL android_SetOutputMute(OPENSL_STREAM* p, BOOL mute); -/* - * Get the current output volume level. - */ -FREERDP_LOCAL int android_GetOutputVolume(OPENSL_STREAM* p); -/* - * Get the maximum output volume level. - */ -FREERDP_LOCAL int android_GetOutputVolumeMax(OPENSL_STREAM* p); + /* + Open the audio device with a given sampling rate (sr), output channels and IO buffer size + in frames. Returns a handle to the OpenSL stream + */ + FREERDP_LOCAL OPENSL_STREAM* android_OpenAudioDevice(int sr, int outchannels, int bufferframes); + /* + Close the audio device + */ + FREERDP_LOCAL void android_CloseAudioDevice(OPENSL_STREAM* p); + /* + Write a buffer to the OpenSL stream *p, of size samples. Returns the number of samples written. + */ + FREERDP_LOCAL int android_AudioOut(OPENSL_STREAM* p, const short* buffer, int size); + /* + * Set the volume input level. + */ + FREERDP_LOCAL void android_SetInputVolume(OPENSL_STREAM* p, int level); + /* + * Get the current output mute setting. + */ + FREERDP_LOCAL int android_GetOutputMute(OPENSL_STREAM* p); + /* + * Change the current output mute setting. + */ + FREERDP_LOCAL BOOL android_SetOutputMute(OPENSL_STREAM* p, BOOL mute); + /* + * Get the current output volume level. + */ + FREERDP_LOCAL int android_GetOutputVolume(OPENSL_STREAM* p); + /* + * Get the maximum output volume level. + */ + FREERDP_LOCAL int android_GetOutputVolumeMax(OPENSL_STREAM* p); -/* - * Set the volume output level. - */ -FREERDP_LOCAL BOOL android_SetOutputVolume(OPENSL_STREAM* p, int level); + /* + * Set the volume output level. + */ + FREERDP_LOCAL BOOL android_SetOutputVolume(OPENSL_STREAM* p, int level); #ifdef __cplusplus }; #endif diff --git a/channels/rdpsnd/client/opensles/rdpsnd_opensles.c b/channels/rdpsnd/client/opensles/rdpsnd_opensles.c index 26ea455..3481d91 100644 --- a/channels/rdpsnd/client/opensles/rdpsnd_opensles.c +++ b/channels/rdpsnd/client/opensles/rdpsnd_opensles.c @@ -66,8 +66,7 @@ static int rdpsnd_opensles_volume_to_millibel(unsigned short level, int max) const int min = SL_MILLIBEL_MIN; const int step = max - min; const int rc = (level * step / 0xFFFF) + min; - DEBUG_SND("level=%hu, min=%d, max=%d, step=%d, result=%d", - level, min, max, step, rc); + DEBUG_SND("level=%hu, min=%d, max=%d, step=%d, result=%d", level, min, max, step, rc); return rc; } @@ -76,8 +75,7 @@ static unsigned short rdpsnd_opensles_millibel_to_volume(int millibel, int max) const int min = SL_MILLIBEL_MIN; const int range = max - min; const int rc = ((millibel - min) * 0xFFFF + range / 2 + 1) / range; - DEBUG_SND("millibel=%d, min=%d, max=%d, range=%d, result=%d", - millibel, min, max, range, rc); + DEBUG_SND("millibel=%d, min=%d, max=%d, range=%d, result=%d", millibel, min, max, range, rc); return rc; } @@ -96,12 +94,11 @@ static bool rdpsnd_opensles_check_handle(const rdpsndopenslesPlugin* hdl) return rc; } -static BOOL rdpsnd_opensles_set_volume(rdpsndDevicePlugin* device, - UINT32 volume); +static BOOL rdpsnd_opensles_set_volume(rdpsndDevicePlugin* device, UINT32 volume); static int rdpsnd_opensles_set_params(rdpsndopenslesPlugin* opensles) { - DEBUG_SND("opensles=%p", (void*) opensles); + DEBUG_SND("opensles=%p", (void*)opensles); if (!rdpsnd_opensles_check_handle(opensles)) return 0; @@ -109,23 +106,23 @@ static int rdpsnd_opensles_set_params(rdpsndopenslesPlugin* opensles) if (opensles->stream) android_CloseAudioDevice(opensles->stream); - opensles->stream = android_OpenAudioDevice( - opensles->rate, opensles->channels, 20); + opensles->stream = android_OpenAudioDevice(opensles->rate, opensles->channels, 20); return 0; } -static BOOL rdpsnd_opensles_set_format(rdpsndDevicePlugin* device, - const AUDIO_FORMAT* format, UINT32 latency) +static BOOL rdpsnd_opensles_set_format(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format, + UINT32 latency) { - rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*) device; + rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*)device; rdpsnd_opensles_check_handle(opensles); - DEBUG_SND("opensles=%p format=%p, latency=%"PRIu32, (void*) opensles, (void*) format, latency); + DEBUG_SND("opensles=%p format=%p, latency=%" PRIu32, (void*)opensles, (void*)format, latency); if (format) { - DEBUG_SND("format=%"PRIu16", cbsize=%"PRIu16", samples=%"PRIu32", bits=%"PRIu16", channels=%"PRIu16", align=%"PRIu16"", + DEBUG_SND("format=%" PRIu16 ", cbsize=%" PRIu16 ", samples=%" PRIu32 ", bits=%" PRIu16 + ", channels=%" PRIu16 ", align=%" PRIu16 "", format->wFormatTag, format->cbSize, format->nSamplesPerSec, - format->wBitsPerSample, format->nChannels, format->nBlockAlign); + format->wBitsPerSample, format->nChannels, format->nBlockAlign); opensles->rate = format->nSamplesPerSec; opensles->channels = format->nChannels; opensles->format = format->wFormatTag; @@ -137,18 +134,17 @@ static BOOL rdpsnd_opensles_set_format(rdpsndDevicePlugin* device, return (rdpsnd_opensles_set_params(opensles) == 0); } -static BOOL rdpsnd_opensles_open(rdpsndDevicePlugin* device, - const AUDIO_FORMAT* format, UINT32 latency) +static BOOL rdpsnd_opensles_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format, + UINT32 latency) { - rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*) device; - DEBUG_SND("opensles=%p format=%p, latency=%"PRIu32", rate=%"PRIu32"", - (void*) opensles, (void*) format, latency, opensles->rate); + rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*)device; + DEBUG_SND("opensles=%p format=%p, latency=%" PRIu32 ", rate=%" PRIu32 "", (void*)opensles, + (void*)format, latency, opensles->rate); if (rdpsnd_opensles_check_handle(opensles)) return TRUE; - opensles->stream = android_OpenAudioDevice(opensles->rate, opensles->channels, - 20); + opensles->stream = android_OpenAudioDevice(opensles->rate, opensles->channels, 20); assert(opensles->stream); if (!opensles->stream) @@ -161,8 +157,8 @@ static BOOL rdpsnd_opensles_open(rdpsndDevicePlugin* device, static void rdpsnd_opensles_close(rdpsndDevicePlugin* device) { - rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*) device; - DEBUG_SND("opensles=%p", (void*) opensles); + rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*)device; + DEBUG_SND("opensles=%p", (void*)opensles); if (!rdpsnd_opensles_check_handle(opensles)) return; @@ -173,28 +169,27 @@ static void rdpsnd_opensles_close(rdpsndDevicePlugin* device) static void rdpsnd_opensles_free(rdpsndDevicePlugin* device) { - rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*) device; - DEBUG_SND("opensles=%p", (void*) opensles); + rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*)device; + DEBUG_SND("opensles=%p", (void*)opensles); assert(opensles); assert(opensles->device_name); free(opensles->device_name); free(opensles); } -static BOOL rdpsnd_opensles_format_supported(rdpsndDevicePlugin* device, - const AUDIO_FORMAT* format) +static BOOL rdpsnd_opensles_format_supported(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format) { - DEBUG_SND("format=%"PRIu16", cbsize=%"PRIu16", samples=%"PRIu32", bits=%"PRIu16", channels=%"PRIu16", align=%"PRIu16"", - format->wFormatTag, format->cbSize, format->nSamplesPerSec, - format->wBitsPerSample, format->nChannels, format->nBlockAlign); + DEBUG_SND("format=%" PRIu16 ", cbsize=%" PRIu16 ", samples=%" PRIu32 ", bits=%" PRIu16 + ", channels=%" PRIu16 ", align=%" PRIu16 "", + format->wFormatTag, format->cbSize, format->nSamplesPerSec, format->wBitsPerSample, + format->nChannels, format->nBlockAlign); assert(device); assert(format); switch (format->wFormatTag) { case WAVE_FORMAT_PCM: - if (format->cbSize == 0 && - format->nSamplesPerSec <= 48000 && + if (format->cbSize == 0 && format->nSamplesPerSec <= 48000 && (format->wBitsPerSample == 8 || format->wBitsPerSample == 16) && (format->nChannels == 1 || format->nChannels == 2)) { @@ -212,8 +207,8 @@ static BOOL rdpsnd_opensles_format_supported(rdpsndDevicePlugin* device, static UINT32 rdpsnd_opensles_get_volume(rdpsndDevicePlugin* device) { - rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*) device; - DEBUG_SND("opensles=%p", (void*) opensles); + rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*)device; + DEBUG_SND("opensles=%p", (void*)opensles); assert(opensles); if (opensles->stream) @@ -233,11 +228,10 @@ static UINT32 rdpsnd_opensles_get_volume(rdpsndDevicePlugin* device) return opensles->volume; } -static BOOL rdpsnd_opensles_set_volume(rdpsndDevicePlugin* device, - UINT32 value) +static BOOL rdpsnd_opensles_set_volume(rdpsndDevicePlugin* device, UINT32 value) { - rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*) device; - DEBUG_SND("opensles=%p, value=%"PRIu32"", (void*) opensles, value); + rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*)device; + DEBUG_SND("opensles=%p, value=%" PRIu32 "", (void*)opensles, value); assert(opensles); opensles->volume = value; @@ -261,23 +255,21 @@ static BOOL rdpsnd_opensles_set_volume(rdpsndDevicePlugin* device, return TRUE; } -static UINT rdpsnd_opensles_play(rdpsndDevicePlugin* device, - const BYTE* data, size_t size) +static UINT rdpsnd_opensles_play(rdpsndDevicePlugin* device, const BYTE* data, size_t size) { - union - { + union { const BYTE* b; const short* s; } src; int ret; - rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*) device; - DEBUG_SND("opensles=%p, data=%p, size=%d", (void*) opensles, (void*) data, size); + rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*)device; + DEBUG_SND("opensles=%p, data=%p, size=%d", (void*)opensles, (void*)data, size); if (!rdpsnd_opensles_check_handle(opensles)) return 0; src.b = data; - DEBUG_SND("size=%d, src=%p", size, (void*) src.b); + DEBUG_SND("size=%d, src=%p", size, (void*)src.b); assert(0 == size % 2); assert(size > 0); assert(src.b); @@ -291,34 +283,29 @@ static UINT rdpsnd_opensles_play(rdpsndDevicePlugin* device, static void rdpsnd_opensles_start(rdpsndDevicePlugin* device) { - rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*) device; + rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*)device; rdpsnd_opensles_check_handle(opensles); - DEBUG_SND("opensles=%p", (void*) opensles); + DEBUG_SND("opensles=%p", (void*)opensles); } -static COMMAND_LINE_ARGUMENT_A rdpsnd_opensles_args[] = -{ - { - "dev", COMMAND_LINE_VALUE_REQUIRED, "", - NULL, NULL, -1, NULL, "device" - }, - { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } -}; - -static int rdpsnd_opensles_parse_addin_args(rdpsndDevicePlugin* device, - ADDIN_ARGV* args) +static int rdpsnd_opensles_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV* args) { int status; DWORD flags; COMMAND_LINE_ARGUMENT_A* arg; - rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*) device; + rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*)device; + COMMAND_LINE_ARGUMENT_A rdpsnd_opensles_args[] = { + { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "device" }, + { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } + }; + assert(opensles); assert(args); - DEBUG_SND("opensles=%p, args=%p", (void*) opensles, (void*) args); - flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | - COMMAND_LINE_IGN_UNKNOWN_KEYWORD; - status = CommandLineParseArgumentsA(args->argc, args->argv, - rdpsnd_opensles_args, flags, opensles, NULL, NULL); + DEBUG_SND("opensles=%p, args=%p", (void*)opensles, (void*)args); + flags = + COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; + status = CommandLineParseArgumentsA(args->argc, args->argv, rdpsnd_opensles_args, flags, + opensles, NULL, NULL); if (status < 0) return status; @@ -330,8 +317,7 @@ static int rdpsnd_opensles_parse_addin_args(rdpsndDevicePlugin* device, if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) continue; - CommandLineSwitchStart(arg) - CommandLineSwitchCase(arg, "dev") + CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "dev") { opensles->device_name = _strdup(arg->Value); @@ -339,18 +325,15 @@ static int rdpsnd_opensles_parse_addin_args(rdpsndDevicePlugin* device, return ERROR_OUTOFMEMORY; } CommandLineSwitchEnd(arg) - } - while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); return status; } #ifdef BUILTIN_CHANNELS -#define freerdp_rdpsnd_client_subsystem_entry \ - opensles_freerdp_rdpsnd_client_subsystem_entry +#define freerdp_rdpsnd_client_subsystem_entry opensles_freerdp_rdpsnd_client_subsystem_entry #else -#define freerdp_rdpsnd_client_subsystem_entry \ - FREERDP_API freerdp_rdpsnd_client_subsystem_entry +#define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry #endif /** @@ -358,14 +341,13 @@ static int rdpsnd_opensles_parse_addin_args(rdpsndDevicePlugin* device, * * @return 0 on success, otherwise a Win32 error code */ -UINT freerdp_rdpsnd_client_subsystem_entry( - PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pEntryPoints) +UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pEntryPoints) { ADDIN_ARGV* args; rdpsndopenslesPlugin* opensles; UINT error; - DEBUG_SND("pEntryPoints=%p", (void*) pEntryPoints); - opensles = (rdpsndopenslesPlugin*) calloc(1, sizeof(rdpsndopenslesPlugin)); + DEBUG_SND("pEntryPoints=%p", (void*)pEntryPoints); + opensles = (rdpsndopenslesPlugin*)calloc(1, sizeof(rdpsndopenslesPlugin)); if (!opensles) return CHANNEL_RC_NO_MEMORY; @@ -379,7 +361,7 @@ UINT freerdp_rdpsnd_client_subsystem_entry( opensles->device.Close = rdpsnd_opensles_close; opensles->device.Free = rdpsnd_opensles_free; args = pEntryPoints->args; - rdpsnd_opensles_parse_addin_args((rdpsndDevicePlugin*) opensles, args); + rdpsnd_opensles_parse_addin_args((rdpsndDevicePlugin*)opensles, args); if (!opensles->device_name) { @@ -395,8 +377,7 @@ UINT freerdp_rdpsnd_client_subsystem_entry( opensles->rate = 44100; opensles->channels = 2; opensles->format = WAVE_FORMAT_ADPCM; - pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, - (rdpsndDevicePlugin*) opensles); + pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*)opensles); DEBUG_SND("success"); return CHANNEL_RC_OK; outstrdup: diff --git a/channels/rdpsnd/client/oss/rdpsnd_oss.c b/channels/rdpsnd/client/oss/rdpsnd_oss.c index ff402c9..7a7937d 100644 --- a/channels/rdpsnd/client/oss/rdpsnd_oss.c +++ b/channels/rdpsnd/client/oss/rdpsnd_oss.c @@ -67,13 +67,12 @@ struct rdpsnd_oss_plugin AUDIO_FORMAT format; }; -#define OSS_LOG_ERR(_text, _error) \ - { \ - if (_error != 0) \ +#define OSS_LOG_ERR(_text, _error) \ + { \ + if (_error != 0) \ WLog_ERR(TAG, "%s: %i - %s", _text, _error, strerror(_error)); \ } - static int rdpsnd_oss_get_format(const AUDIO_FORMAT* format) { switch (format->wFormatTag) @@ -111,8 +110,7 @@ static BOOL rdpsnd_oss_format_supported(rdpsndDevicePlugin* device, const AUDIO_ switch (format->wFormatTag) { case WAVE_FORMAT_PCM: - if (format->cbSize != 0 || - format->nSamplesPerSec > 48000 || + if (format->cbSize != 0 || format->nSamplesPerSec > 48000 || (format->wBitsPerSample != 8 && format->wBitsPerSample != 16) || (format->nChannels != 1 && format->nChannels != 2)) return FALSE; @@ -307,7 +305,7 @@ static UINT32 rdpsnd_oss_get_volume(rdpsndDevicePlugin* device) UINT16 dwVolumeLeft, dwVolumeRight; rdpsndOssPlugin* oss = (rdpsndOssPlugin*)device; /* On error return 50% volume. */ - dwVolumeLeft = ((50 * 0xFFFF) / 100); /* 50% */ + dwVolumeLeft = ((50 * 0xFFFF) / 100); /* 50% */ dwVolumeRight = ((50 * 0xFFFF) / 100); /* 50% */ dwVolume = ((dwVolumeLeft << 16) | dwVolumeRight); @@ -379,8 +377,8 @@ static UINT rdpsnd_oss_play(rdpsndDevicePlugin* device, const BYTE* data, size_t data += status; - if (status <= size) - size -= status; + if ((size_t)status <= size) + size -= (size_t)status; else size = 0; } @@ -388,22 +386,20 @@ static UINT rdpsnd_oss_play(rdpsndDevicePlugin* device, const BYTE* data, size_t return 10; /* TODO: Get real latency in [ms] */ } -static COMMAND_LINE_ARGUMENT_A rdpsnd_oss_args[] = -{ - { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "device" }, - { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } -}; - static int rdpsnd_oss_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV* args) { int status; - char* str_num, *eptr; + char *str_num, *eptr; DWORD flags; COMMAND_LINE_ARGUMENT_A* arg; rdpsndOssPlugin* oss = (rdpsndOssPlugin*)device; - flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; - status = CommandLineParseArgumentsA(args->argc, args->argv, rdpsnd_oss_args, flags, - oss, NULL, NULL); + COMMAND_LINE_ARGUMENT_A rdpsnd_oss_args[] = { { "dev", COMMAND_LINE_VALUE_REQUIRED, "", + NULL, NULL, -1, NULL, "device" }, + { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } }; + flags = + COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; + status = + CommandLineParseArgumentsA(args->argc, args->argv, rdpsnd_oss_args, flags, oss, NULL, NULL); if (status < 0) return status; @@ -416,8 +412,7 @@ static int rdpsnd_oss_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV* a if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) continue; - CommandLineSwitchStart(arg) - CommandLineSwitchCase(arg, "dev") + CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "dev") { str_num = _strdup(arg->Value); @@ -442,16 +437,15 @@ static int rdpsnd_oss_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV* a free(str_num); } CommandLineSwitchEnd(arg) - } - while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); return status; } #ifdef BUILTIN_CHANNELS -#define freerdp_rdpsnd_client_subsystem_entry oss_freerdp_rdpsnd_client_subsystem_entry +#define freerdp_rdpsnd_client_subsystem_entry oss_freerdp_rdpsnd_client_subsystem_entry #else -#define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry +#define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry #endif /** diff --git a/channels/rdpsnd/client/proxy/CMakeLists.txt b/channels/rdpsnd/client/proxy/CMakeLists.txt new file mode 100644 index 0000000..2d40750 --- /dev/null +++ b/channels/rdpsnd/client/proxy/CMakeLists.txt @@ -0,0 +1,33 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# 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. + +define_channel_client_subsystem("rdpsnd" "proxy" "") + +set(${MODULE_PREFIX}_SRCS + rdpsnd_proxy.c) + +include_directories(..) + +add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "") + +list(APPEND ${MODULE_PREFIX}_LIBS freerdp) +list(APPEND ${MODULE_PREFIX}_LIBS winpr) + +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client/proxy") diff --git a/channels/rdpsnd/client/proxy/rdpsnd_proxy.c b/channels/rdpsnd/client/proxy/rdpsnd_proxy.c new file mode 100644 index 0000000..dd6af04 --- /dev/null +++ b/channels/rdpsnd/client/proxy/rdpsnd_proxy.c @@ -0,0 +1,144 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * FreeRDP rdpsnd proxy subsystem + * + * Copyright 2019 Kobi Mizrachi + * + * 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 "rdpsnd_main.h" +#include "../../../../server/proxy/pf_context.h" + +typedef struct rdpsnd_proxy_plugin rdpsndProxyPlugin; + +struct rdpsnd_proxy_plugin +{ + rdpsndDevicePlugin device; + RdpsndServerContext* rdpsnd_server; +}; + +static BOOL rdpsnd_proxy_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format, + UINT32 latency) +{ + rdpsndProxyPlugin* proxy = (rdpsndProxyPlugin*)device; + + /* update proxy's rdpsnd server latency */ + proxy->rdpsnd_server->latency = latency; + return TRUE; +} + +static void rdpsnd_proxy_close(rdpsndDevicePlugin* device) +{ + /* do nothing */ +} + +static BOOL rdpsnd_proxy_set_volume(rdpsndDevicePlugin* device, UINT32 value) +{ + rdpsndProxyPlugin* proxy = (rdpsndProxyPlugin*)device; + proxy->rdpsnd_server->SetVolume(proxy->rdpsnd_server, value, value); + return TRUE; +} + +static void rdpsnd_proxy_free(rdpsndDevicePlugin* device) +{ + rdpsndProxyPlugin* proxy = (rdpsndProxyPlugin*)device; + + if (!proxy) + return; + + free(proxy); +} + +static BOOL rdpsnd_proxy_format_supported(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format) +{ + rdpsndProxyPlugin* proxy = (rdpsndProxyPlugin*)device; + + /* use the same format that proxy's server used */ + if (proxy->rdpsnd_server->selected_client_format == format->wFormatTag) + return TRUE; + + return FALSE; +} + +static UINT rdpsnd_proxy_play(rdpsndDevicePlugin* device, const BYTE* data, size_t size) +{ + rdpsndProxyPlugin* proxy = (rdpsndProxyPlugin*)device; + UINT64 start = GetTickCount(); + proxy->rdpsnd_server->SendSamples(proxy->rdpsnd_server, data, size / 4, start); + return GetTickCount() - start; +} + + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ + +#ifdef BUILTIN_CHANNELS +#define freerdp_rdpsnd_client_subsystem_entry proxy_freerdp_rdpsnd_client_subsystem_entry +#else +#define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry +#endif + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pEntryPoints) +{ + ADDIN_ARGV* args; + rdpsndProxyPlugin* proxy; + pClientContext* pc; + proxy = (rdpsndProxyPlugin*)calloc(1, sizeof(rdpsndProxyPlugin)); + + if (!proxy) + return CHANNEL_RC_NO_MEMORY; + + proxy->device.Open = rdpsnd_proxy_open; + proxy->device.FormatSupported = rdpsnd_proxy_format_supported; + proxy->device.SetVolume = rdpsnd_proxy_set_volume; + proxy->device.Play = rdpsnd_proxy_play; + proxy->device.Close = rdpsnd_proxy_close; + proxy->device.Free = rdpsnd_proxy_free; + args = pEntryPoints->args; + + pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, &proxy->device); + pc = (pClientContext*)freerdp_rdpsnd_get_context(pEntryPoints->rdpsnd); + if (pc == NULL) + { + free(proxy); + return ERROR_INTERNAL_ERROR; + } + + proxy->rdpsnd_server = pc->pdata->ps->rdpsnd; + return CHANNEL_RC_OK; +} diff --git a/channels/rdpsnd/client/pulse/rdpsnd_pulse.c b/channels/rdpsnd/client/pulse/rdpsnd_pulse.c index b367d95..7f3a6da 100644 --- a/channels/rdpsnd/client/pulse/rdpsnd_pulse.c +++ b/channels/rdpsnd/client/pulse/rdpsnd_pulse.c @@ -59,9 +59,11 @@ static void rdpsnd_pulse_get_sink_info(pa_context* c, const pa_sink_info* i, int void* userdata) { uint8_t x; - UINT16 dwVolumeLeft = ((50 * 0xFFFF) / 100); /* 50% */; - UINT16 dwVolumeRight = ((50 * 0xFFFF) / 100); /* 50% */; - rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) userdata; + UINT16 dwVolumeLeft = ((50 * 0xFFFF) / 100); /* 50% */ + ; + UINT16 dwVolumeRight = ((50 * 0xFFFF) / 100); /* 50% */ + ; + rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)userdata; if (!pulse || !c || !i) return; @@ -94,7 +96,7 @@ static void rdpsnd_pulse_get_sink_info(pa_context* c, const pa_sink_info* i, int static void rdpsnd_pulse_context_state_callback(pa_context* context, void* userdata) { pa_context_state_t state; - rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) userdata; + rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)userdata; state = pa_context_get_state(context); switch (state) @@ -117,7 +119,7 @@ static BOOL rdpsnd_pulse_connect(rdpsndDevicePlugin* device) { pa_operation* o; pa_context_state_t state; - rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device; + rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device; if (!pulse->context) return FALSE; @@ -170,7 +172,7 @@ static BOOL rdpsnd_pulse_connect(rdpsndDevicePlugin* device) static void rdpsnd_pulse_stream_success_callback(pa_stream* stream, int success, void* userdata) { - rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) userdata; + rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)userdata; pa_threaded_mainloop_signal(pulse->mainloop, 0); } @@ -190,7 +192,7 @@ static void rdpsnd_pulse_wait_for_operation(rdpsndPulsePlugin* pulse, pa_operati static void rdpsnd_pulse_stream_state_callback(pa_stream* stream, void* userdata) { pa_stream_state_t state; - rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) userdata; + rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)userdata; state = pa_stream_get_state(stream); switch (state) @@ -211,20 +213,20 @@ static void rdpsnd_pulse_stream_state_callback(pa_stream* stream, void* userdata static void rdpsnd_pulse_stream_request_callback(pa_stream* stream, size_t length, void* userdata) { - rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) userdata; + rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)userdata; pa_threaded_mainloop_signal(pulse->mainloop, 0); } static void rdpsnd_pulse_close(rdpsndDevicePlugin* device) { - rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device; + rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device; if (!pulse->context || !pulse->stream) return; pa_threaded_mainloop_lock(pulse->mainloop); - rdpsnd_pulse_wait_for_operation(pulse, pa_stream_drain(pulse->stream, - rdpsnd_pulse_stream_success_callback, pulse)); + rdpsnd_pulse_wait_for_operation( + pulse, pa_stream_drain(pulse->stream, rdpsnd_pulse_stream_success_callback, pulse)); pa_stream_disconnect(pulse->stream); pa_stream_unref(pulse->stream); pulse->stream = NULL; @@ -286,7 +288,7 @@ static BOOL rdpsnd_pulse_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* fo pa_stream_flags_t flags; pa_buffer_attr buffer_attr = { 0 }; char ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; - rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device; + rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device; if (!pulse->context || pulse->stream) return TRUE; @@ -320,14 +322,14 @@ static BOOL rdpsnd_pulse_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* fo { buffer_attr.maxlength = pa_usec_to_bytes(pulse->latency * 2 * 1000, &pulse->sample_spec); buffer_attr.tlength = pa_usec_to_bytes(pulse->latency * 1000, &pulse->sample_spec); - buffer_attr.prebuf = (UINT32) - 1; - buffer_attr.minreq = (UINT32) - 1; - buffer_attr.fragsize = (UINT32) - 1; + buffer_attr.prebuf = (UINT32)-1; + buffer_attr.minreq = (UINT32)-1; + buffer_attr.fragsize = (UINT32)-1; flags |= PA_STREAM_ADJUST_LATENCY; } - if (pa_stream_connect_playback(pulse->stream, - pulse->device_name, pulse->latency > 0 ? &buffer_attr : NULL, flags, NULL, NULL) < 0) + if (pa_stream_connect_playback(pulse->stream, pulse->device_name, + pulse->latency > 0 ? &buffer_attr : NULL, flags, NULL, NULL) < 0) { pa_threaded_mainloop_unlock(pulse->mainloop); return TRUE; @@ -359,7 +361,7 @@ static BOOL rdpsnd_pulse_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* fo static void rdpsnd_pulse_free(rdpsndDevicePlugin* device) { - rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device; + rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device; if (!pulse) return; @@ -388,13 +390,35 @@ static void rdpsnd_pulse_free(rdpsndDevicePlugin* device) free(pulse); } +static BOOL rdpsnd_pulse_default_format(rdpsndDevicePlugin* device, const AUDIO_FORMAT* desired, + AUDIO_FORMAT* defaultFormat) +{ + rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device; + if (!pulse || !defaultFormat) + return FALSE; + + *defaultFormat = *desired; + defaultFormat->data = NULL; + defaultFormat->cbSize = 0; + defaultFormat->wFormatTag = WAVE_FORMAT_PCM; + if ((defaultFormat->nChannels < 1) || (defaultFormat->nChannels > PA_CHANNELS_MAX)) + defaultFormat->nChannels = 2; + if ((defaultFormat->nSamplesPerSec < 1) || (defaultFormat->nSamplesPerSec > PA_RATE_MAX)) + defaultFormat->nSamplesPerSec = 44100; + if ((defaultFormat->wBitsPerSample != 8) && (defaultFormat->wBitsPerSample != 16)) + defaultFormat->wBitsPerSample = 16; + + defaultFormat->nBlockAlign = defaultFormat->nChannels * defaultFormat->wBitsPerSample / 8; + defaultFormat->nAvgBytesPerSec = defaultFormat->nBlockAlign * defaultFormat->nSamplesPerSec; + return TRUE; +} + BOOL rdpsnd_pulse_format_supported(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format) { switch (format->wFormatTag) { case WAVE_FORMAT_PCM: - if (format->cbSize == 0 && - (format->nSamplesPerSec <= PA_RATE_MAX) && + if (format->cbSize == 0 && (format->nSamplesPerSec <= PA_RATE_MAX) && (format->wBitsPerSample == 8 || format->wBitsPerSample == 16) && (format->nChannels >= 1 && format->nChannels <= PA_CHANNELS_MAX)) { @@ -405,8 +429,7 @@ BOOL rdpsnd_pulse_format_supported(rdpsndDevicePlugin* device, const AUDIO_FORMA case WAVE_FORMAT_ALAW: case WAVE_FORMAT_MULAW: - if (format->cbSize == 0 && - (format->nSamplesPerSec <= PA_RATE_MAX) && + if (format->cbSize == 0 && (format->nSamplesPerSec <= PA_RATE_MAX) && (format->wBitsPerSample == 8) && (format->nChannels >= 1 && format->nChannels <= PA_CHANNELS_MAX)) { @@ -422,7 +445,7 @@ BOOL rdpsnd_pulse_format_supported(rdpsndDevicePlugin* device, const AUDIO_FORMA static UINT32 rdpsnd_pulse_get_volume(rdpsndDevicePlugin* device) { pa_operation* o; - rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device; + rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device; if (!pulse) return 0; @@ -443,7 +466,7 @@ static BOOL rdpsnd_pulse_set_volume(rdpsndDevicePlugin* device, UINT32 value) pa_volume_t left; pa_volume_t right; pa_operation* operation; - rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device; + rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device; if (!pulse->context || !pulse->stream) return FALSE; @@ -456,7 +479,7 @@ static BOOL rdpsnd_pulse_set_volume(rdpsndDevicePlugin* device, UINT32 value) cv.values[1] = PA_VOLUME_MUTED + (right * (PA_VOLUME_NORM - PA_VOLUME_MUTED)) / 0xFFFF; pa_threaded_mainloop_lock(pulse->mainloop); operation = pa_context_set_sink_input_volume(pulse->context, pa_stream_get_index(pulse->stream), - &cv, NULL, NULL); + &cv, NULL, NULL); if (operation) pa_operation_unref(operation); @@ -471,7 +494,7 @@ static UINT rdpsnd_pulse_play(rdpsndDevicePlugin* device, const BYTE* data, size int status; pa_usec_t latency; int negative; - rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device; + rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device; if (!pulse->stream || !data) return 0; @@ -483,7 +506,7 @@ static UINT rdpsnd_pulse_play(rdpsndDevicePlugin* device, const BYTE* data, size while ((length = pa_stream_writable_size(pulse->stream)) == 0) pa_threaded_mainloop_wait(pulse->mainloop); - if (length == (size_t) -1) + if (length == (size_t)-1) break; if (length > size) @@ -507,24 +530,6 @@ static UINT rdpsnd_pulse_play(rdpsndDevicePlugin* device, const BYTE* data, size return latency / 1000; } -static void rdpsnd_pulse_start(rdpsndDevicePlugin* device) -{ - rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device; - - if (!pulse->stream) - return; - - pa_threaded_mainloop_lock(pulse->mainloop); - pa_stream_trigger(pulse->stream, NULL, NULL); - pa_threaded_mainloop_unlock(pulse->mainloop); -} - -static COMMAND_LINE_ARGUMENT_A rdpsnd_pulse_args[] = -{ - { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "device" }, - { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } -}; - /** * Function description * @@ -535,10 +540,14 @@ static UINT rdpsnd_pulse_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV int status; DWORD flags; COMMAND_LINE_ARGUMENT_A* arg; - rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device; - flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; - status = CommandLineParseArgumentsA(args->argc, args->argv, - rdpsnd_pulse_args, flags, pulse, NULL, NULL); + rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device; + COMMAND_LINE_ARGUMENT_A rdpsnd_pulse_args[] = { { "dev", COMMAND_LINE_VALUE_REQUIRED, + "", NULL, NULL, -1, NULL, "device" }, + { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } }; + flags = + COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; + status = CommandLineParseArgumentsA(args->argc, args->argv, rdpsnd_pulse_args, flags, pulse, + NULL, NULL); if (status < 0) return ERROR_INVALID_DATA; @@ -550,8 +559,7 @@ static UINT rdpsnd_pulse_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) continue; - CommandLineSwitchStart(arg) - CommandLineSwitchCase(arg, "dev") + CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "dev") { pulse->device_name = _strdup(arg->Value); @@ -559,16 +567,15 @@ static UINT rdpsnd_pulse_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV return ERROR_OUTOFMEMORY; } CommandLineSwitchEnd(arg) - } - while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); return CHANNEL_RC_OK; } #ifdef BUILTIN_CHANNELS -#define freerdp_rdpsnd_client_subsystem_entry pulse_freerdp_rdpsnd_client_subsystem_entry +#define freerdp_rdpsnd_client_subsystem_entry pulse_freerdp_rdpsnd_client_subsystem_entry #else -#define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry +#define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry #endif /** @@ -581,7 +588,7 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p ADDIN_ARGV* args; rdpsndPulsePlugin* pulse; UINT ret; - pulse = (rdpsndPulsePlugin*) calloc(1, sizeof(rdpsndPulsePlugin)); + pulse = (rdpsndPulsePlugin*)calloc(1, sizeof(rdpsndPulsePlugin)); if (!pulse) return CHANNEL_RC_NO_MEMORY; @@ -591,14 +598,14 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p pulse->device.GetVolume = rdpsnd_pulse_get_volume; pulse->device.SetVolume = rdpsnd_pulse_set_volume; pulse->device.Play = rdpsnd_pulse_play; - pulse->device.Start = rdpsnd_pulse_start; pulse->device.Close = rdpsnd_pulse_close; pulse->device.Free = rdpsnd_pulse_free; + pulse->device.DefaultFormat = rdpsnd_pulse_default_format; args = pEntryPoints->args; if (args->argc > 1) { - ret = rdpsnd_pulse_parse_addin_args((rdpsndDevicePlugin*) pulse, args); + ret = rdpsnd_pulse_parse_addin_args((rdpsndDevicePlugin*)pulse, args); if (ret != CHANNEL_RC_OK) { @@ -624,7 +631,7 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p if (!rdpsnd_pulse_connect((rdpsndDevicePlugin*)pulse)) goto error; - pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*) pulse); + pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*)pulse); return CHANNEL_RC_OK; error: rdpsnd_pulse_free((rdpsndDevicePlugin*)pulse); diff --git a/channels/rdpsnd/client/rdpsnd_main.c b/channels/rdpsnd/client/rdpsnd_main.c index cc4167c..9318c95 100644 --- a/channels/rdpsnd/client/rdpsnd_main.c +++ b/channels/rdpsnd/client/rdpsnd_main.c @@ -50,12 +50,35 @@ #include "rdpsnd_common.h" #include "rdpsnd_main.h" +struct _RDPSND_CHANNEL_CALLBACK +{ + IWTSVirtualChannelCallback iface; + + IWTSPlugin* plugin; + IWTSVirtualChannelManager* channel_mgr; + IWTSVirtualChannel* channel; +}; +typedef struct _RDPSND_CHANNEL_CALLBACK RDPSND_CHANNEL_CALLBACK; + +struct _RDPSND_LISTENER_CALLBACK +{ + IWTSListenerCallback iface; + + IWTSPlugin* plugin; + IWTSVirtualChannelManager* channel_mgr; + RDPSND_CHANNEL_CALLBACK* channel_callback; +}; +typedef struct _RDPSND_LISTENER_CALLBACK RDPSND_LISTENER_CALLBACK; + struct rdpsnd_plugin { + IWTSPlugin iface; + IWTSListener* listener; + RDPSND_LISTENER_CALLBACK* listener_callback; + CHANNEL_DEF channelDef; CHANNEL_ENTRY_POINTS_FREERDP_EX channelEntryPoints; - HANDLE thread; wStreamPool* pool; wStream* data_in; @@ -63,7 +86,6 @@ struct rdpsnd_plugin DWORD OpenHandle; wLog* log; - HANDLE stopEvent; BYTE cBlockNo; UINT16 wQualityMode; @@ -77,17 +99,21 @@ struct rdpsnd_plugin BOOL attached; BOOL connected; + BOOL dynamic; BOOL expectingWave; BYTE waveData[4]; UINT16 waveDataSize; - UINT32 wTimeStamp; - UINT32 wArrivalTime; + UINT16 wTimeStamp; + UINT64 wArrivalTime; UINT32 latency; BOOL isOpen; AUDIO_FORMAT* fixed_format; + UINT32 startPlayTime; + size_t totalPlaySize; + char* subsystem; char* device_name; @@ -95,11 +121,19 @@ struct rdpsnd_plugin rdpsndDevicePlugin* device; rdpContext* rdpcontext; - wQueue* queue; FREERDP_DSP_CONTEXT* dsp_context; + + HANDLE thread; + wMessageQueue* queue; }; -static void rdpsnd_recv_close_pdu(rdpsndPlugin* rdpsnd); +static const char* rdpsnd_is_dyn_str(BOOL dynamic) +{ + if (dynamic) + return "[dynamic]"; + return "[static]"; +} + static void rdpsnd_virtual_channel_event_terminated(rdpsndPlugin* rdpsnd); /** @@ -121,16 +155,17 @@ static UINT rdpsnd_send_quality_mode_pdu(rdpsndPlugin* rdpsnd) if (!pdu) { - WLog_ERR(TAG, "Stream_New failed!"); + WLog_ERR(TAG, "%s Stream_New failed!", rdpsnd_is_dyn_str(rdpsnd->dynamic)); return CHANNEL_RC_NO_MEMORY; } - Stream_Write_UINT8(pdu, SNDC_QUALITYMODE); /* msgType */ - Stream_Write_UINT8(pdu, 0); /* bPad */ - Stream_Write_UINT16(pdu, 4); /* BodySize */ + Stream_Write_UINT8(pdu, SNDC_QUALITYMODE); /* msgType */ + Stream_Write_UINT8(pdu, 0); /* bPad */ + Stream_Write_UINT16(pdu, 4); /* BodySize */ Stream_Write_UINT16(pdu, rdpsnd->wQualityMode); /* wQualityMode */ - Stream_Write_UINT16(pdu, 0); /* Reserved */ - WLog_Print(rdpsnd->log, WLOG_DEBUG, "QualityMode: %"PRIu16"", rdpsnd->wQualityMode); + Stream_Write_UINT16(pdu, 0); /* Reserved */ + WLog_Print(rdpsnd->log, WLOG_DEBUG, "%s QualityMode: %" PRIu16 "", + rdpsnd_is_dyn_str(rdpsnd->dynamic), rdpsnd->wQualityMode); return rdpsnd_virtual_channel_write(rdpsnd, pdu); } @@ -188,21 +223,21 @@ static UINT rdpsnd_send_client_audio_formats(rdpsndPlugin* rdpsnd) if (!pdu) { - WLog_ERR(TAG, "Stream_New failed!"); + WLog_ERR(TAG, "%s Stream_New failed!", rdpsnd_is_dyn_str(rdpsnd->dynamic)); return CHANNEL_RC_NO_MEMORY; } - Stream_Write_UINT8(pdu, SNDC_FORMATS); /* msgType */ - Stream_Write_UINT8(pdu, 0); /* bPad */ - Stream_Write_UINT16(pdu, length - 4); /* BodySize */ + Stream_Write_UINT8(pdu, SNDC_FORMATS); /* msgType */ + Stream_Write_UINT8(pdu, 0); /* bPad */ + Stream_Write_UINT16(pdu, length - 4); /* BodySize */ Stream_Write_UINT32(pdu, TSSNDCAPS_ALIVE | TSSNDCAPS_VOLUME); /* dwFlags */ - Stream_Write_UINT32(pdu, dwVolume); /* dwVolume */ - Stream_Write_UINT32(pdu, 0); /* dwPitch */ - Stream_Write_UINT16(pdu, 0); /* wDGramPort */ - Stream_Write_UINT16(pdu, wNumberOfFormats); /* wNumberOfFormats */ - Stream_Write_UINT8(pdu, 0); /* cLastBlockConfirmed */ - Stream_Write_UINT16(pdu, CHANNEL_VERSION_WIN_MAX); /* wVersion */ - Stream_Write_UINT8(pdu, 0); /* bPad */ + Stream_Write_UINT32(pdu, dwVolume); /* dwVolume */ + Stream_Write_UINT32(pdu, 0); /* dwPitch */ + Stream_Write_UINT16(pdu, 0); /* wDGramPort */ + Stream_Write_UINT16(pdu, wNumberOfFormats); /* wNumberOfFormats */ + Stream_Write_UINT8(pdu, 0); /* cLastBlockConfirmed */ + Stream_Write_UINT16(pdu, CHANNEL_VERSION_WIN_MAX); /* wVersion */ + Stream_Write_UINT8(pdu, 0); /* bPad */ for (index = 0; index < wNumberOfFormats; index++) { @@ -215,7 +250,8 @@ static UINT rdpsnd_send_client_audio_formats(rdpsndPlugin* rdpsnd) } } - WLog_Print(rdpsnd->log, WLOG_DEBUG, "Client Audio Formats"); + WLog_Print(rdpsnd->log, WLOG_DEBUG, "%s Client Audio Formats", + rdpsnd_is_dyn_str(rdpsnd->dynamic)); return rdpsnd_virtual_channel_write(rdpsnd, pdu); } @@ -224,8 +260,7 @@ static UINT rdpsnd_send_client_audio_formats(rdpsndPlugin* rdpsnd) * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, - wStream* s) +static UINT rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, wStream* s) { UINT16 index; UINT16 wVersion; @@ -245,8 +280,8 @@ static UINT rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, Stream_Seek_UINT16(s); /* wDGramPort */ Stream_Read_UINT16(s, wNumberOfFormats); Stream_Read_UINT8(s, rdpsnd->cBlockNo); /* cLastBlockConfirmed */ - Stream_Read_UINT16(s, wVersion); /* wVersion */ - Stream_Seek_UINT8(s); /* bPad */ + Stream_Read_UINT16(s, wVersion); /* wVersion */ + Stream_Seek_UINT8(s); /* bPad */ rdpsnd->NumberOfServerFormats = wNumberOfFormats; if (Stream_GetRemainingLength(s) / 14 < wNumberOfFormats) @@ -266,7 +301,8 @@ static UINT rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, } rdpsnd_select_supported_audio_formats(rdpsnd); - WLog_Print(rdpsnd->log, WLOG_DEBUG, "Server Audio Formats"); + WLog_Print(rdpsnd->log, WLOG_DEBUG, "%s Server Audio Formats", + rdpsnd_is_dyn_str(rdpsnd->dynamic)); ret = rdpsnd_send_client_audio_formats(rdpsnd); if (ret == CHANNEL_RC_OK) @@ -288,26 +324,26 @@ out_fail: * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpsnd_send_training_confirm_pdu(rdpsndPlugin* rdpsnd, - UINT16 wTimeStamp, UINT16 wPackSize) +static UINT rdpsnd_send_training_confirm_pdu(rdpsndPlugin* rdpsnd, UINT16 wTimeStamp, + UINT16 wPackSize) { wStream* pdu; pdu = Stream_New(NULL, 8); if (!pdu) { - WLog_ERR(TAG, "Stream_New failed!"); + WLog_ERR(TAG, "%s Stream_New failed!", rdpsnd_is_dyn_str(rdpsnd->dynamic)); return CHANNEL_RC_NO_MEMORY; } Stream_Write_UINT8(pdu, SNDC_TRAINING); /* msgType */ - Stream_Write_UINT8(pdu, 0); /* bPad */ - Stream_Write_UINT16(pdu, 4); /* BodySize */ + Stream_Write_UINT8(pdu, 0); /* bPad */ + Stream_Write_UINT16(pdu, 4); /* BodySize */ Stream_Write_UINT16(pdu, wTimeStamp); Stream_Write_UINT16(pdu, wPackSize); WLog_Print(rdpsnd->log, WLOG_DEBUG, - "Training Response: wTimeStamp: %"PRIu16" wPackSize: %"PRIu16"", - wTimeStamp, wPackSize); + "%s Training Response: wTimeStamp: %" PRIu16 " wPackSize: %" PRIu16 "", + rdpsnd_is_dyn_str(rdpsnd->dynamic), wTimeStamp, wPackSize); return rdpsnd_virtual_channel_write(rdpsnd, pdu); } @@ -327,13 +363,13 @@ static UINT rdpsnd_recv_training_pdu(rdpsndPlugin* rdpsnd, wStream* s) Stream_Read_UINT16(s, wTimeStamp); Stream_Read_UINT16(s, wPackSize); WLog_Print(rdpsnd->log, WLOG_DEBUG, - "Training Request: wTimeStamp: %"PRIu16" wPackSize: %"PRIu16"", - wTimeStamp, wPackSize); + "%s Training Request: wTimeStamp: %" PRIu16 " wPackSize: %" PRIu16 "", + rdpsnd_is_dyn_str(rdpsnd->dynamic), wTimeStamp, wPackSize); return rdpsnd_send_training_confirm_pdu(rdpsnd, wTimeStamp, wPackSize); } static BOOL rdpsnd_ensure_device_is_open(rdpsndPlugin* rdpsnd, UINT32 wFormatNo, - const AUDIO_FORMAT* format) + const AUDIO_FORMAT* format) { if (!rdpsnd) return FALSE; @@ -343,20 +379,27 @@ static BOOL rdpsnd_ensure_device_is_open(rdpsndPlugin* rdpsnd, UINT32 wFormatNo, BOOL rc; BOOL supported; AUDIO_FORMAT deviceFormat = *format; - rdpsnd_recv_close_pdu(rdpsnd); + + IFCALL(rdpsnd->device->Close, rdpsnd->device); supported = IFCALLRESULT(FALSE, rdpsnd->device->FormatSupported, rdpsnd->device, format); if (!supported) { - deviceFormat.wFormatTag = WAVE_FORMAT_PCM; - deviceFormat.wBitsPerSample = 16; - deviceFormat.cbSize = 0; + if (!IFCALLRESULT(FALSE, rdpsnd->device->DefaultFormat, rdpsnd->device, format, + &deviceFormat)) + { + deviceFormat.wFormatTag = WAVE_FORMAT_PCM; + deviceFormat.wBitsPerSample = 16; + deviceFormat.cbSize = 0; + } } - WLog_Print(rdpsnd->log, WLOG_DEBUG, "Opening device with format %s [backend %s]", + WLog_Print(rdpsnd->log, WLOG_DEBUG, "%s Opening device with format %s [backend %s]", + rdpsnd_is_dyn_str(rdpsnd->dynamic), audio_format_get_tag_string(format->wFormatTag), audio_format_get_tag_string(deviceFormat.wFormatTag)); - rc = IFCALLRESULT(FALSE, rdpsnd->device->Open, rdpsnd->device, &deviceFormat, rdpsnd->latency); + rc = IFCALLRESULT(FALSE, rdpsnd->device->Open, rdpsnd->device, &deviceFormat, + rdpsnd->latency); if (!rc) return FALSE; @@ -369,6 +412,8 @@ static BOOL rdpsnd_ensure_device_is_open(rdpsndPlugin* rdpsnd, UINT32 wFormatNo, rdpsnd->isOpen = TRUE; rdpsnd->wCurrentFormatNo = wFormatNo; + rdpsnd->startPlayTime = 0; + rdpsnd->totalPlaySize = 0; } return TRUE; @@ -379,8 +424,7 @@ static BOOL rdpsnd_ensure_device_is_open(rdpsndPlugin* rdpsnd, UINT32 wFormatNo, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpsnd_recv_wave_info_pdu(rdpsndPlugin* rdpsnd, wStream* s, - UINT16 BodySize) +static UINT rdpsnd_recv_wave_info_pdu(rdpsndPlugin* rdpsnd, wStream* s, UINT16 BodySize) { UINT16 wFormatNo; const AUDIO_FORMAT* format; @@ -388,7 +432,7 @@ static UINT rdpsnd_recv_wave_info_pdu(rdpsndPlugin* rdpsnd, wStream* s, if (Stream_GetRemainingLength(s) < 12) return ERROR_BAD_LENGTH; - rdpsnd->wArrivalTime = GetTickCount(); + rdpsnd->wArrivalTime = GetTickCount64(); Stream_Read_UINT16(s, rdpsnd->wTimeStamp); Stream_Read_UINT16(s, wFormatNo); @@ -400,8 +444,10 @@ static UINT rdpsnd_recv_wave_info_pdu(rdpsndPlugin* rdpsnd, wStream* s, Stream_Read(s, rdpsnd->waveData, 4); rdpsnd->waveDataSize = BodySize - 8; format = &rdpsnd->ClientFormats[wFormatNo]; - WLog_Print(rdpsnd->log, WLOG_DEBUG, "WaveInfo: cBlockNo: %"PRIu8" wFormatNo: %"PRIu16" [%s]", - rdpsnd->cBlockNo, wFormatNo, audio_format_get_tag_string(format->wFormatTag)); + WLog_Print(rdpsnd->log, WLOG_DEBUG, + "%s WaveInfo: cBlockNo: %" PRIu8 " wFormatNo: %" PRIu16 " [%s]", + rdpsnd_is_dyn_str(rdpsnd->dynamic), rdpsnd->cBlockNo, wFormatNo, + audio_format_get_tag_string(format->wFormatTag)); if (!rdpsnd_ensure_device_is_open(rdpsnd, wFormatNo, format)) return ERROR_INTERNAL_ERROR; @@ -415,15 +461,15 @@ static UINT rdpsnd_recv_wave_info_pdu(rdpsndPlugin* rdpsnd, wStream* s, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpsnd_send_wave_confirm_pdu(rdpsndPlugin* rdpsnd, - UINT16 wTimeStamp, BYTE cConfirmedBlockNo) +static UINT rdpsnd_send_wave_confirm_pdu(rdpsndPlugin* rdpsnd, UINT16 wTimeStamp, + BYTE cConfirmedBlockNo) { wStream* pdu; pdu = Stream_New(NULL, 8); if (!pdu) { - WLog_ERR(TAG, "Stream_New failed!"); + WLog_ERR(TAG, "%s Stream_New failed!", rdpsnd_is_dyn_str(rdpsnd->dynamic)); return CHANNEL_RC_NO_MEMORY; } @@ -432,27 +478,87 @@ static UINT rdpsnd_send_wave_confirm_pdu(rdpsndPlugin* rdpsnd, Stream_Write_UINT16(pdu, 4); Stream_Write_UINT16(pdu, wTimeStamp); Stream_Write_UINT8(pdu, cConfirmedBlockNo); /* cConfirmedBlockNo */ - Stream_Write_UINT8(pdu, 0); /* bPad */ + Stream_Write_UINT8(pdu, 0); /* bPad */ return rdpsnd_virtual_channel_write(rdpsnd, pdu); } +static BOOL rdpsnd_detect_overrun(rdpsndPlugin* rdpsnd, const AUDIO_FORMAT* format, size_t size) +{ + UINT32 bpf; + UINT32 now; + UINT32 duration; + UINT32 totalDuration; + UINT32 remainingDuration; + UINT32 maxDuration; + + if (!rdpsnd || !format) + return FALSE; + + audio_format_print(WLog_Get(TAG), WLOG_DEBUG, format); + bpf = format->nChannels * format->wBitsPerSample * format->nSamplesPerSec / 8; + if (bpf == 0) + return FALSE; + + duration = (UINT32)(1000 * size / bpf); + totalDuration = (UINT32)(1000 * rdpsnd->totalPlaySize / bpf); + now = GetTickCountPrecise(); + if (rdpsnd->startPlayTime == 0) + { + rdpsnd->startPlayTime = now; + rdpsnd->totalPlaySize = size; + return FALSE; + } + else if (now - rdpsnd->startPlayTime > totalDuration + 10) + { + /* Buffer underrun */ + WLog_Print(rdpsnd->log, WLOG_DEBUG, "%s Buffer underrun by %u ms", + rdpsnd_is_dyn_str(rdpsnd->dynamic), + (UINT)(now - rdpsnd->startPlayTime - totalDuration)); + rdpsnd->startPlayTime = now; + rdpsnd->totalPlaySize = size; + return FALSE; + } + else + { + /* Calculate remaining duration to be played */ + remainingDuration = totalDuration - (now - rdpsnd->startPlayTime); + + /* Maximum allow duration calculation */ + maxDuration = duration * 2 + rdpsnd->latency; + + if (remainingDuration + duration > maxDuration) + { + WLog_Print(rdpsnd->log, WLOG_DEBUG, "%s Buffer overrun pending %u ms dropping %u ms", + rdpsnd_is_dyn_str(rdpsnd->dynamic), remainingDuration, duration); + return TRUE; + } + + rdpsnd->totalPlaySize += size; + return FALSE; + } +} + static UINT rdpsnd_treat_wave(rdpsndPlugin* rdpsnd, wStream* s, size_t size) { BYTE* data; AUDIO_FORMAT* format; - DWORD end; - DWORD diffMS; + UINT64 end; + UINT64 diffMS, ts; UINT latency = 0; if (Stream_GetRemainingLength(s) < size) return ERROR_BAD_LENGTH; + if (rdpsnd->wCurrentFormatNo >= rdpsnd->NumberOfClientFormats) + return ERROR_INTERNAL_ERROR; + data = Stream_Pointer(s); format = &rdpsnd->ClientFormats[rdpsnd->wCurrentFormatNo]; - WLog_Print(rdpsnd->log, WLOG_DEBUG, "Wave: cBlockNo: %"PRIu8" wTimeStamp: %"PRIu16", size: %"PRIdz, - rdpsnd->cBlockNo, rdpsnd->wTimeStamp, size); + WLog_Print(rdpsnd->log, WLOG_DEBUG, + "%s Wave: cBlockNo: %" PRIu8 " wTimeStamp: %" PRIu16 ", size: %" PRIdz, + rdpsnd_is_dyn_str(rdpsnd->dynamic), rdpsnd->cBlockNo, rdpsnd->wTimeStamp, size); - if (rdpsnd->device && rdpsnd->attached) + if (rdpsnd->device && rdpsnd->attached && !rdpsnd_detect_overrun(rdpsnd, format, size)) { UINT status = CHANNEL_RC_OK; wStream* pcmData = StreamPool_Take(rdpsnd->pool, 4096); @@ -468,17 +574,22 @@ static UINT rdpsnd_treat_wave(rdpsndPlugin* rdpsnd, wStream* s, size_t size) else status = ERROR_INTERNAL_ERROR; - StreamPool_Return(rdpsnd->pool, pcmData); + Stream_Release(pcmData); if (status != CHANNEL_RC_OK) return status; } - end = GetTickCount(); + end = GetTickCount64(); diffMS = end - rdpsnd->wArrivalTime + latency; - return rdpsnd_send_wave_confirm_pdu(rdpsnd, rdpsnd->wTimeStamp + diffMS, rdpsnd->cBlockNo); -} + ts = (rdpsnd->wTimeStamp + diffMS) % UINT16_MAX; + /* Don't send wave confirm PDU if on dynamic channel */ + if (rdpsnd->dynamic) + return CHANNEL_RC_OK; + + return rdpsnd_send_wave_confirm_pdu(rdpsnd, (UINT16)ts, rdpsnd->cBlockNo); +} /** * Function description @@ -516,11 +627,15 @@ static UINT rdpsnd_recv_wave2_pdu(rdpsndPlugin* rdpsnd, wStream* s, UINT16 BodyS Stream_Read_UINT8(s, rdpsnd->cBlockNo); Stream_Seek(s, 3); /* bPad */ Stream_Read_UINT32(s, dwAudioTimeStamp); - rdpsnd->waveDataSize = BodySize - 12; + if (wFormatNo >= rdpsnd->NumberOfClientFormats) + return ERROR_INVALID_DATA; format = &rdpsnd->ClientFormats[wFormatNo]; - rdpsnd->wArrivalTime = GetTickCount(); - WLog_Print(rdpsnd->log, WLOG_DEBUG, "Wave2PDU: cBlockNo: %"PRIu8" wFormatNo: %"PRIu16", align=%hu", - rdpsnd->cBlockNo, wFormatNo, format->nBlockAlign); + rdpsnd->waveDataSize = BodySize - 12; + rdpsnd->wArrivalTime = GetTickCount64(); + WLog_Print(rdpsnd->log, WLOG_DEBUG, + "%s Wave2PDU: cBlockNo: %" PRIu8 " wFormatNo: %" PRIu16 ", align=%hu", + rdpsnd_is_dyn_str(rdpsnd->dynamic), rdpsnd->cBlockNo, wFormatNo, + format->nBlockAlign); if (!rdpsnd_ensure_device_is_open(rdpsnd, wFormatNo, format)) return ERROR_INTERNAL_ERROR; @@ -532,12 +647,12 @@ static void rdpsnd_recv_close_pdu(rdpsndPlugin* rdpsnd) { if (rdpsnd->isOpen) { - WLog_Print(rdpsnd->log, WLOG_DEBUG, "Closing device"); - IFCALL(rdpsnd->device->Close, rdpsnd->device); - rdpsnd->isOpen = FALSE; + WLog_Print(rdpsnd->log, WLOG_DEBUG, "%s Closing device", + rdpsnd_is_dyn_str(rdpsnd->dynamic)); } else - WLog_Print(rdpsnd->log, WLOG_DEBUG, "Device already closed"); + WLog_Print(rdpsnd->log, WLOG_DEBUG, "%s Device already closed", + rdpsnd_is_dyn_str(rdpsnd->dynamic)); } /** @@ -554,12 +669,13 @@ static UINT rdpsnd_recv_volume_pdu(rdpsndPlugin* rdpsnd, wStream* s) return ERROR_BAD_LENGTH; Stream_Read_UINT32(s, dwVolume); - WLog_Print(rdpsnd->log, WLOG_DEBUG, "Volume: 0x%08"PRIX32"", dwVolume); + WLog_Print(rdpsnd->log, WLOG_DEBUG, "%s Volume: 0x%08" PRIX32 "", + rdpsnd_is_dyn_str(rdpsnd->dynamic), dwVolume); rc = IFCALLRESULT(FALSE, rdpsnd->device->SetVolume, rdpsnd->device, dwVolume); if (!rc) { - WLog_ERR(TAG, "error setting volume"); + WLog_ERR(TAG, "%s error setting volume", rdpsnd_is_dyn_str(rdpsnd->dynamic)); return CHANNEL_RC_INITIALIZATION_ERROR; } @@ -590,7 +706,7 @@ static UINT rdpsnd_recv_pdu(rdpsndPlugin* rdpsnd, wStream* s) } Stream_Read_UINT8(s, msgType); /* msgType */ - Stream_Seek_UINT8(s); /* bPad */ + Stream_Seek_UINT8(s); /* bPad */ Stream_Read_UINT16(s, BodySize); switch (msgType) @@ -620,21 +736,21 @@ static UINT rdpsnd_recv_pdu(rdpsndPlugin* rdpsnd, wStream* s) break; default: - WLog_ERR(TAG, "unknown msgType %"PRIu8"", msgType); + WLog_ERR(TAG, "%s unknown msgType %" PRIu8 "", rdpsnd_is_dyn_str(rdpsnd->dynamic), + msgType); break; } out: - StreamPool_Return(rdpsnd->pool, s); + Stream_Release(s); return status; } -static void rdpsnd_register_device_plugin(rdpsndPlugin* rdpsnd, - rdpsndDevicePlugin* device) +static void rdpsnd_register_device_plugin(rdpsndPlugin* rdpsnd, rdpsndDevicePlugin* device) { if (rdpsnd->device) { - WLog_ERR(TAG, "existing device, abort."); + WLog_ERR(TAG, "%s existing device, abort.", rdpsnd_is_dyn_str(FALSE)); return; } @@ -647,14 +763,16 @@ static void rdpsnd_register_device_plugin(rdpsndPlugin* rdpsnd, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpsnd_load_device_plugin(rdpsndPlugin* rdpsnd, const char* name, - ADDIN_ARGV* args) +static UINT rdpsnd_load_device_plugin(rdpsndPlugin* rdpsnd, const char* name, ADDIN_ARGV* args) { PFREERDP_RDPSND_DEVICE_ENTRY entry; FREERDP_RDPSND_DEVICE_ENTRY_POINTS entryPoints; UINT error; - entry = (PFREERDP_RDPSND_DEVICE_ENTRY) - freerdp_load_channel_addin_entry("rdpsnd", (LPSTR) name, NULL, 0); + DWORD flags = FREERDP_ADDIN_CHANNEL_STATIC | FREERDP_ADDIN_CHANNEL_ENTRYEX; + if (rdpsnd->dynamic) + flags = FREERDP_ADDIN_CHANNEL_DYNAMIC; + entry = + (PFREERDP_RDPSND_DEVICE_ENTRY)freerdp_load_channel_addin_entry("rdpsnd", name, NULL, flags); if (!entry) return ERROR_INTERNAL_ERROR; @@ -664,9 +782,10 @@ static UINT rdpsnd_load_device_plugin(rdpsndPlugin* rdpsnd, const char* name, entryPoints.args = args; if ((error = entry(&entryPoints))) - WLog_ERR(TAG, "%s entry returns error %"PRIu32"", name, error); + WLog_ERR(TAG, "%s %s entry returns error %" PRIu32 "", rdpsnd_is_dyn_str(rdpsnd->dynamic), + name, error); - WLog_INFO(TAG, "Loaded %s backend for rdpsnd", name); + WLog_INFO(TAG, "%s Loaded %s backend for rdpsnd", rdpsnd_is_dyn_str(rdpsnd->dynamic), name); return error; } @@ -677,25 +796,13 @@ static BOOL rdpsnd_set_subsystem(rdpsndPlugin* rdpsnd, const char* subsystem) return (rdpsnd->subsystem != NULL); } -BOOL rdpsnd_set_device_name(rdpsndPlugin* rdpsnd, const char* device_name) +static BOOL rdpsnd_set_device_name(rdpsndPlugin* rdpsnd, const char* device_name) { free(rdpsnd->device_name); rdpsnd->device_name = _strdup(device_name); return (rdpsnd->device_name != NULL); } -static COMMAND_LINE_ARGUMENT_A rdpsnd_args[] = -{ - { "sys", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "subsystem" }, - { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "device" }, - { "format", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "format" }, - { "rate", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "rate" }, - { "channel", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "channel" }, - { "latency", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "latency" }, - { "quality", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "quality mode" }, - { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } -}; - /** * Function description * @@ -706,13 +813,24 @@ static UINT rdpsnd_process_addin_args(rdpsndPlugin* rdpsnd, ADDIN_ARGV* args) int status; DWORD flags; COMMAND_LINE_ARGUMENT_A* arg; + COMMAND_LINE_ARGUMENT_A rdpsnd_args[] = { + { "sys", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "subsystem" }, + { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "device" }, + { "format", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "format" }, + { "rate", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "rate" }, + { "channel", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "channel" }, + { "latency", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "latency" }, + { "quality", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, + "quality mode" }, + { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } + }; rdpsnd->wQualityMode = HIGH_QUALITY; /* default quality mode */ if (args->argc > 1) { flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON; - status = CommandLineParseArgumentsA(args->argc, args->argv, - rdpsnd_args, flags, rdpsnd, NULL, NULL); + status = CommandLineParseArgumentsA(args->argc, args->argv, rdpsnd_args, flags, rdpsnd, + NULL, NULL); if (status < 0) return CHANNEL_RC_INITIALIZATION_ERROR; @@ -725,8 +843,7 @@ static UINT rdpsnd_process_addin_args(rdpsndPlugin* rdpsnd, ADDIN_ARGV* args) if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) continue; - CommandLineSwitchStart(arg) - CommandLineSwitchCase(arg, "sys") + CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "sys") { if (!rdpsnd_set_subsystem(rdpsnd, arg->Value)) return CHANNEL_RC_NO_MEMORY; @@ -743,7 +860,7 @@ static UINT rdpsnd_process_addin_args(rdpsndPlugin* rdpsnd, ADDIN_ARGV* args) if ((errno != 0) || (val > UINT16_MAX)) return CHANNEL_RC_INITIALIZATION_ERROR; - rdpsnd->fixed_format->wFormatTag = val; + rdpsnd->fixed_format->wFormatTag = (UINT16)val; } CommandLineSwitchCase(arg, "rate") { @@ -761,7 +878,7 @@ static UINT rdpsnd_process_addin_args(rdpsndPlugin* rdpsnd, ADDIN_ARGV* args) if ((errno != 0) || (val > UINT16_MAX)) return CHANNEL_RC_INITIALIZATION_ERROR; - rdpsnd->fixed_format->nChannels = val; + rdpsnd->fixed_format->nChannels = (UINT16)val; } CommandLineSwitchCase(arg, "latency") { @@ -793,14 +910,13 @@ static UINT rdpsnd_process_addin_args(rdpsndPlugin* rdpsnd, ADDIN_ARGV* args) if ((wQualityMode < 0) || (wQualityMode > 2)) wQualityMode = DYNAMIC_QUALITY; - rdpsnd->wQualityMode = (UINT16) wQualityMode; + rdpsnd->wQualityMode = (UINT16)wQualityMode; } CommandLineSwitchDefault(arg) { } CommandLineSwitchEnd(arg) - } - while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); } return CHANNEL_RC_OK; @@ -817,36 +933,34 @@ static UINT rdpsnd_process_connect(rdpsndPlugin* rdpsnd) { const char* subsystem; const char* device; - } - backends[] = - { + } backends[] = { #if defined(WITH_IOSAUDIO) - {"ios", ""}, + { "ios", "" }, #endif #if defined(WITH_OPENSLES) - {"opensles", ""}, + { "opensles", "" }, #endif #if defined(WITH_PULSE) - {"pulse", ""}, + { "pulse", "" }, #endif #if defined(WITH_ALSA) - {"alsa", "default"}, + { "alsa", "default" }, #endif #if defined(WITH_OSS) - {"oss", ""}, + { "oss", "" }, #endif #if defined(WITH_MACAUDIO) - {"mac", "default"}, + { "mac", "default" }, #endif #if defined(WITH_WINMM) - { "winmm", ""}, + { "winmm", "" }, #endif { "fake", "" } }; ADDIN_ARGV* args; UINT status = ERROR_INTERNAL_ERROR; rdpsnd->latency = 0; - args = (ADDIN_ARGV*) rdpsnd->channelEntryPoints.pExtendedData; + args = (ADDIN_ARGV*)rdpsnd->channelEntryPoints.pExtendedData; if (args) { @@ -860,8 +974,9 @@ static UINT rdpsnd_process_connect(rdpsndPlugin* rdpsnd) { if ((status = rdpsnd_load_device_plugin(rdpsnd, rdpsnd->subsystem, args))) { - WLog_ERR(TAG, "unable to load the %s subsystem plugin because of error %"PRIu32"", - rdpsnd->subsystem, status); + WLog_ERR(TAG, + "%s Unable to load sound playback subsystem %s because of error %" PRIu32 "", + rdpsnd_is_dyn_str(rdpsnd->dynamic), rdpsnd->subsystem, status); return status; } } @@ -875,8 +990,10 @@ static UINT rdpsnd_process_connect(rdpsndPlugin* rdpsnd) const char* device_name = backends[x].device; if ((status = rdpsnd_load_device_plugin(rdpsnd, subsystem_name, args))) - WLog_ERR(TAG, "unable to load the %s subsystem plugin because of error %"PRIu32"", - subsystem_name, status); + WLog_ERR(TAG, + "%s Unable to load sound playback subsystem %s because of error %" PRIu32 + "", + rdpsnd_is_dyn_str(rdpsnd->dynamic), subsystem_name, status); if (!rdpsnd->device) continue; @@ -895,11 +1012,6 @@ static UINT rdpsnd_process_connect(rdpsndPlugin* rdpsnd) return CHANNEL_RC_OK; } -static void rdpsnd_process_disconnect(rdpsndPlugin* rdpsnd) -{ - rdpsnd_recv_close_pdu(rdpsnd); -} - /** * Function description * @@ -911,15 +1023,29 @@ UINT rdpsnd_virtual_channel_write(rdpsndPlugin* rdpsnd, wStream* s) if (rdpsnd) { - status = rdpsnd->channelEntryPoints.pVirtualChannelWriteEx(rdpsnd->InitHandle, rdpsnd->OpenHandle, - Stream_Buffer(s), (UINT32) Stream_GetPosition(s), s); - } + if (rdpsnd->dynamic) + { + IWTSVirtualChannel* channel; + if (rdpsnd->listener_callback) + { + channel = rdpsnd->listener_callback->channel_callback->channel; + status = channel->Write(channel, (UINT32)Stream_Length(s), Stream_Buffer(s), NULL); + } + Stream_Free(s, TRUE); + } + else + { + status = rdpsnd->channelEntryPoints.pVirtualChannelWriteEx( + rdpsnd->InitHandle, rdpsnd->OpenHandle, Stream_Buffer(s), + (UINT32)Stream_GetPosition(s), s); - if (status != CHANNEL_RC_OK) - { - Stream_Free(s, TRUE); - WLog_ERR(TAG, "pVirtualChannelWriteEx failed with %s [%08"PRIX32"]", - WTSErrorToString(status), status); + if (status != CHANNEL_RC_OK) + { + Stream_Free(s, TRUE); + WLog_ERR(TAG, "%s pVirtualChannelWriteEx failed with %s [%08" PRIX32 "]", + rdpsnd_is_dyn_str(FALSE), WTSErrorToString(status), status); + } + } } return status; @@ -930,8 +1056,9 @@ UINT rdpsnd_virtual_channel_write(rdpsndPlugin* rdpsnd, wStream* s) * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpsnd_virtual_channel_event_data_received(rdpsndPlugin* plugin, - void* pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) +static UINT rdpsnd_virtual_channel_event_data_received(rdpsndPlugin* plugin, void* pData, + UINT32 dataLength, UINT32 totalLength, + UINT32 dataFlags) { if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME)) return CHANNEL_RC_OK; @@ -954,11 +1081,8 @@ static UINT rdpsnd_virtual_channel_event_data_received(rdpsndPlugin* plugin, Stream_SealLength(plugin->data_in); Stream_SetPosition(plugin->data_in, 0); - if (!Queue_Enqueue(plugin->queue, plugin->data_in)) - { - WLog_ERR(TAG, "Queue_Enqueue failed!"); + if (!MessageQueue_Post(plugin->queue, NULL, 0, plugin->data_in, NULL)) return ERROR_INTERNAL_ERROR; - } plugin->data_in = NULL; } @@ -967,111 +1091,53 @@ static UINT rdpsnd_virtual_channel_event_data_received(rdpsndPlugin* plugin, } static VOID VCAPITYPE rdpsnd_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle, - UINT event, - LPVOID pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) + UINT event, LPVOID pData, + UINT32 dataLength, UINT32 totalLength, + UINT32 dataFlags) { UINT error = CHANNEL_RC_OK; - rdpsndPlugin* rdpsnd = (rdpsndPlugin*) lpUserParam; - - if (!rdpsnd || (rdpsnd->OpenHandle != openHandle)) - { - WLog_ERR(TAG, "error no match"); - return; - } + rdpsndPlugin* rdpsnd = (rdpsndPlugin*)lpUserParam; switch (event) { case CHANNEL_EVENT_DATA_RECEIVED: - if ((error = rdpsnd_virtual_channel_event_data_received(rdpsnd, pData, - dataLength, totalLength, dataFlags))) + if (!rdpsnd) + return; + + if (rdpsnd->OpenHandle != openHandle) + { + WLog_ERR(TAG, "%s error no match", rdpsnd_is_dyn_str(rdpsnd->dynamic)); + return; + } + if ((error = rdpsnd_virtual_channel_event_data_received(rdpsnd, pData, dataLength, + totalLength, dataFlags))) WLog_ERR(TAG, - "rdpsnd_virtual_channel_event_data_received failed with error %"PRIu32"", error); + "%s rdpsnd_virtual_channel_event_data_received failed with error %" PRIu32 + "", + rdpsnd_is_dyn_str(rdpsnd->dynamic), error); break; + case CHANNEL_EVENT_WRITE_CANCELLED: case CHANNEL_EVENT_WRITE_COMPLETE: - break; + { + wStream* s = (wStream*)pData; + Stream_Free(s, TRUE); + } + break; case CHANNEL_EVENT_USER: break; } - if (error && rdpsnd->rdpcontext) - setChannelError(rdpsnd->rdpcontext, error, - "rdpsnd_virtual_channel_open_event_ex reported an error"); -} - -static DWORD WINAPI rdpsnd_virtual_channel_client_thread(LPVOID arg) -{ - BOOL running = TRUE; - rdpsndPlugin* rdpsnd = (rdpsndPlugin*) arg; - DWORD error = CHANNEL_RC_OK; - HANDLE events[2]; - - if ((error = rdpsnd_process_connect(rdpsnd))) + if (error && rdpsnd && rdpsnd->rdpcontext) { - WLog_ERR(TAG, "error connecting sound channel"); - goto out; - } - - events[1] = rdpsnd->stopEvent; - events[0] = Queue_Event(rdpsnd->queue); - - do - { - const DWORD status = WaitForMultipleObjects(ARRAYSIZE(events), events, FALSE, INFINITE); - - switch (status) - { - case WAIT_OBJECT_0: - { - wStream* s = Queue_Dequeue(rdpsnd->queue); - error = rdpsnd_recv_pdu(rdpsnd, s); - } - break; - - case WAIT_OBJECT_0 + 1: - running = FALSE; - break; - - default: - error = status; - break; - } + char buffer[8192]; + _snprintf(buffer, sizeof(buffer), + "%s rdpsnd_virtual_channel_open_event_ex reported an error", + rdpsnd_is_dyn_str(rdpsnd->dynamic)); + setChannelError(rdpsnd->rdpcontext, error, buffer); } - while ((error == CHANNEL_RC_OK) && running); - -out: - - if (error && rdpsnd->rdpcontext) - setChannelError(rdpsnd->rdpcontext, error, - "rdpsnd_virtual_channel_client_thread reported an error"); - - rdpsnd_process_disconnect(rdpsnd); - ExitThread((DWORD)error); - return error; -} - -/* Called during cleanup. - * All streams still in the queue have been removed - * from the streampool and nead cleanup. */ -static void rdpsnd_queue_free(void* data) -{ - wStream* s = (wStream*)data; - Stream_Free(s, TRUE); -} - -static UINT rdpsnd_virtual_channel_event_initialized(rdpsndPlugin* rdpsnd, - LPVOID pData, UINT32 dataLength) -{ - rdpsnd->stopEvent = CreateEventA(NULL, TRUE, FALSE, "rdpsnd->stopEvent"); - - if (!rdpsnd->stopEvent) - goto fail; - - return CHANNEL_RC_OK; -fail: - return ERROR_INTERNAL_ERROR; } /** @@ -1079,18 +1145,21 @@ fail: * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpsnd_virtual_channel_event_connected(rdpsndPlugin* rdpsnd, - LPVOID pData, UINT32 dataLength) +static UINT rdpsnd_virtual_channel_event_connected(rdpsndPlugin* rdpsnd, LPVOID pData, + UINT32 dataLength) { UINT32 status; - status = rdpsnd->channelEntryPoints.pVirtualChannelOpenEx(rdpsnd->InitHandle, - &rdpsnd->OpenHandle, rdpsnd->channelDef.name, - rdpsnd_virtual_channel_open_event_ex); + WINPR_UNUSED(pData); + WINPR_UNUSED(dataLength); + + status = rdpsnd->channelEntryPoints.pVirtualChannelOpenEx( + rdpsnd->InitHandle, &rdpsnd->OpenHandle, rdpsnd->channelDef.name, + rdpsnd_virtual_channel_open_event_ex); if (status != CHANNEL_RC_OK) { - WLog_ERR(TAG, "pVirtualChannelOpenEx failed with %s [%08"PRIX32"]", - WTSErrorToString(status), status); + WLog_ERR(TAG, "%s pVirtualChannelOpenEx failed with %s [%08" PRIX32 "]", + rdpsnd_is_dyn_str(rdpsnd->dynamic), WTSErrorToString(status), status); return status; } @@ -1099,36 +1168,15 @@ static UINT rdpsnd_virtual_channel_event_connected(rdpsndPlugin* rdpsnd, if (!rdpsnd->dsp_context) goto fail; - rdpsnd->queue = Queue_New(TRUE, 32, 2); - - if (!rdpsnd->queue) - goto fail; - - rdpsnd->queue->object.fnObjectFree = rdpsnd_queue_free; rdpsnd->pool = StreamPool_New(TRUE, 4096); if (!rdpsnd->pool) goto fail; - ResetEvent(rdpsnd->stopEvent); - rdpsnd->thread = CreateThread(NULL, 0, - rdpsnd_virtual_channel_client_thread, (void*) rdpsnd, - 0, NULL); - - if (!rdpsnd->thread) - goto fail; - - return CHANNEL_RC_OK; + return rdpsnd_process_connect(rdpsnd); fail: freerdp_dsp_context_free(rdpsnd->dsp_context); StreamPool_Free(rdpsnd->pool); - Queue_Free(rdpsnd->queue); - - if (rdpsnd->stopEvent) - CloseHandle(rdpsnd->stopEvent); - - if (rdpsnd->thread) - CloseHandle(rdpsnd->thread); return CHANNEL_RC_NO_MEMORY; } @@ -1145,22 +1193,16 @@ static UINT rdpsnd_virtual_channel_event_disconnected(rdpsndPlugin* rdpsnd) if (rdpsnd->OpenHandle == 0) return CHANNEL_RC_OK; - SetEvent(rdpsnd->stopEvent); - - if (WaitForSingleObject(rdpsnd->thread, INFINITE) == WAIT_FAILED) - { - error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); - return error; - } + if (rdpsnd->device) + IFCALL(rdpsnd->device->Close, rdpsnd->device); - CloseHandle(rdpsnd->thread); - error = rdpsnd->channelEntryPoints.pVirtualChannelCloseEx(rdpsnd->InitHandle, rdpsnd->OpenHandle); + error = + rdpsnd->channelEntryPoints.pVirtualChannelCloseEx(rdpsnd->InitHandle, rdpsnd->OpenHandle); if (CHANNEL_RC_OK != error) { - WLog_ERR(TAG, "pVirtualChannelCloseEx failed with %s [%08"PRIX32"]", - WTSErrorToString(error), error); + WLog_ERR(TAG, "%s pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]", + rdpsnd_is_dyn_str(rdpsnd->dynamic), WTSErrorToString(error), error); return error; } @@ -1168,7 +1210,7 @@ static UINT rdpsnd_virtual_channel_event_disconnected(rdpsndPlugin* rdpsnd) freerdp_dsp_context_free(rdpsnd->dsp_context); StreamPool_Return(rdpsnd->pool, rdpsnd->data_in); StreamPool_Free(rdpsnd->pool); - Queue_Free(rdpsnd->queue); + audio_formats_free(rdpsnd->ClientFormats, rdpsnd->NumberOfClientFormats); rdpsnd->NumberOfClientFormats = 0; rdpsnd->ClientFormats = NULL; @@ -1185,14 +1227,78 @@ static UINT rdpsnd_virtual_channel_event_disconnected(rdpsndPlugin* rdpsnd) return CHANNEL_RC_OK; } +static void _queue_free(void* obj) +{ + wStream* s = obj; + Stream_Release(s); +} + +static DWORD WINAPI play_thread(LPVOID arg) +{ + UINT error = CHANNEL_RC_OK; + rdpsndPlugin* rdpsnd = arg; + + if (!rdpsnd || !rdpsnd->queue) + return ERROR_INVALID_PARAMETER; + + while (TRUE) + { + int rc; + wMessage message; + wStream* s; + HANDLE handle = MessageQueue_Event(rdpsnd->queue); + WaitForSingleObject(handle, INFINITE); + + rc = MessageQueue_Peek(rdpsnd->queue, &message, TRUE); + if (rc < 1) + continue; + + if (message.id == WMQ_QUIT) + break; + + s = message.wParam; + error = rdpsnd_recv_pdu(rdpsnd, s); + + if (error) + return error; + } + + return CHANNEL_RC_OK; +} + +static UINT rdpsnd_virtual_channel_event_initialized(rdpsndPlugin* rdpsnd) +{ + wObject obj = { 0 }; + + if (!rdpsnd) + return ERROR_INVALID_PARAMETER; + + obj.fnObjectFree = _queue_free; + rdpsnd->queue = MessageQueue_New(&obj); + if (!rdpsnd->queue) + return CHANNEL_RC_NO_MEMORY; + + rdpsnd->thread = CreateThread(NULL, 0, play_thread, rdpsnd, 0, NULL); + if (!rdpsnd->thread) + return CHANNEL_RC_INITIALIZATION_ERROR; + return CHANNEL_RC_OK; +} + static void rdpsnd_virtual_channel_event_terminated(rdpsndPlugin* rdpsnd) { if (rdpsnd) { + MessageQueue_PostQuit(rdpsnd->queue, 0); + if (rdpsnd->thread) + { + WaitForSingleObject(rdpsnd->thread, INFINITE); + CloseHandle(rdpsnd->thread); + } + MessageQueue_Free(rdpsnd->queue); + audio_formats_free(rdpsnd->fixed_format, 1); free(rdpsnd->subsystem); free(rdpsnd->device_name); - CloseHandle(rdpsnd->stopEvent); rdpsnd->InitHandle = 0; } @@ -1200,38 +1306,33 @@ static void rdpsnd_virtual_channel_event_terminated(rdpsndPlugin* rdpsnd) } static VOID VCAPITYPE rdpsnd_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle, - UINT event, LPVOID pData, UINT dataLength) + UINT event, LPVOID pData, + UINT dataLength) { UINT error = CHANNEL_RC_OK; - rdpsndPlugin* plugin = (rdpsndPlugin*) lpUserParam; + rdpsndPlugin* plugin = (rdpsndPlugin*)lpUserParam; + + if (!plugin) + return; - if (!plugin || (plugin->InitHandle != pInitHandle)) + if (plugin->InitHandle != pInitHandle) { - WLog_ERR(TAG, "error no match"); + WLog_ERR(TAG, "%s error no match", rdpsnd_is_dyn_str(plugin->dynamic)); return; } switch (event) { case CHANNEL_EVENT_INITIALIZED: - if ((error = rdpsnd_virtual_channel_event_initialized(plugin, pData, dataLength))) - WLog_ERR(TAG, "rdpsnd_virtual_channel_event_initialized failed with error %"PRIu32"!", - error); - + error = rdpsnd_virtual_channel_event_initialized(plugin); break; case CHANNEL_EVENT_CONNECTED: - if ((error = rdpsnd_virtual_channel_event_connected(plugin, pData, dataLength))) - WLog_ERR(TAG, "rdpsnd_virtual_channel_event_connected failed with error %"PRIu32"!", - error); - + error = rdpsnd_virtual_channel_event_connected(plugin, pData, dataLength); break; case CHANNEL_EVENT_DISCONNECTED: - if ((error = rdpsnd_virtual_channel_event_disconnected(plugin))) - WLog_ERR(TAG, - "rdpsnd_virtual_channel_event_disconnected failed with error %"PRIu32"!", error); - + error = rdpsnd_virtual_channel_event_disconnected(plugin); break; case CHANNEL_EVENT_TERMINATED: @@ -1251,14 +1352,24 @@ static VOID VCAPITYPE rdpsnd_virtual_channel_init_event_ex(LPVOID lpUserParam, L } if (error && plugin && plugin->rdpcontext) - setChannelError(plugin->rdpcontext, error, - "rdpsnd_virtual_channel_init_event reported an error"); + { + char buffer[8192]; + _snprintf(buffer, sizeof(buffer), "%s %s reported an error", + rdpsnd_is_dyn_str(plugin->dynamic), __FUNCTION__); + setChannelError(plugin->rdpcontext, error, buffer); + } } -/* rdpsnd is always built-in */ -#define VirtualChannelEntryEx rdpsnd_VirtualChannelEntryEx +rdpContext* freerdp_rdpsnd_get_context(rdpsndPlugin* plugin) +{ + if (!plugin) + return NULL; -BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID pInitHandle) + return plugin->rdpcontext; +} + +/* rdpsnd is always built-in */ +BOOL VCAPITYPE rdpsnd_VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID pInitHandle) { UINT rc; rdpsndPlugin* rdpsnd; @@ -1267,17 +1378,15 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p if (!pEntryPoints) return FALSE; - rdpsnd = (rdpsndPlugin*) calloc(1, sizeof(rdpsndPlugin)); + rdpsnd = (rdpsndPlugin*)calloc(1, sizeof(rdpsndPlugin)); if (!rdpsnd) return FALSE; rdpsnd->attached = TRUE; - rdpsnd->channelDef.options = - CHANNEL_OPTION_INITIALIZED | - CHANNEL_OPTION_ENCRYPT_RDP; + rdpsnd->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP; sprintf_s(rdpsnd->channelDef.name, ARRAYSIZE(rdpsnd->channelDef.name), "rdpsnd"); - pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*) pEntryPoints; + pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints; if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) && (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER)) @@ -1297,17 +1406,211 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p CopyMemory(&(rdpsnd->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)); rdpsnd->InitHandle = pInitHandle; - rc = rdpsnd->channelEntryPoints.pVirtualChannelInitEx(rdpsnd, NULL, pInitHandle, - &rdpsnd->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, - rdpsnd_virtual_channel_init_event_ex); + rc = rdpsnd->channelEntryPoints.pVirtualChannelInitEx( + rdpsnd, NULL, pInitHandle, &rdpsnd->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, + rdpsnd_virtual_channel_init_event_ex); if (CHANNEL_RC_OK != rc) { - WLog_ERR(TAG, "pVirtualChannelInitEx failed with %s [%08"PRIX32"]", - WTSErrorToString(rc), rc); + WLog_ERR(TAG, "%s pVirtualChannelInitEx failed with %s [%08" PRIX32 "]", + rdpsnd_is_dyn_str(FALSE), WTSErrorToString(rc), rc); free(rdpsnd); return FALSE; } return TRUE; } + +static UINT rdpsnd_on_open(IWTSVirtualChannelCallback* pChannelCallback) +{ + RDPSND_CHANNEL_CALLBACK* callback = (RDPSND_CHANNEL_CALLBACK*)pChannelCallback; + rdpsndPlugin* rdpsnd = (rdpsndPlugin*)callback->plugin; + + rdpsnd->dsp_context = freerdp_dsp_context_new(FALSE); + if (!rdpsnd->dsp_context) + goto fail; + + rdpsnd->pool = StreamPool_New(TRUE, 4096); + if (!rdpsnd->pool) + goto fail; + + return rdpsnd_process_connect(rdpsnd); +fail: + freerdp_dsp_context_free(rdpsnd->dsp_context); + StreamPool_Free(rdpsnd->pool); + return CHANNEL_RC_NO_MEMORY; +} + +static UINT rdpsnd_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data) +{ + RDPSND_CHANNEL_CALLBACK* callback = (RDPSND_CHANNEL_CALLBACK*)pChannelCallback; + rdpsndPlugin* plugin; + wStream* copy; + size_t len = Stream_GetRemainingLength(data); + + if (!callback || !callback->plugin) + return ERROR_INVALID_PARAMETER; + plugin = (rdpsndPlugin*)callback->plugin; + + copy = StreamPool_Take(plugin->pool, len); + if (!copy) + return ERROR_OUTOFMEMORY; + Stream_Copy(data, copy, len); + Stream_SealLength(copy); + Stream_SetPosition(copy, 0); + + if (!MessageQueue_Post(plugin->queue, NULL, 0, copy, NULL)) + { + Stream_Release(copy); + return ERROR_INTERNAL_ERROR; + } + + return CHANNEL_RC_OK; +} + +static UINT rdpsnd_on_close(IWTSVirtualChannelCallback* pChannelCallback) +{ + RDPSND_CHANNEL_CALLBACK* callback = (RDPSND_CHANNEL_CALLBACK*)pChannelCallback; + rdpsndPlugin* rdpsnd = (rdpsndPlugin*)callback->plugin; + + if (rdpsnd->device) + IFCALL(rdpsnd->device->Close, rdpsnd->device); + freerdp_dsp_context_free(rdpsnd->dsp_context); + StreamPool_Return(rdpsnd->pool, rdpsnd->data_in); + StreamPool_Free(rdpsnd->pool); + + audio_formats_free(rdpsnd->ClientFormats, rdpsnd->NumberOfClientFormats); + rdpsnd->NumberOfClientFormats = 0; + rdpsnd->ClientFormats = NULL; + audio_formats_free(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats); + rdpsnd->NumberOfServerFormats = 0; + rdpsnd->ServerFormats = NULL; + if (rdpsnd->device) + { + IFCALL(rdpsnd->device->Free, rdpsnd->device); + rdpsnd->device = NULL; + } + + free(pChannelCallback); + return CHANNEL_RC_OK; +} + +static UINT rdpsnd_on_new_channel_connection(IWTSListenerCallback* pListenerCallback, + IWTSVirtualChannel* pChannel, BYTE* Data, + BOOL* pbAccept, + IWTSVirtualChannelCallback** ppCallback) +{ + RDPSND_CHANNEL_CALLBACK* callback; + RDPSND_LISTENER_CALLBACK* listener_callback = (RDPSND_LISTENER_CALLBACK*)pListenerCallback; + callback = (RDPSND_CHANNEL_CALLBACK*)calloc(1, sizeof(RDPSND_CHANNEL_CALLBACK)); + + WINPR_UNUSED(Data); + WINPR_UNUSED(pbAccept); + + if (!callback) + { + WLog_ERR(TAG, "%s calloc failed!", rdpsnd_is_dyn_str(TRUE)); + return CHANNEL_RC_NO_MEMORY; + } + + callback->iface.OnOpen = rdpsnd_on_open; + callback->iface.OnDataReceived = rdpsnd_on_data_received; + callback->iface.OnClose = rdpsnd_on_close; + callback->plugin = listener_callback->plugin; + callback->channel_mgr = listener_callback->channel_mgr; + callback->channel = pChannel; + listener_callback->channel_callback = callback; + *ppCallback = (IWTSVirtualChannelCallback*)callback; + return CHANNEL_RC_OK; +} + +static UINT rdpsnd_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr) +{ + UINT status; + rdpsndPlugin* rdpsnd = (rdpsndPlugin*)pPlugin; + rdpsnd->listener_callback = + (RDPSND_LISTENER_CALLBACK*)calloc(1, sizeof(RDPSND_LISTENER_CALLBACK)); + + if (!rdpsnd->listener_callback) + { + WLog_ERR(TAG, "%s calloc failed!", rdpsnd_is_dyn_str(TRUE)); + return CHANNEL_RC_NO_MEMORY; + } + + rdpsnd->listener_callback->iface.OnNewChannelConnection = rdpsnd_on_new_channel_connection; + rdpsnd->listener_callback->plugin = pPlugin; + rdpsnd->listener_callback->channel_mgr = pChannelMgr; + status = pChannelMgr->CreateListener(pChannelMgr, RDPSND_DVC_CHANNEL_NAME, 0, + &rdpsnd->listener_callback->iface, &(rdpsnd->listener)); + rdpsnd->listener->pInterface = rdpsnd->iface.pInterface; + return rdpsnd_virtual_channel_event_initialized(rdpsnd); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpsnd_plugin_terminated(IWTSPlugin* pPlugin) +{ + rdpsndPlugin* rdpsnd = (rdpsndPlugin*)pPlugin; + if (rdpsnd) + { + if (rdpsnd->listener_callback) + { + IWTSVirtualChannelManager* mgr = rdpsnd->listener_callback->channel_mgr; + if (mgr) + IFCALL(mgr->DestroyListener, mgr, rdpsnd->listener); + } + free(rdpsnd->listener_callback); + free(rdpsnd->iface.pInterface); + } + rdpsnd_virtual_channel_event_terminated(rdpsnd); + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +UINT rdpsnd_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) +{ + UINT error = CHANNEL_RC_OK; + rdpsndPlugin* rdpsnd = (rdpsndPlugin*)pEntryPoints->GetPlugin(pEntryPoints, "rdpsnd"); + + if (!rdpsnd) + { + rdpsnd = (rdpsndPlugin*)calloc(1, sizeof(rdpsndPlugin)); + if (!rdpsnd) + { + WLog_ERR(TAG, "%s calloc failed!", rdpsnd_is_dyn_str(TRUE)); + return CHANNEL_RC_NO_MEMORY; + } + + rdpsnd->iface.Initialize = rdpsnd_plugin_initialize; + rdpsnd->iface.Connected = NULL; + rdpsnd->iface.Disconnected = NULL; + rdpsnd->iface.Terminated = rdpsnd_plugin_terminated; + rdpsnd->attached = TRUE; + rdpsnd->dynamic = TRUE; + rdpsnd->fixed_format = audio_format_new(); + if (!rdpsnd->fixed_format) + goto fail; + + rdpsnd->log = WLog_Get("com.freerdp.channels.rdpsnd.client"); + rdpsnd->channelEntryPoints.pExtendedData = pEntryPoints->GetPluginData(pEntryPoints); + + error = pEntryPoints->RegisterPlugin(pEntryPoints, "rdpsnd", &rdpsnd->iface); + } + else + { + WLog_ERR(TAG, "%s could not get rdpsnd Plugin.", rdpsnd_is_dyn_str(TRUE)); + return CHANNEL_RC_BAD_CHANNEL; + } + + return error; +fail: + rdpsnd_plugin_terminated(&rdpsnd->iface); + return error; +} diff --git a/channels/rdpsnd/client/rdpsnd_main.h b/channels/rdpsnd/client/rdpsnd_main.h index aee8658..b3b478f 100644 --- a/channels/rdpsnd/client/rdpsnd_main.h +++ b/channels/rdpsnd/client/rdpsnd_main.h @@ -29,10 +29,15 @@ #define TAG CHANNELS_TAG("rdpsnd.client") +FREERDP_API rdpContext* freerdp_rdpsnd_get_context(rdpsndPlugin* rdpsnd); + #if defined(WITH_DEBUG_SND) #define DEBUG_SND(...) WLog_DBG(TAG, __VA_ARGS__) #else -#define DEBUG_SND(...) do { } while (0) +#define DEBUG_SND(...) \ + do \ + { \ + } while (0) #endif #endif /* FREERDP_CHANNEL_RDPSND_CLIENT_MAIN_H */ diff --git a/channels/rdpsnd/client/winmm/rdpsnd_winmm.c b/channels/rdpsnd/client/winmm/rdpsnd_winmm.c index c61e02c..0c51f77 100644 --- a/channels/rdpsnd/client/winmm/rdpsnd_winmm.c +++ b/channels/rdpsnd/client/winmm/rdpsnd_winmm.c @@ -29,11 +29,12 @@ #include #include -#include -#include +#include +#include #include #include +#include #include #include @@ -49,7 +50,11 @@ struct rdpsnd_winmm_plugin HWAVEOUT hWaveOut; WAVEFORMATEX format; UINT32 volume; - HANDLE next; + wLog* log; + UINT32 latency; + HANDLE hThread; + DWORD threadId; + CRITICAL_SECTION cs; }; static BOOL rdpsnd_winmm_convert_format(const AUDIO_FORMAT* in, WAVEFORMATEX* out) @@ -80,49 +85,46 @@ static BOOL rdpsnd_winmm_convert_format(const AUDIO_FORMAT* in, WAVEFORMATEX* ou static BOOL rdpsnd_winmm_set_format(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format, UINT32 latency) { - rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; + rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*)device; + winmm->latency = latency; if (!rdpsnd_winmm_convert_format(format, &winmm->format)) return FALSE; return TRUE; } -static void CALLBACK rdpsnd_winmm_callback_function(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance, - DWORD_PTR dwParam1, DWORD_PTR dwParam2) +static DWORD WINAPI waveOutProc(LPVOID lpParameter) { - LPWAVEHDR lpWaveHdr; - rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) dwInstance; - - switch (uMsg) + MSG msg; + rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*)lpParameter; + while (GetMessage(&msg, NULL, 0, 0)) { - case MM_WOM_OPEN: - WLog_DBG(TAG, "MM_WOM_OPEN"); - break; - - 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: - WLog_DBG(TAG, "UNKNOWN [0x%08"PRIx32"]", uMsg); + if (msg.message == MM_WOM_CLOSE) + { + /* device was closed - exit thread */ break; + } + else if (msg.message == MM_WOM_DONE) + { + /* free buffer */ + LPWAVEHDR waveHdr = (LPWAVEHDR)msg.lParam; + EnterCriticalSection(&winmm->cs); + waveOutUnprepareHeader((HWAVEOUT)msg.wParam, waveHdr, sizeof(WAVEHDR)); + LeaveCriticalSection(&winmm->cs); + free(waveHdr->lpData); + free(waveHdr); + } } + + return 0; } static BOOL rdpsnd_winmm_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format, UINT32 latency) { MMRESULT mmResult; - rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; + rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*)device; if (winmm->hWaveOut) return TRUE; @@ -130,12 +132,19 @@ static BOOL rdpsnd_winmm_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* fo if (!rdpsnd_winmm_set_format(device, format, latency)) return FALSE; + winmm->hThread = CreateThread(NULL, 0, waveOutProc, winmm, 0, &winmm->threadId); + if (!winmm->hThread) + { + WLog_Print(winmm->log, WLOG_ERROR, "CreateThread failed: %" PRIu32 "", GetLastError()); + return FALSE; + } + mmResult = waveOutOpen(&winmm->hWaveOut, WAVE_MAPPER, &winmm->format, - (DWORD_PTR) rdpsnd_winmm_callback_function, (DWORD_PTR) winmm, CALLBACK_FUNCTION); + (DWORD_PTR)winmm->threadId, 0, CALLBACK_THREAD); if (mmResult != MMSYSERR_NOERROR) { - WLog_ERR(TAG, "waveOutOpen failed: %"PRIu32"", mmResult); + WLog_Print(winmm->log, WLOG_ERROR, "waveOutOpen failed: %" PRIu32 "", mmResult); return FALSE; } @@ -143,7 +152,7 @@ static BOOL rdpsnd_winmm_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* fo if (mmResult != MMSYSERR_NOERROR) { - WLog_ERR(TAG, "waveOutSetVolume failed: %"PRIu32"", mmResult); + WLog_Print(winmm->log, WLOG_ERROR, "waveOutSetVolume failed: %" PRIu32 "", mmResult); return FALSE; } @@ -153,30 +162,41 @@ static BOOL rdpsnd_winmm_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* fo static void rdpsnd_winmm_close(rdpsndDevicePlugin* device) { MMRESULT mmResult; - rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; + rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*)device; if (winmm->hWaveOut) { + EnterCriticalSection(&winmm->cs); + mmResult = waveOutReset(winmm->hWaveOut); - mmResult = waveOutClose(winmm->hWaveOut); + if (mmResult != MMSYSERR_NOERROR) + WLog_Print(winmm->log, WLOG_ERROR, "waveOutReset failure: %" PRIu32 "", mmResult); + mmResult = waveOutClose(winmm->hWaveOut); if (mmResult != MMSYSERR_NOERROR) - { - WLog_ERR(TAG, "waveOutClose failure: %"PRIu32"", mmResult); - } + WLog_Print(winmm->log, WLOG_ERROR, "waveOutClose failure: %" PRIu32 "", mmResult); + + LeaveCriticalSection(&winmm->cs); winmm->hWaveOut = NULL; } + + if (winmm->hThread) + { + WaitForSingleObject(winmm->hThread, INFINITE); + CloseHandle(winmm->hThread); + winmm->hThread = NULL; + } } static void rdpsnd_winmm_free(rdpsndDevicePlugin* device) { - rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; + rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*)device; if (winmm) { rdpsnd_winmm_close(device); - CloseHandle(winmm->next); + DeleteCriticalSection(&winmm->cs); free(winmm); } } @@ -186,6 +206,7 @@ static BOOL rdpsnd_winmm_format_supported(rdpsndDevicePlugin* device, const AUDI MMRESULT result; WAVEFORMATEX out; + WINPR_UNUSED(device); if (rdpsnd_winmm_convert_format(format, &out)) { result = waveOutOpen(NULL, WAVE_MAPPER, &out, 0, 0, WAVE_FORMAT_QUERY); @@ -199,88 +220,102 @@ static BOOL rdpsnd_winmm_format_supported(rdpsndDevicePlugin* device, const AUDI static UINT32 rdpsnd_winmm_get_volume(rdpsndDevicePlugin* device) { - DWORD dwVolume; - UINT16 dwVolumeLeft; - UINT16 dwVolumeRight; - rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; - dwVolumeLeft = ((50 * 0xFFFF) / 100); /* 50% */ - dwVolumeRight = ((50 * 0xFFFF) / 100); /* 50% */ - dwVolume = (dwVolumeLeft << 16) | dwVolumeRight; + MMRESULT mmResult; + DWORD dwVolume = UINT32_MAX; + rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*)device; if (!winmm->hWaveOut) return dwVolume; - waveOutGetVolume(winmm->hWaveOut, &dwVolume); + mmResult = waveOutGetVolume(winmm->hWaveOut, &dwVolume); + if (mmResult != MMSYSERR_NOERROR) + { + WLog_Print(winmm->log, WLOG_ERROR, "waveOutGetVolume failure: %" PRIu32 "", mmResult); + dwVolume = UINT32_MAX; + } return dwVolume; } static BOOL rdpsnd_winmm_set_volume(rdpsndDevicePlugin* device, UINT32 value) { - rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; + MMRESULT mmResult; + rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*)device; winmm->volume = value; if (!winmm->hWaveOut) return TRUE; - return (waveOutSetVolume(winmm->hWaveOut, value) == MMSYSERR_NOERROR); -} - -static void rdpsnd_winmm_start(rdpsndDevicePlugin* device) -{ - //rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; + mmResult = waveOutSetVolume(winmm->hWaveOut, value); + if (mmResult != MMSYSERR_NOERROR) + { + WLog_Print(winmm->log, WLOG_ERROR, "waveOutGetVolume failure: %" PRIu32 "", mmResult); + return FALSE; + } + return TRUE; } static UINT rdpsnd_winmm_play(rdpsndDevicePlugin* device, const BYTE* data, size_t size) { MMRESULT mmResult; LPWAVEHDR lpWaveHdr; - rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; + rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*)device; if (!winmm->hWaveOut) return 0; - lpWaveHdr = (LPWAVEHDR) malloc(sizeof(WAVEHDR)); + if (size > UINT32_MAX) + return 0; + lpWaveHdr = (LPWAVEHDR)calloc(1, sizeof(WAVEHDR)); if (!lpWaveHdr) return 0; - ZeroMemory(lpWaveHdr, sizeof(WAVEHDR)); lpWaveHdr->dwFlags = 0; lpWaveHdr->dwLoops = 0; - lpWaveHdr->lpData = (LPSTR) data; - lpWaveHdr->dwBufferLength = size; - lpWaveHdr->dwUser = NULL; - lpWaveHdr->lpNext = NULL; - mmResult = waveOutPrepareHeader(winmm->hWaveOut, lpWaveHdr, sizeof(WAVEHDR)); + lpWaveHdr->lpData = malloc(size); + if (!lpWaveHdr->lpData) + goto fail; + memcpy(lpWaveHdr->lpData, data, size); + lpWaveHdr->dwBufferLength = (DWORD)size; + + EnterCriticalSection(&winmm->cs); + mmResult = waveOutPrepareHeader(winmm->hWaveOut, lpWaveHdr, sizeof(WAVEHDR)); if (mmResult != MMSYSERR_NOERROR) { - WLog_ERR(TAG, "waveOutPrepareHeader failure: %"PRIu32"", mmResult); - return 0; + WLog_Print(winmm->log, WLOG_ERROR, "waveOutPrepareHeader failure: %" PRIu32 "", mmResult); + goto failCS; } mmResult = waveOutWrite(winmm->hWaveOut, lpWaveHdr, sizeof(WAVEHDR)); - if (mmResult != MMSYSERR_NOERROR) { - WLog_ERR(TAG, "waveOutWrite failure: %"PRIu32"", mmResult); + WLog_Print(winmm->log, WLOG_ERROR, "waveOutWrite failure: %" PRIu32 "", mmResult); waveOutUnprepareHeader(winmm->hWaveOut, lpWaveHdr, sizeof(WAVEHDR)); - free(lpWaveHdr); - return 0; + goto failCS; } - WaitForSingleObject(winmm->next, INFINITE); - return 10; /* TODO: Get real latencry in [ms] */ + LeaveCriticalSection(&winmm->cs); + return winmm->latency; +failCS: + LeaveCriticalSection(&winmm->cs); +fail: + if (lpWaveHdr) + free(lpWaveHdr->lpData); + free(lpWaveHdr); + return 0; } static void rdpsnd_winmm_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV* args) { + WINPR_UNUSED(device); + WINPR_UNUSED(args); } #ifdef BUILTIN_CHANNELS -#define freerdp_rdpsnd_client_subsystem_entry winmm_freerdp_rdpsnd_client_subsystem_entry +#define freerdp_rdpsnd_client_subsystem_entry winmm_freerdp_rdpsnd_client_subsystem_entry #else -#define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry +#define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry #endif /** @@ -292,8 +327,14 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p { ADDIN_ARGV* args; rdpsndWinmmPlugin* winmm; - winmm = (rdpsndWinmmPlugin*) calloc(1, sizeof(rdpsndWinmmPlugin)); + if (waveOutGetNumDevs() == 0) + { + WLog_Print(WLog_Get(TAG), WLOG_ERROR, "No sound playback device available!"); + return ERROR_DEVICE_NOT_AVAILABLE; + } + + winmm = (rdpsndWinmmPlugin*)calloc(1, sizeof(rdpsndWinmmPlugin)); if (!winmm) return CHANNEL_RC_NO_MEMORY; @@ -301,21 +342,15 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p winmm->device.FormatSupported = rdpsnd_winmm_format_supported; winmm->device.GetVolume = rdpsnd_winmm_get_volume; winmm->device.SetVolume = rdpsnd_winmm_set_volume; - winmm->device.Start = rdpsnd_winmm_start; 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; - } + winmm->log = WLog_Get(TAG); + InitializeCriticalSection(&winmm->cs); args = pEntryPoints->args; - rdpsnd_winmm_parse_addin_args((rdpsndDevicePlugin*) winmm, args); + rdpsnd_winmm_parse_addin_args((rdpsndDevicePlugin*)winmm, args); winmm->volume = 0xFFFFFFFF; - pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*) winmm); + pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*)winmm); return CHANNEL_RC_OK; } diff --git a/channels/rdpsnd/server/rdpsnd_main.c b/channels/rdpsnd/server/rdpsnd_main.c index 53d4d5c..cb9f5fe 100644 --- a/channels/rdpsnd/server/rdpsnd_main.c +++ b/channels/rdpsnd/server/rdpsnd_main.c @@ -50,20 +50,21 @@ static UINT rdpsnd_server_send_formats(RdpsndServerContext* context, wStream* s) Stream_Write_UINT8(s, SNDC_FORMATS); Stream_Write_UINT8(s, 0); Stream_Seek_UINT16(s); - Stream_Write_UINT32(s, 0); /* dwFlags */ - Stream_Write_UINT32(s, 0); /* dwVolume */ - Stream_Write_UINT32(s, 0); /* dwPitch */ - Stream_Write_UINT16(s, 0); /* wDGramPort */ + Stream_Write_UINT32(s, 0); /* dwFlags */ + Stream_Write_UINT32(s, 0); /* dwVolume */ + Stream_Write_UINT32(s, 0); /* dwPitch */ + Stream_Write_UINT16(s, 0); /* wDGramPort */ Stream_Write_UINT16(s, context->num_server_formats); /* wNumberOfFormats */ - Stream_Write_UINT8(s, context->block_no); /* cLastBlockConfirmed */ - Stream_Write_UINT16(s, CHANNEL_VERSION_WIN_MAX); /* wVersion */ - Stream_Write_UINT8(s, 0); /* bPad */ + Stream_Write_UINT8(s, context->block_no); /* cLastBlockConfirmed */ + Stream_Write_UINT16(s, CHANNEL_VERSION_WIN_MAX); /* wVersion */ + Stream_Write_UINT8(s, 0); /* bPad */ for (i = 0; i < context->num_server_formats; i++) { AUDIO_FORMAT format = context->server_formats[i]; // TODO: Eliminate this!!! - format.nAvgBytesPerSec = format.nSamplesPerSec * format.nChannels * format.wBitsPerSample / 8; + format.nAvgBytesPerSec = + format.nSamplesPerSec * format.nChannels * format.wBitsPerSample / 8; if (!audio_format_write(s, &format)) goto fail; @@ -73,8 +74,8 @@ static UINT rdpsnd_server_send_formats(RdpsndServerContext* context, wStream* s) Stream_SetPosition(s, 2); Stream_Write_UINT16(s, pos - 4); Stream_SetPosition(s, pos); - status = WTSVirtualChannelWrite(context->priv->ChannelHandle, - (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written); + status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR)Stream_Buffer(s), + Stream_GetPosition(s), &written); Stream_SetPosition(s, 0); fail: return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; @@ -85,8 +86,7 @@ fail: * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpsnd_server_recv_waveconfirm(RdpsndServerContext* context, - wStream* s) +static UINT rdpsnd_server_recv_waveconfirm(RdpsndServerContext* context, wStream* s) { UINT16 timestamp; BYTE confirmBlockNum; @@ -101,10 +101,10 @@ static UINT rdpsnd_server_recv_waveconfirm(RdpsndServerContext* context, Stream_Read_UINT16(s, timestamp); Stream_Read_UINT8(s, confirmBlockNum); Stream_Seek_UINT8(s); - IFCALLRET(context->ConfirmBlock, error, context, confirmBlockNum, timestamp); + IFCALLRET(context->ConfirmBlock, error, context, confirmBlockNum, timestamp); if (error) - WLog_ERR(TAG, "context->ConfirmBlock failed with error %"PRIu32"", error); + WLog_ERR(TAG, "context->ConfirmBlock failed with error %" PRIu32 "", error); return error; } @@ -114,8 +114,7 @@ static UINT rdpsnd_server_recv_waveconfirm(RdpsndServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpsnd_server_recv_quality_mode(RdpsndServerContext* context, - wStream* s) +static UINT rdpsnd_server_recv_quality_mode(RdpsndServerContext* context, wStream* s) { UINT16 quality; @@ -127,7 +126,7 @@ static UINT rdpsnd_server_recv_quality_mode(RdpsndServerContext* context, Stream_Read_UINT16(s, quality); Stream_Seek_UINT16(s); // reserved - WLog_DBG(TAG, "Client requested sound quality: 0x%04"PRIX16"", quality); + WLog_DBG(TAG, "Client requested sound quality: 0x%04" PRIX16 "", quality); return CHANNEL_RC_OK; } @@ -150,14 +149,14 @@ static UINT rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s) return ERROR_INVALID_DATA; } - Stream_Read_UINT32(s, flags); /* dwFlags */ - Stream_Read_UINT32(s, vol); /* dwVolume */ - Stream_Read_UINT32(s, pitch); /* dwPitch */ - Stream_Read_UINT16(s, udpPort); /* wDGramPort */ + Stream_Read_UINT32(s, flags); /* dwFlags */ + Stream_Read_UINT32(s, vol); /* dwVolume */ + Stream_Read_UINT32(s, pitch); /* dwPitch */ + Stream_Read_UINT16(s, udpPort); /* wDGramPort */ Stream_Read_UINT16(s, context->num_client_formats); /* wNumberOfFormats */ - Stream_Read_UINT8(s, lastblock); /* cLastBlockConfirmed */ - Stream_Read_UINT16(s, context->clientVersion); /* wVersion */ - Stream_Seek_UINT8(s); /* bPad */ + Stream_Read_UINT8(s, lastblock); /* cLastBlockConfirmed */ + Stream_Read_UINT16(s, context->clientVersion); /* wVersion */ + Stream_Seek_UINT8(s); /* bPad */ /* this check is only a guess as cbSize can influence the size of a format record */ if (Stream_GetRemainingLength(s) < context->num_client_formats * 18) @@ -168,7 +167,7 @@ static UINT rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s) if (!context->num_client_formats) { - WLog_ERR(TAG, "client doesn't support any format!"); + WLog_ERR(TAG, "client doesn't support any format!"); return ERROR_INTERNAL_ERROR; } @@ -176,7 +175,7 @@ static UINT rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s) if (!context->client_formats) { - WLog_ERR(TAG, "calloc failed!"); + WLog_ERR(TAG, "calloc failed!"); return CHANNEL_RC_NO_MEMORY; } @@ -209,15 +208,15 @@ static UINT rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s) if (context->client_formats[i].wFormatTag != 0) { - //lets call this a known format - //TODO: actually look through our own list of known formats + // lets call this a known format + // TODO: actually look through our own list of known formats num_known_format++; } } if (!context->num_client_formats) { - WLog_ERR(TAG, "client doesn't support any known format!"); + WLog_ERR(TAG, "client doesn't support any known format!"); goto out_free; } @@ -245,7 +244,7 @@ static DWORD WINAPI rdpsnd_server_thread(LPVOID arg) if (status == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", error); break; } @@ -254,7 +253,7 @@ static DWORD WINAPI rdpsnd_server_thread(LPVOID arg) if (status == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error); break; } @@ -263,14 +262,13 @@ static DWORD WINAPI rdpsnd_server_thread(LPVOID arg) if ((error = rdpsnd_server_handle_messages(context))) { - WLog_ERR(TAG, "rdpsnd_server_handle_messages failed with error %"PRIu32"", error); + WLog_ERR(TAG, "rdpsnd_server_handle_messages failed with error %" PRIu32 "", error); break; } } if (error && context->rdpcontext) - setChannelError(context->rdpcontext, error, - "rdpsnd_server_thread reported an error"); + setChannelError(context->rdpcontext, error, "rdpsnd_server_thread reported an error"); ExitThread(error); return error; @@ -281,8 +279,7 @@ static DWORD WINAPI rdpsnd_server_thread(LPVOID arg) * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpsnd_server_initialize(RdpsndServerContext* context, - BOOL ownThread) +static UINT rdpsnd_server_initialize(RdpsndServerContext* context, BOOL ownThread) { context->priv->ownThread = ownThread; return context->Start(context); @@ -293,31 +290,29 @@ static UINT rdpsnd_server_initialize(RdpsndServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpsnd_server_select_format(RdpsndServerContext* context, - UINT16 client_format_index) +static UINT rdpsnd_server_select_format(RdpsndServerContext* context, UINT16 client_format_index) { int bs; int out_buffer_size; AUDIO_FORMAT* format; UINT error = CHANNEL_RC_OK; - if ((client_format_index >= context->num_client_formats) - || (!context->src_format)) + if ((client_format_index >= context->num_client_formats) || (!context->src_format)) { - WLog_ERR(TAG, "index %d is not correct.", client_format_index); + WLog_ERR(TAG, "index %d is not correct.", client_format_index); return ERROR_INVALID_DATA; } EnterCriticalSection(&context->priv->lock); context->priv->src_bytes_per_sample = context->src_format->wBitsPerSample / 8; - context->priv->src_bytes_per_frame = context->priv->src_bytes_per_sample * - context->src_format->nChannels; + context->priv->src_bytes_per_frame = + context->priv->src_bytes_per_sample * context->src_format->nChannels; context->selected_client_format = client_format_index; format = &context->client_formats[client_format_index]; if (format->nSamplesPerSec == 0) { - WLog_ERR(TAG, "invalid Client Sound Format!!"); + WLog_ERR(TAG, "invalid Client Sound Format!!"); error = ERROR_INVALID_DATA; goto out; } @@ -325,8 +320,7 @@ static UINT rdpsnd_server_select_format(RdpsndServerContext* context, if (context->latency <= 0) context->latency = 50; - context->priv->out_frames = context->src_format->nSamplesPerSec * - context->latency / 1000; + context->priv->out_frames = context->src_format->nSamplesPerSec * context->latency / 1000; if (context->priv->out_frames < 1) context->priv->out_frames = 1; @@ -353,8 +347,7 @@ static UINT rdpsnd_server_select_format(RdpsndServerContext* context, } context->priv->out_pending_frames = 0; - out_buffer_size = context->priv->out_frames * - context->priv->src_bytes_per_frame; + out_buffer_size = context->priv->out_frames * context->priv->src_bytes_per_frame; if (context->priv->out_buffer_size < out_buffer_size) { @@ -404,8 +397,7 @@ static BOOL rdpsnd_server_align_wave_pdu(wStream* s, UINT32 alignment) * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpsnd_server_send_wave_pdu(RdpsndServerContext* context, - UINT16 wTimestamp) +static UINT rdpsnd_server_send_wave_pdu(RdpsndServerContext* context, UINT16 wTimestamp) { size_t length; size_t start, end = 0; @@ -421,13 +413,13 @@ static UINT rdpsnd_server_send_wave_pdu(RdpsndServerContext* context, format = &context->client_formats[context->selected_client_format]; /* WaveInfo PDU */ Stream_SetPosition(s, 0); - Stream_Write_UINT8(s, SNDC_WAVE); /* msgType */ - Stream_Write_UINT8(s, 0); /* bPad */ - Stream_Write_UINT16(s, 0); /* BodySize */ - Stream_Write_UINT16(s, wTimestamp); /* wTimeStamp */ + Stream_Write_UINT8(s, SNDC_WAVE); /* msgType */ + Stream_Write_UINT8(s, 0); /* bPad */ + Stream_Write_UINT16(s, 0); /* BodySize */ + Stream_Write_UINT16(s, wTimestamp); /* wTimeStamp */ Stream_Write_UINT16(s, context->selected_client_format); /* wFormatNo */ - Stream_Write_UINT8(s, context->block_no); /* cBlockNo */ - Stream_Seek(s, 3); /* bPad */ + Stream_Write_UINT8(s, context->block_no); /* cBlockNo */ + Stream_Seek(s, 3); /* bPad */ start = Stream_GetPosition(s); src = context->priv->out_buffer; length = context->priv->out_pending_frames * context->priv->src_bytes_per_frame; @@ -446,8 +438,8 @@ static UINT rdpsnd_server_send_wave_pdu(RdpsndServerContext* context, Stream_SetPosition(s, end); context->block_no = (context->block_no + 1) % 256; - if (!WTSVirtualChannelWrite(context->priv->ChannelHandle, - (PCHAR) Stream_Buffer(s), start + 4, &written)) + if (!WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR)Stream_Buffer(s), + start + 4, &written)) { WLog_ERR(TAG, "WTSVirtualChannelWrite failed!"); error = ERROR_INTERNAL_ERROR; @@ -465,8 +457,8 @@ static UINT rdpsnd_server_send_wave_pdu(RdpsndServerContext* context, Stream_Write_UINT32(s, 0); /* bPad */ Stream_SetPosition(s, start); - if (!WTSVirtualChannelWrite(context->priv->ChannelHandle, - (PCHAR) Stream_Pointer(s), end - start, &written)) + if (!WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR)Stream_Pointer(s), end - start, + &written)) { WLog_ERR(TAG, "WTSVirtualChannelWrite failed!"); error = ERROR_INTERNAL_ERROR; @@ -484,8 +476,7 @@ out: * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpsnd_server_send_wave2_pdu(RdpsndServerContext* context, - UINT16 wTimestamp) +static UINT rdpsnd_server_send_wave2_pdu(RdpsndServerContext* context, UINT16 wTimestamp) { size_t length; size_t end = 0; @@ -501,14 +492,14 @@ static UINT rdpsnd_server_send_wave2_pdu(RdpsndServerContext* context, format = &context->client_formats[context->selected_client_format]; /* WaveInfo PDU */ Stream_SetPosition(s, 0); - Stream_Write_UINT8(s, SNDC_WAVE2); /* msgType */ - Stream_Write_UINT8(s, 0); /* bPad */ - Stream_Write_UINT16(s, 0); /* BodySize */ - Stream_Write_UINT16(s, wTimestamp); /* wTimeStamp */ + Stream_Write_UINT8(s, SNDC_WAVE2); /* msgType */ + Stream_Write_UINT8(s, 0); /* bPad */ + Stream_Write_UINT16(s, 0); /* BodySize */ + Stream_Write_UINT16(s, wTimestamp); /* wTimeStamp */ Stream_Write_UINT16(s, context->selected_client_format); /* wFormatNo */ - Stream_Write_UINT8(s, context->block_no); /* cBlockNo */ - Stream_Seek(s, 3); /* bPad */ - Stream_Write_UINT32(s, wTimestamp); /* dwAudioTimeStamp */ + Stream_Write_UINT8(s, context->block_no); /* cBlockNo */ + Stream_Seek(s, 3); /* bPad */ + Stream_Write_UINT32(s, wTimestamp); /* dwAudioTimeStamp */ src = context->priv->out_buffer; length = context->priv->out_pending_frames * context->priv->src_bytes_per_frame; @@ -526,13 +517,14 @@ static UINT rdpsnd_server_send_wave2_pdu(RdpsndServerContext* context, Stream_SetPosition(s, 2); Stream_Write_UINT16(s, end - 4); context->block_no = (context->block_no + 1) % 256; - rc = WTSVirtualChannelWrite(context->priv->ChannelHandle, - (PCHAR) Stream_Buffer(s), end, &written); + rc = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR)Stream_Buffer(s), end, + &written); if (!rc || (end != written)) { - WLog_ERR(TAG, "WTSVirtualChannelWrite failed! [stream length=%"PRIdz" - written=%"PRIu32, end, - written); + WLog_ERR(TAG, + "WTSVirtualChannelWrite failed! [stream length=%" PRIdz " - written=%" PRIu32, + end, written); error = ERROR_INTERNAL_ERROR; } } @@ -543,8 +535,7 @@ static UINT rdpsnd_server_send_wave2_pdu(RdpsndServerContext* context, } /* Wrapper function to send WAVE or WAVE2 PDU depending on client connected */ -static UINT rdpsnd_server_send_audio_pdu(RdpsndServerContext* context, - UINT16 wTimestamp) +static UINT rdpsnd_server_send_audio_pdu(RdpsndServerContext* context, UINT16 wTimestamp) { if (context->clientVersion >= CHANNEL_VERSION_WIN_8) return rdpsnd_server_send_wave2_pdu(context, wTimestamp); @@ -557,8 +548,8 @@ static UINT rdpsnd_server_send_audio_pdu(RdpsndServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpsnd_server_send_samples(RdpsndServerContext* context, - const void* buf, int nframes, UINT16 wTimestamp) +static UINT rdpsnd_server_send_samples(RdpsndServerContext* context, const void* buf, int nframes, + UINT16 wTimestamp) { int cframes; int cframesize; @@ -575,13 +566,12 @@ static UINT rdpsnd_server_send_samples(RdpsndServerContext* context, while (nframes > 0) { - cframes = MIN(nframes, context->priv->out_frames - - context->priv->out_pending_frames); + cframes = MIN(nframes, context->priv->out_frames - context->priv->out_pending_frames); cframesize = cframes * context->priv->src_bytes_per_frame; CopyMemory(context->priv->out_buffer + - (context->priv->out_pending_frames * context->priv->src_bytes_per_frame), buf, - cframesize); - buf = (BYTE*) buf + cframesize; + (context->priv->out_pending_frames * context->priv->src_bytes_per_frame), + buf, cframesize); + buf = (BYTE*)buf + cframesize; nframes -= cframes; context->priv->out_pending_frames += cframes; @@ -589,7 +579,7 @@ static UINT rdpsnd_server_send_samples(RdpsndServerContext* context, { if ((error = rdpsnd_server_send_audio_pdu(context, wTimestamp))) { - WLog_ERR(TAG, "rdpsnd_server_send_audio_pdu failed with error %"PRIu32"", error); + WLog_ERR(TAG, "rdpsnd_server_send_audio_pdu failed with error %" PRIu32 "", error); break; } } @@ -605,8 +595,7 @@ out: * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpsnd_server_set_volume(RdpsndServerContext* context, int left, - int right) +static UINT rdpsnd_server_set_volume(RdpsndServerContext* context, int left, int right) { size_t pos; BOOL status; @@ -621,8 +610,8 @@ static UINT rdpsnd_server_set_volume(RdpsndServerContext* context, int left, Stream_SetPosition(s, 2); Stream_Write_UINT16(s, pos - 4); Stream_SetPosition(s, pos); - status = WTSVirtualChannelWrite(context->priv->ChannelHandle, - (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written); + status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR)Stream_Buffer(s), + Stream_GetPosition(s), &written); Stream_SetPosition(s, 0); return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; } @@ -650,7 +639,7 @@ static UINT rdpsnd_server_close(RdpsndServerContext* context) } else if ((error = rdpsnd_server_send_audio_pdu(context, 0))) { - WLog_ERR(TAG, "rdpsnd_server_send_audio_pdu failed with error %"PRIu32"", error); + WLog_ERR(TAG, "rdpsnd_server_send_audio_pdu failed with error %" PRIu32 "", error); } } @@ -667,8 +656,8 @@ static UINT rdpsnd_server_close(RdpsndServerContext* context) Stream_SetPosition(s, 2); Stream_Write_UINT16(s, pos - 4); Stream_SetPosition(s, pos); - status = WTSVirtualChannelWrite(context->priv->ChannelHandle, - (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written); + status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR)Stream_Buffer(s), + Stream_GetPosition(s), &written); Stream_SetPosition(s, 0); return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; } @@ -684,8 +673,7 @@ static UINT rdpsnd_server_start(RdpsndServerContext* context) DWORD bytesReturned; RdpsndServerPrivate* priv = context->priv; UINT error = ERROR_INTERNAL_ERROR; - priv->ChannelHandle = WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, - "rdpsnd"); + priv->ChannelHandle = WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "rdpsnd"); if (!priv->ChannelHandle) { @@ -694,10 +682,12 @@ static UINT rdpsnd_server_start(RdpsndServerContext* context) } if (!WTSVirtualChannelQuery(priv->ChannelHandle, WTSVirtualEventHandle, &buffer, - &bytesReturned) || (bytesReturned != sizeof(HANDLE))) + &bytesReturned) || + (bytesReturned != sizeof(HANDLE))) { WLog_ERR(TAG, - "error during WTSVirtualChannelQuery(WTSVirtualEventHandle) or invalid returned size(%"PRIu32")", + "error during WTSVirtualChannelQuery(WTSVirtualEventHandle) or invalid returned " + "size(%" PRIu32 ")", bytesReturned); if (buffer) @@ -725,7 +715,7 @@ static UINT rdpsnd_server_start(RdpsndServerContext* context) if ((error = rdpsnd_server_send_formats(context, context->priv->rdpsnd_pdu))) { - WLog_ERR(TAG, "rdpsnd_server_send_formats failed with error %"PRIu32"", error); + WLog_ERR(TAG, "rdpsnd_server_send_formats failed with error %" PRIu32 "", error); goto out_lock; } @@ -739,8 +729,8 @@ static UINT rdpsnd_server_start(RdpsndServerContext* context) goto out_lock; } - context->priv->Thread = CreateThread(NULL, 0, - rdpsnd_server_thread, (void*) context, 0, NULL); + context->priv->Thread = + CreateThread(NULL, 0, rdpsnd_server_thread, (void*)context, 0, NULL); if (!context->priv->Thread) { @@ -782,7 +772,7 @@ static UINT rdpsnd_server_stop(RdpsndServerContext* context) if (WaitForSingleObject(context->priv->Thread, INFINITE) == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error); return error; } @@ -820,8 +810,7 @@ RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm) context->SendSamples = rdpsnd_server_send_samples; context->SetVolume = rdpsnd_server_set_volume; context->Close = rdpsnd_server_close; - context->priv = priv = (RdpsndServerPrivate*)calloc(1, - sizeof(RdpsndServerPrivate)); + context->priv = priv = (RdpsndServerPrivate*)calloc(1, sizeof(RdpsndServerPrivate)); if (!priv) { @@ -858,7 +847,6 @@ out_free: return NULL; } - void rdpsnd_server_context_reset(RdpsndServerContext* context) { context->priv->expectedBytes = 4; @@ -879,6 +867,7 @@ void rdpsnd_server_context_free(RdpsndServerContext* context) if (context->priv->input_stream) Stream_Free(context->priv->input_stream, TRUE); + free(context->server_formats); free(context->client_formats); free(context->priv); free(context); @@ -916,7 +905,7 @@ UINT rdpsnd_server_handle_messages(RdpsndServerContext* context) if (GetLastError() == ERROR_NO_DATA) return ERROR_NO_DATA; - WLog_ERR(TAG, "channel connection closed"); + WLog_ERR(TAG, "channel connection closed"); return ERROR_INTERNAL_ERROR; } @@ -952,7 +941,7 @@ UINT rdpsnd_server_handle_messages(RdpsndServerContext* context) /* when here we have the header + the body */ #ifdef WITH_DEBUG_SND - WLog_DBG(TAG, "message type %"PRIu8"", priv->msgType); + WLog_DBG(TAG, "message type %" PRIu8 "", priv->msgType); #endif priv->expectedBytes = 4; priv->waitingHeader = TRUE; @@ -982,7 +971,7 @@ UINT rdpsnd_server_handle_messages(RdpsndServerContext* context) break; default: - WLog_ERR(TAG, "UNKNOWN MESSAGE TYPE!! (0x%02"PRIX8")", priv->msgType); + WLog_ERR(TAG, "UNKNOWN MESSAGE TYPE!! (0x%02" PRIX8 ")", priv->msgType); ret = ERROR_INVALID_DATA; break; } diff --git a/channels/remdesk/client/remdesk_main.c b/channels/remdesk/client/remdesk_main.c index 9252929..54d9c60 100644 --- a/channels/remdesk/client/remdesk_main.c +++ b/channels/remdesk/client/remdesk_main.c @@ -45,17 +45,19 @@ static UINT remdesk_virtual_channel_write(remdeskPlugin* remdesk, wStream* s) if (!remdesk) { WLog_ERR(TAG, "remdesk was null!"); + Stream_Free(s, TRUE); return CHANNEL_RC_INVALID_INSTANCE; } - status = remdesk->channelEntryPoints.pVirtualChannelWriteEx(remdesk->InitHandle, - remdesk->OpenHandle, - Stream_Buffer(s), (UINT32) Stream_Length(s), s); + status = remdesk->channelEntryPoints.pVirtualChannelWriteEx( + remdesk->InitHandle, remdesk->OpenHandle, Stream_Buffer(s), (UINT32)Stream_Length(s), s); if (status != CHANNEL_RC_OK) - WLog_ERR(TAG, "pVirtualChannelWriteEx failed with %s [%08"PRIX32"]", + { + Stream_Free(s, TRUE); + WLog_ERR(TAG, "pVirtualChannelWriteEx failed with %s [%08" PRIX32 "]", WTSErrorToString(status), status); - + } return status; } @@ -90,8 +92,8 @@ static UINT remdesk_generate_expert_blob(remdeskPlugin* remdesk) if (!name) name = "Expert"; - remdesk->EncryptedPassStub = freerdp_assistance_encrypt_pass_stub(password, - settings->RemoteAssistancePassStub, &(remdesk->EncryptedPassStubSize)); + remdesk->EncryptedPassStub = freerdp_assistance_encrypt_pass_stub( + password, settings->RemoteAssistancePassStub, &(remdesk->EncryptedPassStubSize)); if (!remdesk->EncryptedPassStub) { @@ -100,7 +102,7 @@ static UINT remdesk_generate_expert_blob(remdeskPlugin* remdesk) } pass = freerdp_assistance_bin_to_hex_string(remdesk->EncryptedPassStub, - remdesk->EncryptedPassStubSize); + remdesk->EncryptedPassStubSize); if (!pass) { @@ -125,8 +127,7 @@ static UINT remdesk_generate_expert_blob(remdeskPlugin* remdesk) * * @return 0 on success, otherwise a Win32 error code */ -static UINT remdesk_read_channel_header(wStream* s, - REMDESK_CHANNEL_HEADER* header) +static UINT remdesk_read_channel_header(wStream* s, REMDESK_CHANNEL_HEADER* header) { int status; UINT32 ChannelNameLen; @@ -138,7 +139,7 @@ static UINT remdesk_read_channel_header(wStream* s, return ERROR_INVALID_DATA; } - Stream_Read_UINT32(s, ChannelNameLen); /* ChannelNameLen (4 bytes) */ + Stream_Read_UINT32(s, ChannelNameLen); /* ChannelNameLen (4 bytes) */ Stream_Read_UINT32(s, header->DataLength); /* DataLen (4 bytes) */ if (ChannelNameLen > 64) @@ -160,9 +161,9 @@ static UINT remdesk_read_channel_header(wStream* s, } ZeroMemory(header->ChannelName, sizeof(header->ChannelName)); - pChannelName = (char*) header->ChannelName; - status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), - ChannelNameLen / 2, &pChannelName, 32, NULL, NULL); + pChannelName = (char*)header->ChannelName; + status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*)Stream_Pointer(s), ChannelNameLen / 2, + &pChannelName, 32, NULL, NULL); Stream_Seek(s, ChannelNameLen); if (status <= 0) @@ -179,8 +180,7 @@ static UINT remdesk_read_channel_header(wStream* s, * * @return 0 on success, otherwise a Win32 error code */ -static UINT remdesk_write_channel_header(wStream* s, - REMDESK_CHANNEL_HEADER* header) +static UINT remdesk_write_channel_header(wStream* s, REMDESK_CHANNEL_HEADER* header) { int index; UINT32 ChannelNameLen; @@ -189,12 +189,12 @@ static UINT remdesk_write_channel_header(wStream* s, for (index = 0; index < 32; index++) { - ChannelNameW[index] = (WCHAR) header->ChannelName[index]; + ChannelNameW[index] = (WCHAR)header->ChannelName[index]; } - ChannelNameLen = (strlen(header->ChannelName) + 1) * 2; - Stream_Write_UINT32(s, ChannelNameLen); /* ChannelNameLen (4 bytes) */ - Stream_Write_UINT32(s, header->DataLength); /* DataLen (4 bytes) */ + ChannelNameLen = (strnlen(header->ChannelName, sizeof(header->ChannelName)) + 1) * 2; + Stream_Write_UINT32(s, ChannelNameLen); /* ChannelNameLen (4 bytes) */ + Stream_Write_UINT32(s, header->DataLength); /* DataLen (4 bytes) */ Stream_Write(s, ChannelNameW, ChannelNameLen); /* ChannelName (variable) */ return CHANNEL_RC_OK; } @@ -206,7 +206,7 @@ static UINT remdesk_write_channel_header(wStream* s, */ static UINT remdesk_write_ctl_header(wStream* s, REMDESK_CTL_HEADER* ctlHeader) { - remdesk_write_channel_header(s, (REMDESK_CHANNEL_HEADER*) ctlHeader); + remdesk_write_channel_header(s, (REMDESK_CHANNEL_HEADER*)ctlHeader); Stream_Write_UINT32(s, ctlHeader->msgType); /* msgType (4 bytes) */ return CHANNEL_RC_OK; } @@ -216,8 +216,8 @@ static UINT remdesk_write_ctl_header(wStream* s, REMDESK_CTL_HEADER* ctlHeader) * * @return 0 on success, otherwise a Win32 error code */ -static UINT remdesk_prepare_ctl_header(REMDESK_CTL_HEADER* ctlHeader, - UINT32 msgType, UINT32 msgSize) +static UINT remdesk_prepare_ctl_header(REMDESK_CTL_HEADER* ctlHeader, UINT32 msgType, + UINT32 msgSize) { ctlHeader->msgType = msgType; sprintf_s(ctlHeader->ChannelName, ARRAYSIZE(ctlHeader->ChannelName), REMDESK_CHANNEL_CTL_NAME); @@ -230,8 +230,8 @@ static UINT remdesk_prepare_ctl_header(REMDESK_CTL_HEADER* ctlHeader, * * @return 0 on success, otherwise a Win32 error code */ -static UINT remdesk_recv_ctl_server_announce_pdu(remdeskPlugin* remdesk, - wStream* s, REMDESK_CHANNEL_HEADER* header) +static UINT remdesk_recv_ctl_server_announce_pdu(remdeskPlugin* remdesk, wStream* s, + REMDESK_CHANNEL_HEADER* header) { return CHANNEL_RC_OK; } @@ -241,8 +241,8 @@ static UINT remdesk_recv_ctl_server_announce_pdu(remdeskPlugin* remdesk, * * @return 0 on success, otherwise a Win32 error code */ -static UINT remdesk_recv_ctl_version_info_pdu(remdeskPlugin* remdesk, - wStream* s, REMDESK_CHANNEL_HEADER* header) +static UINT remdesk_recv_ctl_version_info_pdu(remdeskPlugin* remdesk, wStream* s, + REMDESK_CHANNEL_HEADER* header) { UINT32 versionMajor; UINT32 versionMinor; @@ -255,7 +255,14 @@ 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; } @@ -268,7 +275,7 @@ static UINT remdesk_send_ctl_version_info_pdu(remdeskPlugin* remdesk) { wStream* s; REMDESK_CTL_VERSION_INFO_PDU pdu; - UINT error; + UINT error; remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_VERSIONINFO, 8); pdu.versionMajor = 1; pdu.versionMinor = 2; @@ -286,10 +293,7 @@ static UINT remdesk_send_ctl_version_info_pdu(remdeskPlugin* remdesk) Stream_SealLength(s); if ((error = remdesk_virtual_channel_write(remdesk, s))) - WLog_ERR(TAG, "remdesk_virtual_channel_write failed with error %"PRIu32"!", error); - - if (error != CHANNEL_RC_OK) - Stream_Free(s, TRUE); + WLog_ERR(TAG, "remdesk_virtual_channel_write failed with error %" PRIu32 "!", error); return error; } @@ -312,7 +316,7 @@ static UINT remdesk_recv_ctl_result_pdu(remdeskPlugin* remdesk, wStream* s, Stream_Read_UINT32(s, result); /* result (4 bytes) */ *pResult = result; - //WLog_DBG(TAG, "RemdeskRecvResult: 0x%08"PRIX32"", result); + // WLog_DBG(TAG, "RemdeskRecvResult: 0x%08"PRIX32"", result); return CHANNEL_RC_OK; } @@ -334,14 +338,13 @@ static UINT remdesk_send_ctl_authenticate_pdu(remdeskPlugin* remdesk) if ((error = remdesk_generate_expert_blob(remdesk))) { - WLog_ERR(TAG, "remdesk_generate_expert_blob failed with error %"PRIu32"", error); + WLog_ERR(TAG, "remdesk_generate_expert_blob failed with error %" PRIu32 "", error); return error; } pdu.expertBlob = remdesk->ExpertBlob; pdu.raConnectionString = remdesk->settings->RemoteAssistanceRCTicket; - status = ConvertToUnicode(CP_UTF8, 0, pdu.raConnectionString, -1, - &raConnectionStringW, 0); + status = ConvertToUnicode(CP_UTF8, 0, pdu.raConnectionString, -1, &raConnectionStringW, 0); if (status <= 0) { @@ -372,20 +375,17 @@ static UINT remdesk_send_ctl_authenticate_pdu(remdeskPlugin* remdesk) } remdesk_write_ctl_header(s, &(pdu.ctlHeader)); - Stream_Write(s, (BYTE*) raConnectionStringW, cbRaConnectionStringW); - Stream_Write(s, (BYTE*) expertBlobW, cbExpertBlobW); + Stream_Write(s, (BYTE*)raConnectionStringW, cbRaConnectionStringW); + Stream_Write(s, (BYTE*)expertBlobW, cbExpertBlobW); Stream_SealLength(s); if ((error = remdesk_virtual_channel_write(remdesk, s))) - WLog_ERR(TAG, "remdesk_virtual_channel_write failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "remdesk_virtual_channel_write failed with error %" PRIu32 "!", error); out: free(raConnectionStringW); free(expertBlobW); - if (error != CHANNEL_RC_OK) - Stream_Free(s, TRUE); - return error; } @@ -403,8 +403,7 @@ static UINT remdesk_send_ctl_remote_control_desktop_pdu(remdeskPlugin* remdesk) WCHAR* raConnectionStringW = NULL; REMDESK_CTL_REMOTE_CONTROL_DESKTOP_PDU pdu; pdu.raConnectionString = remdesk->settings->RemoteAssistanceRCTicket; - status = ConvertToUnicode(CP_UTF8, 0, pdu.raConnectionString, -1, - &raConnectionStringW, 0); + status = ConvertToUnicode(CP_UTF8, 0, pdu.raConnectionString, -1, &raConnectionStringW, 0); if (status <= 0) { @@ -425,18 +424,15 @@ static UINT remdesk_send_ctl_remote_control_desktop_pdu(remdeskPlugin* remdesk) } remdesk_write_ctl_header(s, &(pdu.ctlHeader)); - Stream_Write(s, (BYTE*) raConnectionStringW, cbRaConnectionStringW); + Stream_Write(s, (BYTE*)raConnectionStringW, cbRaConnectionStringW); Stream_SealLength(s); if ((error = remdesk_virtual_channel_write(remdesk, s))) - WLog_ERR(TAG, "remdesk_virtual_channel_write failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "remdesk_virtual_channel_write failed with error %" PRIu32 "!", error); out: free(raConnectionStringW); - if (error != CHANNEL_RC_OK) - Stream_Free(s, TRUE); - return error; } @@ -456,7 +452,7 @@ static UINT remdesk_send_ctl_verify_password_pdu(remdeskPlugin* remdesk) if ((error = remdesk_generate_expert_blob(remdesk))) { - WLog_ERR(TAG, "remdesk_generate_expert_blob failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "remdesk_generate_expert_blob failed with error %" PRIu32 "!", error); return error; } @@ -470,8 +466,7 @@ static UINT remdesk_send_ctl_verify_password_pdu(remdeskPlugin* remdesk) } cbExpertBlobW = status * 2; - remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_VERIFY_PASSWORD, - cbExpertBlobW); + remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_VERIFY_PASSWORD, cbExpertBlobW); s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.DataLength); if (!s) @@ -482,18 +477,15 @@ static UINT remdesk_send_ctl_verify_password_pdu(remdeskPlugin* remdesk) } remdesk_write_ctl_header(s, &(pdu.ctlHeader)); - Stream_Write(s, (BYTE*) expertBlobW, cbExpertBlobW); + Stream_Write(s, (BYTE*)expertBlobW, cbExpertBlobW); Stream_SealLength(s); if ((error = remdesk_virtual_channel_write(remdesk, s))) - WLog_ERR(TAG, "remdesk_virtual_channel_write failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "remdesk_virtual_channel_write failed with error %" PRIu32 "!", error); out: free(expertBlobW); - if (error != CHANNEL_RC_OK) - Stream_Free(s, TRUE); - return error; } @@ -510,7 +502,7 @@ static UINT remdesk_send_ctl_expert_on_vista_pdu(remdeskPlugin* remdesk) if ((error = remdesk_generate_expert_blob(remdesk))) { - WLog_ERR(TAG, "remdesk_generate_expert_blob failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "remdesk_generate_expert_blob failed with error %" PRIu32 "!", error); return error; } @@ -537,8 +529,7 @@ static UINT remdesk_send_ctl_expert_on_vista_pdu(remdeskPlugin* remdesk) * * @return 0 on success, otherwise a Win32 error code */ -static UINT remdesk_recv_ctl_pdu(remdeskPlugin* remdesk, wStream* s, - REMDESK_CHANNEL_HEADER* header) +static UINT remdesk_recv_ctl_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEADER* header) { UINT error = CHANNEL_RC_OK; UINT32 msgType = 0; @@ -552,7 +543,7 @@ static UINT remdesk_recv_ctl_pdu(remdeskPlugin* remdesk, wStream* s, Stream_Read_UINT32(s, msgType); /* msgType (4 bytes) */ - //WLog_DBG(TAG, "msgType: %"PRIu32"", msgType); + // WLog_DBG(TAG, "msgType: %"PRIu32"", msgType); switch (msgType) { @@ -561,7 +552,7 @@ static UINT remdesk_recv_ctl_pdu(remdeskPlugin* remdesk, wStream* s, case REMDESK_CTL_RESULT: if ((error = remdesk_recv_ctl_result_pdu(remdesk, s, header, &result))) - WLog_ERR(TAG, "remdesk_recv_ctl_result_pdu failed with error %"PRIu32"", error); + WLog_ERR(TAG, "remdesk_recv_ctl_result_pdu failed with error %" PRIu32 "", error); break; @@ -570,7 +561,7 @@ static UINT remdesk_recv_ctl_pdu(remdeskPlugin* remdesk, wStream* s, case REMDESK_CTL_SERVER_ANNOUNCE: if ((error = remdesk_recv_ctl_server_announce_pdu(remdesk, s, header))) - WLog_ERR(TAG, "remdesk_recv_ctl_server_announce_pdu failed with error %"PRIu32"", + WLog_ERR(TAG, "remdesk_recv_ctl_server_announce_pdu failed with error %" PRIu32 "", error); break; @@ -581,7 +572,8 @@ static UINT remdesk_recv_ctl_pdu(remdeskPlugin* remdesk, wStream* s, case REMDESK_CTL_VERSIONINFO: if ((error = remdesk_recv_ctl_version_info_pdu(remdesk, s, header))) { - WLog_ERR(TAG, "remdesk_recv_ctl_version_info_pdu failed with error %"PRIu32"", error); + WLog_ERR(TAG, "remdesk_recv_ctl_version_info_pdu failed with error %" PRIu32 "", + error); break; } @@ -589,20 +581,24 @@ static UINT remdesk_recv_ctl_pdu(remdeskPlugin* remdesk, wStream* s, { if ((error = remdesk_send_ctl_version_info_pdu(remdesk))) { - WLog_ERR(TAG, "remdesk_send_ctl_version_info_pdu failed with error %"PRIu32"", error); + WLog_ERR(TAG, "remdesk_send_ctl_version_info_pdu failed with error %" PRIu32 "", + error); break; } if ((error = remdesk_send_ctl_authenticate_pdu(remdesk))) { - WLog_ERR(TAG, "remdesk_send_ctl_authenticate_pdu failed with error %"PRIu32"", error); + WLog_ERR(TAG, "remdesk_send_ctl_authenticate_pdu failed with error %" PRIu32 "", + error); break; } if ((error = remdesk_send_ctl_remote_control_desktop_pdu(remdesk))) { - WLog_ERR(TAG, - "remdesk_send_ctl_remote_control_desktop_pdu failed with error %"PRIu32"", error); + WLog_ERR( + TAG, + "remdesk_send_ctl_remote_control_desktop_pdu failed with error %" PRIu32 "", + error); break; } } @@ -610,14 +606,16 @@ static UINT remdesk_recv_ctl_pdu(remdeskPlugin* remdesk, wStream* s, { if ((error = remdesk_send_ctl_expert_on_vista_pdu(remdesk))) { - WLog_ERR(TAG, "remdesk_send_ctl_expert_on_vista_pdu failed with error %"PRIu32"", + WLog_ERR(TAG, + "remdesk_send_ctl_expert_on_vista_pdu failed with error %" PRIu32 "", error); break; } if ((error = remdesk_send_ctl_verify_password_pdu(remdesk))) { - WLog_ERR(TAG, "remdesk_send_ctl_verify_password_pdu failed with error %"PRIu32"", + WLog_ERR(TAG, + "remdesk_send_ctl_verify_password_pdu failed with error %" PRIu32 "", error); break; } @@ -644,7 +642,7 @@ static UINT remdesk_recv_ctl_pdu(remdeskPlugin* remdesk, wStream* s, break; default: - WLog_ERR(TAG, "unknown msgType: %"PRIu32"", msgType); + WLog_ERR(TAG, "unknown msgType: %" PRIu32 "", msgType); error = ERROR_INVALID_DATA; break; } @@ -668,7 +666,7 @@ static UINT remdesk_process_receive(remdeskPlugin* remdesk, wStream* s) if ((status = remdesk_read_channel_header(s, &header))) { - WLog_ERR(TAG, "remdesk_read_channel_header failed with error %"PRIu32"", status); + WLog_ERR(TAG, "remdesk_read_channel_header failed with error %" PRIu32 "", status); return status; } @@ -700,17 +698,17 @@ static UINT remdesk_process_receive(remdeskPlugin* remdesk, wStream* s) static void remdesk_process_connect(remdeskPlugin* remdesk) { - remdesk->settings = (rdpSettings*) remdesk->channelEntryPoints.pExtendedData; + remdesk->settings = (rdpSettings*)remdesk->channelEntryPoints.pExtendedData; } - /** * Function description * * @return 0 on success, otherwise a Win32 error code */ -static UINT remdesk_virtual_channel_event_data_received(remdeskPlugin* remdesk, - void* pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) +static UINT remdesk_virtual_channel_event_data_received(remdeskPlugin* remdesk, const void* pData, + UINT32 dataLength, UINT32 totalLength, + UINT32 dataFlags) { wStream* data_in; @@ -735,7 +733,7 @@ static UINT remdesk_virtual_channel_event_data_received(remdeskPlugin* remdesk, data_in = remdesk->data_in; - if (!Stream_EnsureRemainingCapacity(data_in, (int) dataLength)) + if (!Stream_EnsureRemainingCapacity(data_in, dataLength)) { WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); return CHANNEL_RC_NO_MEMORY; @@ -747,7 +745,7 @@ static UINT remdesk_virtual_channel_event_data_received(remdeskPlugin* remdesk, { if (Stream_Capacity(data_in) != Stream_GetPosition(data_in)) { - WLog_ERR(TAG, "read error"); + WLog_ERR(TAG, "read error"); return ERROR_INTERNAL_ERROR; } @@ -755,7 +753,7 @@ static UINT remdesk_virtual_channel_event_data_received(remdeskPlugin* remdesk, Stream_SealLength(data_in); Stream_SetPosition(data_in, 0); - if (!MessageQueue_Post(remdesk->queue, NULL, 0, (void*) data_in, NULL)) + if (!MessageQueue_Post(remdesk->queue, NULL, 0, (void*)data_in, NULL)) { WLog_ERR(TAG, "MessageQueue_Post failed!"); return ERROR_INTERNAL_ERROR; @@ -766,40 +764,47 @@ static UINT remdesk_virtual_channel_event_data_received(remdeskPlugin* remdesk, } static VOID VCAPITYPE remdesk_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle, - UINT event, - LPVOID pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) + UINT event, LPVOID pData, + UINT32 dataLength, UINT32 totalLength, + UINT32 dataFlags) { UINT error = CHANNEL_RC_OK; - remdeskPlugin* remdesk = (remdeskPlugin*) lpUserParam; - - if (!remdesk || (remdesk->OpenHandle != openHandle)) - { - WLog_ERR(TAG, "error no match"); - return; - } + remdeskPlugin* remdesk = (remdeskPlugin*)lpUserParam; switch (event) { case CHANNEL_EVENT_DATA_RECEIVED: - if ((error = remdesk_virtual_channel_event_data_received(remdesk, pData, - dataLength, totalLength, dataFlags))) + if (!remdesk || (remdesk->OpenHandle != openHandle)) + { + WLog_ERR(TAG, "error no match"); + return; + } + if ((error = remdesk_virtual_channel_event_data_received(remdesk, pData, dataLength, + totalLength, dataFlags))) WLog_ERR(TAG, - "remdesk_virtual_channel_event_data_received failed with error %"PRIu32"!", error); + "remdesk_virtual_channel_event_data_received failed with error %" PRIu32 + "!", + error); break; + case CHANNEL_EVENT_WRITE_CANCELLED: case CHANNEL_EVENT_WRITE_COMPLETE: - break; + { + wStream* s = (wStream*)pData; + Stream_Free(s, TRUE); + } + break; case CHANNEL_EVENT_USER: break; default: - WLog_ERR(TAG, "unhandled event %"PRIu32"!", event); + WLog_ERR(TAG, "unhandled event %" PRIu32 "!", event); error = ERROR_INTERNAL_ERROR; } - if (error && remdesk->rdpcontext) + if (error && remdesk && remdesk->rdpcontext) setChannelError(remdesk->rdpcontext, error, "remdesk_virtual_channel_open_event_ex reported an error"); } @@ -808,7 +813,7 @@ static DWORD WINAPI remdesk_virtual_channel_client_thread(LPVOID arg) { wStream* data; wMessage message; - remdeskPlugin* remdesk = (remdeskPlugin*) arg; + remdeskPlugin* remdesk = (remdeskPlugin*)arg; UINT error = CHANNEL_RC_OK; remdesk_process_connect(remdesk); @@ -833,13 +838,16 @@ static DWORD WINAPI remdesk_virtual_channel_client_thread(LPVOID arg) if (message.id == 0) { - data = (wStream*) message.wParam; + data = (wStream*)message.wParam; if ((error = remdesk_process_receive(remdesk, data))) { - WLog_ERR(TAG, "remdesk_process_receive failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "remdesk_process_receive failed with error %" PRIu32 "!", error); + Stream_Free(data, TRUE); break; } + + Stream_Free(data, TRUE); } } @@ -856,18 +864,18 @@ static DWORD WINAPI remdesk_virtual_channel_client_thread(LPVOID arg) * * @return 0 on success, otherwise a Win32 error code */ -static UINT remdesk_virtual_channel_event_connected(remdeskPlugin* remdesk, - LPVOID pData, UINT32 dataLength) +static UINT remdesk_virtual_channel_event_connected(remdeskPlugin* remdesk, LPVOID pData, + UINT32 dataLength) { UINT32 status; UINT error; - status = remdesk->channelEntryPoints.pVirtualChannelOpenEx(remdesk->InitHandle, - &remdesk->OpenHandle, remdesk->channelDef.name, - remdesk_virtual_channel_open_event_ex); + status = remdesk->channelEntryPoints.pVirtualChannelOpenEx( + remdesk->InitHandle, &remdesk->OpenHandle, remdesk->channelDef.name, + remdesk_virtual_channel_open_event_ex); if (status != CHANNEL_RC_OK) { - WLog_ERR(TAG, "pVirtualChannelOpenEx failed with %s [%08"PRIX32"]", + WLog_ERR(TAG, "pVirtualChannelOpenEx failed with %s [%08" PRIX32 "]", WTSErrorToString(status), status); return status; } @@ -881,9 +889,8 @@ static UINT remdesk_virtual_channel_event_connected(remdeskPlugin* remdesk, goto error_out; } - remdesk->thread = CreateThread(NULL, 0, - remdesk_virtual_channel_client_thread, (void*) remdesk, - 0, NULL); + remdesk->thread = + CreateThread(NULL, 0, remdesk_virtual_channel_client_thread, (void*)remdesk, 0, NULL); if (!remdesk->thread) { @@ -911,11 +918,11 @@ static UINT remdesk_virtual_channel_event_disconnected(remdeskPlugin* remdesk) if (remdesk->OpenHandle == 0) return CHANNEL_RC_OK; - if (MessageQueue_PostQuit(remdesk->queue, 0) - && (WaitForSingleObject(remdesk->thread, INFINITE) == WAIT_FAILED)) + if (MessageQueue_PostQuit(remdesk->queue, 0) && + (WaitForSingleObject(remdesk->thread, INFINITE) == WAIT_FAILED)) { rc = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", rc); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", rc); return rc; } @@ -923,12 +930,13 @@ static UINT remdesk_virtual_channel_event_disconnected(remdeskPlugin* remdesk) CloseHandle(remdesk->thread); remdesk->queue = NULL; remdesk->thread = NULL; - rc = remdesk->channelEntryPoints.pVirtualChannelCloseEx(remdesk->InitHandle, remdesk->OpenHandle); + rc = remdesk->channelEntryPoints.pVirtualChannelCloseEx(remdesk->InitHandle, + remdesk->OpenHandle); if (CHANNEL_RC_OK != rc) { - WLog_ERR(TAG, "pVirtualChannelCloseEx failed with %s [%08"PRIX32"]", - WTSErrorToString(rc), rc); + WLog_ERR(TAG, "pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]", WTSErrorToString(rc), + rc); } remdesk->OpenHandle = 0; @@ -950,24 +958,24 @@ static void remdesk_virtual_channel_event_terminated(remdeskPlugin* remdesk) } static VOID VCAPITYPE remdesk_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle, - UINT event, LPVOID pData, - UINT dataLength) + UINT event, LPVOID pData, + UINT dataLength) { UINT error = CHANNEL_RC_OK; - remdeskPlugin* remdesk = (remdeskPlugin*) lpUserParam; + remdeskPlugin* remdesk = (remdeskPlugin*)lpUserParam; if (!remdesk || (remdesk->InitHandle != pInitHandle)) { - WLog_ERR(TAG, "error no match"); + WLog_ERR(TAG, "error no match"); return; } switch (event) { case CHANNEL_EVENT_CONNECTED: - if ((error = remdesk_virtual_channel_event_connected(remdesk, pData, - dataLength))) - WLog_ERR(TAG, "remdesk_virtual_channel_event_connected failed with error %"PRIu32"", + if ((error = remdesk_virtual_channel_event_connected(remdesk, pData, dataLength))) + WLog_ERR(TAG, + "remdesk_virtual_channel_event_connected failed with error %" PRIu32 "", error); break; @@ -975,7 +983,8 @@ static VOID VCAPITYPE remdesk_virtual_channel_init_event_ex(LPVOID lpUserParam, case CHANNEL_EVENT_DISCONNECTED: if ((error = remdesk_virtual_channel_event_disconnected(remdesk))) WLog_ERR(TAG, - "remdesk_virtual_channel_event_disconnected failed with error %"PRIu32"", error); + "remdesk_virtual_channel_event_disconnected failed with error %" PRIu32 "", + error); break; @@ -995,7 +1004,7 @@ static VOID VCAPITYPE remdesk_virtual_channel_init_event_ex(LPVOID lpUserParam, } /* remdesk is always built-in */ -#define VirtualChannelEntryEx remdesk_VirtualChannelEntryEx +#define VirtualChannelEntryEx remdesk_VirtualChannelEntryEx BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID pInitHandle) { @@ -1009,7 +1018,7 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p return FALSE; } - remdesk = (remdeskPlugin*) calloc(1, sizeof(remdeskPlugin)); + remdesk = (remdeskPlugin*)calloc(1, sizeof(remdeskPlugin)); if (!remdesk) { @@ -1017,19 +1026,16 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p return FALSE; } - remdesk->channelDef.options = - CHANNEL_OPTION_INITIALIZED | - CHANNEL_OPTION_ENCRYPT_RDP | - CHANNEL_OPTION_COMPRESS_RDP | - CHANNEL_OPTION_SHOW_PROTOCOL; + remdesk->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP | + CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL; sprintf_s(remdesk->channelDef.name, ARRAYSIZE(remdesk->channelDef.name), "remdesk"); remdesk->Version = 2; - pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*) pEntryPoints; + pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints; if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) && (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER)) { - context = (RemdeskClientContext*) calloc(1, sizeof(RemdeskClientContext)); + context = (RemdeskClientContext*)calloc(1, sizeof(RemdeskClientContext)); if (!context) { @@ -1037,7 +1043,7 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p goto error_out; } - context->handle = (void*) remdesk; + context->handle = (void*)remdesk; remdesk->context = context; remdesk->rdpcontext = pEntryPointsEx->context; } @@ -1045,14 +1051,14 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p CopyMemory(&(remdesk->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)); remdesk->InitHandle = pInitHandle; - rc = remdesk->channelEntryPoints.pVirtualChannelInitEx(remdesk, context, pInitHandle, - &remdesk->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, - remdesk_virtual_channel_init_event_ex); + rc = remdesk->channelEntryPoints.pVirtualChannelInitEx( + remdesk, context, pInitHandle, &remdesk->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, + remdesk_virtual_channel_init_event_ex); if (CHANNEL_RC_OK != rc) { - WLog_ERR(TAG, "pVirtualChannelInitEx failed with %s [%08"PRIX32"]", - WTSErrorToString(rc), rc); + WLog_ERR(TAG, "pVirtualChannelInitEx failed with %s [%08" PRIX32 "]", WTSErrorToString(rc), + rc); goto error_out; } 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/remdesk/server/remdesk_main.c b/channels/remdesk/server/remdesk_main.c index 447ede4..aeaa332 100644 --- a/channels/remdesk/server/remdesk_main.c +++ b/channels/remdesk/server/remdesk_main.c @@ -34,13 +34,12 @@ * * @return 0 on success, otherwise a Win32 error code */ -static UINT remdesk_virtual_channel_write(RemdeskServerContext* context, - wStream* s) +static UINT remdesk_virtual_channel_write(RemdeskServerContext* context, wStream* s) { BOOL status; ULONG BytesWritten = 0; - status = WTSVirtualChannelWrite(context->priv->ChannelHandle, - (PCHAR) Stream_Buffer(s), Stream_Length(s), &BytesWritten); + status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR)Stream_Buffer(s), + Stream_Length(s), &BytesWritten); return (status) ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; } @@ -49,8 +48,7 @@ static UINT remdesk_virtual_channel_write(RemdeskServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT remdesk_read_channel_header(wStream* s, - REMDESK_CHANNEL_HEADER* header) +static UINT remdesk_read_channel_header(wStream* s, REMDESK_CHANNEL_HEADER* header) { int status; UINT32 ChannelNameLen; @@ -62,7 +60,7 @@ static UINT remdesk_read_channel_header(wStream* s, return CHANNEL_RC_NO_MEMORY; } - Stream_Read_UINT32(s, ChannelNameLen); /* ChannelNameLen (4 bytes) */ + Stream_Read_UINT32(s, ChannelNameLen); /* ChannelNameLen (4 bytes) */ Stream_Read_UINT32(s, header->DataLength); /* DataLen (4 bytes) */ if (ChannelNameLen > 64) @@ -84,9 +82,9 @@ static UINT remdesk_read_channel_header(wStream* s, } ZeroMemory(header->ChannelName, sizeof(header->ChannelName)); - pChannelName = (char*) header->ChannelName; - status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), - ChannelNameLen / 2, &pChannelName, 32, NULL, NULL); + pChannelName = (char*)header->ChannelName; + status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*)Stream_Pointer(s), ChannelNameLen / 2, + &pChannelName, 32, NULL, NULL); Stream_Seek(s, ChannelNameLen); if (status <= 0) @@ -103,8 +101,7 @@ static UINT remdesk_read_channel_header(wStream* s, * * @return 0 on success, otherwise a Win32 error code */ -static UINT remdesk_write_channel_header(wStream* s, - REMDESK_CHANNEL_HEADER* header) +static UINT remdesk_write_channel_header(wStream* s, REMDESK_CHANNEL_HEADER* header) { int index; UINT32 ChannelNameLen; @@ -113,12 +110,12 @@ static UINT remdesk_write_channel_header(wStream* s, for (index = 0; index < 32; index++) { - ChannelNameW[index] = (WCHAR) header->ChannelName[index]; + ChannelNameW[index] = (WCHAR)header->ChannelName[index]; } - ChannelNameLen = (strlen(header->ChannelName) + 1) * 2; - Stream_Write_UINT32(s, ChannelNameLen); /* ChannelNameLen (4 bytes) */ - Stream_Write_UINT32(s, header->DataLength); /* DataLen (4 bytes) */ + ChannelNameLen = (strnlen(header->ChannelName, sizeof(header->ChannelName)) + 1) * 2; + Stream_Write_UINT32(s, ChannelNameLen); /* ChannelNameLen (4 bytes) */ + Stream_Write_UINT32(s, header->DataLength); /* DataLen (4 bytes) */ Stream_Write(s, ChannelNameW, ChannelNameLen); /* ChannelName (variable) */ return CHANNEL_RC_OK; } @@ -132,10 +129,9 @@ static UINT remdesk_write_ctl_header(wStream* s, REMDESK_CTL_HEADER* ctlHeader) { UINT error; - if ((error = remdesk_write_channel_header(s, - (REMDESK_CHANNEL_HEADER*) ctlHeader))) + if ((error = remdesk_write_channel_header(s, (REMDESK_CHANNEL_HEADER*)ctlHeader))) { - WLog_ERR(TAG, "remdesk_write_channel_header failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "remdesk_write_channel_header failed with error %" PRIu32 "!", error); return error; } @@ -148,8 +144,8 @@ static UINT remdesk_write_ctl_header(wStream* s, REMDESK_CTL_HEADER* ctlHeader) * * @return 0 on success, otherwise a Win32 error code */ -static UINT remdesk_prepare_ctl_header(REMDESK_CTL_HEADER* ctlHeader, - UINT32 msgType, UINT32 msgSize) +static UINT remdesk_prepare_ctl_header(REMDESK_CTL_HEADER* ctlHeader, UINT32 msgType, + UINT32 msgSize) { ctlHeader->msgType = msgType; sprintf_s(ctlHeader->ChannelName, ARRAYSIZE(ctlHeader->ChannelName), REMDESK_CHANNEL_CTL_NAME); @@ -162,18 +158,16 @@ static UINT remdesk_prepare_ctl_header(REMDESK_CTL_HEADER* ctlHeader, * * @return 0 on success, otherwise a Win32 error code */ -static UINT remdesk_send_ctl_result_pdu(RemdeskServerContext* context, - UINT32 result) +static UINT remdesk_send_ctl_result_pdu(RemdeskServerContext* context, UINT32 result) { wStream* s; REMDESK_CTL_RESULT_PDU pdu; UINT error; pdu.result = result; - if ((error = remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_RESULT, - 4))) + if ((error = remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_RESULT, 4))) { - WLog_ERR(TAG, "remdesk_prepare_ctl_header failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "remdesk_prepare_ctl_header failed with error %" PRIu32 "!", error); return error; } @@ -187,7 +181,7 @@ static UINT remdesk_send_ctl_result_pdu(RemdeskServerContext* context, if ((error = remdesk_write_ctl_header(s, &(pdu.ctlHeader)))) { - WLog_ERR(TAG, "remdesk_write_ctl_header failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "remdesk_write_ctl_header failed with error %" PRIu32 "!", error); goto out; } @@ -195,7 +189,7 @@ static UINT remdesk_send_ctl_result_pdu(RemdeskServerContext* context, Stream_SealLength(s); if ((error = remdesk_virtual_channel_write(context, s))) - WLog_ERR(TAG, "remdesk_virtual_channel_write failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "remdesk_virtual_channel_write failed with error %" PRIu32 "!", error); out: Stream_Free(s, TRUE); @@ -213,10 +207,9 @@ static UINT remdesk_send_ctl_version_info_pdu(RemdeskServerContext* context) REMDESK_CTL_VERSION_INFO_PDU pdu; UINT error; - if ((error = remdesk_prepare_ctl_header(&(pdu.ctlHeader), - REMDESK_CTL_VERSIONINFO, 8))) + if ((error = remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_VERSIONINFO, 8))) { - WLog_ERR(TAG, "remdesk_prepare_ctl_header failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "remdesk_prepare_ctl_header failed with error %" PRIu32 "!", error); return error; } @@ -232,7 +225,7 @@ static UINT remdesk_send_ctl_version_info_pdu(RemdeskServerContext* context) if ((error = remdesk_write_ctl_header(s, &(pdu.ctlHeader)))) { - WLog_ERR(TAG, "remdesk_write_ctl_header failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "remdesk_write_ctl_header failed with error %" PRIu32 "!", error); goto out; } @@ -241,7 +234,7 @@ static UINT remdesk_send_ctl_version_info_pdu(RemdeskServerContext* context) Stream_SealLength(s); if ((error = remdesk_virtual_channel_write(context, s))) - WLog_ERR(TAG, "remdesk_virtual_channel_write failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "remdesk_virtual_channel_write failed with error %" PRIu32 "!", error); out: Stream_Free(s, TRUE); @@ -253,8 +246,8 @@ out: * * @return 0 on success, otherwise a Win32 error code */ -static UINT remdesk_recv_ctl_version_info_pdu(RemdeskServerContext* context, - wStream* s, REMDESK_CHANNEL_HEADER* header) +static UINT remdesk_recv_ctl_version_info_pdu(RemdeskServerContext* context, wStream* s, + REMDESK_CHANNEL_HEADER* header) { UINT32 versionMajor; UINT32 versionMinor; @@ -275,8 +268,8 @@ static UINT remdesk_recv_ctl_version_info_pdu(RemdeskServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT remdesk_recv_ctl_remote_control_desktop_pdu( - RemdeskServerContext* context, wStream* s, REMDESK_CHANNEL_HEADER* header) +static UINT remdesk_recv_ctl_remote_control_desktop_pdu(RemdeskServerContext* context, wStream* s, + REMDESK_CHANNEL_HEADER* header) { int status; int cchStringW; @@ -287,7 +280,7 @@ static UINT remdesk_recv_ctl_remote_control_desktop_pdu( REMDESK_CTL_REMOTE_CONTROL_DESKTOP_PDU pdu; UINT error; msgLength = header->DataLength - 4; - pStringW = (WCHAR*) Stream_Pointer(s); + pStringW = (WCHAR*)Stream_Pointer(s); raConnectionStringW = pStringW; cchStringW = 0; @@ -303,8 +296,8 @@ static UINT remdesk_recv_ctl_remote_control_desktop_pdu( cchStringW++; cbRaConnectionStringW = cchStringW * 2; pdu.raConnectionString = NULL; - status = ConvertFromUnicode(CP_UTF8, 0, raConnectionStringW, - cbRaConnectionStringW / 2, &pdu.raConnectionString, 0, NULL, NULL); + status = ConvertFromUnicode(CP_UTF8, 0, raConnectionStringW, cbRaConnectionStringW / 2, + &pdu.raConnectionString, 0, NULL, NULL); if (status <= 0) { @@ -312,12 +305,11 @@ static UINT remdesk_recv_ctl_remote_control_desktop_pdu( return ERROR_INTERNAL_ERROR; } - WLog_INFO(TAG, "RaConnectionString: %s", - pdu.raConnectionString); + WLog_INFO(TAG, "RaConnectionString: %s", pdu.raConnectionString); free(pdu.raConnectionString); if ((error = remdesk_send_ctl_result_pdu(context, 0))) - WLog_ERR(TAG, "remdesk_send_ctl_result_pdu failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "remdesk_send_ctl_result_pdu failed with error %" PRIu32 "!", error); return error; } @@ -327,8 +319,8 @@ static UINT remdesk_recv_ctl_remote_control_desktop_pdu( * * @return 0 on success, otherwise a Win32 error code */ -static UINT remdesk_recv_ctl_authenticate_pdu(RemdeskServerContext* context, - wStream* s, REMDESK_CHANNEL_HEADER* header) +static UINT remdesk_recv_ctl_authenticate_pdu(RemdeskServerContext* context, wStream* s, + REMDESK_CHANNEL_HEADER* header) { int status; int cchStringW; @@ -340,7 +332,7 @@ static UINT remdesk_recv_ctl_authenticate_pdu(RemdeskServerContext* context, WCHAR* raConnectionStringW = NULL; REMDESK_CTL_AUTHENTICATE_PDU pdu; msgLength = header->DataLength - 4; - pStringW = (WCHAR*) Stream_Pointer(s); + pStringW = (WCHAR*)Stream_Pointer(s); raConnectionStringW = pStringW; cchStringW = 0; @@ -371,8 +363,8 @@ static UINT remdesk_recv_ctl_authenticate_pdu(RemdeskServerContext* context, cchStringW++; cbExpertBlobW = cchStringW * 2; pdu.raConnectionString = NULL; - status = ConvertFromUnicode(CP_UTF8, 0, raConnectionStringW, - cbRaConnectionStringW / 2, &pdu.raConnectionString, 0, NULL, NULL); + status = ConvertFromUnicode(CP_UTF8, 0, raConnectionStringW, cbRaConnectionStringW / 2, + &pdu.raConnectionString, 0, NULL, NULL); if (status <= 0) { @@ -381,8 +373,8 @@ static UINT remdesk_recv_ctl_authenticate_pdu(RemdeskServerContext* context, } pdu.expertBlob = NULL; - status = ConvertFromUnicode(CP_UTF8, 0, expertBlobW, - cbExpertBlobW / 2, &pdu.expertBlob, 0, NULL, NULL); + status = ConvertFromUnicode(CP_UTF8, 0, expertBlobW, cbExpertBlobW / 2, &pdu.expertBlob, 0, + NULL, NULL); if (status <= 0) { @@ -391,8 +383,7 @@ static UINT remdesk_recv_ctl_authenticate_pdu(RemdeskServerContext* context, return ERROR_INTERNAL_ERROR; } - WLog_INFO(TAG, "RaConnectionString: %s ExpertBlob: %s", - pdu.raConnectionString, pdu.expertBlob); + WLog_INFO(TAG, "RaConnectionString: %s ExpertBlob: %s", pdu.raConnectionString, pdu.expertBlob); free(pdu.raConnectionString); free(pdu.expertBlob); return CHANNEL_RC_OK; @@ -403,8 +394,8 @@ static UINT remdesk_recv_ctl_authenticate_pdu(RemdeskServerContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT remdesk_recv_ctl_verify_password_pdu(RemdeskServerContext* context, - wStream* s, REMDESK_CHANNEL_HEADER* header) +static UINT remdesk_recv_ctl_verify_password_pdu(RemdeskServerContext* context, wStream* s, + REMDESK_CHANNEL_HEADER* header) { int status; int cbExpertBlobW = 0; @@ -419,10 +410,10 @@ static UINT remdesk_recv_ctl_verify_password_pdu(RemdeskServerContext* context, } pdu.expertBlob = NULL; - expertBlobW = (WCHAR*) Stream_Pointer(s); + expertBlobW = (WCHAR*)Stream_Pointer(s); cbExpertBlobW = header->DataLength - 4; - status = ConvertFromUnicode(CP_UTF8, 0, expertBlobW, cbExpertBlobW / 2, - &pdu.expertBlob, 0, NULL, NULL); + status = ConvertFromUnicode(CP_UTF8, 0, expertBlobW, cbExpertBlobW / 2, &pdu.expertBlob, 0, + NULL, NULL); if (status <= 0) { @@ -433,7 +424,7 @@ static UINT remdesk_recv_ctl_verify_password_pdu(RemdeskServerContext* context, WLog_INFO(TAG, "ExpertBlob: %s", pdu.expertBlob); if ((error = remdesk_send_ctl_result_pdu(context, 0))) - WLog_ERR(TAG, "remdesk_send_ctl_result_pdu failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "remdesk_send_ctl_result_pdu failed with error %" PRIu32 "!", error); return error; } @@ -456,7 +447,7 @@ static UINT remdesk_recv_ctl_pdu(RemdeskServerContext* context, wStream* s, } Stream_Read_UINT32(s, msgType); /* msgType (4 bytes) */ - WLog_INFO(TAG, "msgType: %"PRIu32"", msgType); + WLog_INFO(TAG, "msgType: %" PRIu32 "", msgType); switch (msgType) { @@ -464,7 +455,9 @@ static UINT remdesk_recv_ctl_pdu(RemdeskServerContext* context, wStream* s, if ((error = remdesk_recv_ctl_remote_control_desktop_pdu(context, s, header))) { WLog_ERR(TAG, - "remdesk_recv_ctl_remote_control_desktop_pdu failed with error %"PRIu32"!", error); + "remdesk_recv_ctl_remote_control_desktop_pdu failed with error %" PRIu32 + "!", + error); return error; } @@ -473,7 +466,7 @@ static UINT remdesk_recv_ctl_pdu(RemdeskServerContext* context, wStream* s, case REMDESK_CTL_AUTHENTICATE: if ((error = remdesk_recv_ctl_authenticate_pdu(context, s, header))) { - WLog_ERR(TAG, "remdesk_recv_ctl_authenticate_pdu failed with error %"PRIu32"!", + WLog_ERR(TAG, "remdesk_recv_ctl_authenticate_pdu failed with error %" PRIu32 "!", error); return error; } @@ -486,7 +479,7 @@ static UINT remdesk_recv_ctl_pdu(RemdeskServerContext* context, wStream* s, case REMDESK_CTL_VERSIONINFO: if ((error = remdesk_recv_ctl_version_info_pdu(context, s, header))) { - WLog_ERR(TAG, "remdesk_recv_ctl_version_info_pdu failed with error %"PRIu32"!", + WLog_ERR(TAG, "remdesk_recv_ctl_version_info_pdu failed with error %" PRIu32 "!", error); return error; } @@ -499,7 +492,7 @@ static UINT remdesk_recv_ctl_pdu(RemdeskServerContext* context, wStream* s, case REMDESK_CTL_VERIFY_PASSWORD: if ((error = remdesk_recv_ctl_verify_password_pdu(context, s, header))) { - WLog_ERR(TAG, "remdesk_recv_ctl_verify_password_pdu failed with error %"PRIu32"!", + WLog_ERR(TAG, "remdesk_recv_ctl_verify_password_pdu failed with error %" PRIu32 "!", error); return error; } @@ -519,7 +512,7 @@ static UINT remdesk_recv_ctl_pdu(RemdeskServerContext* context, wStream* s, break; default: - WLog_ERR(TAG, "remdesk_recv_control_pdu: unknown msgType: %"PRIu32"", msgType); + WLog_ERR(TAG, "remdesk_recv_control_pdu: unknown msgType: %" PRIu32 "", msgType); error = ERROR_INVALID_DATA; break; } @@ -532,8 +525,7 @@ static UINT remdesk_recv_ctl_pdu(RemdeskServerContext* context, wStream* s, * * @return 0 on success, otherwise a Win32 error code */ -static UINT remdesk_server_receive_pdu(RemdeskServerContext* context, - wStream* s) +static UINT remdesk_server_receive_pdu(RemdeskServerContext* context, wStream* s) { UINT error = CHANNEL_RC_OK; REMDESK_CHANNEL_HEADER header; @@ -544,7 +536,7 @@ static UINT remdesk_server_receive_pdu(RemdeskServerContext* context, if ((error = remdesk_read_channel_header(s, &header))) { - WLog_ERR(TAG, "remdesk_read_channel_header failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "remdesk_read_channel_header failed with error %" PRIu32 "!", error); return error; } @@ -552,7 +544,7 @@ static UINT remdesk_server_receive_pdu(RemdeskServerContext* context, { if ((error = remdesk_recv_ctl_pdu(context, s, &header))) { - WLog_ERR(TAG, "remdesk_recv_ctl_pdu failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "remdesk_recv_ctl_pdu failed with error %" PRIu32 "!", error); return error; } } @@ -591,7 +583,7 @@ static DWORD WINAPI remdesk_server_thread(LPVOID arg) DWORD BytesReturned; RemdeskServerContext* context; UINT error; - context = (RemdeskServerContext*) arg; + context = (RemdeskServerContext*)arg; buffer = NULL; BytesReturned = 0; ChannelEvent = NULL; @@ -604,8 +596,8 @@ static DWORD WINAPI remdesk_server_thread(LPVOID arg) goto out; } - if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, - &buffer, &BytesReturned) == TRUE) + if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, + &BytesReturned) == TRUE) { if (BytesReturned == sizeof(HANDLE)) CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); @@ -625,8 +617,7 @@ static DWORD WINAPI remdesk_server_thread(LPVOID arg) if ((error = remdesk_send_ctl_version_info_pdu(context))) { - WLog_ERR(TAG, "remdesk_send_ctl_version_info_pdu failed with error %"PRIu32"!", - error); + WLog_ERR(TAG, "remdesk_send_ctl_version_info_pdu failed with error %" PRIu32 "!", error); goto out; } @@ -637,7 +628,7 @@ static DWORD WINAPI remdesk_server_thread(LPVOID arg) if (status == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"", error); + WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error); break; } @@ -646,7 +637,7 @@ static DWORD WINAPI remdesk_server_thread(LPVOID arg) if (status == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error); break; } @@ -655,8 +646,8 @@ static DWORD WINAPI remdesk_server_thread(LPVOID arg) break; } - if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0, - (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned)) + if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0, (PCHAR)Stream_Buffer(s), + Stream_Capacity(s), &BytesReturned)) { if (BytesReturned) Stream_Seek(s, BytesReturned); @@ -673,7 +664,7 @@ static DWORD WINAPI remdesk_server_thread(LPVOID arg) if (Stream_GetPosition(s) >= 8) { - pHeader = (UINT32*) Stream_Buffer(s); + pHeader = (UINT32*)Stream_Buffer(s); PduLength = pHeader[0] + pHeader[1] + 8; if (PduLength >= Stream_GetPosition(s)) @@ -683,7 +674,8 @@ static DWORD WINAPI remdesk_server_thread(LPVOID arg) if ((error = remdesk_server_receive_pdu(context, s))) { - WLog_ERR(TAG, "remdesk_server_receive_pdu failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "remdesk_server_receive_pdu failed with error %" PRIu32 "!", + error); break; } @@ -696,8 +688,7 @@ static DWORD WINAPI remdesk_server_thread(LPVOID arg) out: if (error && context->rdpcontext) - setChannelError(context->rdpcontext, error, - "remdesk_server_thread reported an error"); + setChannelError(context->rdpcontext, error, "remdesk_server_thread reported an error"); ExitThread(error); return error; @@ -710,8 +701,8 @@ out: */ static UINT remdesk_server_start(RemdeskServerContext* context) { - context->priv->ChannelHandle = WTSVirtualChannelOpen(context->vcm, - WTS_CURRENT_SESSION, "remdesk"); + context->priv->ChannelHandle = + WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "remdesk"); if (!context->priv->ChannelHandle) { @@ -725,8 +716,8 @@ static UINT remdesk_server_start(RemdeskServerContext* context) return ERROR_INTERNAL_ERROR; } - if (!(context->priv->Thread = CreateThread(NULL, 0, - remdesk_server_thread, (void*) context, 0, NULL))) + if (!(context->priv->Thread = + CreateThread(NULL, 0, remdesk_server_thread, (void*)context, 0, NULL))) { WLog_ERR(TAG, "CreateThread failed!"); CloseHandle(context->priv->StopEvent); @@ -750,7 +741,7 @@ static UINT remdesk_server_stop(RemdeskServerContext* context) if (WaitForSingleObject(context->priv->Thread, INFINITE) == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error); return error; } @@ -762,14 +753,14 @@ static UINT remdesk_server_stop(RemdeskServerContext* context) RemdeskServerContext* remdesk_server_context_new(HANDLE vcm) { RemdeskServerContext* context; - context = (RemdeskServerContext*) calloc(1, sizeof(RemdeskServerContext)); + context = (RemdeskServerContext*)calloc(1, sizeof(RemdeskServerContext)); if (context) { context->vcm = vcm; context->Start = remdesk_server_start; context->Stop = remdesk_server_stop; - context->priv = (RemdeskServerPrivate*) calloc(1, sizeof(RemdeskServerPrivate)); + context->priv = (RemdeskServerPrivate*)calloc(1, sizeof(RemdeskServerPrivate)); if (!context->priv) { diff --git a/channels/remdesk/server/remdesk_main.h b/channels/remdesk/server/remdesk_main.h index 857376a..f47d037 100644 --- a/channels/remdesk/server/remdesk_main.h +++ b/channels/remdesk/server/remdesk_main.h @@ -39,4 +39,3 @@ struct _remdesk_server_private }; #endif /* FREERDP_CHANNEL_REMDESK_SERVER_MAIN_H */ - diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index 5d6286b..afe67b4 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -49,7 +49,7 @@ * CommWriteFile by WriteFile etc.. */ #if defined __linux__ && !defined ANDROID -#define MAX_IRP_THREADS 5 +#define MAX_IRP_THREADS 5 typedef struct _SERIAL_DEVICE SERIAL_DEVICE; @@ -81,7 +81,8 @@ struct _IRP_THREAD_DATA static UINT32 _GetLastErrorToIoStatus(SERIAL_DEVICE* serial) { - /* http://msdn.microsoft.com/en-us/library/ff547466%28v=vs.85%29.aspx#generic_status_values_for_serial_device_control_requests */ + /* http://msdn.microsoft.com/en-us/library/ff547466%28v=vs.85%29.aspx#generic_status_values_for_serial_device_control_requests + */ switch (GetLastError()) { case ERROR_BAD_DEVICE: @@ -119,8 +120,7 @@ static UINT32 _GetLastErrorToIoStatus(SERIAL_DEVICE* serial) /* no default */ } - WLog_Print(serial->log, WLOG_DEBUG, "unexpected last-error: 0x%08"PRIX32"", - GetLastError()); + WLog_Print(serial->log, WLOG_DEBUG, "unexpected last-error: 0x%08" PRIX32 "", GetLastError()); return STATUS_UNSUCCESSFUL; } @@ -134,19 +134,18 @@ static UINT serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp) if (Stream_GetRemainingLength(irp->input) < 32) return ERROR_INVALID_DATA; - Stream_Read_UINT32(irp->input, DesiredAccess); /* DesiredAccess (4 bytes) */ - Stream_Seek_UINT64(irp->input); /* AllocationSize (8 bytes) */ - Stream_Seek_UINT32(irp->input); /* FileAttributes (4 bytes) */ - Stream_Read_UINT32(irp->input, SharedAccess); /* SharedAccess (4 bytes) */ - Stream_Read_UINT32(irp->input, CreateDisposition); /* CreateDisposition (4 bytes) */ - Stream_Seek_UINT32(irp->input); /* CreateOptions (4 bytes) */ - Stream_Read_UINT32(irp->input, PathLength); /* PathLength (4 bytes) */ + Stream_Read_UINT32(irp->input, DesiredAccess); /* DesiredAccess (4 bytes) */ + Stream_Seek_UINT64(irp->input); /* AllocationSize (8 bytes) */ + Stream_Seek_UINT32(irp->input); /* FileAttributes (4 bytes) */ + Stream_Read_UINT32(irp->input, SharedAccess); /* SharedAccess (4 bytes) */ + Stream_Read_UINT32(irp->input, CreateDisposition); /* CreateDisposition (4 bytes) */ + Stream_Seek_UINT32(irp->input); /* CreateOptions (4 bytes) */ + Stream_Read_UINT32(irp->input, PathLength); /* PathLength (4 bytes) */ - if (Stream_GetRemainingLength(irp->input) < PathLength) + if (!Stream_SafeSeek(irp->input, PathLength)) /* Path (variable) */ return ERROR_INVALID_DATA; - Stream_Seek(irp->input, PathLength); /* Path (variable) */ - assert(PathLength == 0); /* MS-RDPESP 2.2.2.2 */ + assert(PathLength == 0); /* MS-RDPESP 2.2.2.2 */ #ifndef _WIN32 /* Windows 2012 server sends on a first call : * DesiredAccess = 0x00100080: SYNCHRONIZE | FILE_READ_ATTRIBUTES @@ -154,9 +153,9 @@ static UINT serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp) * CreateDisposition = 0x00000001: CREATE_NEW * * then Windows 2012 sends : - * DesiredAccess = 0x00120089: SYNCHRONIZE | READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_READ_DATA - * SharedAccess = 0x00000007: FILE_SHARE_DELETE | FILE_SHARE_WRITE | FILE_SHARE_READ - * CreateDisposition = 0x00000001: CREATE_NEW + * DesiredAccess = 0x00120089: SYNCHRONIZE | READ_CONTROL | FILE_READ_ATTRIBUTES | + * FILE_READ_EA | FILE_READ_DATA SharedAccess = 0x00000007: FILE_SHARE_DELETE | + * FILE_SHARE_WRITE | FILE_SHARE_READ CreateDisposition = 0x00000001: CREATE_NEW * * assert(DesiredAccess == (GENERIC_READ | GENERIC_WRITE)); * assert(SharedAccess == 0); @@ -164,24 +163,22 @@ static UINT serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp) * */ WLog_Print(serial->log, WLOG_DEBUG, - "DesiredAccess: 0x%"PRIX32", SharedAccess: 0x%"PRIX32", CreateDisposition: 0x%"PRIX32"", + "DesiredAccess: 0x%" PRIX32 ", SharedAccess: 0x%" PRIX32 + ", CreateDisposition: 0x%" PRIX32 "", DesiredAccess, SharedAccess, CreateDisposition); /* FIXME: As of today only the flags below are supported by CommCreateFileA: */ - DesiredAccess = GENERIC_READ | GENERIC_WRITE; - SharedAccess = 0; + DesiredAccess = GENERIC_READ | GENERIC_WRITE; + SharedAccess = 0; CreateDisposition = OPEN_EXISTING; #endif - serial->hComm = CreateFile(serial->device.name, - DesiredAccess, - SharedAccess, - NULL, /* SecurityAttributes */ - CreateDisposition, - 0, /* FlagsAndAttributes */ - NULL); /* TemplateFile */ + serial->hComm = + CreateFile(serial->device.name, DesiredAccess, SharedAccess, NULL, /* SecurityAttributes */ + CreateDisposition, 0, /* FlagsAndAttributes */ + NULL); /* TemplateFile */ if (!serial->hComm || (serial->hComm == INVALID_HANDLE_VALUE)) { - WLog_Print(serial->log, WLOG_WARN, "CreateFile failure: %s last-error: 0x%08"PRIX32"", + WLog_Print(serial->log, WLOG_WARN, "CreateFile failure: %s last-error: 0x%08" PRIX32 "", serial->device.name, GetLastError()); irp->IoStatus = STATUS_UNSUCCESSFUL; goto error_handle; @@ -200,11 +197,11 @@ static UINT serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp) assert(irp->FileId == 0); irp->FileId = irp->devman->id_sequence++; /* FIXME: why not ((WINPR_COMM*)hComm)->fd? */ irp->IoStatus = STATUS_SUCCESS; - WLog_Print(serial->log, WLOG_DEBUG, "%s (DeviceId: %"PRIu32", FileId: %"PRIu32") created.", + WLog_Print(serial->log, WLOG_DEBUG, "%s (DeviceId: %" PRIu32 ", FileId: %" PRIu32 ") created.", serial->device.name, irp->device->id, irp->FileId); error_handle: - Stream_Write_UINT32(irp->output, irp->FileId); /* FileId (4 bytes) */ - Stream_Write_UINT8(irp->output, 0); /* Information (1 byte) */ + Stream_Write_UINT32(irp->output, irp->FileId); /* FileId (4 bytes) */ + Stream_Write_UINT8(irp->output, 0); /* Information (1 byte) */ return CHANNEL_RC_OK; } @@ -217,13 +214,13 @@ static UINT serial_process_irp_close(SERIAL_DEVICE* serial, IRP* irp) if (!CloseHandle(serial->hComm)) { - WLog_Print(serial->log, WLOG_WARN, "CloseHandle failure: %s (%"PRIu32") closed.", + WLog_Print(serial->log, WLOG_WARN, "CloseHandle failure: %s (%" PRIu32 ") closed.", serial->device.name, irp->device->id); irp->IoStatus = STATUS_UNSUCCESSFUL; goto error_handle; } - WLog_Print(serial->log, WLOG_DEBUG, "%s (DeviceId: %"PRIu32", FileId: %"PRIu32") closed.", + WLog_Print(serial->log, WLOG_DEBUG, "%s (DeviceId: %" PRIu32 ", FileId: %" PRIu32 ") closed.", serial->device.name, irp->device->id, irp->FileId); serial->hComm = NULL; irp->IoStatus = STATUS_SUCCESS; @@ -249,7 +246,7 @@ static UINT serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp) Stream_Read_UINT32(irp->input, Length); /* Length (4 bytes) */ Stream_Read_UINT64(irp->input, Offset); /* Offset (8 bytes) */ - Stream_Seek(irp->input, 20); /* Padding (20 bytes) */ + Stream_Seek(irp->input, 20); /* Padding (20 bytes) */ buffer = (BYTE*)calloc(Length, sizeof(BYTE)); if (buffer == NULL) @@ -261,7 +258,7 @@ static UINT serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp) /* MS-RDPESP 3.2.5.1.4: If the Offset field is not set to 0, the value MUST be ignored * assert(Offset == 0); */ - WLog_Print(serial->log, WLOG_DEBUG, "reading %"PRIu32" bytes from %s", Length, + WLog_Print(serial->log, WLOG_DEBUG, "reading %" PRIu32 " bytes from %s", Length, serial->device.name); /* FIXME: CommReadFile to be replaced by ReadFile */ @@ -272,12 +269,12 @@ static UINT serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp) else { WLog_Print(serial->log, WLOG_DEBUG, - "read failure to %s, nbRead=%"PRIu32", last-error: 0x%08"PRIX32"", serial->device.name, - nbRead, GetLastError()); + "read failure to %s, nbRead=%" PRIu32 ", last-error: 0x%08" PRIX32 "", + serial->device.name, nbRead, GetLastError()); irp->IoStatus = _GetLastErrorToIoStatus(serial); } - WLog_Print(serial->log, WLOG_DEBUG, "%"PRIu32" bytes read from %s", nbRead, + WLog_Print(serial->log, WLOG_DEBUG, "%" PRIu32 " bytes read from %s", nbRead, serial->device.name); error_handle: Stream_Write_UINT32(irp->output, nbRead); /* Length (4 bytes) */ @@ -302,6 +299,7 @@ static UINT serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp) { UINT32 Length; UINT64 Offset; + void* ptr; DWORD nbWritten = 0; if (Stream_GetRemainingLength(irp->input) < 32) @@ -309,38 +307,41 @@ static UINT serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp) Stream_Read_UINT32(irp->input, Length); /* Length (4 bytes) */ Stream_Read_UINT64(irp->input, Offset); /* Offset (8 bytes) */ - Stream_Seek(irp->input, 20); /* Padding (20 bytes) */ + if (!Stream_SafeSeek(irp->input, 20)) /* Padding (20 bytes) */ + return ERROR_INVALID_DATA; + /* MS-RDPESP 3.2.5.1.5: The Offset field is ignored * assert(Offset == 0); * * Using a serial printer, noticed though this field could be * set. */ - WLog_Print(serial->log, WLOG_DEBUG, "writing %"PRIu32" bytes to %s", Length, + WLog_Print(serial->log, WLOG_DEBUG, "writing %" PRIu32 " bytes to %s", Length, serial->device.name); + ptr = Stream_Pointer(irp->input); + if (!Stream_SafeSeek(irp->input, Length)) + return ERROR_INVALID_DATA; /* FIXME: CommWriteFile to be replaced by WriteFile */ - if (CommWriteFile(serial->hComm, Stream_Pointer(irp->input), Length, &nbWritten, - NULL)) + if (CommWriteFile(serial->hComm, ptr, Length, &nbWritten, NULL)) { irp->IoStatus = STATUS_SUCCESS; } else { WLog_Print(serial->log, WLOG_DEBUG, - "write failure to %s, nbWritten=%"PRIu32", last-error: 0x%08"PRIX32"", serial->device.name, - nbWritten, GetLastError()); + "write failure to %s, nbWritten=%" PRIu32 ", last-error: 0x%08" PRIX32 "", + serial->device.name, nbWritten, GetLastError()); irp->IoStatus = _GetLastErrorToIoStatus(serial); } - WLog_Print(serial->log, WLOG_DEBUG, "%"PRIu32" bytes written to %s", nbWritten, + WLog_Print(serial->log, WLOG_DEBUG, "%" PRIu32 " bytes written to %s", nbWritten, serial->device.name); Stream_Write_UINT32(irp->output, nbWritten); /* Length (4 bytes) */ - Stream_Write_UINT8(irp->output, 0); /* Padding (1 byte) */ + Stream_Write_UINT8(irp->output, 0); /* Padding (1 byte) */ return CHANNEL_RC_OK; } - /** * Function description * @@ -350,18 +351,18 @@ static UINT serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) { UINT32 IoControlCode; UINT32 InputBufferLength; - BYTE* InputBuffer = NULL; + BYTE* InputBuffer = NULL; UINT32 OutputBufferLength; - BYTE* OutputBuffer = NULL; - DWORD BytesReturned = 0; + BYTE* OutputBuffer = NULL; + DWORD BytesReturned = 0; if (Stream_GetRemainingLength(irp->input) < 32) return ERROR_INVALID_DATA; Stream_Read_UINT32(irp->input, OutputBufferLength); /* OutputBufferLength (4 bytes) */ - Stream_Read_UINT32(irp->input, InputBufferLength); /* InputBufferLength (4 bytes) */ - Stream_Read_UINT32(irp->input, IoControlCode); /* IoControlCode (4 bytes) */ - Stream_Seek(irp->input, 20); /* Padding (20 bytes) */ + Stream_Read_UINT32(irp->input, InputBufferLength); /* InputBufferLength (4 bytes) */ + Stream_Read_UINT32(irp->input, IoControlCode); /* IoControlCode (4 bytes) */ + Stream_Seek(irp->input, 20); /* Padding (20 bytes) */ if (Stream_GetRemainingLength(irp->input) < InputBufferLength) return ERROR_INVALID_DATA; @@ -384,20 +385,23 @@ static UINT serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) Stream_Read(irp->input, InputBuffer, InputBufferLength); WLog_Print(serial->log, WLOG_DEBUG, - "CommDeviceIoControl: CompletionId=%"PRIu32", IoControlCode=[0x%"PRIX32"] %s", + "CommDeviceIoControl: CompletionId=%" PRIu32 ", IoControlCode=[0x%" PRIX32 "] %s", irp->CompletionId, IoControlCode, _comm_serial_ioctl_name(IoControlCode)); /* FIXME: CommDeviceIoControl to be replaced by DeviceIoControl() */ - if (CommDeviceIoControl(serial->hComm, IoControlCode, InputBuffer, - InputBufferLength, OutputBuffer, OutputBufferLength, &BytesReturned, NULL)) + if (CommDeviceIoControl(serial->hComm, IoControlCode, InputBuffer, InputBufferLength, + OutputBuffer, OutputBufferLength, &BytesReturned, NULL)) { - /* WLog_Print(serial->log, WLOG_DEBUG, "CommDeviceIoControl: CompletionId=%"PRIu32", IoControlCode=[0x%"PRIX32"] %s done", irp->CompletionId, IoControlCode, _comm_serial_ioctl_name(IoControlCode)); */ + /* WLog_Print(serial->log, WLOG_DEBUG, "CommDeviceIoControl: CompletionId=%"PRIu32", + * IoControlCode=[0x%"PRIX32"] %s done", irp->CompletionId, IoControlCode, + * _comm_serial_ioctl_name(IoControlCode)); */ irp->IoStatus = STATUS_SUCCESS; } else { WLog_Print(serial->log, WLOG_DEBUG, - "CommDeviceIoControl failure: IoControlCode=[0x%"PRIX32"] %s, last-error: 0x%08"PRIX32"", + "CommDeviceIoControl failure: IoControlCode=[0x%" PRIX32 + "] %s, last-error: 0x%08" PRIX32 "", IoControlCode, _comm_serial_ioctl_name(IoControlCode), GetLastError()); irp->IoStatus = _GetLastErrorToIoStatus(serial); } @@ -444,7 +448,7 @@ static UINT serial_process_irp(SERIAL_DEVICE* serial, IRP* irp) { UINT error = CHANNEL_RC_OK; WLog_Print(serial->log, WLOG_DEBUG, - "IRP MajorFunction: 0x%08"PRIX32" MinorFunction: 0x%08"PRIX32"\n", + "IRP MajorFunction: 0x%08" PRIX32 " MinorFunction: 0x%08" PRIX32 "\n", irp->MajorFunction, irp->MinorFunction); switch (irp->MajorFunction) @@ -459,7 +463,7 @@ static UINT serial_process_irp(SERIAL_DEVICE* serial, IRP* irp) case IRP_MJ_READ: if ((error = serial_process_irp_read(serial, irp))) - WLog_ERR(TAG, "serial_process_irp_read failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "serial_process_irp_read failed with error %" PRIu32 "!", error); break; @@ -469,7 +473,7 @@ static UINT serial_process_irp(SERIAL_DEVICE* serial, IRP* irp) case IRP_MJ_DEVICE_CONTROL: if ((error = serial_process_irp_device_control(serial, irp))) - WLog_ERR(TAG, "serial_process_irp_device_control failed with error %"PRIu32"!", + WLog_ERR(TAG, "serial_process_irp_device_control failed with error %" PRIu32 "!", error); break; @@ -482,7 +486,6 @@ static UINT serial_process_irp(SERIAL_DEVICE* serial, IRP* irp) return error; } - static DWORD WINAPI irp_thread_func(LPVOID arg) { IRP_THREAD_DATA* data = (IRP_THREAD_DATA*)arg; @@ -491,7 +494,7 @@ static DWORD WINAPI irp_thread_func(LPVOID arg) /* blocks until the end of the request */ if ((error = serial_process_irp(data->serial, data->irp))) { - WLog_ERR(TAG, "serial_process_irp failed with error %"PRIu32"", error); + WLog_ERR(TAG, "serial_process_irp failed with error %" PRIu32 "", error); goto error_out; } @@ -502,8 +505,7 @@ static DWORD WINAPI irp_thread_func(LPVOID arg) error_out: if (error && data->serial->rdpcontext) - setChannelError(data->serial->rdpcontext, error, - "irp_thread_func reported an error"); + setChannelError(data->serial->rdpcontext, error, "irp_thread_func reported an error"); /* NB: At this point, the server might already being reusing * the CompletionId whereas the thread is not yet @@ -513,7 +515,6 @@ error_out: return error; } - static void create_irp_thread(SERIAL_DEVICE* serial, IRP* irp) { IRP_THREAD_DATA* data = NULL; @@ -547,13 +548,15 @@ static void create_irp_thread(SERIAL_DEVICE* serial, IRP* irp) DWORD waitResult; ULONG_PTR id = ids[i]; irpThread = ListDictionary_GetItemValue(serial->IrpThreads, (void*)id); - /* FIXME: not quite sure a zero timeout is a good thing to check whether a thread is stil alived or not */ + /* FIXME: not quite sure a zero timeout is a good thing to check whether a thread is + * stil alived or not */ waitResult = WaitForSingleObject(irpThread, 0); if (waitResult == WAIT_OBJECT_0) { /* terminating thread */ - /* WLog_Print(serial->log, WLOG_DEBUG, "IRP thread with CompletionId=%"PRIuz" naturally died", id); */ + /* WLog_Print(serial->log, WLOG_DEBUG, "IRP thread with CompletionId=%"PRIuz" + * naturally died", id); */ CloseHandle(irpThread); ListDictionary_Remove(serial->IrpThreads, (void*)id); serial->IrpThreadToBeTerminatedCount--; @@ -562,7 +565,8 @@ static void create_irp_thread(SERIAL_DEVICE* serial, IRP* irp) { /* unexpected thread state */ WLog_Print(serial->log, WLOG_WARN, - "WaitForSingleObject, got an unexpected result=0x%"PRIX32"\n", waitResult); + "WaitForSingleObject, got an unexpected result=0x%" PRIX32 "\n", + waitResult); assert(FALSE); } @@ -571,7 +575,7 @@ static void create_irp_thread(SERIAL_DEVICE* serial, IRP* irp) if (serial->IrpThreadToBeTerminatedCount > 0) { - WLog_Print(serial->log, WLOG_DEBUG, "%"PRIu32" IRP thread(s) not yet terminated", + WLog_Print(serial->log, WLOG_DEBUG, "%" PRIu32 " IRP thread(s) not yet terminated", serial->IrpThreadToBeTerminatedCount); Sleep(1); /* 1 ms */ } @@ -597,7 +601,7 @@ static void create_irp_thread(SERIAL_DEVICE* serial, IRP* irp) { /* Thread still alived <=> Request still pending */ WLog_Print(serial->log, WLOG_DEBUG, - "IRP recall: IRP with the CompletionId=%"PRIu32" not yet completed!", + "IRP recall: IRP with the CompletionId=%" PRIu32 " not yet completed!", irp->CompletionId); assert(FALSE); /* unimplemented */ /* TODO: asserts that previousIrpThread handles well @@ -623,11 +627,11 @@ static void create_irp_thread(SERIAL_DEVICE* serial, IRP* irp) "Number of IRP threads threshold reached: %d, keep on anyway", ListDictionary_Count(serial->IrpThreads)); assert(FALSE); /* unimplemented */ - /* TODO: MAX_IRP_THREADS has been thought to avoid a - * flooding of pending requests. Use - * WaitForMultipleObjects() when available in winpr - * for threads. - */ + /* TODO: MAX_IRP_THREADS has been thought to avoid a + * flooding of pending requests. Use + * WaitForMultipleObjects() when available in winpr + * for threads. + */ } /* error_handle to be used ... */ @@ -642,12 +646,7 @@ static void create_irp_thread(SERIAL_DEVICE* serial, IRP* irp) data->serial = serial; data->irp = irp; /* data freed by irp_thread_func */ - irpThread = CreateThread(NULL, - 0, - irp_thread_func, - (void*)data, - 0, - NULL); + irpThread = CreateThread(NULL, 0, irp_thread_func, (void*)data, 0, NULL); if (irpThread == INVALID_HANDLE_VALUE) { @@ -670,7 +669,6 @@ error_handle: free(data); } - static void terminate_pending_irp_threads(SERIAL_DEVICE* serial) { ULONG_PTR* ids; @@ -692,19 +690,18 @@ static void terminate_pending_irp_threads(SERIAL_DEVICE* serial) } CloseHandle(irpThread); - WLog_Print(serial->log, WLOG_DEBUG, "IRP thread terminated, CompletionId %p", (void*) id); + WLog_Print(serial->log, WLOG_DEBUG, "IRP thread terminated, CompletionId %p", (void*)id); } ListDictionary_Clear(serial->IrpThreads); free(ids); } - static DWORD WINAPI serial_thread_func(LPVOID arg) { IRP* irp; wMessage message; - SERIAL_DEVICE* serial = (SERIAL_DEVICE*) arg; + SERIAL_DEVICE* serial = (SERIAL_DEVICE*)arg; UINT error = CHANNEL_RC_OK; while (1) @@ -729,21 +726,19 @@ static DWORD WINAPI serial_thread_func(LPVOID arg) break; } - irp = (IRP*) message.wParam; + irp = (IRP*)message.wParam; if (irp) create_irp_thread(serial, irp); } if (error && serial->rdpcontext) - setChannelError(serial->rdpcontext, error, - "serial_thread_func reported an error"); + setChannelError(serial->rdpcontext, error, "serial_thread_func reported an error"); ExitThread(error); return error; } - /** * Function description * @@ -751,7 +746,7 @@ static DWORD WINAPI serial_thread_func(LPVOID arg) */ static UINT serial_irp_request(DEVICE* device, IRP* irp) { - SERIAL_DEVICE* serial = (SERIAL_DEVICE*) device; + SERIAL_DEVICE* serial = (SERIAL_DEVICE*)device; assert(irp != NULL); if (irp == NULL) @@ -762,7 +757,7 @@ static UINT serial_irp_request(DEVICE* device, IRP* irp) * write requests. */ - if (!MessageQueue_Post(serial->MainIrpQueue, NULL, 0, (void*) irp, NULL)) + if (!MessageQueue_Post(serial->MainIrpQueue, NULL, 0, (void*)irp, NULL)) { WLog_ERR(TAG, "MessageQueue_Post failed!"); return ERROR_INTERNAL_ERROR; @@ -771,7 +766,6 @@ static UINT serial_irp_request(DEVICE* device, IRP* irp) return CHANNEL_RC_OK; } - /** * Function description * @@ -780,14 +774,14 @@ static UINT serial_irp_request(DEVICE* device, IRP* irp) static UINT serial_free(DEVICE* device) { UINT error; - SERIAL_DEVICE* serial = (SERIAL_DEVICE*) device; + SERIAL_DEVICE* serial = (SERIAL_DEVICE*)device; WLog_Print(serial->log, WLOG_DEBUG, "freeing"); MessageQueue_PostQuit(serial->MainIrpQueue, 0); if (WaitForSingleObject(serial->MainThread, INFINITE) == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error); return error; } @@ -808,9 +802,9 @@ static UINT serial_free(DEVICE* device) #endif /* __linux__ */ #ifdef BUILTIN_CHANNELS -#define DeviceServiceEntry serial_DeviceServiceEntry +#define DeviceServiceEntry serial_DeviceServiceEntry #else -#define DeviceServiceEntry FREERDP_API DeviceServiceEntry +#define DeviceServiceEntry FREERDP_API DeviceServiceEntry #endif /** @@ -825,11 +819,11 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) char* driver; RDPDR_SERIAL* device; #if defined __linux__ && !defined ANDROID - int i, len; + size_t i, len; SERIAL_DEVICE* serial; #endif /* __linux__ */ UINT error = CHANNEL_RC_OK; - device = (RDPDR_SERIAL*) pEntryPoints->device; + device = (RDPDR_SERIAL*)pEntryPoints->device; name = device->Name; path = device->Path; driver = device->Driver; @@ -846,8 +840,7 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) log = WLog_Get("com.freerdp.channel.serial.client"); WLog_Print(log, WLOG_DEBUG, "initializing"); #ifndef __linux__ /* to be removed */ - WLog_Print(log, WLOG_WARN, - "Serial ports redirection not supported on this platform."); + WLog_Print(log, WLOG_WARN, "Serial ports redirection not supported on this platform."); return CHANNEL_RC_INITIALIZATION_ERROR; #else /* __linux __ */ WLog_Print(log, WLOG_DEBUG, "Defining %s as %s", name, path); @@ -855,11 +848,11 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) if (!DefineCommDevice(name /* eg: COM1 */, path /* eg: /dev/ttyS0 */)) { DWORD status = GetLastError(); - WLog_ERR(TAG, "DefineCommDevice failed with %08"PRIx32, status); + WLog_ERR(TAG, "DefineCommDevice failed with %08" PRIx32, status); return ERROR_INTERNAL_ERROR; } - serial = (SERIAL_DEVICE*) calloc(1, sizeof(SERIAL_DEVICE)); + serial = (SERIAL_DEVICE*)calloc(1, sizeof(SERIAL_DEVICE)); if (!serial) { @@ -921,8 +914,8 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) } } - WLog_Print(serial->log, WLOG_DEBUG, "Server's serial driver: %s (id: %d)", - driver, serial->ServerSerialDriverId); + WLog_Print(serial->log, WLOG_DEBUG, "Server's serial driver: %s (id: %d)", driver, + serial->ServerSerialDriverId); /* TODO: implement auto detection of the server's serial driver */ serial->MainIrpQueue = MessageQueue_New(NULL); @@ -946,19 +939,14 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) serial->IrpThreadToBeTerminatedCount = 0; InitializeCriticalSection(&serial->TerminatingIrpThreadsLock); - if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, - (DEVICE*) serial))) + if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*)serial))) { - WLog_ERR(TAG, "EntryPoints->RegisterDevice failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "EntryPoints->RegisterDevice failed with error %" PRIu32 "!", error); goto error_out; } - if (!(serial->MainThread = CreateThread(NULL, - 0, - serial_thread_func, - (void*) serial, - 0, - NULL))) + if (!(serial->MainThread = + CreateThread(NULL, 0, serial_thread_func, (void*)serial, 0, NULL))) { WLog_ERR(TAG, "CreateThread failed!"); error = ERROR_INTERNAL_ERROR; diff --git a/channels/server/channels.c b/channels/server/channels.c index 8efff3f..40c55ee 100644 --- a/channels/server/channels.c +++ b/channels/server/channels.c @@ -49,9 +49,11 @@ #include #include #include +#include #include +#include -void freerdp_channels_dummy() +void freerdp_channels_dummy(void) { audin_server_context* audin; RdpsndServerContext* rdpsnd; @@ -62,7 +64,9 @@ void freerdp_channels_dummy() RdpeiServerContext* rdpei; RemdeskServerContext* remdesk; EncomspServerContext* encomsp; + RailServerContext* rail; RdpgfxServerContext* rdpgfx; + DispServerContext* disp; audin = audin_server_context_new(NULL); audin_server_context_free(audin); rdpsnd = rdpsnd_server_context_new(NULL); @@ -81,8 +85,12 @@ void freerdp_channels_dummy() remdesk_server_context_free(remdesk); encomsp = encomsp_server_context_new(NULL); encomsp_server_context_free(encomsp); + rail = rail_server_context_new(NULL); + rail_server_context_free(rail); rdpgfx = rdpgfx_server_context_new(NULL); rdpgfx_server_context_free(rdpgfx); + disp = disp_server_context_new(NULL); + disp_server_context_free(disp); } /** diff --git a/channels/server/channels.h b/channels/server/channels.h index f054c91..a6c4791 100644 --- a/channels/server/channels.h +++ b/channels/server/channels.h @@ -21,6 +21,4 @@ #ifndef FREERDP_CHANNEL_SERVER_CHANNELS_H #define FREERDP_CHANNEL_SERVER_CHANNELS_H - - #endif /* FREERDP_CHANNEL_SERVER_CHANNELS_H */ diff --git a/channels/smartcard/client/smartcard_main.c b/channels/smartcard/client/smartcard_main.c index 134c021..46c0980 100644 --- a/channels/smartcard/client/smartcard_main.c +++ b/channels/smartcard/client/smartcard_main.c @@ -39,7 +39,7 @@ static SMARTCARD_DEVICE* sSmartcard = NULL; static SMARTCARD_DEVICE* cast_device_from(DEVICE* device, const char* fkt, const char* file, - int line) + int line) { if (!device) { @@ -49,7 +49,7 @@ static SMARTCARD_DEVICE* cast_device_from(DEVICE* device, const char* fkt, const if (device->type != RDPDR_DTYP_SMARTCARD) { - WLog_ERR(TAG, "%s [%s:%d] Called smartcard channel with invalid device of type %"PRIx32, + WLog_ERR(TAG, "%s [%s:%d] Called smartcard channel with invalid device of type %" PRIx32, fkt, file, line, device->type); return NULL; } @@ -79,7 +79,7 @@ static DWORD WINAPI smartcard_context_thread(LPVOID arg) if (waitStatus == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", error); break; } @@ -88,7 +88,7 @@ static DWORD WINAPI smartcard_context_thread(LPVOID arg) if (waitStatus == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error); break; } @@ -104,18 +104,18 @@ static DWORD WINAPI smartcard_context_thread(LPVOID arg) if (message.id == WMQ_QUIT) break; - operation = (SMARTCARD_OPERATION*) message.wParam; + operation = (SMARTCARD_OPERATION*)message.wParam; if (operation) { if ((status = smartcard_irp_device_control_call(smartcard, operation))) { - WLog_ERR(TAG, "smartcard_irp_device_control_call failed with error %"PRIu32"", + WLog_ERR(TAG, "smartcard_irp_device_control_call failed with error %" PRIu32 "", status); break; } - if (!Queue_Enqueue(smartcard->CompletedIrpQueue, (void*) operation->irp)) + if (!Queue_Enqueue(smartcard->CompletedIrpQueue, (void*)operation->irp)) { WLog_ERR(TAG, "Queue_Enqueue failed!"); status = ERROR_INTERNAL_ERROR; @@ -128,18 +128,16 @@ static DWORD WINAPI smartcard_context_thread(LPVOID arg) } if (status && smartcard->rdpcontext) - setChannelError(smartcard->rdpcontext, error, - "smartcard_context_thread reported an error"); + setChannelError(smartcard->rdpcontext, error, "smartcard_context_thread reported an error"); ExitThread(status); return error; } -SMARTCARD_CONTEXT* smartcard_context_new(SMARTCARD_DEVICE* smartcard, - SCARDCONTEXT hContext) +SMARTCARD_CONTEXT* smartcard_context_new(SMARTCARD_DEVICE* smartcard, SCARDCONTEXT hContext) { SMARTCARD_CONTEXT* pContext; - pContext = (SMARTCARD_CONTEXT*) calloc(1, sizeof(SMARTCARD_CONTEXT)); + pContext = (SMARTCARD_CONTEXT*)calloc(1, sizeof(SMARTCARD_CONTEXT)); if (!pContext) { @@ -157,9 +155,7 @@ SMARTCARD_CONTEXT* smartcard_context_new(SMARTCARD_DEVICE* smartcard, goto error_irpqueue; } - pContext->thread = CreateThread(NULL, 0, - smartcard_context_thread, - pContext, 0, NULL); + pContext->thread = CreateThread(NULL, 0, smartcard_context_thread, pContext, 0, NULL); if (!pContext->thread) { @@ -185,9 +181,9 @@ void smartcard_context_free(void* pCtx) /* cancel blocking calls like SCardGetStatusChange */ SCardCancel(pContext->hContext); - if (MessageQueue_PostQuit(pContext->IrpQueue, 0) - && (WaitForSingleObject(pContext->thread, INFINITE) == WAIT_FAILED)) - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", GetLastError()); + if (MessageQueue_PostQuit(pContext->IrpQueue, 0) && + (WaitForSingleObject(pContext->thread, INFINITE) == WAIT_FAILED)) + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", GetLastError()); CloseHandle(pContext->thread); MessageQueue_Free(pContext->IrpQueue); @@ -204,8 +200,9 @@ static void smartcard_release_all_contexts(SMARTCARD_DEVICE* smartcard) /** * On protocol termination, the following actions are performed: - * For each context in rgSCardContextList, SCardCancel is called causing all SCardGetStatusChange calls to be processed. - * After that, SCardReleaseContext is called on each context and the context MUST be removed from rgSCardContextList. + * For each context in rgSCardContextList, SCardCancel is called causing all + * SCardGetStatusChange calls to be processed. After that, SCardReleaseContext is called on each + * context and the context MUST be removed from rgSCardContextList. */ /** @@ -219,8 +216,8 @@ static void smartcard_release_all_contexts(SMARTCARD_DEVICE* smartcard) for (index = 0; index < keyCount; index++) { - pContext = (SMARTCARD_CONTEXT*) ListDictionary_GetItemValue( - smartcard->rgSCardContextList, (void*) pKeys[index]); + pContext = (SMARTCARD_CONTEXT*)ListDictionary_GetItemValue( + smartcard->rgSCardContextList, (void*)pKeys[index]); if (!pContext) continue; @@ -247,8 +244,8 @@ static void smartcard_release_all_contexts(SMARTCARD_DEVICE* smartcard) for (index = 0; index < keyCount; index++) { - pContext = (SMARTCARD_CONTEXT*) ListDictionary_Remove( - smartcard->rgSCardContextList, (void*) pKeys[index]); + pContext = (SMARTCARD_CONTEXT*)ListDictionary_Remove(smartcard->rgSCardContextList, + (void*)pKeys[index]); if (!pContext) continue; @@ -259,9 +256,10 @@ static void smartcard_release_all_contexts(SMARTCARD_DEVICE* smartcard) { SCardReleaseContext(hContext); - if (MessageQueue_PostQuit(pContext->IrpQueue, 0) - && (WaitForSingleObject(pContext->thread, INFINITE) == WAIT_FAILED)) - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", GetLastError()); + if (MessageQueue_PostQuit(pContext->IrpQueue, 0) && + (WaitForSingleObject(pContext->thread, INFINITE) == WAIT_FAILED)) + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", + GetLastError()); CloseHandle(pContext->thread); MessageQueue_Free(pContext->IrpQueue); @@ -319,11 +317,11 @@ static UINT smartcard_free(DEVICE* device) if (smartcard->IrpQueue) { - if (MessageQueue_PostQuit(smartcard->IrpQueue, 0) - && (WaitForSingleObject(smartcard->thread, INFINITE) == WAIT_FAILED)) + if (MessageQueue_PostQuit(smartcard->IrpQueue, 0) && + (WaitForSingleObject(smartcard->thread, INFINITE) == WAIT_FAILED)) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error); return error; } } @@ -363,7 +361,7 @@ static UINT smartcard_init(DEVICE* device) static UINT smartcard_complete_irp(SMARTCARD_DEVICE* smartcard, IRP* irp) { void* key; - key = (void*)(size_t) irp->CompletionId; + key = (void*)(size_t)irp->CompletionId; ListDictionary_Remove(smartcard->rgOutstandingMessages, key); return irp->Complete(irp); } @@ -385,7 +383,7 @@ static UINT smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp) BOOL asyncIrp = FALSE; SMARTCARD_CONTEXT* pContext = NULL; SMARTCARD_OPERATION* operation = NULL; - key = (void*)(size_t) irp->CompletionId; + key = (void*)(size_t)irp->CompletionId; if (!ListDictionary_Add(smartcard->rgOutstandingMessages, key, irp)) { @@ -395,7 +393,7 @@ static UINT smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp) if (irp->MajorFunction == IRP_MJ_DEVICE_CONTROL) { - operation = (SMARTCARD_OPERATION*) calloc(1, sizeof(SMARTCARD_OPERATION)); + operation = (SMARTCARD_OPERATION*)calloc(1, sizeof(SMARTCARD_OPERATION)); if (!operation) { @@ -410,7 +408,7 @@ static UINT smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp) { irp->IoStatus = (UINT32)STATUS_UNSUCCESSFUL; - if (!Queue_Enqueue(smartcard->CompletedIrpQueue, (void*) irp)) + if (!Queue_Enqueue(smartcard->CompletedIrpQueue, (void*)irp)) { free(operation); WLog_ERR(TAG, "Queue_Enqueue failed!"); @@ -430,7 +428,7 @@ static UINT smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp) case SCARD_IOCTL_ISVALIDCONTEXT: case SCARD_IOCTL_CANCEL: case SCARD_IOCTL_ACCESSSTARTEDEVENT: - case SCARD_IOCTL_RELEASESTARTEDEVENT: + case SCARD_IOCTL_RELEASETARTEDEVENT: asyncIrp = FALSE; break; @@ -480,8 +478,8 @@ static UINT smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp) break; } - pContext = ListDictionary_GetItemValue(smartcard->rgSCardContextList, - (void*) operation->hContext); + pContext = + ListDictionary_GetItemValue(smartcard->rgSCardContextList, (void*)operation->hContext); if (!pContext) asyncIrp = FALSE; @@ -490,12 +488,12 @@ static UINT smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp) { if ((status = smartcard_irp_device_control_call(smartcard, operation))) { - WLog_ERR(TAG, "smartcard_irp_device_control_call failed with error %"PRId32"!", + WLog_ERR(TAG, "smartcard_irp_device_control_call failed with error %" PRId32 "!", status); return (UINT32)status; } - if (!Queue_Enqueue(smartcard->CompletedIrpQueue, (void*) irp)) + if (!Queue_Enqueue(smartcard->CompletedIrpQueue, (void*)irp)) { free(operation); WLog_ERR(TAG, "Queue_Enqueue failed!"); @@ -508,7 +506,7 @@ static UINT smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp) { if (pContext) { - if (!MessageQueue_Post(pContext->IrpQueue, NULL, 0, (void*) operation, NULL)) + if (!MessageQueue_Post(pContext->IrpQueue, NULL, 0, (void*)operation, NULL)) { WLog_ERR(TAG, "MessageQueue_Post failed!"); return ERROR_INTERNAL_ERROR; @@ -519,11 +517,12 @@ static UINT smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp) else { WLog_ERR(TAG, - "Unexpected SmartCard IRP: MajorFunction 0x%08"PRIX32" MinorFunction: 0x%08"PRIX32"", + "Unexpected SmartCard IRP: MajorFunction 0x%08" PRIX32 + " MinorFunction: 0x%08" PRIX32 "", irp->MajorFunction, irp->MinorFunction); irp->IoStatus = (UINT32)STATUS_NOT_SUPPORTED; - if (!Queue_Enqueue(smartcard->CompletedIrpQueue, (void*) irp)) + if (!Queue_Enqueue(smartcard->CompletedIrpQueue, (void*)irp)) { WLog_ERR(TAG, "Queue_Enqueue failed!"); return ERROR_INTERNAL_ERROR; @@ -557,7 +556,7 @@ static DWORD WINAPI smartcard_thread_func(LPVOID arg) if (status == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", error); break; } @@ -566,7 +565,7 @@ static DWORD WINAPI smartcard_thread_func(LPVOID arg) if (status == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error); break; } @@ -588,14 +587,14 @@ static DWORD WINAPI smartcard_thread_func(LPVOID arg) if (status == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error); goto out; } if (status == WAIT_TIMEOUT) break; - irp = (IRP*) Queue_Dequeue(smartcard->CompletedIrpQueue); + irp = (IRP*)Queue_Dequeue(smartcard->CompletedIrpQueue); if (irp) { @@ -606,7 +605,8 @@ static DWORD WINAPI smartcard_thread_func(LPVOID arg) if (status == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", + error); goto out; } @@ -616,7 +616,8 @@ static DWORD WINAPI smartcard_thread_func(LPVOID arg) if ((error = smartcard_complete_irp(smartcard, irp))) { - WLog_ERR(TAG, "smartcard_complete_irp failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "smartcard_complete_irp failed with error %" PRIu32 "!", + error); goto out; } } @@ -625,13 +626,13 @@ static DWORD WINAPI smartcard_thread_func(LPVOID arg) break; } - irp = (IRP*) message.wParam; + irp = (IRP*)message.wParam; if (irp) { if ((error = smartcard_process_irp(smartcard, irp))) { - WLog_ERR(TAG, "smartcard_process_irp failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "smartcard_process_irp failed with error %" PRIu32 "!", error); goto out; } } @@ -642,13 +643,13 @@ static DWORD WINAPI smartcard_thread_func(LPVOID arg) if (status == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error); break; } if (status == WAIT_OBJECT_0) { - irp = (IRP*) Queue_Dequeue(smartcard->CompletedIrpQueue); + irp = (IRP*)Queue_Dequeue(smartcard->CompletedIrpQueue); if (irp) { @@ -659,7 +660,7 @@ static DWORD WINAPI smartcard_thread_func(LPVOID arg) if (status == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error); break; } @@ -675,7 +676,7 @@ static DWORD WINAPI smartcard_thread_func(LPVOID arg) goto out; } - WLog_ERR(TAG, "smartcard_complete_irp failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "smartcard_complete_irp failed with error %" PRIu32 "!", error); goto out; } } @@ -685,8 +686,7 @@ static DWORD WINAPI smartcard_thread_func(LPVOID arg) out: if (error && smartcard->rdpcontext) - setChannelError(smartcard->rdpcontext, error, - "smartcard_thread_func reported an error"); + setChannelError(smartcard->rdpcontext, error, "smartcard_thread_func reported an error"); ExitThread(error); return error; @@ -704,7 +704,7 @@ static UINT smartcard_irp_request(DEVICE* device, IRP* irp) if (!smartcard) return ERROR_INVALID_PARAMETER; - if (!MessageQueue_Post(smartcard->IrpQueue, NULL, 0, (void*) irp, NULL)) + if (!MessageQueue_Post(smartcard->IrpQueue, NULL, 0, (void*)irp, NULL)) { WLog_ERR(TAG, "MessageQueue_Post failed!"); return ERROR_INTERNAL_ERROR; @@ -714,7 +714,7 @@ static UINT smartcard_irp_request(DEVICE* device, IRP* irp) } /* smartcard is always built-in */ -#define DeviceServiceEntry smartcard_DeviceServiceEntry +#define DeviceServiceEntry smartcard_DeviceServiceEntry /** * Function description @@ -730,7 +730,7 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) if (!sSmartcard) { wObject* obj; - smartcard = (SMARTCARD_DEVICE*) calloc(1, sizeof(SMARTCARD_DEVICE)); + smartcard = (SMARTCARD_DEVICE*)calloc(1, sizeof(SMARTCARD_DEVICE)); if (!smartcard) { @@ -795,9 +795,8 @@ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) goto fail; } - smartcard->thread = CreateThread(NULL, 0, - smartcard_thread_func, - smartcard, CREATE_SUSPENDED, NULL); + smartcard->thread = + CreateThread(NULL, 0, smartcard_thread_func, smartcard, CREATE_SUSPENDED, NULL); if (!smartcard->thread) { @@ -820,4 +819,3 @@ fail: smartcard_free_(smartcard); return error; } - diff --git a/channels/smartcard/client/smartcard_main.h b/channels/smartcard/client/smartcard_main.h index a867e69..48d8d02 100644 --- a/channels/smartcard/client/smartcard_main.h +++ b/channels/smartcard/client/smartcard_main.h @@ -34,56 +34,61 @@ #define TAG CHANNELS_TAG("smartcard.client") -#define RDP_SCARD_CTL_CODE(code) CTL_CODE(FILE_DEVICE_FILE_SYSTEM, (code), METHOD_BUFFERED, FILE_ANY_ACCESS) +#define RDP_SCARD_CTL_CODE(code) \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, (code), METHOD_BUFFERED, FILE_ANY_ACCESS) -#define SCARD_IOCTL_ESTABLISHCONTEXT RDP_SCARD_CTL_CODE(5) /* SCardEstablishContext */ -#define SCARD_IOCTL_RELEASECONTEXT RDP_SCARD_CTL_CODE(6) /* SCardReleaseContext */ -#define SCARD_IOCTL_ISVALIDCONTEXT RDP_SCARD_CTL_CODE(7) /* SCardIsValidContext */ -#define SCARD_IOCTL_LISTREADERGROUPSA RDP_SCARD_CTL_CODE(8) /* SCardListReaderGroupsA */ -#define SCARD_IOCTL_LISTREADERGROUPSW RDP_SCARD_CTL_CODE(9) /* SCardListReaderGroupsW */ -#define SCARD_IOCTL_LISTREADERSA RDP_SCARD_CTL_CODE(10) /* SCardListReadersA */ -#define SCARD_IOCTL_LISTREADERSW RDP_SCARD_CTL_CODE(11) /* SCardListReadersW */ -#define SCARD_IOCTL_INTRODUCEREADERGROUPA RDP_SCARD_CTL_CODE(20) /* SCardIntroduceReaderGroupA */ -#define SCARD_IOCTL_INTRODUCEREADERGROUPW RDP_SCARD_CTL_CODE(21) /* SCardIntroduceReaderGroupW */ -#define SCARD_IOCTL_FORGETREADERGROUPA RDP_SCARD_CTL_CODE(22) /* SCardForgetReaderGroupA */ -#define SCARD_IOCTL_FORGETREADERGROUPW RDP_SCARD_CTL_CODE(23) /* SCardForgetReaderGroupW */ -#define SCARD_IOCTL_INTRODUCEREADERA RDP_SCARD_CTL_CODE(24) /* SCardIntroduceReaderA */ -#define SCARD_IOCTL_INTRODUCEREADERW RDP_SCARD_CTL_CODE(25) /* SCardIntroduceReaderW */ -#define SCARD_IOCTL_FORGETREADERA RDP_SCARD_CTL_CODE(26) /* SCardForgetReaderA */ -#define SCARD_IOCTL_FORGETREADERW RDP_SCARD_CTL_CODE(27) /* SCardForgetReaderW */ -#define SCARD_IOCTL_ADDREADERTOGROUPA RDP_SCARD_CTL_CODE(28) /* SCardAddReaderToGroupA */ -#define SCARD_IOCTL_ADDREADERTOGROUPW RDP_SCARD_CTL_CODE(29) /* SCardAddReaderToGroupW */ -#define SCARD_IOCTL_REMOVEREADERFROMGROUPA RDP_SCARD_CTL_CODE(30) /* SCardRemoveReaderFromGroupA */ -#define SCARD_IOCTL_REMOVEREADERFROMGROUPW RDP_SCARD_CTL_CODE(31) /* SCardRemoveReaderFromGroupW */ -#define SCARD_IOCTL_LOCATECARDSA RDP_SCARD_CTL_CODE(38) /* SCardLocateCardsA */ -#define SCARD_IOCTL_LOCATECARDSW RDP_SCARD_CTL_CODE(39) /* SCardLocateCardsW */ -#define SCARD_IOCTL_GETSTATUSCHANGEA RDP_SCARD_CTL_CODE(40) /* SCardGetStatusChangeA */ -#define SCARD_IOCTL_GETSTATUSCHANGEW RDP_SCARD_CTL_CODE(41) /* SCardGetStatusChangeW */ -#define SCARD_IOCTL_CANCEL RDP_SCARD_CTL_CODE(42) /* SCardCancel */ -#define SCARD_IOCTL_CONNECTA RDP_SCARD_CTL_CODE(43) /* SCardConnectA */ -#define SCARD_IOCTL_CONNECTW RDP_SCARD_CTL_CODE(44) /* SCardConnectW */ -#define SCARD_IOCTL_RECONNECT RDP_SCARD_CTL_CODE(45) /* SCardReconnect */ -#define SCARD_IOCTL_DISCONNECT RDP_SCARD_CTL_CODE(46) /* SCardDisconnect */ -#define SCARD_IOCTL_BEGINTRANSACTION RDP_SCARD_CTL_CODE(47) /* SCardBeginTransaction */ -#define SCARD_IOCTL_ENDTRANSACTION RDP_SCARD_CTL_CODE(48) /* SCardEndTransaction */ -#define SCARD_IOCTL_STATE RDP_SCARD_CTL_CODE(49) /* SCardState */ -#define SCARD_IOCTL_STATUSA RDP_SCARD_CTL_CODE(50) /* SCardStatusA */ -#define SCARD_IOCTL_STATUSW RDP_SCARD_CTL_CODE(51) /* SCardStatusW */ -#define SCARD_IOCTL_TRANSMIT RDP_SCARD_CTL_CODE(52) /* SCardTransmit */ -#define SCARD_IOCTL_CONTROL RDP_SCARD_CTL_CODE(53) /* SCardControl */ -#define SCARD_IOCTL_GETATTRIB RDP_SCARD_CTL_CODE(54) /* SCardGetAttrib */ -#define SCARD_IOCTL_SETATTRIB RDP_SCARD_CTL_CODE(55) /* SCardSetAttrib */ -#define SCARD_IOCTL_ACCESSSTARTEDEVENT RDP_SCARD_CTL_CODE(56) /* SCardAccessStartedEvent */ -#define SCARD_IOCTL_LOCATECARDSBYATRA RDP_SCARD_CTL_CODE(58) /* SCardLocateCardsByATRA */ -#define SCARD_IOCTL_LOCATECARDSBYATRW RDP_SCARD_CTL_CODE(59) /* SCardLocateCardsByATRW */ -#define SCARD_IOCTL_READCACHEA RDP_SCARD_CTL_CODE(60) /* SCardReadCacheA */ -#define SCARD_IOCTL_READCACHEW RDP_SCARD_CTL_CODE(61) /* SCardReadCacheW */ -#define SCARD_IOCTL_WRITECACHEA RDP_SCARD_CTL_CODE(62) /* SCardWriteCacheA */ -#define SCARD_IOCTL_WRITECACHEW RDP_SCARD_CTL_CODE(63) /* SCardWriteCacheW */ -#define SCARD_IOCTL_GETTRANSMITCOUNT RDP_SCARD_CTL_CODE(64) /* SCardGetTransmitCount */ -#define SCARD_IOCTL_RELEASESTARTEDEVENT RDP_SCARD_CTL_CODE(66) /* SCardReleaseStartedEvent */ -#define SCARD_IOCTL_GETREADERICON RDP_SCARD_CTL_CODE(67) /* SCardGetReaderIconA */ -#define SCARD_IOCTL_GETDEVICETYPEID RDP_SCARD_CTL_CODE(68) /* SCardGetDeviceTypeIdA */ +#define SCARD_IOCTL_ESTABLISHCONTEXT RDP_SCARD_CTL_CODE(5) /* SCardEstablishContext */ +#define SCARD_IOCTL_RELEASECONTEXT RDP_SCARD_CTL_CODE(6) /* SCardReleaseContext */ +#define SCARD_IOCTL_ISVALIDCONTEXT RDP_SCARD_CTL_CODE(7) /* SCardIsValidContext */ +#define SCARD_IOCTL_LISTREADERGROUPSA RDP_SCARD_CTL_CODE(8) /* SCardListReaderGroupsA */ +#define SCARD_IOCTL_LISTREADERGROUPSW RDP_SCARD_CTL_CODE(9) /* SCardListReaderGroupsW */ +#define SCARD_IOCTL_LISTREADERSA RDP_SCARD_CTL_CODE(10) /* SCardListReadersA */ +#define SCARD_IOCTL_LISTREADERSW RDP_SCARD_CTL_CODE(11) /* SCardListReadersW */ +#define SCARD_IOCTL_INTRODUCEREADERGROUPA RDP_SCARD_CTL_CODE(20) /* SCardIntroduceReaderGroupA */ +#define SCARD_IOCTL_INTRODUCEREADERGROUPW RDP_SCARD_CTL_CODE(21) /* SCardIntroduceReaderGroupW */ +#define SCARD_IOCTL_FORGETREADERGROUPA RDP_SCARD_CTL_CODE(22) /* SCardForgetReaderGroupA */ +#define SCARD_IOCTL_FORGETREADERGROUPW RDP_SCARD_CTL_CODE(23) /* SCardForgetReaderGroupW */ +#define SCARD_IOCTL_INTRODUCEREADERA RDP_SCARD_CTL_CODE(24) /* SCardIntroduceReaderA */ +#define SCARD_IOCTL_INTRODUCEREADERW RDP_SCARD_CTL_CODE(25) /* SCardIntroduceReaderW */ +#define SCARD_IOCTL_FORGETREADERA RDP_SCARD_CTL_CODE(26) /* SCardForgetReaderA */ +#define SCARD_IOCTL_FORGETREADERW RDP_SCARD_CTL_CODE(27) /* SCardForgetReaderW */ +#define SCARD_IOCTL_ADDREADERTOGROUPA RDP_SCARD_CTL_CODE(28) /* SCardAddReaderToGroupA */ +#define SCARD_IOCTL_ADDREADERTOGROUPW RDP_SCARD_CTL_CODE(29) /* SCardAddReaderToGroupW */ +#define SCARD_IOCTL_REMOVEREADERFROMGROUPA \ + RDP_SCARD_CTL_CODE(30) /* SCardRemoveReaderFromGroupA \ + */ +#define SCARD_IOCTL_REMOVEREADERFROMGROUPW \ + RDP_SCARD_CTL_CODE(31) /* SCardRemoveReaderFromGroupW \ + */ +#define SCARD_IOCTL_LOCATECARDSA RDP_SCARD_CTL_CODE(38) /* SCardLocateCardsA */ +#define SCARD_IOCTL_LOCATECARDSW RDP_SCARD_CTL_CODE(39) /* SCardLocateCardsW */ +#define SCARD_IOCTL_GETSTATUSCHANGEA RDP_SCARD_CTL_CODE(40) /* SCardGetStatusChangeA */ +#define SCARD_IOCTL_GETSTATUSCHANGEW RDP_SCARD_CTL_CODE(41) /* SCardGetStatusChangeW */ +#define SCARD_IOCTL_CANCEL RDP_SCARD_CTL_CODE(42) /* SCardCancel */ +#define SCARD_IOCTL_CONNECTA RDP_SCARD_CTL_CODE(43) /* SCardConnectA */ +#define SCARD_IOCTL_CONNECTW RDP_SCARD_CTL_CODE(44) /* SCardConnectW */ +#define SCARD_IOCTL_RECONNECT RDP_SCARD_CTL_CODE(45) /* SCardReconnect */ +#define SCARD_IOCTL_DISCONNECT RDP_SCARD_CTL_CODE(46) /* SCardDisconnect */ +#define SCARD_IOCTL_BEGINTRANSACTION RDP_SCARD_CTL_CODE(47) /* SCardBeginTransaction */ +#define SCARD_IOCTL_ENDTRANSACTION RDP_SCARD_CTL_CODE(48) /* SCardEndTransaction */ +#define SCARD_IOCTL_STATE RDP_SCARD_CTL_CODE(49) /* SCardState */ +#define SCARD_IOCTL_STATUSA RDP_SCARD_CTL_CODE(50) /* SCardStatusA */ +#define SCARD_IOCTL_STATUSW RDP_SCARD_CTL_CODE(51) /* SCardStatusW */ +#define SCARD_IOCTL_TRANSMIT RDP_SCARD_CTL_CODE(52) /* SCardTransmit */ +#define SCARD_IOCTL_CONTROL RDP_SCARD_CTL_CODE(53) /* SCardControl */ +#define SCARD_IOCTL_GETATTRIB RDP_SCARD_CTL_CODE(54) /* SCardGetAttrib */ +#define SCARD_IOCTL_SETATTRIB RDP_SCARD_CTL_CODE(55) /* SCardSetAttrib */ +#define SCARD_IOCTL_ACCESSSTARTEDEVENT RDP_SCARD_CTL_CODE(56) /* SCardAccessStartedEvent */ +#define SCARD_IOCTL_RELEASETARTEDEVENT RDP_SCARD_CTL_CODE(57) /* SCardReleaseStartedEvent */ +#define SCARD_IOCTL_LOCATECARDSBYATRA RDP_SCARD_CTL_CODE(58) /* SCardLocateCardsByATRA */ +#define SCARD_IOCTL_LOCATECARDSBYATRW RDP_SCARD_CTL_CODE(59) /* SCardLocateCardsByATRW */ +#define SCARD_IOCTL_READCACHEA RDP_SCARD_CTL_CODE(60) /* SCardReadCacheA */ +#define SCARD_IOCTL_READCACHEW RDP_SCARD_CTL_CODE(61) /* SCardReadCacheW */ +#define SCARD_IOCTL_WRITECACHEA RDP_SCARD_CTL_CODE(62) /* SCardWriteCacheA */ +#define SCARD_IOCTL_WRITECACHEW RDP_SCARD_CTL_CODE(63) /* SCardWriteCacheW */ +#define SCARD_IOCTL_GETTRANSMITCOUNT RDP_SCARD_CTL_CODE(64) /* SCardGetTransmitCount */ +#define SCARD_IOCTL_GETREADERICON RDP_SCARD_CTL_CODE(65) /* SCardGetReaderIconA */ +#define SCARD_IOCTL_GETDEVICETYPEID RDP_SCARD_CTL_CODE(66) /* SCardGetDeviceTypeIdA */ typedef struct _SMARTCARD_DEVICE SMARTCARD_DEVICE; @@ -124,7 +129,7 @@ SMARTCARD_CONTEXT* smartcard_context_new(SMARTCARD_DEVICE* smartcard, SCARDCONTE void smartcard_context_free(void* pContext); LONG smartcard_irp_device_control_decode(SMARTCARD_DEVICE* smartcard, - SMARTCARD_OPERATION* operation); + SMARTCARD_OPERATION* operation); LONG smartcard_irp_device_control_call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERATION* operation); #include "smartcard_pack.h" diff --git a/channels/smartcard/client/smartcard_operations.c b/channels/smartcard/client/smartcard_operations.c index 4009b9f..5bcd624 100644 --- a/channels/smartcard/client/smartcard_operations.c +++ b/channels/smartcard/client/smartcard_operations.c @@ -39,7 +39,29 @@ #include "smartcard_main.h" -const char* smartcard_get_ioctl_string(UINT32 ioControlCode, BOOL funcName) +static LONG log_status_error(const char* tag, const char* what, LONG status) +{ + if (status != SCARD_S_SUCCESS) + { + DWORD level = WLOG_ERROR; + switch (status) + { + case SCARD_E_TIMEOUT: + level = WLOG_DEBUG; + break; + case SCARD_E_NO_READERS_AVAILABLE: + level = WLOG_INFO; + break; + default: + break; + } + WLog_Print(WLog_Get(tag), level, "%s failed with error %s [%" PRId32 "]", what, + SCardGetErrorString(status), status); + } + return status; +} + +static const char* smartcard_get_ioctl_string(UINT32 ioControlCode, BOOL funcName) { switch (ioControlCode) { @@ -178,8 +200,8 @@ const char* smartcard_get_ioctl_string(UINT32 ioControlCode, BOOL funcName) case SCARD_IOCTL_GETTRANSMITCOUNT: return funcName ? "SCardGetTransmitCount" : "SCARD_IOCTL_GETTRANSMITCOUNT"; - case SCARD_IOCTL_RELEASESTARTEDEVENT: - return funcName ? "SCardReleaseStartedEvent" : "SCARD_IOCTL_RELEASESTARTEDEVENT"; + case SCARD_IOCTL_RELEASETARTEDEVENT: + return funcName ? "SCardReleaseStartedEvent" : "SCARD_IOCTL_RELEASETARTEDEVENT"; case SCARD_IOCTL_GETREADERICON: return funcName ? "SCardGetReaderIcon" : "SCARD_IOCTL_GETREADERICON"; @@ -190,12 +212,10 @@ const char* smartcard_get_ioctl_string(UINT32 ioControlCode, BOOL funcName) default: return funcName ? "SCardUnknown" : "SCARD_IOCTL_UNKNOWN"; } - - return funcName ? "SCardUnknown" : "SCARD_IOCTL_UNKNOWN"; } static LONG smartcard_EstablishContext_Decode(SMARTCARD_DEVICE* smartcard, - SMARTCARD_OPERATION* operation) + SMARTCARD_OPERATION* operation) { LONG status; EstablishContext_Call* call; @@ -205,21 +225,20 @@ static LONG smartcard_EstablishContext_Decode(SMARTCARD_DEVICE* smartcard, if (!call) return STATUS_NO_MEMORY; - if ((status = smartcard_unpack_establish_context_call(smartcard, irp->input, call))) + status = smartcard_unpack_establish_context_call(smartcard, irp->input, call); + if (status != SCARD_S_SUCCESS) { - WLog_ERR(TAG, "smartcard_unpack_establish_context_call failed with error %"PRId32"", status); - return status; + return log_status_error(TAG, "smartcard_unpack_establish_context_call", status); } - smartcard_trace_establish_context_call(smartcard, call); return SCARD_S_SUCCESS; } static LONG smartcard_EstablishContext_Call(SMARTCARD_DEVICE* smartcard, - SMARTCARD_OPERATION* operation) + SMARTCARD_OPERATION* operation) { LONG status; - SCARDCONTEXT hContext = -1; + SCARDCONTEXT hContext = { 0 }; EstablishContext_Return ret; IRP* irp = operation->irp; EstablishContext_Call* call = operation->call; @@ -228,7 +247,7 @@ static LONG smartcard_EstablishContext_Call(SMARTCARD_DEVICE* smartcard, if (ret.ReturnCode == SCARD_S_SUCCESS) { SMARTCARD_CONTEXT* pContext; - void* key = (void*)(size_t) hContext; + void* key = (void*)(size_t)hContext; // TODO: handle return values pContext = smartcard_context_new(smartcard, hContext); @@ -238,7 +257,7 @@ static LONG smartcard_EstablishContext_Call(SMARTCARD_DEVICE* smartcard, return STATUS_NO_MEMORY; } - if (!ListDictionary_Add(smartcard->rgSCardContextList, key, (void*) pContext)) + if (!ListDictionary_Add(smartcard->rgSCardContextList, key, (void*)pContext)) { WLog_ERR(TAG, "ListDictionary_Add failed!"); return STATUS_INTERNAL_ERROR; @@ -246,24 +265,22 @@ static LONG smartcard_EstablishContext_Call(SMARTCARD_DEVICE* smartcard, } else { - WLog_ERR(TAG, "SCardEstablishContext failed with error %"PRId32"", status); - return status; + return log_status_error(TAG, "SCardEstablishContext", status); } smartcard_scard_context_native_to_redir(smartcard, &(ret.hContext), hContext); - smartcard_trace_establish_context_return(smartcard, &ret); - if ((status = smartcard_pack_establish_context_return(smartcard, irp->output, &ret))) + status = smartcard_pack_establish_context_return(smartcard, irp->output, &ret); + if (status != SCARD_S_SUCCESS) { - WLog_ERR(TAG, "smartcard_pack_establish_context_return failed with error %"PRId32"", status); - return status; + return log_status_error(TAG, "smartcard_pack_establish_context_return", status); } return ret.ReturnCode; } static LONG smartcard_ReleaseContext_Decode(SMARTCARD_DEVICE* smartcard, - SMARTCARD_OPERATION* operation) + SMARTCARD_OPERATION* operation) { LONG status; Context_Call* call; @@ -273,32 +290,30 @@ static LONG smartcard_ReleaseContext_Decode(SMARTCARD_DEVICE* smartcard, if (!call) return STATUS_NO_MEMORY; - if ((status = smartcard_unpack_context_call(smartcard, irp->input, call))) - WLog_ERR(TAG, "smartcard_unpack_context_call failed with error %"PRId32"", status); + status = smartcard_unpack_context_call(smartcard, irp->input, call, "ReleaseContext"); + if (status != SCARD_S_SUCCESS) + log_status_error(TAG, "smartcard_unpack_context_call", status); - smartcard_trace_context_call(smartcard, call, "ReleaseContext"); operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); return status; } static LONG smartcard_ReleaseContext_Call(SMARTCARD_DEVICE* smartcard, - SMARTCARD_OPERATION* operation) + SMARTCARD_OPERATION* operation) { - LONG status; Long_Return ret; - status = ret.ReturnCode = SCardReleaseContext(operation->hContext); + ret.ReturnCode = SCardReleaseContext(operation->hContext); if (ret.ReturnCode == SCARD_S_SUCCESS) { SMARTCARD_CONTEXT* pContext; - void* key = (void*)(size_t) operation->hContext; - pContext = (SMARTCARD_CONTEXT*) ListDictionary_Remove(smartcard->rgSCardContextList, key); + void* key = (void*)(size_t)operation->hContext; + pContext = (SMARTCARD_CONTEXT*)ListDictionary_Remove(smartcard->rgSCardContextList, key); smartcard_context_free(pContext); } else { - WLog_ERR(TAG, "SCardReleaseContext failed with error %"PRId32"", status); - return status; + return log_status_error(TAG, "SCardReleaseContext", ret.ReturnCode); } smartcard_trace_long_return(smartcard, &ret, "ReleaseContext"); @@ -306,7 +321,7 @@ static LONG smartcard_ReleaseContext_Call(SMARTCARD_DEVICE* smartcard, } static LONG smartcard_IsValidContext_Decode(SMARTCARD_DEVICE* smartcard, - SMARTCARD_OPERATION* operation) + SMARTCARD_OPERATION* operation) { LONG status; Context_Call* call; @@ -316,32 +331,24 @@ static LONG smartcard_IsValidContext_Decode(SMARTCARD_DEVICE* smartcard, if (!call) return STATUS_NO_MEMORY; - if ((status = smartcard_unpack_context_call(smartcard, irp->input, call))) - WLog_ERR(TAG, "smartcard_unpack_context_call failed with error %"PRId32"", status); + status = smartcard_unpack_context_call(smartcard, irp->input, call, "IsValidContext"); - smartcard_trace_context_call(smartcard, call, "IsValidContext"); operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); return status; } static LONG smartcard_IsValidContext_Call(SMARTCARD_DEVICE* smartcard, - SMARTCARD_OPERATION* operation) + SMARTCARD_OPERATION* operation) { - LONG status; Long_Return ret; - if ((status = ret.ReturnCode = SCardIsValidContext(operation->hContext))) - { - WLog_ERR(TAG, "SCardIsValidContext failed with error %"PRId32"", status); - return status; - } - + ret.ReturnCode = SCardIsValidContext(operation->hContext); smartcard_trace_long_return(smartcard, &ret, "IsValidContext"); return ret.ReturnCode; } static LONG smartcard_ListReaderGroupsA_Decode(SMARTCARD_DEVICE* smartcard, - SMARTCARD_OPERATION* operation) + SMARTCARD_OPERATION* operation) { LONG status; ListReaderGroups_Call* call; @@ -351,14 +358,14 @@ static LONG smartcard_ListReaderGroupsA_Decode(SMARTCARD_DEVICE* smartcard, if (!call) return STATUS_NO_MEMORY; - status = smartcard_unpack_list_reader_groups_call(smartcard, irp->input, call); - smartcard_trace_list_reader_groups_call(smartcard, call, FALSE); + status = smartcard_unpack_list_reader_groups_call(smartcard, irp->input, call, FALSE); + operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); return status; } static LONG smartcard_ListReaderGroupsA_Call(SMARTCARD_DEVICE* smartcard, - SMARTCARD_OPERATION* operation) + SMARTCARD_OPERATION* operation) { LONG status; ListReaderGroups_Return ret; @@ -366,16 +373,15 @@ static LONG smartcard_ListReaderGroupsA_Call(SMARTCARD_DEVICE* smartcard, DWORD cchGroups = 0; IRP* irp = operation->irp; cchGroups = SCARD_AUTOALLOCATE; - status = ret.ReturnCode = SCardListReaderGroupsA(operation->hContext, (LPSTR) &mszGroups, - &cchGroups); - ret.msz = (BYTE*) mszGroups; + status = ret.ReturnCode = + SCardListReaderGroupsA(operation->hContext, (LPSTR)&mszGroups, &cchGroups); + ret.msz = (BYTE*)mszGroups; ret.cBytes = cchGroups; if (status != SCARD_S_SUCCESS) return status; - smartcard_trace_list_reader_groups_return(smartcard, &ret, FALSE); - status = smartcard_pack_list_reader_groups_return(smartcard, irp->output, &ret); + status = smartcard_pack_list_reader_groups_return(smartcard, irp->output, &ret, FALSE); if (status != SCARD_S_SUCCESS) return status; @@ -387,7 +393,7 @@ static LONG smartcard_ListReaderGroupsA_Call(SMARTCARD_DEVICE* smartcard, } static LONG smartcard_ListReaderGroupsW_Decode(SMARTCARD_DEVICE* smartcard, - SMARTCARD_OPERATION* operation) + SMARTCARD_OPERATION* operation) { LONG status; ListReaderGroups_Call* call; @@ -397,14 +403,14 @@ static LONG smartcard_ListReaderGroupsW_Decode(SMARTCARD_DEVICE* smartcard, if (!call) return STATUS_NO_MEMORY; - status = smartcard_unpack_list_reader_groups_call(smartcard, irp->input, call); - smartcard_trace_list_reader_groups_call(smartcard, call, TRUE); + status = smartcard_unpack_list_reader_groups_call(smartcard, irp->input, call, TRUE); + operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); return status; } static LONG smartcard_ListReaderGroupsW_Call(SMARTCARD_DEVICE* smartcard, - SMARTCARD_OPERATION* operation) + SMARTCARD_OPERATION* operation) { LONG status; ListReaderGroups_Return ret; @@ -412,16 +418,15 @@ static LONG smartcard_ListReaderGroupsW_Call(SMARTCARD_DEVICE* smartcard, DWORD cchGroups = 0; IRP* irp = operation->irp; cchGroups = SCARD_AUTOALLOCATE; - status = ret.ReturnCode = SCardListReaderGroupsW(operation->hContext, (LPWSTR) &mszGroups, - &cchGroups); - ret.msz = (BYTE*) mszGroups; + status = ret.ReturnCode = + SCardListReaderGroupsW(operation->hContext, (LPWSTR)&mszGroups, &cchGroups); + ret.msz = (BYTE*)mszGroups; ret.cBytes = cchGroups; if (status != SCARD_S_SUCCESS) return status; - smartcard_trace_list_reader_groups_return(smartcard, &ret, TRUE); - status = smartcard_pack_list_reader_groups_return(smartcard, irp->output, &ret); + status = smartcard_pack_list_reader_groups_return(smartcard, irp->output, &ret, TRUE); if (status != SCARD_S_SUCCESS) return status; @@ -457,7 +462,7 @@ static DWORD filter_device_by_name_a(wLinkedList* list, LPSTR* mszReaders, DWORD { size_t rpos = 0, wpos = 0; - if (LinkedList_Count(list) < 1) + if (*mszReaders == NULL || LinkedList_Count(list) < 1) return cchReaders; do @@ -465,17 +470,17 @@ static DWORD filter_device_by_name_a(wLinkedList* list, LPSTR* mszReaders, DWORD LPCSTR rreader = &(*mszReaders)[rpos]; LPSTR wreader = &(*mszReaders)[wpos]; size_t readerLen = strnlen(rreader, cchReaders - rpos); + rpos += readerLen + 1; if (filter_match(list, rreader, readerLen)) { if (rreader != wreader) - memmove(wreader, rreader, readerLen); + memmove(wreader, rreader, readerLen + 1); wpos += readerLen + 1; } - } - while (rpos < cchReaders); + } while (rpos < cchReaders); /* this string must be double 0 terminated */ if (rpos != wpos) @@ -486,26 +491,30 @@ static DWORD filter_device_by_name_a(wLinkedList* list, LPSTR* mszReaders, DWORD (*mszReaders)[wpos++] = '\0'; } - return wpos; + return (DWORD)wpos; } static DWORD filter_device_by_name_w(wLinkedList* list, LPWSTR* mszReaders, DWORD cchReaders) { + int res; DWORD rc; - LPSTR readers; + LPSTR readers = NULL; if (LinkedList_Count(list) < 1) return cchReaders; - if (ConvertFromUnicode(CP_UTF8, 0, *mszReaders, (int)cchReaders, &readers, 0, NULL, - NULL) != cchReaders) + res = ConvertFromUnicode(CP_UTF8, 0, *mszReaders, (int)cchReaders, &readers, 0, NULL, NULL); + + /* When res==0, readers may have been set to NULL by ConvertFromUnicode */ + if ((res < 0) || ((DWORD)res != cchReaders) || (readers == 0)) return 0; free(*mszReaders); *mszReaders = NULL; rc = filter_device_by_name_a(list, &readers, cchReaders); + res = ConvertToUnicode(CP_UTF8, 0, readers, (int)rc, mszReaders, 0); - if (ConvertToUnicode(CP_UTF8, 0, readers, (int)rc, mszReaders, 0) != rc) + if ((res < 0) || ((DWORD)res != rc)) rc = 0; free(readers); @@ -513,7 +522,7 @@ static DWORD filter_device_by_name_w(wLinkedList* list, LPWSTR* mszReaders, DWOR } static LONG smartcard_ListReadersA_Decode(SMARTCARD_DEVICE* smartcard, - SMARTCARD_OPERATION* operation) + SMARTCARD_OPERATION* operation) { LONG status; ListReaders_Call* call; @@ -523,10 +532,8 @@ static LONG smartcard_ListReadersA_Decode(SMARTCARD_DEVICE* smartcard, if (!call) return STATUS_NO_MEMORY; - if ((status = smartcard_unpack_list_readers_call(smartcard, irp->input, call))) - WLog_ERR(TAG, "smartcard_unpack_list_readers_call failed with error %"PRId32"", status); + status = smartcard_unpack_list_readers_call(smartcard, irp->input, call, FALSE); - smartcard_trace_list_readers_call(smartcard, call, FALSE); operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); return status; } @@ -540,11 +547,8 @@ static LONG smartcard_ListReadersA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_O IRP* irp = operation->irp; ListReaders_Call* call = operation->call; cchReaders = SCARD_AUTOALLOCATE; - status = ret.ReturnCode = SCardListReadersA(operation->hContext, (LPCSTR) call->mszGroups, - (LPSTR) &mszReaders, &cchReaders); - cchReaders = filter_device_by_name_a(smartcard->names, &mszReaders, cchReaders); - ret.msz = (BYTE*) mszReaders; - ret.cBytes = cchReaders; + status = ret.ReturnCode = SCardListReadersA(operation->hContext, (LPCSTR)call->mszGroups, + (LPSTR)&mszReaders, &cchReaders); if (call->mszGroups) { @@ -552,18 +556,19 @@ static LONG smartcard_ListReadersA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_O call->mszGroups = NULL; } - if (status) + if (status != SCARD_S_SUCCESS) { - WLog_ERR(TAG, "SCardListReadersA failed with error %"PRId32"", status); - return status; + return log_status_error(TAG, "SCardListReadersA", status); } - smartcard_trace_list_readers_return(smartcard, &ret, FALSE); + cchReaders = filter_device_by_name_a(smartcard->names, &mszReaders, cchReaders); + ret.msz = (BYTE*)mszReaders; + ret.cBytes = cchReaders; - if ((status = smartcard_pack_list_readers_return(smartcard, irp->output, &ret))) + status = smartcard_pack_list_readers_return(smartcard, irp->output, &ret, FALSE); + if (status != SCARD_S_SUCCESS) { - WLog_ERR(TAG, "smartcard_pack_list_readers_return failed with error %"PRId32"", status); - return status; + return log_status_error(TAG, "smartcard_pack_list_readers_return", status); } if (mszReaders) @@ -576,7 +581,7 @@ static LONG smartcard_ListReadersA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_O } static LONG smartcard_ListReadersW_Decode(SMARTCARD_DEVICE* smartcard, - SMARTCARD_OPERATION* operation) + SMARTCARD_OPERATION* operation) { LONG status; ListReaders_Call* call; @@ -586,10 +591,110 @@ static LONG smartcard_ListReadersW_Decode(SMARTCARD_DEVICE* smartcard, if (!call) return STATUS_NO_MEMORY; - if ((status = smartcard_unpack_list_readers_call(smartcard, irp->input, call))) - WLog_ERR(TAG, "smartcard_unpack_list_readers_call failed with error %"PRId32"", status); + status = smartcard_unpack_list_readers_call(smartcard, irp->input, call, TRUE); + + operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); + return status; +} + +static LONG smartcard_context_and_two_strings_a_Decode(SMARTCARD_DEVICE* smartcard, + SMARTCARD_OPERATION* operation) +{ + LONG status; + ContextAndTwoStringA_Call* call; + IRP* irp = operation->irp; + operation->call = call = calloc(1, sizeof(ContextAndTwoStringA_Call)); + + if (!call) + return STATUS_NO_MEMORY; + + status = smartcard_unpack_context_and_two_strings_a_call(smartcard, irp->input, call); + + operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); + return status; +} + +static LONG smartcard_context_and_two_strings_w_Decode(SMARTCARD_DEVICE* smartcard, + SMARTCARD_OPERATION* operation) +{ + LONG status; + ContextAndTwoStringW_Call* call; + IRP* irp = operation->irp; + operation->call = call = calloc(1, sizeof(ContextAndTwoStringW_Call)); + + if (!call) + return STATUS_NO_MEMORY; + + status = smartcard_unpack_context_and_two_strings_w_call(smartcard, irp->input, call); + + operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); + return status; +} + +static LONG smartcard_context_and_string_a_Decode(SMARTCARD_DEVICE* smartcard, + SMARTCARD_OPERATION* operation) +{ + LONG status; + ContextAndStringA_Call* call; + IRP* irp = operation->irp; + operation->call = call = calloc(1, sizeof(ContextAndStringA_Call)); + + if (!call) + return STATUS_NO_MEMORY; + + status = smartcard_unpack_context_and_string_a_call(smartcard, irp->input, call); + + operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); + return status; +} + +static LONG smartcard_context_and_string_w_Decode(SMARTCARD_DEVICE* smartcard, + SMARTCARD_OPERATION* operation) +{ + LONG status; + ContextAndStringW_Call* call; + IRP* irp = operation->irp; + operation->call = call = calloc(1, sizeof(ContextAndStringW_Call)); + + if (!call) + return STATUS_NO_MEMORY; + + status = smartcard_unpack_context_and_string_w_call(smartcard, irp->input, call); + + operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); + return status; +} + +static LONG smartcard_LocateCardsA_Decode(SMARTCARD_DEVICE* smartcard, + SMARTCARD_OPERATION* operation) +{ + LONG status; + LocateCardsA_Call* call; + IRP* irp = operation->irp; + operation->call = call = calloc(1, sizeof(LocateCardsA_Call)); + + if (!call) + return STATUS_NO_MEMORY; + + status = smartcard_unpack_locate_cards_a_call(smartcard, irp->input, call); + + operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); + return status; +} + +static LONG smartcard_LocateCardsW_Decode(SMARTCARD_DEVICE* smartcard, + SMARTCARD_OPERATION* operation) +{ + LONG status; + LocateCardsW_Call* call; + IRP* irp = operation->irp; + operation->call = call = calloc(1, sizeof(LocateCardsW_Call)); + + if (!call) + return STATUS_NO_MEMORY; + + status = smartcard_unpack_locate_cards_w_call(smartcard, irp->input, call); - smartcard_trace_list_readers_call(smartcard, call, TRUE); operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); return status; } @@ -598,16 +703,25 @@ static LONG smartcard_ListReadersW_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_O { LONG status; ListReaders_Return ret; - LPWSTR mszReaders = NULL; DWORD cchReaders = 0; IRP* irp = operation->irp; ListReaders_Call* call = operation->call; + union { + const BYTE* bp; + const char* sz; + const WCHAR* wz; + } string; + union { + WCHAR** ppw; + WCHAR* pw; + CHAR* pc; + BYTE* pb; + } mszReaders; + + string.bp = call->mszGroups; cchReaders = SCARD_AUTOALLOCATE; - status = ret.ReturnCode = SCardListReadersW(operation->hContext, - (LPCWSTR) call->mszGroups, (LPWSTR) &mszReaders, &cchReaders); - cchReaders = filter_device_by_name_w(smartcard->names, &mszReaders, cchReaders); - ret.msz = (BYTE*) mszReaders; - ret.cBytes = cchReaders * 2; + status = ret.ReturnCode = + SCardListReadersW(operation->hContext, string.wz, (LPWSTR)&mszReaders.pw, &cchReaders); if (call->mszGroups) { @@ -616,22 +730,471 @@ static LONG smartcard_ListReadersW_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_O } if (status != SCARD_S_SUCCESS) - { - WLog_ERR(TAG, "SCardListReadersW failed with error %"PRId32"", status); + return log_status_error(TAG, "SCardListReadersW", status); + + cchReaders = filter_device_by_name_w(smartcard->names, &mszReaders.pw, cchReaders); + ret.msz = mszReaders.pb; + ret.cBytes = cchReaders; + status = smartcard_pack_list_readers_return(smartcard, irp->output, &ret, TRUE); + + if (mszReaders.pb) + SCardFreeMemory(operation->hContext, mszReaders.pb); + + if (status != SCARD_S_SUCCESS) + return status; + + return ret.ReturnCode; +} + +static LONG smartcard_IntroduceReaderGroupA_Call(SMARTCARD_DEVICE* smartcard, + SMARTCARD_OPERATION* operation) +{ + Long_Return ret; + ContextAndStringA_Call* call = operation->call; + ret.ReturnCode = SCardIntroduceReaderGroupA(operation->hContext, call->sz); + log_status_error(TAG, "SCardIntroduceReaderGroupA", ret.ReturnCode); + if (call->sz) + { + free(call->sz); + call->sz = NULL; + } + + smartcard_trace_long_return(smartcard, &ret, "IntroduceReaderGroupA"); + return ret.ReturnCode; +} + +static LONG smartcard_IntroduceReaderGroupW_Call(SMARTCARD_DEVICE* smartcard, + SMARTCARD_OPERATION* operation) +{ + Long_Return ret; + ContextAndStringW_Call* call = operation->call; + ret.ReturnCode = SCardIntroduceReaderGroupW(operation->hContext, call->sz); + log_status_error(TAG, "SCardIntroduceReaderGroupW", ret.ReturnCode); + if (call->sz) + { + free(call->sz); + call->sz = NULL; + } + + smartcard_trace_long_return(smartcard, &ret, "IntroduceReaderGroupW"); + return ret.ReturnCode; +} + +static LONG smartcard_IntroduceReaderA_Call(SMARTCARD_DEVICE* smartcard, + SMARTCARD_OPERATION* operation) +{ + Long_Return ret; + ContextAndTwoStringA_Call* call = operation->call; + ret.ReturnCode = SCardIntroduceReaderA(operation->hContext, call->sz1, call->sz2); + log_status_error(TAG, "SCardIntroduceReaderA", ret.ReturnCode); + free(call->sz1); + call->sz1 = NULL; + free(call->sz2); + call->sz2 = NULL; + + smartcard_trace_long_return(smartcard, &ret, "IntroduceReaderA"); + return ret.ReturnCode; +} + +static LONG smartcard_IntroduceReaderW_Call(SMARTCARD_DEVICE* smartcard, + SMARTCARD_OPERATION* operation) +{ + Long_Return ret; + ContextAndTwoStringW_Call* call = operation->call; + ret.ReturnCode = SCardIntroduceReaderW(operation->hContext, call->sz1, call->sz2); + log_status_error(TAG, "SCardIntroduceReaderW", ret.ReturnCode); + free(call->sz1); + call->sz1 = NULL; + free(call->sz2); + call->sz2 = NULL; + + smartcard_trace_long_return(smartcard, &ret, "IntroduceReaderW"); + return ret.ReturnCode; +} + +static LONG smartcard_ForgetReaderA_Call(SMARTCARD_DEVICE* smartcard, + SMARTCARD_OPERATION* operation) +{ + Long_Return ret; + ContextAndStringA_Call* call = operation->call; + ret.ReturnCode = SCardForgetReaderA(operation->hContext, call->sz); + log_status_error(TAG, "SCardForgetReaderA", ret.ReturnCode); + if (call->sz) + { + free(call->sz); + call->sz = NULL; + } + + smartcard_trace_long_return(smartcard, &ret, "SCardForgetReaderA"); + return ret.ReturnCode; +} + +static LONG smartcard_ForgetReaderW_Call(SMARTCARD_DEVICE* smartcard, + SMARTCARD_OPERATION* operation) +{ + Long_Return ret; + ContextAndStringW_Call* call = operation->call; + ret.ReturnCode = SCardForgetReaderW(operation->hContext, call->sz); + log_status_error(TAG, "SCardForgetReaderW", ret.ReturnCode); + if (call->sz) + { + free(call->sz); + call->sz = NULL; + } + + smartcard_trace_long_return(smartcard, &ret, "SCardForgetReaderW"); + return ret.ReturnCode; +} + +static LONG smartcard_AddReaderToGroupA_Call(SMARTCARD_DEVICE* smartcard, + SMARTCARD_OPERATION* operation) +{ + Long_Return ret; + ContextAndTwoStringA_Call* call = operation->call; + ret.ReturnCode = SCardAddReaderToGroupA(operation->hContext, call->sz1, call->sz2); + log_status_error(TAG, "SCardAddReaderToGroupA", ret.ReturnCode); + free(call->sz1); + call->sz1 = NULL; + free(call->sz2); + call->sz2 = NULL; + + smartcard_trace_long_return(smartcard, &ret, "SCardAddReaderToGroupA"); + return ret.ReturnCode; +} + +static LONG smartcard_AddReaderToGroupW_Call(SMARTCARD_DEVICE* smartcard, + SMARTCARD_OPERATION* operation) +{ + Long_Return ret; + ContextAndTwoStringW_Call* call = operation->call; + ret.ReturnCode = SCardAddReaderToGroupW(operation->hContext, call->sz1, call->sz2); + log_status_error(TAG, "SCardAddReaderToGroupW", ret.ReturnCode); + free(call->sz1); + call->sz1 = NULL; + free(call->sz2); + call->sz2 = NULL; + + smartcard_trace_long_return(smartcard, &ret, "SCardAddReaderToGroupA"); + return ret.ReturnCode; +} + +static LONG smartcard_RemoveReaderFromGroupA_Call(SMARTCARD_DEVICE* smartcard, + SMARTCARD_OPERATION* operation) +{ + Long_Return ret; + ContextAndTwoStringA_Call* call = operation->call; + ret.ReturnCode = SCardRemoveReaderFromGroupA(operation->hContext, call->sz1, call->sz2); + log_status_error(TAG, "SCardRemoveReaderFromGroupA", ret.ReturnCode); + free(call->sz1); + call->sz1 = NULL; + free(call->sz2); + call->sz2 = NULL; + + smartcard_trace_long_return(smartcard, &ret, "SCardRemoveReaderFromGroupA"); + return ret.ReturnCode; +} + +static LONG smartcard_RemoveReaderFromGroupW_Call(SMARTCARD_DEVICE* smartcard, + SMARTCARD_OPERATION* operation) +{ + Long_Return ret; + ContextAndTwoStringW_Call* call = operation->call; + ret.ReturnCode = SCardRemoveReaderFromGroupW(operation->hContext, call->sz1, call->sz2); + log_status_error(TAG, "SCardRemoveReaderFromGroupW", ret.ReturnCode); + free(call->sz1); + call->sz1 = NULL; + free(call->sz2); + call->sz2 = NULL; + + smartcard_trace_long_return(smartcard, &ret, "SCardRemoveReaderFromGroupW"); + return ret.ReturnCode; +} + +static LONG smartcard_LocateCardsA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERATION* operation) +{ + UINT32 x; + LONG status; + LocateCards_Return ret; + LocateCardsA_Call* call = operation->call; + IRP* irp = operation->irp; + + ret.ReturnCode = SCardLocateCardsA(operation->hContext, call->mszCards, call->rgReaderStates, + call->cReaders); + log_status_error(TAG, "SCardLocateCardsA", ret.ReturnCode); + ret.cReaders = call->cReaders; + ret.rgReaderStates = NULL; + + free(call->mszCards); + + if (ret.cReaders > 0) + { + ret.rgReaderStates = (ReaderState_Return*)calloc(ret.cReaders, sizeof(ReaderState_Return)); + + if (!ret.rgReaderStates) + return STATUS_NO_MEMORY; + } + + for (x = 0; x < ret.cReaders; x++) + { + ret.rgReaderStates[x].dwCurrentState = call->rgReaderStates[x].dwCurrentState; + ret.rgReaderStates[x].dwEventState = call->rgReaderStates[x].dwEventState; + ret.rgReaderStates[x].cbAtr = call->rgReaderStates[x].cbAtr; + CopyMemory(&(ret.rgReaderStates[x].rgbAtr), &(call->rgReaderStates[x].rgbAtr), + sizeof(ret.rgReaderStates[x].rgbAtr)); + } + + status = smartcard_pack_locate_cards_return(smartcard, irp->output, &ret); + + for (x = 0; x < call->cReaders; x++) + { + SCARD_READERSTATEA* state = &call->rgReaderStates[x]; + free(state->szReader); + } + + free(call->rgReaderStates); + + if (status != SCARD_S_SUCCESS) + return status; + + return ret.ReturnCode; +} + +static LONG smartcard_LocateCardsW_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERATION* operation) +{ + UINT32 x; + LONG status; + LocateCards_Return ret; + LocateCardsW_Call* call = operation->call; + IRP* irp = operation->irp; + + ret.ReturnCode = SCardLocateCardsW(operation->hContext, call->mszCards, call->rgReaderStates, + call->cReaders); + log_status_error(TAG, "SCardLocateCardsW", ret.ReturnCode); + ret.cReaders = call->cReaders; + ret.rgReaderStates = NULL; + + free(call->mszCards); + + if (ret.cReaders > 0) + { + ret.rgReaderStates = (ReaderState_Return*)calloc(ret.cReaders, sizeof(ReaderState_Return)); + + if (!ret.rgReaderStates) + return STATUS_NO_MEMORY; + } + + for (x = 0; x < ret.cReaders; x++) + { + ret.rgReaderStates[x].dwCurrentState = call->rgReaderStates[x].dwCurrentState; + ret.rgReaderStates[x].dwEventState = call->rgReaderStates[x].dwEventState; + ret.rgReaderStates[x].cbAtr = call->rgReaderStates[x].cbAtr; + CopyMemory(&(ret.rgReaderStates[x].rgbAtr), &(call->rgReaderStates[x].rgbAtr), + sizeof(ret.rgReaderStates[x].rgbAtr)); + } + + status = smartcard_pack_locate_cards_return(smartcard, irp->output, &ret); + + for (x = 0; x < call->cReaders; x++) + { + SCARD_READERSTATEW* state = &call->rgReaderStates[x]; + free(state->szReader); + } + + free(call->rgReaderStates); + + if (status != SCARD_S_SUCCESS) + return status; + + return ret.ReturnCode; +} + +static LONG smartcard_ReadCacheA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERATION* operation) +{ + LONG status; + ReadCache_Return ret = { 0 }; + ReadCacheA_Call* call = operation->call; + IRP* irp = operation->irp; + BOOL autoalloc = (call->Common.cbDataLen == SCARD_AUTOALLOCATE); + + if (!call->Common.fPbDataIsNULL) + { + ret.cbDataLen = call->Common.cbDataLen; + if (!autoalloc) + { + ret.pbData = malloc(ret.cbDataLen); + if (!ret.pbData) + return SCARD_F_INTERNAL_ERROR; + } + } + + if (autoalloc) + ret.ReturnCode = SCardReadCacheA(operation->hContext, call->Common.CardIdentifier, + call->Common.FreshnessCounter, call->szLookupName, + (BYTE*)&ret.pbData, &ret.cbDataLen); + else + ret.ReturnCode = SCardReadCacheA(operation->hContext, call->Common.CardIdentifier, + call->Common.FreshnessCounter, call->szLookupName, + ret.pbData, &ret.cbDataLen); + if ((ret.ReturnCode != SCARD_W_CACHE_ITEM_NOT_FOUND) && + (ret.ReturnCode != SCARD_W_CACHE_ITEM_STALE)) + { + log_status_error(TAG, "SCardReadCacheA", ret.ReturnCode); + } + free(call->szLookupName); + free(call->Common.CardIdentifier); + + status = smartcard_pack_read_cache_return(smartcard, irp->output, &ret); + if (autoalloc) + SCardFreeMemory(operation->hContext, ret.pbData); + else + free(ret.pbData); + if (status != SCARD_S_SUCCESS) + return status; + + return ret.ReturnCode; +} + +static LONG smartcard_ReadCacheW_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERATION* operation) +{ + LONG status; + ReadCache_Return ret = { 0 }; + ReadCacheW_Call* call = operation->call; + IRP* irp = operation->irp; + BOOL autoalloc = (call->Common.cbDataLen == SCARD_AUTOALLOCATE); + if (!call->Common.fPbDataIsNULL) + { + ret.cbDataLen = call->Common.cbDataLen; + if (!autoalloc) + { + ret.pbData = malloc(ret.cbDataLen); + if (!ret.pbData) + return SCARD_F_INTERNAL_ERROR; + } + } + + if (autoalloc) + ret.ReturnCode = SCardReadCacheW(operation->hContext, call->Common.CardIdentifier, + call->Common.FreshnessCounter, call->szLookupName, + (BYTE*)&ret.pbData, &ret.cbDataLen); + else + ret.ReturnCode = SCardReadCacheW(operation->hContext, call->Common.CardIdentifier, + call->Common.FreshnessCounter, call->szLookupName, + ret.pbData, &ret.cbDataLen); + if ((ret.ReturnCode != SCARD_W_CACHE_ITEM_NOT_FOUND) && + (ret.ReturnCode != SCARD_W_CACHE_ITEM_STALE)) + { + log_status_error(TAG, "SCardReadCacheA", ret.ReturnCode); + } + free(call->szLookupName); + free(call->Common.CardIdentifier); + + status = smartcard_pack_read_cache_return(smartcard, irp->output, &ret); + if (autoalloc) + SCardFreeMemory(operation->hContext, ret.pbData); + else + free(ret.pbData); + if (status != SCARD_S_SUCCESS) + return status; + + return ret.ReturnCode; +} + +static LONG smartcard_WriteCacheA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERATION* operation) +{ + Long_Return ret; + WriteCacheA_Call* call = operation->call; + + ret.ReturnCode = SCardWriteCacheA(operation->hContext, call->Common.CardIdentifier, + call->Common.FreshnessCounter, call->szLookupName, + call->Common.pbData, call->Common.cbDataLen); + log_status_error(TAG, "SCardWriteCacheA", ret.ReturnCode); + free(call->szLookupName); + free(call->Common.CardIdentifier); + free(call->Common.pbData); + + smartcard_trace_long_return(smartcard, &ret, "SCardWriteCacheA"); + return ret.ReturnCode; +} + +static LONG smartcard_WriteCacheW_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERATION* operation) +{ + Long_Return ret; + WriteCacheW_Call* call = operation->call; + + ret.ReturnCode = SCardWriteCacheW(operation->hContext, call->Common.CardIdentifier, + call->Common.FreshnessCounter, call->szLookupName, + call->Common.pbData, call->Common.cbDataLen); + log_status_error(TAG, "SCardWriteCacheW", ret.ReturnCode); + free(call->szLookupName); + free(call->Common.CardIdentifier); + free(call->Common.pbData); + + smartcard_trace_long_return(smartcard, &ret, "SCardWriteCacheW"); + return ret.ReturnCode; +} + +static LONG smartcard_GetTransmitCount_Call(SMARTCARD_DEVICE* smartcard, + SMARTCARD_OPERATION* operation) +{ + LONG status; + GetTransmitCount_Return ret; + IRP* irp = operation->irp; + + ret.ReturnCode = SCardGetTransmitCount(operation->hContext, &ret.cTransmitCount); + log_status_error(TAG, "SCardGetTransmitCount", ret.ReturnCode); + status = smartcard_pack_get_transmit_count_return(smartcard, irp->output, &ret); + if (status != SCARD_S_SUCCESS) + return status; + + return ret.ReturnCode; +} + +static LONG smartcard_ReleaseStartedEvent_Call(SMARTCARD_DEVICE* smartcard, + SMARTCARD_OPERATION* operation) +{ + WINPR_UNUSED(smartcard); + WINPR_UNUSED(operation); + + WLog_WARN(TAG, "According to [MS-RDPESC] 3.1.4 Message Processing Events and Sequencing Rules " + "this is not supported?!?"); + return SCARD_E_UNSUPPORTED_FEATURE; +} + +static LONG smartcard_GetReaderIcon_Call(SMARTCARD_DEVICE* smartcard, + SMARTCARD_OPERATION* operation) +{ + LONG status; + GetReaderIcon_Return ret = { 0 }; + GetReaderIcon_Call* call = operation->call; + IRP* irp = operation->irp; + + ret.cbDataLen = SCARD_AUTOALLOCATE; + ret.ReturnCode = SCardGetReaderIconW(operation->hContext, call->szReaderName, + (LPBYTE)&ret.pbData, &ret.cbDataLen); + log_status_error(TAG, "SCardGetReaderIconW", ret.ReturnCode); + free(call->szReaderName); + status = smartcard_pack_get_reader_icon_return(smartcard, irp->output, &ret); + SCardFreeMemory(operation->hContext, ret.pbData); + if (status != SCARD_S_SUCCESS) return status; - } - smartcard_trace_list_readers_return(smartcard, &ret, TRUE); + return ret.ReturnCode; +} - if ((status = smartcard_pack_list_readers_return(smartcard, irp->output, &ret))) - { - WLog_ERR(TAG, "smartcard_pack_list_readers_return failed with error %"PRId32"", status); - return status; - } +static LONG smartcard_GetDeviceTypeId_Call(SMARTCARD_DEVICE* smartcard, + SMARTCARD_OPERATION* operation) +{ + LONG status; + GetDeviceTypeId_Return ret; + GetDeviceTypeId_Call* call = operation->call; + IRP* irp = operation->irp; - if (mszReaders) - SCardFreeMemory(operation->hContext, mszReaders); + ret.ReturnCode = + SCardGetDeviceTypeIdW(operation->hContext, call->szReaderName, &ret.dwDeviceId); + log_status_error(TAG, "SCardGetDeviceTypeIdW", ret.ReturnCode); + free(call->szReaderName); + status = smartcard_pack_device_type_id_return(smartcard, irp->output, &ret); if (status != SCARD_S_SUCCESS) return status; @@ -639,7 +1202,7 @@ static LONG smartcard_ListReadersW_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_O } static LONG smartcard_GetStatusChangeA_Decode(SMARTCARD_DEVICE* smartcard, - SMARTCARD_OPERATION* operation) + SMARTCARD_OPERATION* operation) { LONG status; GetStatusChangeA_Call* call; @@ -649,33 +1212,29 @@ static LONG smartcard_GetStatusChangeA_Decode(SMARTCARD_DEVICE* smartcard, if (!call) return STATUS_NO_MEMORY; - if ((status = smartcard_unpack_get_status_change_a_call(smartcard, irp->input, call))) - { - WLog_ERR(TAG, "smartcard_unpack_get_status_change_a_call failed with error %"PRId32"", status); - return status; - } + status = smartcard_unpack_get_status_change_a_call(smartcard, irp->input, call); - smartcard_trace_get_status_change_a_call(smartcard, call); operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); return status; } static LONG smartcard_GetStatusChangeA_Call(SMARTCARD_DEVICE* smartcard, - SMARTCARD_OPERATION* operation) + SMARTCARD_OPERATION* operation) { UINT32 index; GetStatusChange_Return ret; LPSCARD_READERSTATEA rgReaderState = NULL; IRP* irp = operation->irp; GetStatusChangeA_Call* call = operation->call; - ret.ReturnCode = SCardGetStatusChangeA(operation->hContext, call->dwTimeOut, call->rgReaderStates, - call->cReaders); + ret.ReturnCode = SCardGetStatusChangeA(operation->hContext, call->dwTimeOut, + call->rgReaderStates, call->cReaders); + log_status_error(TAG, "SCardGetStatusChangeA", ret.ReturnCode); ret.cReaders = call->cReaders; ret.rgReaderStates = NULL; if (ret.cReaders > 0) { - ret.rgReaderStates = (ReaderState_Return*) calloc(ret.cReaders, sizeof(ReaderState_Return)); + ret.rgReaderStates = (ReaderState_Return*)calloc(ret.cReaders, sizeof(ReaderState_Return)); if (!ret.rgReaderStates) return STATUS_NO_MEMORY; @@ -686,11 +1245,11 @@ static LONG smartcard_GetStatusChangeA_Call(SMARTCARD_DEVICE* smartcard, ret.rgReaderStates[index].dwCurrentState = call->rgReaderStates[index].dwCurrentState; ret.rgReaderStates[index].dwEventState = call->rgReaderStates[index].dwEventState; ret.rgReaderStates[index].cbAtr = call->rgReaderStates[index].cbAtr; - CopyMemory(&(ret.rgReaderStates[index].rgbAtr), &(call->rgReaderStates[index].rgbAtr), 32); + CopyMemory(&(ret.rgReaderStates[index].rgbAtr), &(call->rgReaderStates[index].rgbAtr), + sizeof(ret.rgReaderStates[index].rgbAtr)); } - smartcard_trace_get_status_change_return(smartcard, &ret, FALSE); - smartcard_pack_get_status_change_return(smartcard, irp->output, &ret); + smartcard_pack_get_status_change_return(smartcard, irp->output, &ret, FALSE); if (call->rgReaderStates) { @@ -708,7 +1267,7 @@ static LONG smartcard_GetStatusChangeA_Call(SMARTCARD_DEVICE* smartcard, } static LONG smartcard_GetStatusChangeW_Decode(SMARTCARD_DEVICE* smartcard, - SMARTCARD_OPERATION* operation) + SMARTCARD_OPERATION* operation) { LONG status; GetStatusChangeW_Call* call; @@ -718,16 +1277,14 @@ static LONG smartcard_GetStatusChangeW_Decode(SMARTCARD_DEVICE* smartcard, if (!call) return STATUS_NO_MEMORY; - if ((status = smartcard_unpack_get_status_change_w_call(smartcard, irp->input, call))) - WLog_ERR(TAG, "smartcard_unpack_get_status_change_w_call failed with error %"PRId32"", status); + status = smartcard_unpack_get_status_change_w_call(smartcard, irp->input, call); - smartcard_trace_get_status_change_w_call(smartcard, call); operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); return status; } static LONG smartcard_GetStatusChangeW_Call(SMARTCARD_DEVICE* smartcard, - SMARTCARD_OPERATION* operation) + SMARTCARD_OPERATION* operation) { UINT32 index; GetStatusChange_Return ret; @@ -736,12 +1293,13 @@ static LONG smartcard_GetStatusChangeW_Call(SMARTCARD_DEVICE* smartcard, GetStatusChangeW_Call* call = operation->call; ret.ReturnCode = SCardGetStatusChangeW(operation->hContext, call->dwTimeOut, call->rgReaderStates, call->cReaders); + log_status_error(TAG, "SCardGetStatusChangeW", ret.ReturnCode); ret.cReaders = call->cReaders; ret.rgReaderStates = NULL; if (ret.cReaders > 0) { - ret.rgReaderStates = (ReaderState_Return*) calloc(ret.cReaders, sizeof(ReaderState_Return)); + ret.rgReaderStates = (ReaderState_Return*)calloc(ret.cReaders, sizeof(ReaderState_Return)); if (!ret.rgReaderStates) return STATUS_NO_MEMORY; @@ -752,11 +1310,11 @@ static LONG smartcard_GetStatusChangeW_Call(SMARTCARD_DEVICE* smartcard, ret.rgReaderStates[index].dwCurrentState = call->rgReaderStates[index].dwCurrentState; ret.rgReaderStates[index].dwEventState = call->rgReaderStates[index].dwEventState; ret.rgReaderStates[index].cbAtr = call->rgReaderStates[index].cbAtr; - CopyMemory(&(ret.rgReaderStates[index].rgbAtr), &(call->rgReaderStates[index].rgbAtr), 32); + CopyMemory(&(ret.rgReaderStates[index].rgbAtr), &(call->rgReaderStates[index].rgbAtr), + sizeof(ret.rgReaderStates[index].rgbAtr)); } - smartcard_trace_get_status_change_return(smartcard, &ret, TRUE); - smartcard_pack_get_status_change_return(smartcard, irp->output, &ret); + smartcard_pack_get_status_change_return(smartcard, irp->output, &ret, TRUE); if (call->rgReaderStates) { @@ -783,25 +1341,18 @@ static LONG smartcard_Cancel_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERA if (!call) return STATUS_NO_MEMORY; - if ((status = smartcard_unpack_context_call(smartcard, irp->input, call))) - WLog_ERR(TAG, "smartcard_unpack_context_call failed with error %"PRId32"", status); + status = smartcard_unpack_context_call(smartcard, irp->input, call, "Cancel"); - smartcard_trace_context_call(smartcard, call, "Cancel"); operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); return status; } static LONG smartcard_Cancel_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERATION* operation) { - LONG status; Long_Return ret; - if ((status = ret.ReturnCode = SCardCancel(operation->hContext))) - { - WLog_ERR(TAG, "SCardCancel failed with error %"PRId32"", status); - return status; - } - + ret.ReturnCode = SCardCancel(operation->hContext); + log_status_error(TAG, "SCardCancel", ret.ReturnCode); smartcard_trace_long_return(smartcard, &ret, "Cancel"); return ret.ReturnCode; } @@ -816,12 +1367,10 @@ static LONG smartcard_ConnectA_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPE if (!call) return STATUS_NO_MEMORY; - if ((status = smartcard_unpack_connect_a_call(smartcard, irp->input, call))) - WLog_ERR(TAG, "smartcard_unpack_connect_a_call failed with error %"PRId32"", status); + status = smartcard_unpack_connect_a_call(smartcard, irp->input, call); - smartcard_trace_connect_a_call(smartcard, call); - operation->hContext = smartcard_scard_context_native_from_redir(smartcard, - &(call->Common.hContext)); + operation->hContext = + smartcard_scard_context_native_from_redir(smartcard, &(call->Common.hContext)); return status; } @@ -839,24 +1388,15 @@ static LONG smartcard_ConnectA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERA call->Common.dwPreferredProtocols = SCARD_PROTOCOL_Tx; } - status = ret.ReturnCode = SCardConnectA(operation->hContext, (char*) call->szReader, - call->Common.dwShareMode, - call->Common.dwPreferredProtocols, &hCard, &ret.dwActiveProtocol); + status = ret.ReturnCode = + SCardConnectA(operation->hContext, (char*)call->szReader, call->Common.dwShareMode, + call->Common.dwPreferredProtocols, &hCard, &ret.dwActiveProtocol); smartcard_scard_context_native_to_redir(smartcard, &(ret.hContext), operation->hContext); smartcard_scard_handle_native_to_redir(smartcard, &(ret.hCard), hCard); - smartcard_trace_connect_return(smartcard, &ret); - - if (status) - { - WLog_ERR(TAG, "SCardConnectA failed with error %"PRId32"", status); - goto out_fail; - } - if ((status = smartcard_pack_connect_return(smartcard, irp->output, &ret))) - { - WLog_ERR(TAG, "smartcard_pack_connect_return failed with error %"PRId32"", status); + status = smartcard_pack_connect_return(smartcard, irp->output, &ret); + if (status != SCARD_S_SUCCESS) goto out_fail; - } status = ret.ReturnCode; out_fail: @@ -874,12 +1414,10 @@ static LONG smartcard_ConnectW_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPE if (!call) return STATUS_NO_MEMORY; - if ((status = smartcard_unpack_connect_w_call(smartcard, irp->input, call))) - WLog_ERR(TAG, "smartcard_unpack_connect_w_call failed with error %"PRId32"", status); + status = smartcard_unpack_connect_w_call(smartcard, irp->input, call); - smartcard_trace_connect_w_call(smartcard, call); - operation->hContext = smartcard_scard_context_native_from_redir(smartcard, - &(call->Common.hContext)); + operation->hContext = + smartcard_scard_context_native_from_redir(smartcard, &(call->Common.hContext)); return status; } @@ -897,24 +1435,15 @@ static LONG smartcard_ConnectW_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERA call->Common.dwPreferredProtocols = SCARD_PROTOCOL_Tx; } - status = ret.ReturnCode = SCardConnectW(operation->hContext, (WCHAR*) call->szReader, - call->Common.dwShareMode, - call->Common.dwPreferredProtocols, &hCard, &ret.dwActiveProtocol); + status = ret.ReturnCode = + SCardConnectW(operation->hContext, (WCHAR*)call->szReader, call->Common.dwShareMode, + call->Common.dwPreferredProtocols, &hCard, &ret.dwActiveProtocol); smartcard_scard_context_native_to_redir(smartcard, &(ret.hContext), operation->hContext); smartcard_scard_handle_native_to_redir(smartcard, &(ret.hCard), hCard); - smartcard_trace_connect_return(smartcard, &ret); - - if (status) - { - WLog_ERR(TAG, "SCardConnectW failed with error %"PRId32"", status); - goto out_fail; - } - if ((status = smartcard_pack_connect_return(smartcard, irp->output, &ret))) - { - WLog_ERR(TAG, "smartcard_pack_connect_return failed with error %"PRId32"", status); + status = smartcard_pack_connect_return(smartcard, irp->output, &ret); + if (status != SCARD_S_SUCCESS) goto out_fail; - } status = ret.ReturnCode; out_fail: @@ -932,10 +1461,8 @@ static LONG smartcard_Reconnect_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_OP if (!call) return STATUS_NO_MEMORY; - if ((status = smartcard_unpack_reconnect_call(smartcard, irp->input, call))) - WLog_ERR(TAG, "smartcard_unpack_reconnect_call failed with error %"PRId32"", status); + status = smartcard_unpack_reconnect_call(smartcard, irp->input, call); - smartcard_trace_reconnect_call(smartcard, call); operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); operation->hCard = smartcard_scard_handle_native_from_redir(smartcard, &(call->hCard)); return status; @@ -947,15 +1474,12 @@ static LONG smartcard_Reconnect_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPER Reconnect_Return ret; IRP* irp = operation->irp; Reconnect_Call* call = operation->call; - ret.ReturnCode = SCardReconnect(operation->hCard, call->dwShareMode, - call->dwPreferredProtocols, call->dwInitialization, &ret.dwActiveProtocol); - smartcard_trace_reconnect_return(smartcard, &ret); - - if ((status = smartcard_pack_reconnect_return(smartcard, irp->output, &ret))) - { - WLog_ERR(TAG, "smartcard_pack_reconnect_return failed with error %"PRId32"", status); + ret.ReturnCode = SCardReconnect(operation->hCard, call->dwShareMode, call->dwPreferredProtocols, + call->dwInitialization, &ret.dwActiveProtocol); + log_status_error(TAG, "SCardReconnect", ret.ReturnCode); + status = smartcard_pack_reconnect_return(smartcard, irp->output, &ret); + if (status != SCARD_S_SUCCESS) return status; - } return ret.ReturnCode; } @@ -970,10 +1494,8 @@ static LONG smartcard_Disconnect_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_O if (!call) return STATUS_NO_MEMORY; - if ((status = smartcard_unpack_hcard_and_disposition_call(smartcard, irp->input, call))) - WLog_ERR(TAG, "smartcard_unpack_hcard_and_disposition_call failed with error %"PRId32"", status); + status = smartcard_unpack_hcard_and_disposition_call(smartcard, irp->input, call, "Disconnect"); - smartcard_trace_hcard_and_disposition_call(smartcard, call, "Disconnect"); operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); operation->hCard = smartcard_scard_handle_native_from_redir(smartcard, &(call->hCard)); return status; @@ -981,26 +1503,18 @@ static LONG smartcard_Disconnect_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_O static LONG smartcard_Disconnect_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERATION* operation) { - LONG status; Long_Return ret; HCardAndDisposition_Call* call = operation->call; - if ((status = ret.ReturnCode = SCardDisconnect(operation->hCard, call->dwDisposition))) - { - WLog_ERR(TAG, "SCardDisconnect failed with error %"PRId32"", status); - return status; - } - + ret.ReturnCode = SCardDisconnect(operation->hCard, call->dwDisposition); + log_status_error(TAG, "SCardDisconnect", ret.ReturnCode); smartcard_trace_long_return(smartcard, &ret, "Disconnect"); - if (status != SCARD_S_SUCCESS) - return status; - return ret.ReturnCode; } static LONG smartcard_BeginTransaction_Decode(SMARTCARD_DEVICE* smartcard, - SMARTCARD_OPERATION* operation) + SMARTCARD_OPERATION* operation) { LONG status; HCardAndDisposition_Call* call; @@ -1010,32 +1524,27 @@ static LONG smartcard_BeginTransaction_Decode(SMARTCARD_DEVICE* smartcard, if (!call) return STATUS_NO_MEMORY; - if ((status = smartcard_unpack_hcard_and_disposition_call(smartcard, irp->input, call))) - WLog_ERR(TAG, "smartcard_unpack_hcard_and_disposition_call failed with error %"PRId32"", status); + status = smartcard_unpack_hcard_and_disposition_call(smartcard, irp->input, call, + "BeginTransaction"); - smartcard_trace_hcard_and_disposition_call(smartcard, call, "BeginTransaction"); operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); operation->hCard = smartcard_scard_handle_native_from_redir(smartcard, &(call->hCard)); return status; } static LONG smartcard_BeginTransaction_Call(SMARTCARD_DEVICE* smartcard, - SMARTCARD_OPERATION* operation) + SMARTCARD_OPERATION* operation) { Long_Return ret; - if ((ret.ReturnCode = SCardBeginTransaction(operation->hCard))) - { - WLog_ERR(TAG, "SCardBeginTransaction failed with error %"PRId32"", ret.ReturnCode); - return ret.ReturnCode; - } - + ret.ReturnCode = SCardBeginTransaction(operation->hCard); + log_status_error(TAG, "SCardBeginTransaction", ret.ReturnCode); smartcard_trace_long_return(smartcard, &ret, "BeginTransaction"); return ret.ReturnCode; } static LONG smartcard_EndTransaction_Decode(SMARTCARD_DEVICE* smartcard, - SMARTCARD_OPERATION* operation) + SMARTCARD_OPERATION* operation) { LONG status; HCardAndDisposition_Call* call; @@ -1045,27 +1554,22 @@ static LONG smartcard_EndTransaction_Decode(SMARTCARD_DEVICE* smartcard, if (!call) return STATUS_NO_MEMORY; - if ((status = smartcard_unpack_hcard_and_disposition_call(smartcard, irp->input, call))) - WLog_ERR(TAG, "smartcard_unpack_hcard_and_disposition_call failed with error %"PRId32"", status); + status = + smartcard_unpack_hcard_and_disposition_call(smartcard, irp->input, call, "EndTransaction"); - smartcard_trace_hcard_and_disposition_call(smartcard, call, "EndTransaction"); operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); operation->hCard = smartcard_scard_handle_native_from_redir(smartcard, &(call->hCard)); return status; } static LONG smartcard_EndTransaction_Call(SMARTCARD_DEVICE* smartcard, - SMARTCARD_OPERATION* operation) + SMARTCARD_OPERATION* operation) { Long_Return ret; HCardAndDisposition_Call* call = operation->call; - if ((ret.ReturnCode = SCardEndTransaction(operation->hCard, call->dwDisposition))) - { - WLog_ERR(TAG, "SCardEndTransaction failed with error %"PRId32"", ret.ReturnCode); - return ret.ReturnCode; - } - + ret.ReturnCode = SCardEndTransaction(operation->hCard, call->dwDisposition); + log_status_error(TAG, "SCardEndTransaction", ret.ReturnCode); smartcard_trace_long_return(smartcard, &ret, "EndTransaction"); return ret.ReturnCode; } @@ -1080,8 +1584,7 @@ static LONG smartcard_State_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERAT if (!call) return STATUS_NO_MEMORY; - if ((status = smartcard_unpack_state_call(smartcard, irp->input, call))) - WLog_ERR(TAG, "smartcard_unpack_state_call failed with error %"PRId32"", status); + status = smartcard_unpack_state_call(smartcard, irp->input, call); operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); operation->hCard = smartcard_scard_handle_native_from_redir(smartcard, &(call->hCard)); @@ -1094,14 +1597,13 @@ static LONG smartcard_State_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERATIO State_Return ret; IRP* irp = operation->irp; ret.cbAtrLen = SCARD_ATR_LENGTH; - ret.ReturnCode = SCardState(operation->hCard, &ret.dwState, &ret.dwProtocol, (BYTE*) &ret.rgAtr, + ret.ReturnCode = SCardState(operation->hCard, &ret.dwState, &ret.dwProtocol, (BYTE*)&ret.rgAtr, &ret.cbAtrLen); - if ((status = smartcard_pack_state_return(smartcard, irp->output, &ret))) - { - WLog_ERR(TAG, "smartcard_pack_state_return failed with error %"PRId32"", status); + log_status_error(TAG, "SCardState", ret.ReturnCode); + status = smartcard_pack_state_return(smartcard, irp->output, &ret); + if (status != SCARD_S_SUCCESS) return status; - } return ret.ReturnCode; } @@ -1116,10 +1618,8 @@ static LONG smartcard_StatusA_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPER if (!call) return STATUS_NO_MEMORY; - if ((status = smartcard_unpack_status_call(smartcard, irp->input, call))) - WLog_ERR(TAG, "smartcard_unpack_status_call failed with error %"PRId32"", status); + status = smartcard_unpack_status_call(smartcard, irp->input, call, FALSE); - smartcard_trace_status_call(smartcard, call, FALSE); operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); operation->hCard = smartcard_scard_handle_native_from_redir(smartcard, &(call->hCard)); return status; @@ -1134,7 +1634,7 @@ static LONG smartcard_StatusA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERAT LPSTR mszReaderNames = NULL; IRP* irp = operation->irp; Status_Call* call = operation->call; - ZeroMemory(ret.pbAtr, 32); + call->cbAtrLen = 32; cbAtrLen = call->cbAtrLen; @@ -1143,15 +1643,16 @@ static LONG smartcard_StatusA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERAT else cchReaderLen = SCARD_AUTOALLOCATE; - status = ret.ReturnCode = SCardStatusA(operation->hCard, - call->fmszReaderNamesIsNULL ? NULL : (LPSTR) &mszReaderNames, - &cchReaderLen, &ret.dwState, &ret.dwProtocol, - cbAtrLen ? (BYTE*) &ret.pbAtr : NULL, &cbAtrLen); + status = ret.ReturnCode = + SCardStatusA(operation->hCard, call->fmszReaderNamesIsNULL ? NULL : (LPSTR)&mszReaderNames, + &cchReaderLen, &ret.dwState, &ret.dwProtocol, + cbAtrLen ? (BYTE*)&ret.pbAtr : NULL, &cbAtrLen); + log_status_error(TAG, "SCardStatusA", status); if (status == SCARD_S_SUCCESS) { if (!call->fmszReaderNamesIsNULL) - ret.mszReaderNames = (BYTE*) mszReaderNames; + ret.mszReaderNames = (BYTE*)mszReaderNames; ret.cBytes = cchReaderLen; @@ -1159,19 +1660,13 @@ static LONG smartcard_StatusA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERAT ret.cbAtrLen = cbAtrLen; } - smartcard_trace_status_return(smartcard, &ret, FALSE); - - if ((status = smartcard_pack_status_return(smartcard, irp->output, &ret))) - { - WLog_ERR(TAG, "smartcard_pack_status_return failed with error %"PRId32"", status); - return status; - } + status = smartcard_pack_status_return(smartcard, irp->output, &ret, FALSE); if (mszReaderNames) - { SCardFreeMemory(operation->hContext, mszReaderNames); - } + if (status != SCARD_S_SUCCESS) + return status; return ret.ReturnCode; } @@ -1185,10 +1680,8 @@ static LONG smartcard_StatusW_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPER if (!call) return STATUS_NO_MEMORY; - if ((status = smartcard_unpack_status_call(smartcard, irp->input, call))) - WLog_ERR(TAG, "smartcard_unpack_status_call failed with error %"PRId32"", status); + status = smartcard_unpack_status_call(smartcard, irp->input, call, TRUE); - smartcard_trace_status_call(smartcard, call, TRUE); operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); operation->hCard = smartcard_scard_handle_native_from_redir(smartcard, &(call->hCard)); return status; @@ -1197,51 +1690,38 @@ static LONG smartcard_StatusW_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPER static LONG smartcard_StatusW_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERATION* operation) { LONG status; - Status_Return ret; - DWORD cchReaderLen = 0; + Status_Return ret = { 0 }; LPWSTR mszReaderNames = NULL; IRP* irp = operation->irp; Status_Call* call = operation->call; DWORD cbAtrLen; - if (call->cbAtrLen > 32) - call->cbAtrLen = 32; + /** + * [MS-RDPESC] + * According to 2.2.2.18 Status_Call cbAtrLen is unused an must be ignored upon receipt. + */ + cbAtrLen = call->cbAtrLen = 32; if (call->fmszReaderNamesIsNULL) - cchReaderLen = 0; + ret.cBytes = 0; else - cchReaderLen = SCARD_AUTOALLOCATE; - - cbAtrLen = call->cbAtrLen; - ZeroMemory(ret.pbAtr, 32); - status = ret.ReturnCode = SCardStatusW(operation->hCard, - call->fmszReaderNamesIsNULL ? NULL : (LPWSTR) &mszReaderNames, - &cchReaderLen, &ret.dwState, &ret.dwProtocol, (BYTE*) &ret.pbAtr, &cbAtrLen); + ret.cBytes = SCARD_AUTOALLOCATE; + status = ret.ReturnCode = + SCardStatusW(operation->hCard, call->fmszReaderNamesIsNULL ? NULL : (LPWSTR)&mszReaderNames, + &ret.cBytes, &ret.dwState, &ret.dwProtocol, (BYTE*)&ret.pbAtr, &cbAtrLen); + log_status_error(TAG, "SCardStatusW", status); if (status == SCARD_S_SUCCESS) { if (!call->fmszReaderNamesIsNULL) - ret.mszReaderNames = (BYTE*) mszReaderNames; - - // WinScard returns the number of CHARACTERS whereas pcsc-lite returns the - // number of BYTES. -#ifdef _WIN32 - ret.cBytes = cchReaderLen * 2; -#else - ret.cBytes = cchReaderLen; -#endif + ret.mszReaderNames = (BYTE*)mszReaderNames; - if (call->cbAtrLen) - ret.cbAtrLen = cbAtrLen; + ret.cbAtrLen = cbAtrLen; } - smartcard_trace_status_return(smartcard, &ret, TRUE); - - if ((status = smartcard_pack_status_return(smartcard, irp->output, &ret))) - { - WLog_ERR(TAG, "smartcard_pack_status_return failed with error %"PRId32"", status); + status = smartcard_pack_status_return(smartcard, irp->output, &ret, TRUE); + if (status != SCARD_S_SUCCESS) return status; - } if (mszReaderNames) SCardFreeMemory(operation->hContext, mszReaderNames); @@ -1259,10 +1739,8 @@ static LONG smartcard_Transmit_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPE if (!call) return STATUS_NO_MEMORY; - if ((status = smartcard_unpack_transmit_call(smartcard, irp->input, call))) - WLog_ERR(TAG, "smartcard_unpack_transmit_call failed with error %"PRId32"", status); + status = smartcard_unpack_transmit_call(smartcard, irp->input, call); - smartcard_trace_transmit_call(smartcard, call); operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); operation->hCard = smartcard_scard_handle_native_from_redir(smartcard, &(call->hCard)); return status; @@ -1283,27 +1761,27 @@ static LONG smartcard_Transmit_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERA call->cbRecvLength = 66560; ret.cbRecvLength = call->cbRecvLength; - ret.pbRecvBuffer = (BYTE*) malloc(ret.cbRecvLength); + ret.pbRecvBuffer = (BYTE*)malloc(ret.cbRecvLength); if (!ret.pbRecvBuffer) return STATUS_NO_MEMORY; } ret.pioRecvPci = call->pioRecvPci; - ret.ReturnCode = SCardTransmit(operation->hCard, call->pioSendPci, call->pbSendBuffer, - call->cbSendLength, ret.pioRecvPci, ret.pbRecvBuffer, &(ret.cbRecvLength)); - smartcard_trace_transmit_return(smartcard, &ret); + ret.ReturnCode = + SCardTransmit(operation->hCard, call->pioSendPci, call->pbSendBuffer, call->cbSendLength, + ret.pioRecvPci, ret.pbRecvBuffer, &(ret.cbRecvLength)); - if ((status = smartcard_pack_transmit_return(smartcard, irp->output, &ret))) - { - WLog_ERR(TAG, "smartcard_pack_transmit_return failed with error %"PRId32"", status); - return status; - } + log_status_error(TAG, "SCardTransmit", ret.ReturnCode); + status = smartcard_pack_transmit_return(smartcard, irp->output, &ret); free(call->pbSendBuffer); free(ret.pbRecvBuffer); free(call->pioSendPci); free(call->pioRecvPci); + + if (status != SCARD_S_SUCCESS) + return status; return ret.ReturnCode; } @@ -1317,10 +1795,8 @@ static LONG smartcard_Control_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPER if (!call) return STATUS_NO_MEMORY; - if ((status = smartcard_unpack_control_call(smartcard, irp->input, call))) - WLog_ERR(TAG, "smartcard_unpack_control_call failed with error %"PRId32"", status); + status = smartcard_unpack_control_call(smartcard, irp->input, call); - smartcard_trace_control_call(smartcard, call); operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); operation->hCard = smartcard_scard_handle_native_from_redir(smartcard, &(call->hCard)); return status; @@ -1329,28 +1805,25 @@ static LONG smartcard_Control_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPER static LONG smartcard_Control_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERATION* operation) { LONG status; - Control_Return ret; + Control_Return ret = { 0 }; IRP* irp = operation->irp; Control_Call* call = operation->call; ret.cbOutBufferSize = call->cbOutBufferSize; - ret.pvOutBuffer = (BYTE*) malloc(call->cbOutBufferSize); + ret.pvOutBuffer = (BYTE*)malloc(call->cbOutBufferSize); if (!ret.pvOutBuffer) return SCARD_E_NO_MEMORY; - ret.ReturnCode = SCardControl(operation->hCard, - call->dwControlCode, call->pvInBuffer, call->cbInBufferSize, - ret.pvOutBuffer, call->cbOutBufferSize, &ret.cbOutBufferSize); - smartcard_trace_control_return(smartcard, &ret); - - if ((status = smartcard_pack_control_return(smartcard, irp->output, &ret))) - { - WLog_ERR(TAG, "smartcard_pack_control_return failed with error %"PRId32"", status); - return status; - } + ret.ReturnCode = + SCardControl(operation->hCard, call->dwControlCode, call->pvInBuffer, call->cbInBufferSize, + ret.pvOutBuffer, call->cbOutBufferSize, &ret.cbOutBufferSize); + log_status_error(TAG, "SCardControl", ret.ReturnCode); + status = smartcard_pack_control_return(smartcard, irp->output, &ret); free(call->pvInBuffer); free(ret.pvOutBuffer); + if (status != SCARD_S_SUCCESS) + return status; return ret.ReturnCode; } @@ -1364,10 +1837,25 @@ static LONG smartcard_GetAttrib_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_OP if (!call) return STATUS_NO_MEMORY; - if ((status = smartcard_unpack_get_attrib_call(smartcard, irp->input, call))) - WLog_ERR(TAG, "smartcard_unpack_get_attrib_call failed with error %"PRId32"", status); + status = smartcard_unpack_get_attrib_call(smartcard, irp->input, call); + + operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); + operation->hCard = smartcard_scard_handle_native_from_redir(smartcard, &(call->hCard)); + return status; +} + +static LONG smartcard_SetAttrib_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERATION* operation) +{ + LONG status; + SetAttrib_Call* call; + IRP* irp = operation->irp; + operation->call = call = calloc(1, sizeof(SetAttrib_Call)); + + if (!call) + return STATUS_NO_MEMORY; + + status = smartcard_unpack_set_attrib_call(smartcard, irp->input, call); - smartcard_trace_get_attrib_call(smartcard, call); operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); operation->hCard = smartcard_scard_handle_native_from_redir(smartcard, &(call->hCard)); return status; @@ -1390,42 +1878,49 @@ static LONG smartcard_GetAttrib_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPER if (call->cbAttrLen && !autoAllocate) { - ret.pbAttr = (BYTE*) malloc(call->cbAttrLen); + ret.pbAttr = (BYTE*)malloc(call->cbAttrLen); if (!ret.pbAttr) return SCARD_E_NO_MEMORY; } cbAttrLen = call->cbAttrLen; - ret.ReturnCode = SCardGetAttrib(operation->hCard, call->dwAttrId, - autoAllocate ? (LPBYTE) & (ret.pbAttr) : ret.pbAttr, &cbAttrLen); + ret.ReturnCode = + SCardGetAttrib(operation->hCard, call->dwAttrId, + autoAllocate ? (LPBYTE) & (ret.pbAttr) : ret.pbAttr, &cbAttrLen); + log_status_error(TAG, "SCardGetAttrib", ret.ReturnCode); ret.cbAttrLen = cbAttrLen; - smartcard_trace_get_attrib_return(smartcard, &ret, call->dwAttrId); - if (ret.ReturnCode) - { - WLog_WARN(TAG, "SCardGetAttrib: %s (0x%08"PRIX32") cbAttrLen: %"PRIu32"", - SCardGetAttributeString(call->dwAttrId), call->dwAttrId, call->cbAttrLen); - Stream_Zero(irp->output, 256); + status = smartcard_pack_get_attrib_return(smartcard, irp->output, &ret, call->dwAttrId); + + if (autoAllocate) + SCardFreeMemory(operation->hContext, ret.pbAttr); + else free(ret.pbAttr); - return ret.ReturnCode; - } + return status; +} - if ((status = smartcard_pack_get_attrib_return(smartcard, irp->output, &ret))) - { - WLog_ERR(TAG, "smartcard_pack_get_attrib_return failed with error %"PRId32"", status); - return status; - } +static LONG smartcard_SetAttrib_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERATION* operation) +{ + Long_Return ret; + SetAttrib_Call* call = operation->call; + + ret.ReturnCode = + SCardSetAttrib(operation->hCard, call->dwAttrId, call->pbAttr, call->cbAttrLen); + log_status_error(TAG, "SCardSetAttrib", ret.ReturnCode); + free(call->pbAttr); + smartcard_trace_long_return(smartcard, &ret, "SetAttrib"); - free(ret.pbAttr); return ret.ReturnCode; } static LONG smartcard_AccessStartedEvent_Decode(SMARTCARD_DEVICE* smartcard, - SMARTCARD_OPERATION* operation) + SMARTCARD_OPERATION* operation) { Long_Call* call; - IRP* irp = operation->irp; + IRP* irp; + WINPR_UNUSED(smartcard); + irp = operation->irp; operation->call = call = calloc(1, sizeof(Long_Call)); if (!call) @@ -1433,19 +1928,20 @@ static LONG smartcard_AccessStartedEvent_Decode(SMARTCARD_DEVICE* smartcard, if (Stream_GetRemainingLength(irp->input) < 4) { - WLog_WARN(TAG, "AccessStartedEvent is too short: %"PRIuz"", + WLog_WARN(TAG, "AccessStartedEvent is too short: %" PRIuz "", Stream_GetRemainingLength(irp->input)); return SCARD_F_INTERNAL_ERROR; } - Stream_Read_UINT32(irp->input, call->LongValue); /* Unused (4 bytes) */ + Stream_Read_INT32(irp->input, call->LongValue); /* Unused (4 bytes) */ return SCARD_S_SUCCESS; } static LONG smartcard_AccessStartedEvent_Call(SMARTCARD_DEVICE* smartcard, - SMARTCARD_OPERATION* operation) + SMARTCARD_OPERATION* operation) { LONG status = SCARD_S_SUCCESS; + WINPR_UNUSED(operation); if (!smartcard->StartedEvent) smartcard->StartedEvent = SCardAccessStartedEvent(); @@ -1457,7 +1953,7 @@ static LONG smartcard_AccessStartedEvent_Call(SMARTCARD_DEVICE* smartcard, } static LONG smartcard_LocateCardsByATRA_Decode(SMARTCARD_DEVICE* smartcard, - SMARTCARD_OPERATION* operation) + SMARTCARD_OPERATION* operation) { LONG status; LocateCardsByATRA_Call* call; @@ -1467,16 +1963,162 @@ static LONG smartcard_LocateCardsByATRA_Decode(SMARTCARD_DEVICE* smartcard, if (!call) return STATUS_NO_MEMORY; - if ((status = smartcard_unpack_locate_cards_by_atr_a_call(smartcard, irp->input, call))) - WLog_ERR(TAG, "smartcard_unpack_locate_cards_by_atr_a_call failed with error %"PRId32"", status); + status = smartcard_unpack_locate_cards_by_atr_a_call(smartcard, irp->input, call); + + operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); + return status; +} + +static LONG smartcard_LocateCardsByATRW_Decode(SMARTCARD_DEVICE* smartcard, + SMARTCARD_OPERATION* operation) +{ + LONG status; + LocateCardsByATRW_Call* call; + IRP* irp = operation->irp; + operation->call = call = calloc(1, sizeof(LocateCardsByATRW_Call)); + + if (!call) + return STATUS_NO_MEMORY; + + status = smartcard_unpack_locate_cards_by_atr_w_call(smartcard, irp->input, call); + + operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); + return status; +} + +static LONG smartcard_ReadCacheA_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERATION* operation) +{ + LONG status; + ReadCacheA_Call* call; + IRP* irp = operation->irp; + operation->call = call = calloc(1, sizeof(ReadCacheA_Call)); + + if (!call) + return STATUS_NO_MEMORY; + + status = smartcard_unpack_read_cache_a_call(smartcard, irp->input, call); + + operation->hContext = + smartcard_scard_context_native_from_redir(smartcard, &(call->Common.hContext)); + return status; +} + +static LONG smartcard_ReadCacheW_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERATION* operation) +{ + LONG status; + ReadCacheW_Call* call; + IRP* irp = operation->irp; + operation->call = call = calloc(1, sizeof(ReadCacheW_Call)); + + if (!call) + return STATUS_NO_MEMORY; + + status = smartcard_unpack_read_cache_w_call(smartcard, irp->input, call); + + operation->hContext = + smartcard_scard_context_native_from_redir(smartcard, &(call->Common.hContext)); + return status; +} + +static LONG smartcard_WriteCacheA_Decode(SMARTCARD_DEVICE* smartcard, + SMARTCARD_OPERATION* operation) +{ + LONG status; + WriteCacheA_Call* call; + IRP* irp = operation->irp; + operation->call = call = calloc(1, sizeof(WriteCacheA_Call)); + + if (!call) + return STATUS_NO_MEMORY; + + status = smartcard_unpack_write_cache_a_call(smartcard, irp->input, call); + + operation->hContext = + smartcard_scard_context_native_from_redir(smartcard, &(call->Common.hContext)); + return status; +} + +static LONG smartcard_WriteCacheW_Decode(SMARTCARD_DEVICE* smartcard, + SMARTCARD_OPERATION* operation) +{ + LONG status; + WriteCacheW_Call* call; + IRP* irp = operation->irp; + operation->call = call = calloc(1, sizeof(WriteCacheW_Call)); + + if (!call) + return STATUS_NO_MEMORY; + + status = smartcard_unpack_write_cache_w_call(smartcard, irp->input, call); + + operation->hContext = + smartcard_scard_context_native_from_redir(smartcard, &(call->Common.hContext)); + return status; +} + +static LONG smartcard_GetTransmitCount_Decode(SMARTCARD_DEVICE* smartcard, + SMARTCARD_OPERATION* operation) +{ + LONG status; + GetTransmitCount_Call* call; + IRP* irp = operation->irp; + operation->call = call = calloc(1, sizeof(GetTransmitCount_Call)); + + if (!call) + return STATUS_NO_MEMORY; + + status = smartcard_unpack_get_transmit_count_call(smartcard, irp->input, call); + + operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); + return status; +} + +static LONG smartcard_ReleaseStartedEvent_Decode(SMARTCARD_DEVICE* smartcard, + SMARTCARD_OPERATION* operation) +{ + WINPR_UNUSED(smartcard); + WINPR_UNUSED(operation); + WLog_WARN(TAG, "According to [MS-RDPESC] 3.1.4 Message Processing Events and Sequencing Rules " + "SCARD_IOCTL_RELEASETARTEDEVENT is not supported"); + return SCARD_E_UNSUPPORTED_FEATURE; +} + +static LONG smartcard_GetReaderIcon_Decode(SMARTCARD_DEVICE* smartcard, + SMARTCARD_OPERATION* operation) +{ + LONG status; + GetReaderIcon_Call* call; + IRP* irp = operation->irp; + operation->call = call = calloc(1, sizeof(GetReaderIcon_Call)); + + if (!call) + return STATUS_NO_MEMORY; + + status = smartcard_unpack_get_reader_icon_call(smartcard, irp->input, call); + + operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); + return status; +} + +static LONG smartcard_GetDeviceTypeId_Decode(SMARTCARD_DEVICE* smartcard, + SMARTCARD_OPERATION* operation) +{ + LONG status; + GetDeviceTypeId_Call* call; + IRP* irp = operation->irp; + operation->call = call = calloc(1, sizeof(GetDeviceTypeId_Call)); + + if (!call) + return STATUS_NO_MEMORY; + + status = smartcard_unpack_get_device_type_id_call(smartcard, irp->input, call); - smartcard_trace_locate_cards_by_atr_a_call(smartcard, call); operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext)); return status; } static LONG smartcard_LocateCardsByATRA_Call(SMARTCARD_DEVICE* smartcard, - SMARTCARD_OPERATION* operation) + SMARTCARD_OPERATION* operation) { LONG status; DWORD i, j, k; @@ -1485,23 +2127,24 @@ static LONG smartcard_LocateCardsByATRA_Call(SMARTCARD_DEVICE* smartcard, LPSCARD_READERSTATEA states = NULL; IRP* irp = operation->irp; LocateCardsByATRA_Call* call = operation->call; - states = (LPSCARD_READERSTATEA) calloc(call->cReaders, sizeof(SCARD_READERSTATEA)); + states = (LPSCARD_READERSTATEA)calloc(call->cReaders, sizeof(SCARD_READERSTATEA)); if (!states) return STATUS_NO_MEMORY; for (i = 0; i < call->cReaders; i++) { - states[i].szReader = (LPCSTR) call->rgReaderStates[i].szReader; - states[i].dwCurrentState = call->rgReaderStates[i].Common.dwCurrentState; - states[i].dwEventState = call->rgReaderStates[i].Common.dwEventState; - states[i].cbAtr = call->rgReaderStates[i].Common.cbAtr; - CopyMemory(&(states[i].rgbAtr), &(call->rgReaderStates[i].Common.rgbAtr), 36); + states[i].szReader = (LPSTR)call->rgReaderStates[i].szReader; + states[i].dwCurrentState = call->rgReaderStates[i].dwCurrentState; + states[i].dwEventState = call->rgReaderStates[i].dwEventState; + states[i].cbAtr = call->rgReaderStates[i].cbAtr; + CopyMemory(&(states[i].rgbAtr), &(call->rgReaderStates[i].rgbAtr), 36); } - status = ret.ReturnCode = SCardGetStatusChangeA(operation->hContext, 0x000001F4, states, - call->cReaders); + status = ret.ReturnCode = + SCardGetStatusChangeA(operation->hContext, 0x000001F4, states, call->cReaders); + log_status_error(TAG, "SCardGetStatusChangeA", status); if (status && (status != SCARD_E_TIMEOUT) && (status != SCARD_E_CANCELLED)) { call->cReaders = 0; @@ -1528,10 +2171,13 @@ static LONG smartcard_LocateCardsByATRA_Call(SMARTCARD_DEVICE* smartcard, ret.rgReaderStates = NULL; if (ret.cReaders > 0) - ret.rgReaderStates = (ReaderState_Return*) calloc(ret.cReaders, sizeof(ReaderState_Return)); + ret.rgReaderStates = (ReaderState_Return*)calloc(ret.cReaders, sizeof(ReaderState_Return)); if (!ret.rgReaderStates) + { + free(states); return STATUS_NO_MEMORY; + } for (i = 0; i < ret.cReaders; i++) { @@ -1539,27 +2185,25 @@ static LONG smartcard_LocateCardsByATRA_Call(SMARTCARD_DEVICE* smartcard, ret.rgReaderStates[i].dwCurrentState = state->dwCurrentState; ret.rgReaderStates[i].dwEventState = state->dwEventState; ret.rgReaderStates[i].cbAtr = state->cbAtr; - CopyMemory(&(ret.rgReaderStates[i].rgbAtr), &(state->rgbAtr), 32); + CopyMemory(&(ret.rgReaderStates[i].rgbAtr), &(state->rgbAtr), + sizeof(ret.rgReaderStates[i].rgbAtr)); } free(states); - smartcard_trace_get_status_change_return(smartcard, &ret, FALSE); - if ((status = smartcard_pack_get_status_change_return(smartcard, irp->output, &ret))) - { - WLog_ERR(TAG, "smartcard_pack_get_status_change_return failed with error %"PRId32"", status); + status = smartcard_pack_get_status_change_return(smartcard, irp->output, &ret, FALSE); + if (status != SCARD_S_SUCCESS) return status; - } if (call->rgReaderStates) { for (i = 0; i < call->cReaders; i++) { - state = (LPSCARD_READERSTATEA) &call->rgReaderStates[i]; + state = (LPSCARD_READERSTATEA)&call->rgReaderStates[i]; if (state->szReader) { - free((void*) state->szReader); + free((void*)state->szReader); state->szReader = NULL; } } @@ -1573,7 +2217,7 @@ static LONG smartcard_LocateCardsByATRA_Call(SMARTCARD_DEVICE* smartcard, } LONG smartcard_irp_device_control_decode(SMARTCARD_DEVICE* smartcard, - SMARTCARD_OPERATION* operation) + SMARTCARD_OPERATION* operation) { LONG status; UINT32 offset; @@ -1586,43 +2230,38 @@ LONG smartcard_irp_device_control_decode(SMARTCARD_DEVICE* smartcard, if (Stream_GetRemainingLength(irp->input) < 32) { - WLog_WARN(TAG, "Device Control Request is too short: %"PRIuz"", + WLog_WARN(TAG, "Device Control Request is too short: %" PRIuz "", Stream_GetRemainingLength(irp->input)); return SCARD_F_INTERNAL_ERROR; } Stream_Read_UINT32(irp->input, outputBufferLength); /* OutputBufferLength (4 bytes) */ - Stream_Read_UINT32(irp->input, inputBufferLength); /* InputBufferLength (4 bytes) */ - Stream_Read_UINT32(irp->input, ioControlCode); /* IoControlCode (4 bytes) */ - Stream_Seek(irp->input, 20); /* Padding (20 bytes) */ + Stream_Read_UINT32(irp->input, inputBufferLength); /* InputBufferLength (4 bytes) */ + Stream_Read_UINT32(irp->input, ioControlCode); /* IoControlCode (4 bytes) */ + Stream_Seek(irp->input, 20); /* Padding (20 bytes) */ operation->ioControlCode = ioControlCode; if (Stream_Length(irp->input) != (Stream_GetPosition(irp->input) + inputBufferLength)) { - WLog_WARN(TAG, "InputBufferLength mismatch: Actual: %"PRIuz" Expected: %"PRIuz"", - Stream_Length(irp->input), - Stream_GetPosition(irp->input) + inputBufferLength); + WLog_WARN(TAG, "InputBufferLength mismatch: Actual: %" PRIuz " Expected: %" PRIuz "", + Stream_Length(irp->input), Stream_GetPosition(irp->input) + inputBufferLength); return SCARD_F_INTERNAL_ERROR; } - WLog_DBG(TAG, "%s (0x%08"PRIX32") FileId: %"PRIu32" CompletionId: %"PRIu32"", - smartcard_get_ioctl_string(ioControlCode, TRUE), - ioControlCode, irp->FileId, irp->CompletionId); + WLog_DBG(TAG, "%s (0x%08" PRIX32 ") FileId: %" PRIu32 " CompletionId: %" PRIu32 "", + smartcard_get_ioctl_string(ioControlCode, TRUE), ioControlCode, irp->FileId, + irp->CompletionId); if ((ioControlCode != SCARD_IOCTL_ACCESSSTARTEDEVENT) && - (ioControlCode != SCARD_IOCTL_RELEASESTARTEDEVENT)) + (ioControlCode != SCARD_IOCTL_RELEASETARTEDEVENT)) { - if ((status = smartcard_unpack_common_type_header(smartcard, irp->input))) - { - WLog_ERR(TAG, "smartcard_unpack_common_type_header failed with error %"PRId32"", status); - return SCARD_F_INTERNAL_ERROR; - } + status = smartcard_unpack_common_type_header(smartcard, irp->input); + if (status != SCARD_S_SUCCESS) + return status; - if ((status = smartcard_unpack_private_type_header(smartcard, irp->input))) - { - WLog_ERR(TAG, "smartcard_unpack_common_type_header failed with error %"PRId32"", status); - return SCARD_F_INTERNAL_ERROR; - } + status = smartcard_unpack_private_type_header(smartcard, irp->input); + if (status != SCARD_S_SUCCESS) + return status; } /* Decode */ @@ -1659,59 +2298,59 @@ LONG smartcard_irp_device_control_decode(SMARTCARD_DEVICE* smartcard, break; case SCARD_IOCTL_INTRODUCEREADERGROUPA: - status = SCARD_F_INTERNAL_ERROR; + status = smartcard_context_and_string_a_Decode(smartcard, operation); break; case SCARD_IOCTL_INTRODUCEREADERGROUPW: - status = SCARD_F_INTERNAL_ERROR; + status = smartcard_context_and_string_w_Decode(smartcard, operation); break; case SCARD_IOCTL_FORGETREADERGROUPA: - status = SCARD_F_INTERNAL_ERROR; + status = smartcard_context_and_string_a_Decode(smartcard, operation); break; case SCARD_IOCTL_FORGETREADERGROUPW: - status = SCARD_F_INTERNAL_ERROR; + status = smartcard_context_and_string_w_Decode(smartcard, operation); break; case SCARD_IOCTL_INTRODUCEREADERA: - status = SCARD_F_INTERNAL_ERROR; + status = smartcard_context_and_two_strings_a_Decode(smartcard, operation); break; case SCARD_IOCTL_INTRODUCEREADERW: - status = SCARD_F_INTERNAL_ERROR; + status = smartcard_context_and_two_strings_w_Decode(smartcard, operation); break; case SCARD_IOCTL_FORGETREADERA: - status = SCARD_F_INTERNAL_ERROR; + status = smartcard_context_and_string_a_Decode(smartcard, operation); break; case SCARD_IOCTL_FORGETREADERW: - status = SCARD_F_INTERNAL_ERROR; + status = smartcard_context_and_string_w_Decode(smartcard, operation); break; case SCARD_IOCTL_ADDREADERTOGROUPA: - status = SCARD_F_INTERNAL_ERROR; + status = smartcard_context_and_two_strings_a_Decode(smartcard, operation); break; case SCARD_IOCTL_ADDREADERTOGROUPW: - status = SCARD_F_INTERNAL_ERROR; + status = smartcard_context_and_two_strings_w_Decode(smartcard, operation); break; case SCARD_IOCTL_REMOVEREADERFROMGROUPA: - status = SCARD_F_INTERNAL_ERROR; + status = smartcard_context_and_two_strings_a_Decode(smartcard, operation); break; case SCARD_IOCTL_REMOVEREADERFROMGROUPW: - status = SCARD_F_INTERNAL_ERROR; + status = smartcard_context_and_two_strings_w_Decode(smartcard, operation); break; case SCARD_IOCTL_LOCATECARDSA: - status = SCARD_F_INTERNAL_ERROR; + status = smartcard_LocateCardsA_Decode(smartcard, operation); break; case SCARD_IOCTL_LOCATECARDSW: - status = SCARD_F_INTERNAL_ERROR; + status = smartcard_LocateCardsW_Decode(smartcard, operation); break; case SCARD_IOCTL_GETSTATUSCHANGEA: @@ -1775,7 +2414,7 @@ LONG smartcard_irp_device_control_decode(SMARTCARD_DEVICE* smartcard, break; case SCARD_IOCTL_SETATTRIB: - status = SCARD_F_INTERNAL_ERROR; + status = smartcard_SetAttrib_Decode(smartcard, operation); break; case SCARD_IOCTL_ACCESSSTARTEDEVENT: @@ -1787,39 +2426,39 @@ LONG smartcard_irp_device_control_decode(SMARTCARD_DEVICE* smartcard, break; case SCARD_IOCTL_LOCATECARDSBYATRW: - status = SCARD_F_INTERNAL_ERROR; + status = smartcard_LocateCardsByATRW_Decode(smartcard, operation); break; case SCARD_IOCTL_READCACHEA: - status = SCARD_F_INTERNAL_ERROR; + status = smartcard_ReadCacheA_Decode(smartcard, operation); break; case SCARD_IOCTL_READCACHEW: - status = SCARD_F_INTERNAL_ERROR; + status = smartcard_ReadCacheW_Decode(smartcard, operation); break; case SCARD_IOCTL_WRITECACHEA: - status = SCARD_F_INTERNAL_ERROR; + status = smartcard_WriteCacheA_Decode(smartcard, operation); break; case SCARD_IOCTL_WRITECACHEW: - status = SCARD_F_INTERNAL_ERROR; + status = smartcard_WriteCacheW_Decode(smartcard, operation); break; case SCARD_IOCTL_GETTRANSMITCOUNT: - status = SCARD_F_INTERNAL_ERROR; + status = smartcard_GetTransmitCount_Decode(smartcard, operation); break; - case SCARD_IOCTL_RELEASESTARTEDEVENT: - status = SCARD_F_INTERNAL_ERROR; + case SCARD_IOCTL_RELEASETARTEDEVENT: + status = smartcard_ReleaseStartedEvent_Decode(smartcard, operation); break; case SCARD_IOCTL_GETREADERICON: - status = SCARD_F_INTERNAL_ERROR; + status = smartcard_GetReaderIcon_Decode(smartcard, operation); break; case SCARD_IOCTL_GETDEVICETYPEID: - status = SCARD_F_INTERNAL_ERROR; + status = smartcard_GetDeviceTypeId_Decode(smartcard, operation); break; default: @@ -1828,7 +2467,7 @@ LONG smartcard_irp_device_control_decode(SMARTCARD_DEVICE* smartcard, } if ((ioControlCode != SCARD_IOCTL_ACCESSSTARTEDEVENT) && - (ioControlCode != SCARD_IOCTL_RELEASESTARTEDEVENT)) + (ioControlCode != SCARD_IOCTL_RELEASETARTEDEVENT)) { offset = (RDPDR_DEVICE_IO_REQUEST_LENGTH + RDPDR_DEVICE_IO_CONTROL_REQ_HDR_LENGTH); smartcard_unpack_read_size_align(smartcard, irp->input, @@ -1840,8 +2479,10 @@ LONG smartcard_irp_device_control_decode(SMARTCARD_DEVICE* smartcard, SIZE_T difference; difference = Stream_Length(irp->input) - Stream_GetPosition(irp->input); WLog_WARN(TAG, - "IRP was not fully parsed %s (0x%08"PRIX32"): Actual: %"PRIuz", Expected: %"PRIuz", Difference: %"PRIuz"", - smartcard_get_ioctl_string(ioControlCode, TRUE), ioControlCode, + "IRP was not fully parsed %s (%s [0x%08" PRIX32 "]): Actual: %" PRIuz + ", Expected: %" PRIuz ", Difference: %" PRIuz "", + smartcard_get_ioctl_string(ioControlCode, TRUE), + smartcard_get_ioctl_string(ioControlCode, FALSE), ioControlCode, Stream_GetPosition(irp->input), Stream_Length(irp->input), difference); winpr_HexDump(TAG, WLOG_WARN, Stream_Pointer(irp->input), difference); } @@ -1851,7 +2492,8 @@ LONG smartcard_irp_device_control_decode(SMARTCARD_DEVICE* smartcard, SIZE_T difference; difference = Stream_GetPosition(irp->input) - Stream_Length(irp->input); WLog_WARN(TAG, - "IRP was parsed beyond its end %s (0x%08"PRIX32"): Actual: %"PRIuz", Expected: %"PRIuz", Difference: %"PRIuz"", + "IRP was parsed beyond its end %s (0x%08" PRIX32 "): Actual: %" PRIuz + ", Expected: %" PRIuz ", Difference: %" PRIuz "", smartcard_get_ioctl_string(ioControlCode, TRUE), ioControlCode, Stream_GetPosition(irp->input), Stream_Length(irp->input), difference); } @@ -1882,12 +2524,15 @@ LONG smartcard_irp_device_control_call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OP * Since it's a SHOULD and not a MUST, we don't care * about it, but we still reserve at least 2048 bytes. */ - Stream_EnsureRemainingCapacity(irp->output, 2048); + if (!Stream_EnsureRemainingCapacity(irp->output, 2048)) + return SCARD_E_NO_MEMORY; + /* Device Control Response */ Stream_Seek_UINT32(irp->output); /* OutputBufferLength (4 bytes) */ Stream_Seek(irp->output, SMARTCARD_COMMON_TYPE_HEADER_LENGTH); /* CommonTypeHeader (8 bytes) */ - Stream_Seek(irp->output, SMARTCARD_PRIVATE_TYPE_HEADER_LENGTH); /* PrivateTypeHeader (8 bytes) */ - Stream_Seek_UINT32(irp->output); /* Result (4 bytes) */ + Stream_Seek(irp->output, + SMARTCARD_PRIVATE_TYPE_HEADER_LENGTH); /* PrivateTypeHeader (8 bytes) */ + Stream_Seek_UINT32(irp->output); /* Result (4 bytes) */ /* Call */ @@ -1922,59 +2567,59 @@ LONG smartcard_irp_device_control_call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OP break; case SCARD_IOCTL_INTRODUCEREADERGROUPA: - result = SCARD_F_INTERNAL_ERROR; + result = smartcard_IntroduceReaderGroupA_Call(smartcard, operation); break; case SCARD_IOCTL_INTRODUCEREADERGROUPW: - result = SCARD_F_INTERNAL_ERROR; + result = smartcard_IntroduceReaderGroupW_Call(smartcard, operation); break; case SCARD_IOCTL_FORGETREADERGROUPA: - result = SCARD_F_INTERNAL_ERROR; + result = smartcard_ForgetReaderA_Call(smartcard, operation); break; case SCARD_IOCTL_FORGETREADERGROUPW: - result = SCARD_F_INTERNAL_ERROR; + result = smartcard_ForgetReaderW_Call(smartcard, operation); break; case SCARD_IOCTL_INTRODUCEREADERA: - result = SCARD_F_INTERNAL_ERROR; + result = smartcard_IntroduceReaderA_Call(smartcard, operation); break; case SCARD_IOCTL_INTRODUCEREADERW: - result = SCARD_F_INTERNAL_ERROR; + result = smartcard_IntroduceReaderW_Call(smartcard, operation); break; case SCARD_IOCTL_FORGETREADERA: - result = SCARD_F_INTERNAL_ERROR; + result = smartcard_ForgetReaderA_Call(smartcard, operation); break; case SCARD_IOCTL_FORGETREADERW: - result = SCARD_F_INTERNAL_ERROR; + result = smartcard_ForgetReaderW_Call(smartcard, operation); break; case SCARD_IOCTL_ADDREADERTOGROUPA: - result = SCARD_F_INTERNAL_ERROR; + result = smartcard_AddReaderToGroupA_Call(smartcard, operation); break; case SCARD_IOCTL_ADDREADERTOGROUPW: - result = SCARD_F_INTERNAL_ERROR; + result = smartcard_AddReaderToGroupW_Call(smartcard, operation); break; case SCARD_IOCTL_REMOVEREADERFROMGROUPA: - result = SCARD_F_INTERNAL_ERROR; + result = smartcard_RemoveReaderFromGroupA_Call(smartcard, operation); break; case SCARD_IOCTL_REMOVEREADERFROMGROUPW: - result = SCARD_F_INTERNAL_ERROR; + result = smartcard_RemoveReaderFromGroupW_Call(smartcard, operation); break; case SCARD_IOCTL_LOCATECARDSA: - result = SCARD_F_INTERNAL_ERROR; + result = smartcard_LocateCardsA_Call(smartcard, operation); break; case SCARD_IOCTL_LOCATECARDSW: - result = SCARD_F_INTERNAL_ERROR; + result = smartcard_LocateCardsW_Call(smartcard, operation); break; case SCARD_IOCTL_GETSTATUSCHANGEA: @@ -2038,7 +2683,7 @@ LONG smartcard_irp_device_control_call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OP break; case SCARD_IOCTL_SETATTRIB: - result = SCARD_F_INTERNAL_ERROR; + result = smartcard_SetAttrib_Call(smartcard, operation); break; case SCARD_IOCTL_ACCESSSTARTEDEVENT: @@ -2050,39 +2695,39 @@ LONG smartcard_irp_device_control_call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OP break; case SCARD_IOCTL_LOCATECARDSBYATRW: - result = SCARD_F_INTERNAL_ERROR; + result = smartcard_LocateCardsW_Call(smartcard, operation); break; case SCARD_IOCTL_READCACHEA: - result = SCARD_F_INTERNAL_ERROR; + result = smartcard_ReadCacheA_Call(smartcard, operation); break; case SCARD_IOCTL_READCACHEW: - result = SCARD_F_INTERNAL_ERROR; + result = smartcard_ReadCacheW_Call(smartcard, operation); break; case SCARD_IOCTL_WRITECACHEA: - result = SCARD_F_INTERNAL_ERROR; + result = smartcard_WriteCacheA_Call(smartcard, operation); break; case SCARD_IOCTL_WRITECACHEW: - result = SCARD_F_INTERNAL_ERROR; + result = smartcard_WriteCacheW_Call(smartcard, operation); break; case SCARD_IOCTL_GETTRANSMITCOUNT: - result = SCARD_F_INTERNAL_ERROR; + result = smartcard_GetTransmitCount_Call(smartcard, operation); break; - case SCARD_IOCTL_RELEASESTARTEDEVENT: - result = SCARD_F_INTERNAL_ERROR; + case SCARD_IOCTL_RELEASETARTEDEVENT: + result = smartcard_ReleaseStartedEvent_Call(smartcard, operation); break; case SCARD_IOCTL_GETREADERICON: - result = SCARD_F_INTERNAL_ERROR; + result = smartcard_GetReaderIcon_Call(smartcard, operation); break; case SCARD_IOCTL_GETDEVICETYPEID: - result = SCARD_F_INTERNAL_ERROR; + result = smartcard_GetDeviceTypeId_Call(smartcard, operation); break; default: @@ -2100,28 +2745,29 @@ LONG smartcard_irp_device_control_call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OP */ if ((ioControlCode != SCARD_IOCTL_ACCESSSTARTEDEVENT) && - (ioControlCode != SCARD_IOCTL_RELEASESTARTEDEVENT)) + (ioControlCode != SCARD_IOCTL_RELEASETARTEDEVENT)) { offset = (RDPDR_DEVICE_IO_RESPONSE_LENGTH + RDPDR_DEVICE_IO_CONTROL_RSP_HDR_LENGTH); - smartcard_pack_write_size_align(smartcard, irp->output, Stream_GetPosition(irp->output) - offset, - 8); + smartcard_pack_write_size_align(smartcard, irp->output, + Stream_GetPosition(irp->output) - offset, 8); } if ((result != SCARD_S_SUCCESS) && (result != SCARD_E_TIMEOUT) && - (result != SCARD_E_NO_READERS_AVAILABLE) && (result != SCARD_E_NO_SERVICE)) + (result != SCARD_E_NO_READERS_AVAILABLE) && (result != SCARD_E_NO_SERVICE) && + (result != SCARD_W_CACHE_ITEM_NOT_FOUND) && (result != SCARD_W_CACHE_ITEM_STALE)) { - WLog_WARN(TAG, "IRP failure: %s (0x%08"PRIX32"), status: %s (0x%08"PRIX32")", + WLog_WARN(TAG, "IRP failure: %s (0x%08" PRIX32 "), status: %s (0x%08" PRIX32 ")", smartcard_get_ioctl_string(ioControlCode, TRUE), ioControlCode, SCardGetErrorString(result), result); } irp->IoStatus = STATUS_SUCCESS; - if ((result & 0xC0000000) == 0xC0000000) + if ((result & 0xC0000000L) == 0xC0000000L) { /* NTSTATUS error */ irp->IoStatus = (UINT32)result; - WLog_WARN(TAG, "IRP failure: %s (0x%08"PRIX32"), ntstatus: 0x%08"PRIX32"", + WLog_WARN(TAG, "IRP failure: %s (0x%08" PRIX32 "), ntstatus: 0x%08" PRIX32 "", smartcard_get_ioctl_string(ioControlCode, TRUE), ioControlCode, result); } @@ -2130,12 +2776,11 @@ LONG smartcard_irp_device_control_call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OP objectBufferLength = outputBufferLength - RDPDR_DEVICE_IO_RESPONSE_LENGTH; Stream_SetPosition(irp->output, RDPDR_DEVICE_IO_RESPONSE_LENGTH); /* Device Control Response */ - Stream_Write_UINT32(irp->output, outputBufferLength); /* OutputBufferLength (4 bytes) */ + Stream_Write_UINT32(irp->output, outputBufferLength); /* OutputBufferLength (4 bytes) */ smartcard_pack_common_type_header(smartcard, irp->output); /* CommonTypeHeader (8 bytes) */ smartcard_pack_private_type_header(smartcard, irp->output, objectBufferLength); /* PrivateTypeHeader (8 bytes) */ - Stream_Write_UINT32(irp->output, result); /* Result (4 bytes) */ + Stream_Write_INT32(irp->output, result); /* Result (4 bytes) */ Stream_SetPosition(irp->output, Stream_Length(irp->output)); return SCARD_S_SUCCESS; } - diff --git a/channels/smartcard/client/smartcard_pack.c b/channels/smartcard/client/smartcard_pack.c index b2f3563..a85cce6 100644 --- a/channels/smartcard/client/smartcard_pack.c +++ b/channels/smartcard/client/smartcard_pack.c @@ -5,6 +5,8 @@ * Copyright 2014 Marc-Andre Moreau * Copyright 2015 Thincast Technologies GmbH * Copyright 2015 DI (FH) Martin Haimberger + * Copyright 2020 Armin Novak + * Copyright 2020 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. @@ -28,2210 +30,2772 @@ #include "smartcard_pack.h" -LONG smartcard_unpack_common_type_header(SMARTCARD_DEVICE* smartcard, wStream* s) -{ - UINT8 version; - UINT32 filler; - UINT8 endianness; - UINT16 commonHeaderLength; +static const DWORD g_LogLevel = WLOG_DEBUG; + +#define smartcard_unpack_redir_scard_context(smartcard, s, context, index) \ + smartcard_unpack_redir_scard_context_((smartcard), (s), (context), (index), __FILE__, \ + __FUNCTION__, __LINE__) +#define smartcard_unpack_redir_scard_handle(smartcard, s, context, index) \ + smartcard_unpack_redir_scard_handle_((smartcard), (s), (context), (index), __FILE__, \ + __FUNCTION__, __LINE__) + +static LONG smartcard_unpack_redir_scard_context_(SMARTCARD_DEVICE* smartcard, wStream* s, + REDIR_SCARDCONTEXT* context, UINT32* index, + const char* file, const char* function, int line); +static LONG smartcard_pack_redir_scard_context(SMARTCARD_DEVICE* smartcard, wStream* s, + const REDIR_SCARDCONTEXT* context, DWORD* index); +static LONG smartcard_unpack_redir_scard_handle_(SMARTCARD_DEVICE* smartcard, wStream* s, + REDIR_SCARDHANDLE* handle, UINT32* index, + const char* file, const char* function, int line); +static LONG smartcard_pack_redir_scard_handle(SMARTCARD_DEVICE* smartcard, wStream* s, + const REDIR_SCARDHANDLE* handle, DWORD* index); +static LONG smartcard_unpack_redir_scard_context_ref(SMARTCARD_DEVICE* smartcard, wStream* s, + REDIR_SCARDCONTEXT* context); +static LONG smartcard_pack_redir_scard_context_ref(SMARTCARD_DEVICE* smartcard, wStream* s, + const REDIR_SCARDCONTEXT* context); + +static LONG smartcard_unpack_redir_scard_handle_ref(SMARTCARD_DEVICE* smartcard, wStream* s, + REDIR_SCARDHANDLE* handle); +static LONG smartcard_pack_redir_scard_handle_ref(SMARTCARD_DEVICE* smartcard, wStream* s, + const REDIR_SCARDHANDLE* handle); + +typedef enum +{ + NDR_PTR_FULL, + NDR_PTR_SIMPLE, + NDR_PTR_FIXED +} ndr_ptr_t; + +/* Reads a NDR pointer and checks if the value read has the expected relative + * addressing */ +#define smartcard_ndr_pointer_read(s, index, ptr) \ + smartcard_ndr_pointer_read_((s), (index), (ptr), __FILE__, __FUNCTION__, __LINE__) +static BOOL smartcard_ndr_pointer_read_(wStream* s, UINT32* index, UINT32* ptr, const char* file, + const char* fkt, int line) +{ + const UINT32 expect = 0x20000 + (*index) * 4; + UINT32 ndrPtr; + WINPR_UNUSED(file); + if (!s) + return FALSE; + if (Stream_GetRemainingLength(s) < 4) + return FALSE; - if (Stream_GetRemainingLength(s) < 8) + Stream_Read_UINT32(s, ndrPtr); /* mszGroupsNdrPtr (4 bytes) */ + if (ptr) + *ptr = ndrPtr; + if (expect != ndrPtr) { - WLog_WARN(TAG, "CommonTypeHeader is too short: %"PRIuz"", - Stream_GetRemainingLength(s)); - return STATUS_BUFFER_TOO_SMALL; + /* Allow NULL pointer if we read the result */ + if (ptr && (ndrPtr == 0)) + return TRUE; + WLog_WARN(TAG, "[%s:%d] Read context pointer 0x%08" PRIx32 ", expected 0x%08" PRIx32, fkt, + line, ndrPtr, expect); + return FALSE; } - /* Process CommonTypeHeader */ - Stream_Read_UINT8(s, version); /* Version (1 byte) */ - Stream_Read_UINT8(s, endianness); /* Endianness (1 byte) */ - Stream_Read_UINT16(s, commonHeaderLength); /* CommonHeaderLength (2 bytes) */ - Stream_Read_UINT32(s, filler); /* Filler (4 bytes), should be 0xCCCCCCCC */ + (*index) = (*index) + 1; + return TRUE; +} - if (version != 1) +static LONG smartcard_ndr_read(wStream* s, BYTE** data, size_t min, size_t elementSize, + ndr_ptr_t type) +{ + size_t len, offset, len2; + void* r; + size_t required; + + switch (type) { - WLog_WARN(TAG, "Unsupported CommonTypeHeader Version %"PRIu8"", version); - return STATUS_INVALID_PARAMETER; + case NDR_PTR_FULL: + required = 12; + break; + case NDR_PTR_SIMPLE: + required = 4; + break; + case NDR_PTR_FIXED: + required = min; + break; } - if (endianness != 0x10) + if (Stream_GetRemainingLength(s) < required) { - WLog_WARN(TAG, "Unsupported CommonTypeHeader Endianness %"PRIu8"", endianness); - return STATUS_INVALID_PARAMETER; + WLog_ERR(TAG, "Short data while trying to read NDR pointer, expected 4, got %" PRIu32, + Stream_GetRemainingLength(s)); + return STATUS_BUFFER_TOO_SMALL; } - if (commonHeaderLength != 8) + switch (type) { - WLog_WARN(TAG, "Unsupported CommonTypeHeader CommonHeaderLength %"PRIu16"", commonHeaderLength); - return STATUS_INVALID_PARAMETER; + case NDR_PTR_FULL: + Stream_Read_UINT32(s, len); + Stream_Read_UINT32(s, offset); + Stream_Read_UINT32(s, len2); + if (len != offset + len2) + { + WLog_ERR(TAG, + "Invalid data when reading full NDR pointer: total=%" PRIu32 + ", offset=%" PRIu32 ", remaining=%" PRIu32, + len, offset, len2); + return STATUS_BUFFER_TOO_SMALL; + } + break; + case NDR_PTR_SIMPLE: + Stream_Read_UINT32(s, len); + + if ((len != min) && (min > 0)) + { + WLog_ERR(TAG, + "Invalid data when reading simple NDR pointer: total=%" PRIu32 + ", expected=%" PRIu32, + len, min); + return STATUS_BUFFER_TOO_SMALL; + } + break; + case NDR_PTR_FIXED: + len = (UINT32)min; + break; } - if (filler != 0xCCCCCCCC) + if (min > len) { - WLog_WARN(TAG, "Unexpected CommonTypeHeader Filler 0x%08"PRIX32"", filler); - return STATUS_INVALID_PARAMETER; + WLog_ERR(TAG, "Invalid length read from NDR pointer, minimum %" PRIu32 ", got %" PRIu32, + min, len); + return STATUS_DATA_ERROR; } - return SCARD_S_SUCCESS; -} + if (len > SIZE_MAX / 2) + return STATUS_BUFFER_TOO_SMALL; -void smartcard_pack_common_type_header(SMARTCARD_DEVICE* smartcard, wStream* s) -{ - Stream_Write_UINT8(s, 1); /* Version (1 byte) */ - Stream_Write_UINT8(s, 0x10); /* Endianness (1 byte) */ - Stream_Write_UINT16(s, 8); /* CommonHeaderLength (2 bytes) */ - Stream_Write_UINT32(s, 0xCCCCCCCC); /* Filler (4 bytes), should be 0xCCCCCCCC */ + if (Stream_GetRemainingLength(s) / elementSize < len) + { + WLog_ERR(TAG, + "Short data while trying to read data from NDR pointer, expected %" PRIu32 + ", got %" PRIu32, + len, Stream_GetRemainingLength(s)); + return STATUS_BUFFER_TOO_SMALL; + } + len *= elementSize; + + r = calloc(len + 1, sizeof(CHAR)); + if (!r) + return SCARD_E_NO_MEMORY; + Stream_Read(s, r, len); + smartcard_unpack_read_size_align(NULL, s, len, 4); + *data = r; + return STATUS_SUCCESS; } -LONG smartcard_unpack_private_type_header(SMARTCARD_DEVICE* smartcard, wStream* s) +static BOOL smartcard_ndr_pointer_write(wStream* s, UINT32* index, DWORD length) { - UINT32 filler; - UINT32 objectBufferLength; + const UINT32 ndrPtr = 0x20000 + (*index) * 4; - if (Stream_GetRemainingLength(s) < 8) + if (!s) + return FALSE; + if (!Stream_EnsureRemainingCapacity(s, 4)) + return FALSE; + + if (length > 0) { - WLog_WARN(TAG, "PrivateTypeHeader is too short: %"PRIuz"", - Stream_GetRemainingLength(s)); - return STATUS_BUFFER_TOO_SMALL; + Stream_Write_UINT32(s, ndrPtr); /* mszGroupsNdrPtr (4 bytes) */ + (*index) = (*index) + 1; } + else + Stream_Write_UINT32(s, 0); + return TRUE; +} - Stream_Read_UINT32(s, objectBufferLength); /* ObjectBufferLength (4 bytes) */ - Stream_Read_UINT32(s, filler); /* Filler (4 bytes), should be 0x00000000 */ +static LONG smartcard_ndr_write(wStream* s, const BYTE* data, UINT32 size, UINT32 elementSize, + ndr_ptr_t type) +{ + const UINT32 offset = 0; + const UINT32 len = size; + const UINT32 dataLen = size * elementSize; + size_t required; - if (filler != 0x00000000) + if (size == 0) + return SCARD_S_SUCCESS; + + switch (type) { - WLog_WARN(TAG, "Unexpected PrivateTypeHeader Filler 0x%08"PRIX32"", filler); - return STATUS_INVALID_PARAMETER; + case NDR_PTR_FULL: + required = 12; + break; + case NDR_PTR_SIMPLE: + required = 4; + break; + case NDR_PTR_FIXED: + required = 0; + break; } - if (objectBufferLength != Stream_GetRemainingLength(s)) + if (!Stream_EnsureRemainingCapacity(s, required + dataLen + 4)) + return STATUS_BUFFER_TOO_SMALL; + + switch (type) { - WLog_WARN(TAG, - "PrivateTypeHeader ObjectBufferLength mismatch: Actual: %"PRIu32", Expected: %"PRIuz"", - objectBufferLength, Stream_GetRemainingLength(s)); - return STATUS_INVALID_PARAMETER; + case NDR_PTR_FULL: + Stream_Write_UINT32(s, len); + Stream_Write_UINT32(s, offset); + Stream_Write_UINT32(s, len); + break; + case NDR_PTR_SIMPLE: + Stream_Write_UINT32(s, len); + break; + case NDR_PTR_FIXED: + break; } - return SCARD_S_SUCCESS; + if (data) + Stream_Write(s, data, dataLen); + else + Stream_Zero(s, dataLen); + return smartcard_pack_write_size_align(NULL, s, len, 4); } -void smartcard_pack_private_type_header(SMARTCARD_DEVICE* smartcard, wStream* s, - UINT32 objectBufferLength) +static LONG smartcard_ndr_write_state(wStream* s, const ReaderState_Return* data, UINT32 size, + ndr_ptr_t type) { - Stream_Write_UINT32(s, objectBufferLength); /* ObjectBufferLength (4 bytes) */ - Stream_Write_UINT32(s, 0x00000000); /* Filler (4 bytes), should be 0x00000000 */ + union { + const ReaderState_Return* reader; + const BYTE* data; + } cnv; + + cnv.reader = data; + return smartcard_ndr_write(s, cnv.data, size, sizeof(ReaderState_Return), type); } -LONG smartcard_unpack_read_size_align(SMARTCARD_DEVICE* smartcard, wStream* s, UINT32 size, - UINT32 alignment) +static LONG smartcard_ndr_read_atrmask(wStream* s, LocateCards_ATRMask** data, size_t min, + ndr_ptr_t type) { - UINT32 pad; - pad = size; - size = (size + alignment - 1) & ~(alignment - 1); - pad = size - pad; - - if (pad) - Stream_Seek(s, pad); + union { + LocateCards_ATRMask** ppc; + BYTE** ppv; + } u; + u.ppc = data; + return smartcard_ndr_read(s, u.ppv, min, sizeof(LocateCards_ATRMask), type); +} - return pad; +static LONG smartcard_ndr_read_fixed_string_a(wStream* s, CHAR** data, size_t min, ndr_ptr_t type) +{ + union { + CHAR** ppc; + BYTE** ppv; + } u; + u.ppc = data; + return smartcard_ndr_read(s, u.ppv, min, sizeof(CHAR), type); } -LONG smartcard_pack_write_size_align(SMARTCARD_DEVICE* smartcard, wStream* s, UINT32 size, - UINT32 alignment) +static LONG smartcard_ndr_read_fixed_string_w(wStream* s, WCHAR** data, size_t min, ndr_ptr_t type) { - UINT32 pad; - pad = size; - size = (size + alignment - 1) & ~(alignment - 1); - pad = size - pad; + union { + WCHAR** ppc; + BYTE** ppv; + } u; + u.ppc = data; + return smartcard_ndr_read(s, u.ppv, min, sizeof(WCHAR), type); +} - if (pad) - { - if (!Stream_EnsureRemainingCapacity(s, pad)) - { - WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); - return SCARD_F_INTERNAL_ERROR; - } +static LONG smartcard_ndr_read_a(wStream* s, CHAR** data, ndr_ptr_t type) +{ + union { + CHAR** ppc; + BYTE** ppv; + } u; + u.ppc = data; + return smartcard_ndr_read(s, u.ppv, 0, sizeof(CHAR), type); +} - Stream_Zero(s, pad); - } +static LONG smartcard_ndr_read_w(wStream* s, WCHAR** data, ndr_ptr_t type) +{ + union { + WCHAR** ppc; + BYTE** ppv; + } u; + u.ppc = data; + return smartcard_ndr_read(s, u.ppv, 0, sizeof(WCHAR), type); +} - return SCARD_S_SUCCESS; +static LONG smartcard_ndr_read_u(wStream* s, UUID** data) +{ + union { + UUID** ppc; + BYTE** ppv; + } u; + u.ppc = data; + return smartcard_ndr_read(s, u.ppv, 1, sizeof(UUID), NDR_PTR_FIXED); } -SCARDCONTEXT smartcard_scard_context_native_from_redir(SMARTCARD_DEVICE* smartcard, - REDIR_SCARDCONTEXT* context) +static char* smartcard_convert_string_list(const void* in, size_t bytes, BOOL unicode) { - SCARDCONTEXT hContext = 0; + size_t index, length; + union { + const void* pv; + const char* sz; + const WCHAR* wz; + } string; + char* mszA = NULL; - if ((context->cbContext != sizeof(ULONG_PTR)) && (context->cbContext != 0)) + string.pv = in; + + if (bytes < 1) + return NULL; + + if (unicode) { - WLog_WARN(TAG, - "REDIR_SCARDCONTEXT does not match native size: Actual: %"PRIu32", Expected: %"PRIuz"", - context->cbContext, sizeof(ULONG_PTR)); - return 0; + length = (bytes / 2); + if (ConvertFromUnicode(CP_UTF8, 0, string.wz, (int)length, &mszA, 0, NULL, NULL) != + (int)length) + { + free(mszA); + return NULL; + } } - - if (context->cbContext) - CopyMemory(&hContext, &(context->pbContext), context->cbContext); else - ZeroMemory(&hContext, sizeof(ULONG_PTR)); + { + length = bytes; + mszA = (char*)malloc(length); + if (!mszA) + return NULL; + CopyMemory(mszA, string.sz, length); + } - return hContext; -} + for (index = 0; index < length - 1; index++) + { + if (mszA[index] == '\0') + mszA[index] = ','; + } -void smartcard_scard_context_native_to_redir(SMARTCARD_DEVICE* smartcard, - REDIR_SCARDCONTEXT* context, SCARDCONTEXT hContext) -{ - ZeroMemory(context, sizeof(REDIR_SCARDCONTEXT)); - context->cbContext = sizeof(ULONG_PTR); - CopyMemory(&(context->pbContext), &hContext, context->cbContext); + return mszA; } -SCARDHANDLE smartcard_scard_handle_native_from_redir(SMARTCARD_DEVICE* smartcard, - REDIR_SCARDHANDLE* handle) +static char* smartcard_msz_dump_a(const char* msz, size_t len, char* buffer, size_t bufferLen) { - SCARDHANDLE hCard = 0; + char* buf = buffer; + const char* cur = msz; - if (handle->cbHandle != sizeof(ULONG_PTR)) + while ((len > 0) && cur && cur[0] != '\0' && (bufferLen > 0)) { - WLog_WARN(TAG, - "REDIR_SCARDHANDLE does not match native size: Actual: %"PRIu32", Expected: %"PRIuz"", - handle->cbHandle, sizeof(ULONG_PTR)); - return 0; - } + size_t clen = strnlen(cur, len); + int rc = _snprintf(buf, bufferLen, "%s", cur); + bufferLen -= (size_t)rc; + buf += rc; - if (handle->cbHandle) - CopyMemory(&hCard, &(handle->pbHandle), handle->cbHandle); + cur += clen; + } - return hCard; + return buffer; } -void smartcard_scard_handle_native_to_redir(SMARTCARD_DEVICE* smartcard, REDIR_SCARDHANDLE* handle, - SCARDHANDLE hCard) +static char* smartcard_msz_dump_w(const WCHAR* msz, size_t len, char* buffer, size_t bufferLen) { - ZeroMemory(handle, sizeof(REDIR_SCARDHANDLE)); - handle->cbHandle = sizeof(ULONG_PTR); - CopyMemory(&(handle->pbHandle), &hCard, handle->cbHandle); + char* sz = NULL; + ConvertFromUnicode(CP_UTF8, 0, msz, (int)len, &sz, 0, NULL, NULL); + return smartcard_msz_dump_a(sz, len, buffer, bufferLen); } -LONG smartcard_unpack_redir_scard_context(SMARTCARD_DEVICE* smartcard, wStream* s, - REDIR_SCARDCONTEXT* context) +static char* smartcard_array_dump(const void* pd, size_t len, char* buffer, size_t bufferLen) { - UINT32 pbContextNdrPtr; - ZeroMemory(context, sizeof(REDIR_SCARDCONTEXT)); + const BYTE* data = pd; + size_t x; + int rc; + char* start = buffer; - if (Stream_GetRemainingLength(s) < 4) + /* Ensure '\0' termination */ + if (bufferLen > 0) { - WLog_WARN(TAG, "REDIR_SCARDCONTEXT is too short: %"PRIuz"", - Stream_GetRemainingLength(s)); - return STATUS_BUFFER_TOO_SMALL; + buffer[bufferLen - 1] = '\0'; + bufferLen--; } - Stream_Read_UINT32(s, context->cbContext); /* cbContext (4 bytes) */ - - if (Stream_GetRemainingLength(s) < context->cbContext) - { - WLog_WARN(TAG, "REDIR_SCARDCONTEXT is too short: Actual: %"PRIuz", Expected: %"PRIu32"", - Stream_GetRemainingLength(s), context->cbContext); - return STATUS_BUFFER_TOO_SMALL; - } + rc = _snprintf(buffer, bufferLen, "{ "); + if ((rc < 0) || ((size_t)rc > bufferLen)) + goto fail; + buffer += rc; + bufferLen -= (size_t)rc; - if ((context->cbContext != 0) && (context->cbContext != 4) && (context->cbContext != 8)) + for (x = 0; x < len; x++) { - WLog_WARN(TAG, "REDIR_SCARDCONTEXT length is not 0, 4 or 8: %"PRIu32"", context->cbContext); - return STATUS_INVALID_PARAMETER; + rc = _snprintf(buffer, bufferLen, "%02X", data[x]); + if ((rc < 0) || ((size_t)rc > bufferLen)) + goto fail; + buffer += rc; + bufferLen -= (size_t)rc; } - Stream_Read_UINT32(s, pbContextNdrPtr); /* pbContextNdrPtr (4 bytes) */ - - if (((context->cbContext == 0) && pbContextNdrPtr) || ((context->cbContext != 0) && - !pbContextNdrPtr)) - { - WLog_WARN(TAG, "REDIR_SCARDCONTEXT cbContext (%"PRIu32") pbContextNdrPtr (%"PRIu32") inconsistency", - context->cbContext, pbContextNdrPtr); - return STATUS_INVALID_PARAMETER; - } + rc = _snprintf(buffer, bufferLen, " }"); + if ((rc < 0) || ((size_t)rc > bufferLen)) + goto fail; + buffer += rc; + bufferLen -= (size_t)rc; - if (context->cbContext > Stream_GetRemainingLength(s)) - { - WLog_WARN(TAG, "REDIR_SCARDCONTEXT is too long: Actual: %"PRIuz", Expected: %"PRIu32"", - Stream_GetRemainingLength(s), context->cbContext); - return STATUS_INVALID_PARAMETER; - } +fail: + return start; +} +static void smartcard_log_redir_handle(const char* tag, const REDIR_SCARDHANDLE* pHandle) +{ + char buffer[128]; - return SCARD_S_SUCCESS; + WLog_LVL(tag, g_LogLevel, " hContext: %s", + smartcard_array_dump(pHandle->pbHandle, pHandle->cbHandle, buffer, sizeof(buffer))); } -LONG smartcard_pack_redir_scard_context(SMARTCARD_DEVICE* smartcard, wStream* s, - REDIR_SCARDCONTEXT* context) +static void smartcard_log_context(const char* tag, const REDIR_SCARDCONTEXT* phContext) { - UINT32 pbContextNdrPtr; - pbContextNdrPtr = (context->cbContext) ? 0x00020001 : 0; - Stream_Write_UINT32(s, context->cbContext); /* cbContext (4 bytes) */ - Stream_Write_UINT32(s, pbContextNdrPtr); /* pbContextNdrPtr (4 bytes) */ - return SCARD_S_SUCCESS; + char buffer[128]; + WLog_DBG( + tag, "hContext: %s", + smartcard_array_dump(phContext->pbContext, phContext->cbContext, buffer, sizeof(buffer))); } -LONG smartcard_unpack_redir_scard_context_ref(SMARTCARD_DEVICE* smartcard, wStream* s, - REDIR_SCARDCONTEXT* context) +static void smartcard_trace_context_and_string_call_a(const char* name, + const REDIR_SCARDCONTEXT* phContext, + const CHAR* sz) { - UINT32 length; + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) + return; - if (context->cbContext == 0) - return SCARD_S_SUCCESS; + WLog_LVL(TAG, g_LogLevel, "%s {", name); + smartcard_log_context(TAG, phContext); + WLog_LVL(TAG, g_LogLevel, " sz=%s", sz); - if (Stream_GetRemainingLength(s) < 4) - { - WLog_WARN(TAG, "REDIR_SCARDCONTEXT is too short: Actual: %"PRIuz", Expected: 4", - Stream_GetRemainingLength(s)); - return STATUS_BUFFER_TOO_SMALL; - } + WLog_LVL(TAG, g_LogLevel, "}"); +} - Stream_Read_UINT32(s, length); /* Length (4 bytes) */ +static void smartcard_trace_context_and_string_call_w(const char* name, + const REDIR_SCARDCONTEXT* phContext, + const WCHAR* sz) +{ + char* tmp = NULL; + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) + return; - if (length != context->cbContext) - { - WLog_WARN(TAG, "REDIR_SCARDCONTEXT length (%"PRIu32") cbContext (%"PRIu32") mismatch", - length, context->cbContext); - return STATUS_INVALID_PARAMETER; - } + WLog_LVL(TAG, g_LogLevel, "%s {", name); + smartcard_log_context(TAG, phContext); + ConvertFromUnicode(CP_UTF8, 0, sz, -1, &tmp, 0, NULL, NULL); + WLog_LVL(TAG, g_LogLevel, " sz=%s", tmp); + free(tmp); - if ((context->cbContext != 0) && (context->cbContext != 4) && (context->cbContext != 8)) - { - WLog_WARN(TAG, "REDIR_SCARDCONTEXT length is not 4 or 8: %"PRIu32"", context->cbContext); - return STATUS_INVALID_PARAMETER; - } + WLog_LVL(TAG, g_LogLevel, "}"); +} - if (Stream_GetRemainingLength(s) < context->cbContext) - { - WLog_WARN(TAG, "REDIR_SCARDCONTEXT is too short: Actual: %"PRIuz", Expected: %"PRIu32"", - Stream_GetRemainingLength(s), context->cbContext); - return STATUS_BUFFER_TOO_SMALL; - } +static void smartcard_trace_context_call(SMARTCARD_DEVICE* smartcard, const Context_Call* call, + const char* name) +{ + WINPR_UNUSED(smartcard); - if (context->cbContext) - Stream_Read(s, &(context->pbContext), context->cbContext); - else - ZeroMemory(&(context->pbContext), sizeof(context->pbContext)); + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) + return; - return SCARD_S_SUCCESS; + WLog_LVL(TAG, g_LogLevel, "%s_Call {", name); + smartcard_log_context(TAG, &call->hContext); + + WLog_LVL(TAG, g_LogLevel, "}"); } -LONG smartcard_pack_redir_scard_context_ref(SMARTCARD_DEVICE* smartcard, wStream* s, - REDIR_SCARDCONTEXT* context) +static void smartcard_trace_list_reader_groups_call(SMARTCARD_DEVICE* smartcard, + const ListReaderGroups_Call* call, BOOL unicode) { - Stream_Write_UINT32(s, context->cbContext); /* Length (4 bytes) */ + WINPR_UNUSED(smartcard); - if (context->cbContext) - { - Stream_Write(s, &(context->pbContext), context->cbContext); - } + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) + return; - return SCARD_S_SUCCESS; + WLog_LVL(TAG, g_LogLevel, "ListReaderGroups%S_Call {", unicode ? "W" : "A"); + smartcard_log_context(TAG, &call->hContext); + + WLog_LVL(TAG, g_LogLevel, "fmszGroupsIsNULL: %" PRId32 " cchGroups: 0x%08" PRIx32, + call->fmszGroupsIsNULL, call->cchGroups); + WLog_LVL(TAG, g_LogLevel, "}"); } -LONG smartcard_unpack_redir_scard_handle(SMARTCARD_DEVICE* smartcard, wStream* s, - REDIR_SCARDHANDLE* handle) +static void smartcard_trace_get_status_change_w_call(SMARTCARD_DEVICE* smartcard, + const GetStatusChangeW_Call* call) { - UINT32 pbHandleNdrPtr; - ZeroMemory(handle, sizeof(REDIR_SCARDHANDLE)); + UINT32 index; + char* szEventState; + char* szCurrentState; + LPSCARD_READERSTATEW readerState; + WINPR_UNUSED(smartcard); - if (Stream_GetRemainingLength(s) < 4) - { - WLog_WARN(TAG, "SCARDHANDLE is too short: %"PRIuz"", - Stream_GetRemainingLength(s)); - return STATUS_BUFFER_TOO_SMALL; - } + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) + return; - Stream_Read_UINT32(s, handle->cbHandle); /* Length (4 bytes) */ + WLog_LVL(TAG, g_LogLevel, "GetStatusChangeW_Call {"); + smartcard_log_context(TAG, &call->hContext); - if ((Stream_GetRemainingLength(s) < handle->cbHandle) || (!handle->cbHandle)) + WLog_LVL(TAG, g_LogLevel, "dwTimeOut: 0x%08" PRIX32 " cReaders: %" PRIu32 "", call->dwTimeOut, + call->cReaders); + + for (index = 0; index < call->cReaders; index++) { - WLog_WARN(TAG, "SCARDHANDLE is too short: Actual: %"PRIuz", Expected: %"PRIu32"", - Stream_GetRemainingLength(s), handle->cbHandle); - return STATUS_BUFFER_TOO_SMALL; + char* szReaderA = NULL; + readerState = &call->rgReaderStates[index]; + ConvertFromUnicode(CP_UTF8, 0, readerState->szReader, -1, &szReaderA, 0, NULL, NULL); + WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: szReader: %s cbAtr: %" PRIu32 "", index, + szReaderA, readerState->cbAtr); + szCurrentState = SCardGetReaderStateString(readerState->dwCurrentState); + szEventState = SCardGetReaderStateString(readerState->dwEventState); + WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: dwCurrentState: %s (0x%08" PRIX32 ")", index, + szCurrentState, readerState->dwCurrentState); + WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: dwEventState: %s (0x%08" PRIX32 ")", index, + szEventState, readerState->dwEventState); + free(szCurrentState); + free(szEventState); + free(szReaderA); } - Stream_Read_UINT32(s, pbHandleNdrPtr); /* NdrPtr (4 bytes) */ - return SCARD_S_SUCCESS; + WLog_LVL(TAG, g_LogLevel, "}"); } -LONG smartcard_pack_redir_scard_handle(SMARTCARD_DEVICE* smartcard, wStream* s, - REDIR_SCARDHANDLE* handle) +static void smartcard_trace_list_reader_groups_return(SMARTCARD_DEVICE* smartcard, + const ListReaderGroups_Return* ret, + BOOL unicode) { - UINT32 pbHandleNdrPtr; - pbHandleNdrPtr = (handle->cbHandle) ? 0x00020002 : 0; - Stream_Write_UINT32(s, handle->cbHandle); /* cbHandle (4 bytes) */ - Stream_Write_UINT32(s, pbHandleNdrPtr); /* pbHandleNdrPtr (4 bytes) */ - return SCARD_S_SUCCESS; + char* mszA = NULL; + WINPR_UNUSED(smartcard); + + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) + return; + + mszA = smartcard_convert_string_list(ret->msz, ret->cBytes, unicode); + + WLog_LVL(TAG, g_LogLevel, "ListReaderGroups%s_Return {", unicode ? "W" : "A"); + WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIx32 ")", + SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); + WLog_LVL(TAG, g_LogLevel, " cBytes: %" PRIu32 " msz: %s", ret->cBytes, mszA); + WLog_LVL(TAG, g_LogLevel, "}"); + free(mszA); } -LONG smartcard_unpack_redir_scard_handle_ref(SMARTCARD_DEVICE* smartcard, wStream* s, - REDIR_SCARDHANDLE* handle) +static void smartcard_trace_list_readers_call(SMARTCARD_DEVICE* smartcard, + const ListReaders_Call* call, BOOL unicode) { - UINT32 length; + char* mszGroupsA = NULL; + WINPR_UNUSED(smartcard); - if (Stream_GetRemainingLength(s) < 4) - { - WLog_WARN(TAG, "REDIR_SCARDHANDLE is too short: Actual: %"PRIuz", Expected: 4", - Stream_GetRemainingLength(s)); - return STATUS_BUFFER_TOO_SMALL; - } - - Stream_Read_UINT32(s, length); /* Length (4 bytes) */ - - if (length != handle->cbHandle) - { - WLog_WARN(TAG, "REDIR_SCARDHANDLE length (%"PRIu32") cbHandle (%"PRIu32") mismatch", - length, handle->cbHandle); - return STATUS_INVALID_PARAMETER; - } + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) + return; - if ((handle->cbHandle != 4) && (handle->cbHandle != 8)) - { - WLog_WARN(TAG, "REDIR_SCARDHANDLE length is not 4 or 8: %"PRIu32"", handle->cbHandle); - return STATUS_INVALID_PARAMETER; - } + mszGroupsA = smartcard_convert_string_list(call->mszGroups, call->cBytes, unicode); - if ((Stream_GetRemainingLength(s) < handle->cbHandle) || (!handle->cbHandle)) - { - WLog_WARN(TAG, "REDIR_SCARDHANDLE is too short: Actual: %"PRIuz", Expected: %"PRIu32"", - Stream_GetRemainingLength(s), handle->cbHandle); - return STATUS_BUFFER_TOO_SMALL; - } + WLog_LVL(TAG, g_LogLevel, "ListReaders%s_Call {", unicode ? "W" : "A"); + smartcard_log_context(TAG, &call->hContext); - if (handle->cbHandle) - Stream_Read(s, &(handle->pbHandle), handle->cbHandle); + WLog_LVL(TAG, g_LogLevel, + "cBytes: %" PRIu32 " mszGroups: %s fmszReadersIsNULL: %" PRId32 + " cchReaders: 0x%08" PRIX32 "", + call->cBytes, mszGroupsA, call->fmszReadersIsNULL, call->cchReaders); + WLog_LVL(TAG, g_LogLevel, "}"); - return SCARD_S_SUCCESS; + free(mszGroupsA); } -LONG smartcard_pack_redir_scard_handle_ref(SMARTCARD_DEVICE* smartcard, wStream* s, - REDIR_SCARDHANDLE* handle) +static void smartcard_trace_locate_cards_by_atr_a_call(SMARTCARD_DEVICE* smartcard, + const LocateCardsByATRA_Call* call) { - Stream_Write_UINT32(s, handle->cbHandle); /* Length (4 bytes) */ + UINT32 index; + char* szEventState; + char* szCurrentState; - if (handle->cbHandle) - Stream_Write(s, &(handle->pbHandle), handle->cbHandle); + WINPR_UNUSED(smartcard); - return SCARD_S_SUCCESS; -} + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) + return; -LONG smartcard_unpack_establish_context_call(SMARTCARD_DEVICE* smartcard, wStream* s, - EstablishContext_Call* call) -{ - if (Stream_GetRemainingLength(s) < 4) + WLog_LVL(TAG, g_LogLevel, "LocateCardsByATRA_Call {"); + smartcard_log_context(TAG, &call->hContext); + + for (index = 0; index < call->cReaders; index++) { - WLog_WARN(TAG, "EstablishContext_Call is too short: Actual: %"PRIuz", Expected: 4", - Stream_GetRemainingLength(s)); - return STATUS_BUFFER_TOO_SMALL; + char buffer[1024]; + const LPSCARD_READERSTATEA readerState = &call->rgReaderStates[index]; + + WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: szReader: %s cbAtr: %" PRIu32 "", index, + readerState->szReader, readerState->cbAtr); + szCurrentState = SCardGetReaderStateString(readerState->dwCurrentState); + szEventState = SCardGetReaderStateString(readerState->dwEventState); + WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: dwCurrentState: %s (0x%08" PRIX32 ")", index, + szCurrentState, readerState->dwCurrentState); + WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: dwEventState: %s (0x%08" PRIX32 ")", index, + szEventState, readerState->dwEventState); + + WLog_DBG( + TAG, "\t[%" PRIu32 "]: cbAtr: %" PRIu32 " rgbAtr: %s", index, readerState->cbAtr, + smartcard_array_dump(readerState->rgbAtr, readerState->cbAtr, buffer, sizeof(buffer))); + + free(szCurrentState); + free(szEventState); } - Stream_Read_UINT32(s, call->dwScope); /* dwScope (4 bytes) */ - return SCARD_S_SUCCESS; + WLog_LVL(TAG, g_LogLevel, "}"); } -void smartcard_trace_establish_context_call(SMARTCARD_DEVICE* smartcard, - EstablishContext_Call* call) +static void smartcard_trace_locate_cards_a_call(SMARTCARD_DEVICE* smartcard, + const LocateCardsA_Call* call) { - if (!WLog_IsLevelActive(WLog_Get(TAG), WLOG_DEBUG)) + char buffer[8192]; + WINPR_UNUSED(smartcard); + + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) return; - WLog_DBG(TAG, "EstablishContext_Call {"); - WLog_DBG(TAG, "dwScope: %s (0x%08"PRIX32")", - SCardGetScopeString(call->dwScope), call->dwScope); - WLog_DBG(TAG, "}"); + WLog_LVL(TAG, g_LogLevel, "LocateCardsA_Call {"); + smartcard_log_context(TAG, &call->hContext); + WLog_LVL(TAG, g_LogLevel, " cBytes=%" PRId32, call->cBytes); + WLog_LVL(TAG, g_LogLevel, " mszCards=%s", + smartcard_msz_dump_a(call->mszCards, call->cBytes, buffer, sizeof(buffer))); + WLog_LVL(TAG, g_LogLevel, " cReaders=%" PRId32, call->cReaders); + // WLog_LVL(TAG, g_LogLevel, " cReaders=%" PRId32, call->rgReaderStates); + + WLog_LVL(TAG, g_LogLevel, "}"); } -LONG smartcard_pack_establish_context_return(SMARTCARD_DEVICE* smartcard, wStream* s, - EstablishContext_Return* ret) +static void smartcard_trace_locate_cards_return(SMARTCARD_DEVICE* smartcard, + const LocateCards_Return* ret) { - LONG status; + WINPR_UNUSED(smartcard); + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) + return; + + WLog_LVL(TAG, g_LogLevel, "LocateCards_Return {"); + WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", + SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); - if ((status = smartcard_pack_redir_scard_context(smartcard, s, &(ret->hContext)))) + if (ret->ReturnCode == SCARD_S_SUCCESS) { - WLog_ERR(TAG, "smartcard_pack_redir_scard_context failed with error %"PRId32"", status); - return status; + WLog_LVL(TAG, g_LogLevel, " cReaders=%" PRId32, ret->cReaders); } - - if ((status = smartcard_pack_redir_scard_context_ref(smartcard, s, &(ret->hContext)))) - WLog_ERR(TAG, "smartcard_pack_redir_scard_context_ref failed with error %"PRId32"", status); - - return status; + WLog_LVL(TAG, g_LogLevel, "}"); } -void smartcard_trace_establish_context_return(SMARTCARD_DEVICE* smartcard, - EstablishContext_Return* ret) +static void smartcard_trace_get_reader_icon_return(SMARTCARD_DEVICE* smartcard, + const GetReaderIcon_Return* ret) { - BYTE* pb; - - if (!WLog_IsLevelActive(WLog_Get(TAG), WLOG_DEBUG)) + WINPR_UNUSED(smartcard); + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) return; - WLog_DBG(TAG, "EstablishContext_Return {"); - WLog_DBG(TAG, "ReturnCode: %s (0x%08"PRIX32")", + WLog_LVL(TAG, g_LogLevel, "GetReaderIcon_Return {"); + WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); - pb = (BYTE*) & (ret->hContext.pbContext); - if (ret->hContext.cbContext > 4) - { - WLog_DBG(TAG, - "hContext: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], pb[4], pb[5], pb[6], pb[7], ret->hContext.cbContext); - } - else + if (ret->ReturnCode == SCARD_S_SUCCESS) { - WLog_DBG(TAG, "hContext: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], ret->hContext.cbContext); + WLog_LVL(TAG, g_LogLevel, " cbDataLen=%" PRId32, ret->cbDataLen); } - - WLog_DBG(TAG, "}"); + WLog_LVL(TAG, g_LogLevel, "}"); } -LONG smartcard_unpack_context_call(SMARTCARD_DEVICE* smartcard, wStream* s, Context_Call* call) +static void smartcard_trace_get_transmit_count_return(SMARTCARD_DEVICE* smartcard, + const GetTransmitCount_Return* ret) { - LONG status; - - if ((status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext)))) - { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_context failed with error %"PRId32"", status); - return status; - } + WINPR_UNUSED(smartcard); + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) + return; - if ((status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->hContext)))) - WLog_ERR(TAG, "smartcard_unpack_redir_scard_context_ref failed with error %"PRId32"", status); + WLog_LVL(TAG, g_LogLevel, "GetTransmitCount_Return {"); + WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", + SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); - return status; + WLog_LVL(TAG, g_LogLevel, " cTransmitCount=%" PRIu32, ret->cTransmitCount); + WLog_LVL(TAG, g_LogLevel, "}"); } -void smartcard_trace_context_call(SMARTCARD_DEVICE* smartcard, Context_Call* call, const char* name) +static void smartcard_trace_read_cache_return(SMARTCARD_DEVICE* smartcard, + const ReadCache_Return* ret) { - BYTE* pb; - - if (!WLog_IsLevelActive(WLog_Get(TAG), WLOG_DEBUG)) + WINPR_UNUSED(smartcard); + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) return; - WLog_DBG(TAG, "%s_Call {", name); - pb = (BYTE*) & (call->hContext.pbContext); + WLog_LVL(TAG, g_LogLevel, "ReadCache_Return {"); + WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", + SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); - if (call->hContext.cbContext > 4) + if (ret->ReturnCode == SCARD_S_SUCCESS) { - WLog_DBG(TAG, - "hContext: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], pb[4], pb[5], pb[6], pb[7], call->hContext.cbContext); + char buffer[1024]; + WLog_LVL(TAG, g_LogLevel, " cbDataLen=%" PRId32, ret->cbDataLen); + WLog_LVL(TAG, g_LogLevel, " cbData: %s", + smartcard_array_dump(ret->pbData, ret->cbDataLen, buffer, sizeof(buffer))); } - else - { - WLog_DBG(TAG, "hContext: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], call->hContext.cbContext); - } - - WLog_DBG(TAG, "}"); + WLog_LVL(TAG, g_LogLevel, "}"); } -void smartcard_trace_long_return(SMARTCARD_DEVICE* smartcard, Long_Return* ret, const char* name) +static void smartcard_trace_locate_cards_w_call(SMARTCARD_DEVICE* smartcard, + const LocateCardsW_Call* call) { - if (!WLog_IsLevelActive(WLog_Get(TAG), WLOG_DEBUG)) + char buffer[8192]; + WINPR_UNUSED(smartcard); + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) return; - WLog_DBG(TAG, "%s_Return {", name); - WLog_DBG(TAG, "ReturnCode: %s (0x%08"PRIX32")", - SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); - WLog_DBG(TAG, "}"); + WLog_LVL(TAG, g_LogLevel, "LocateCardsW_Call {"); + smartcard_log_context(TAG, &call->hContext); + WLog_LVL(TAG, g_LogLevel, " cBytes=%" PRId32, call->cBytes); + WLog_LVL(TAG, g_LogLevel, " sz2=%s", + smartcard_msz_dump_w(call->mszCards, call->cBytes, buffer, sizeof(buffer))); + WLog_LVL(TAG, g_LogLevel, " cReaders=%" PRId32, call->cReaders); + // WLog_LVL(TAG, g_LogLevel, " sz2=%s", call->rgReaderStates); + WLog_LVL(TAG, g_LogLevel, "}"); } -LONG smartcard_unpack_list_reader_groups_call(SMARTCARD_DEVICE* smartcard, wStream* s, - ListReaderGroups_Call* call) +static void smartcard_trace_list_readers_return(SMARTCARD_DEVICE* smartcard, + const ListReaders_Return* ret, BOOL unicode) { - LONG status; - status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext)); + char* mszA = NULL; + WINPR_UNUSED(smartcard); - if (status) - return status; + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) + return; - if (Stream_GetRemainingLength(s) < 8) + WLog_LVL(TAG, g_LogLevel, "ListReaders%s_Return {", unicode ? "W" : "A"); + WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", + SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); + + if (ret->ReturnCode != SCARD_S_SUCCESS) { - WLog_WARN(TAG, "ListReaderGroups_Call is too short: %d", - (int) Stream_GetRemainingLength(s)); - return STATUS_BUFFER_TOO_SMALL; + WLog_LVL(TAG, g_LogLevel, "}"); + return; } - Stream_Read_UINT32(s, call->fmszGroupsIsNULL); /* fmszGroupsIsNULL (4 bytes) */ - Stream_Read_UINT32(s, call->cchGroups); /* cchGroups (4 bytes) */ - status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->hContext)); - - if (status) - return status; + mszA = smartcard_convert_string_list(ret->msz, ret->cBytes, unicode); - return SCARD_S_SUCCESS; + WLog_LVL(TAG, g_LogLevel, " cBytes: %" PRIu32 " msz: %s", ret->cBytes, mszA); + WLog_LVL(TAG, g_LogLevel, "}"); + free(mszA); } -void smartcard_trace_list_reader_groups_call(SMARTCARD_DEVICE* smartcard, - ListReaderGroups_Call* call, BOOL unicode) +static void smartcard_trace_get_status_change_return(SMARTCARD_DEVICE* smartcard, + const GetStatusChange_Return* ret, + BOOL unicode) { - BYTE* pb; + UINT32 index; + char* szEventState; + char* szCurrentState; - if (!WLog_IsLevelActive(WLog_Get(TAG), WLOG_DEBUG)) + WINPR_UNUSED(smartcard); + + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) return; - WLog_DBG(TAG, "ListReaderGroups%S_Call {", unicode ? "W" : "A"); - pb = (BYTE*) & (call->hContext.pbContext); + WLog_LVL(TAG, g_LogLevel, "GetStatusChange%s_Return {", unicode ? "W" : "A"); + WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", + SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); + WLog_LVL(TAG, g_LogLevel, " cReaders: %" PRIu32 "", ret->cReaders); - if (call->hContext.cbContext > 4) - { - WLog_DBG(TAG, - "hContext: 0x%02"PRIx8"%02"PRIx8"%02"PRIx8"%02"PRIx8"%02"PRIx8"%02"PRIx8"%02"PRIx8"%02"PRIx8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], pb[4], pb[5], pb[6], pb[7], call->hContext.cbContext); - } - else + for (index = 0; index < ret->cReaders; index++) { - WLog_DBG(TAG, "hContext: 0x%02"PRIx8"%02"PRIx8"%02"PRIx8"%02"PRIx8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], call->hContext.cbContext); + char buffer[1024]; + const ReaderState_Return* rgReaderState = &(ret->rgReaderStates[index]); + szCurrentState = SCardGetReaderStateString(rgReaderState->dwCurrentState); + szEventState = SCardGetReaderStateString(rgReaderState->dwEventState); + WLog_LVL(TAG, g_LogLevel, " [%" PRIu32 "]: dwCurrentState: %s (0x%08" PRIX32 ")", index, + szCurrentState, rgReaderState->dwCurrentState); + WLog_LVL(TAG, g_LogLevel, " [%" PRIu32 "]: dwEventState: %s (0x%08" PRIX32 ")", index, + szEventState, rgReaderState->dwEventState); + WLog_LVL(TAG, g_LogLevel, " [%" PRIu32 "]: cbAtr: %" PRIu32 " rgbAtr: %s", index, + rgReaderState->cbAtr, + smartcard_array_dump(rgReaderState->rgbAtr, rgReaderState->cbAtr, buffer, + sizeof(buffer))); + free(szCurrentState); + free(szEventState); } - WLog_DBG(TAG, "fmszGroupsIsNULL: %"PRId32" cchGroups: 0x%08"PRIx32, - call->fmszGroupsIsNULL, call->cchGroups); - WLog_DBG(TAG, "}"); + WLog_LVL(TAG, g_LogLevel, "}"); } -LONG smartcard_pack_list_reader_groups_return(SMARTCARD_DEVICE* smartcard, wStream* s, - ListReaderGroups_Return* ret) +static void smartcard_trace_context_and_two_strings_a_call(SMARTCARD_DEVICE* smartcard, + const ContextAndTwoStringA_Call* call) { - UINT32 mszNdrPtr; - mszNdrPtr = (ret->cBytes) ? 0x00020008 : 0; - Stream_EnsureRemainingCapacity(s, ret->cBytes + 32); - Stream_Write_UINT32(s, ret->cBytes); /* cBytes (4 bytes) */ - Stream_Write_UINT32(s, mszNdrPtr); /* mszNdrPtr (4 bytes) */ + WINPR_UNUSED(smartcard); + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) + return; - if (mszNdrPtr) - { - Stream_Write_UINT32(s, ret->cBytes); /* mszNdrLen (4 bytes) */ + WLog_LVL(TAG, g_LogLevel, "ContextAndTwoStringW_Call {"); + smartcard_log_context(TAG, &call->hContext); + WLog_LVL(TAG, g_LogLevel, " sz1=%s", call->sz1); + WLog_LVL(TAG, g_LogLevel, " sz2=%s", call->sz2); + WLog_LVL(TAG, g_LogLevel, "}"); +} - if (ret->msz) - Stream_Write(s, ret->msz, ret->cBytes); - else - Stream_Zero(s, ret->cBytes); +static void smartcard_trace_context_and_two_strings_w_call(SMARTCARD_DEVICE* smartcard, + const ContextAndTwoStringW_Call* call) +{ + CHAR* sz1 = NULL; + CHAR* sz2 = NULL; - smartcard_pack_write_size_align(smartcard, s, ret->cBytes, 4); - } + WINPR_UNUSED(smartcard); + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) + return; - return SCARD_S_SUCCESS; + WLog_LVL(TAG, g_LogLevel, "ContextAndTwoStringW_Call {"); + smartcard_log_context(TAG, &call->hContext); + ConvertFromUnicode(CP_UTF8, 0, call->sz1, -1, &sz1, 0, NULL, NULL); + ConvertFromUnicode(CP_UTF8, 0, call->sz2, -1, &sz2, 0, NULL, NULL); + WLog_LVL(TAG, g_LogLevel, " sz1=%s", sz1); + WLog_LVL(TAG, g_LogLevel, " sz2=%s", sz2); + free(sz1); + free(sz2); + + WLog_LVL(TAG, g_LogLevel, "}"); } -void smartcard_trace_list_reader_groups_return(SMARTCARD_DEVICE* smartcard, - ListReaderGroups_Return* ret, BOOL unicode) +static void smartcard_trace_get_transmit_count_call(SMARTCARD_DEVICE* smartcard, + const GetTransmitCount_Call* call) { - int index; - int length; - char* mszA = NULL; - - if (!WLog_IsLevelActive(WLog_Get(TAG), WLOG_DEBUG)) + WINPR_UNUSED(smartcard); + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) return; - if (unicode) - { - length = ret->cBytes / 2; - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) ret->msz, length, &mszA, 0, NULL, NULL); - } - else - { - length = ret->cBytes; - mszA = (char*) malloc(length); - CopyMemory(mszA, ret->msz, ret->cBytes); - } - - for (index = 0; index < length - 2; index++) - { - if (mszA[index] == '\0') - mszA[index] = ','; - } + WLog_LVL(TAG, g_LogLevel, "GetTransmitCount_Call {"); + smartcard_log_context(TAG, &call->hContext); + smartcard_log_redir_handle(TAG, &call->hCard); - WLog_DBG(TAG, "ListReaderGroups%s_Return {", unicode ? "W" : "A"); - WLog_DBG(TAG, "ReturnCode: %s (0x%08"PRIx32")", - SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); - WLog_DBG(TAG, "cBytes: %"PRIu32" msz: %s", ret->cBytes, mszA); - WLog_DBG(TAG, "}"); - free(mszA); + WLog_LVL(TAG, g_LogLevel, "}"); } -LONG smartcard_unpack_list_readers_call(SMARTCARD_DEVICE* smartcard, wStream* s, - ListReaders_Call* call) +static void smartcard_trace_write_cache_a_call(SMARTCARD_DEVICE* smartcard, + const WriteCacheA_Call* call) { - LONG status; - UINT32 count; - UINT32 mszGroupsNdrPtr; - call->mszGroups = NULL; + char buffer[1024]; + WINPR_UNUSED(smartcard); + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) + return; - if ((status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext)))) - { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_context failed with error %"PRId32"", status); - return status; - } + WLog_LVL(TAG, g_LogLevel, "GetTransmitCount_Call {"); - if (Stream_GetRemainingLength(s) < 16) - { - WLog_WARN(TAG, "ListReaders_Call is too short: %"PRIuz"", - Stream_GetRemainingLength(s)); - return STATUS_BUFFER_TOO_SMALL; - } + WLog_LVL(TAG, g_LogLevel, " szLookupName=%s", call->szLookupName); - Stream_Read_UINT32(s, call->cBytes); /* cBytes (4 bytes) */ - Stream_Read_UINT32(s, mszGroupsNdrPtr); /* mszGroupsNdrPtr (4 bytes) */ - Stream_Read_UINT32(s, call->fmszReadersIsNULL); /* fmszReadersIsNULL (4 bytes) */ - Stream_Read_UINT32(s, call->cchReaders); /* cchReaders (4 bytes) */ + smartcard_log_context(TAG, &call->Common.hContext); + WLog_DBG( + TAG, "..CardIdentifier=%s", + smartcard_array_dump(call->Common.CardIdentifier, sizeof(UUID), buffer, sizeof(buffer))); + WLog_LVL(TAG, g_LogLevel, " FreshnessCounter=%" PRIu32, call->Common.FreshnessCounter); + WLog_LVL(TAG, g_LogLevel, " cbDataLen=%" PRIu32, call->Common.cbDataLen); + WLog_DBG( + TAG, " pbData=%s", + smartcard_array_dump(call->Common.pbData, call->Common.cbDataLen, buffer, sizeof(buffer))); + WLog_LVL(TAG, g_LogLevel, "}"); +} - if ((status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->hContext)))) - { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_context_ref failed with error %"PRId32"", status); - return status; - } +static void smartcard_trace_write_cache_w_call(SMARTCARD_DEVICE* smartcard, + const WriteCacheW_Call* call) +{ + char* tmp = NULL; + char buffer[1024]; + WINPR_UNUSED(smartcard); + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) + return; - if ((mszGroupsNdrPtr && !call->cBytes) || (!mszGroupsNdrPtr && call->cBytes)) - { - WLog_WARN(TAG, - "ListReaders_Call mszGroupsNdrPtr (0x%08"PRIX32") and cBytes (0x%08"PRIX32") inconsistency", - mszGroupsNdrPtr, call->cBytes); - return STATUS_INVALID_PARAMETER; - } + WLog_LVL(TAG, g_LogLevel, "GetTransmitCount_Call {"); + + ConvertFromUnicode(CP_UTF8, 0, call->szLookupName, -1, &tmp, 0, NULL, NULL); + WLog_LVL(TAG, g_LogLevel, " szLookupName=%s", tmp); + free(tmp); + smartcard_log_context(TAG, &call->Common.hContext); + WLog_DBG( + TAG, "..CardIdentifier=%s", + smartcard_array_dump(call->Common.CardIdentifier, sizeof(UUID), buffer, sizeof(buffer))); + WLog_LVL(TAG, g_LogLevel, " FreshnessCounter=%" PRIu32, call->Common.FreshnessCounter); + WLog_LVL(TAG, g_LogLevel, " cbDataLen=%" PRIu32, call->Common.cbDataLen); + WLog_DBG( + TAG, " pbData=%s", + smartcard_array_dump(call->Common.pbData, call->Common.cbDataLen, buffer, sizeof(buffer))); + WLog_LVL(TAG, g_LogLevel, "}"); +} + +static void smartcard_trace_read_cache_a_call(SMARTCARD_DEVICE* smartcard, + const ReadCacheA_Call* call) +{ + char buffer[1024]; + WINPR_UNUSED(smartcard); + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) + return; - if (mszGroupsNdrPtr) - { - Stream_Read_UINT32(s, count); /* NdrCount (4 bytes) */ + WLog_LVL(TAG, g_LogLevel, "GetTransmitCount_Call {"); - if (count != call->cBytes) - { - WLog_WARN(TAG, "ListReaders_Call NdrCount (0x%08"PRIX32") and cBytes (0x%08"PRIX32") inconsistency", - count, call->cBytes); - return STATUS_INVALID_PARAMETER; - } + WLog_LVL(TAG, g_LogLevel, " szLookupName=%s", call->szLookupName); + smartcard_log_context(TAG, &call->Common.hContext); + WLog_DBG( + TAG, "..CardIdentifier=%s", + smartcard_array_dump(call->Common.CardIdentifier, sizeof(UUID), buffer, sizeof(buffer))); + WLog_LVL(TAG, g_LogLevel, " FreshnessCounter=%" PRIu32, call->Common.FreshnessCounter); + WLog_LVL(TAG, g_LogLevel, " fPbDataIsNULL=%" PRId32, call->Common.fPbDataIsNULL); + WLog_LVL(TAG, g_LogLevel, " cbDataLen=%" PRIu32, call->Common.cbDataLen); - if (Stream_GetRemainingLength(s) < call->cBytes) - { - WLog_WARN(TAG, "ListReaders_Call is too short: Actual: %"PRIuz", Expected: %"PRIu32"", - Stream_GetRemainingLength(s), call->cBytes); - return STATUS_BUFFER_TOO_SMALL; - } + WLog_LVL(TAG, g_LogLevel, "}"); +} - call->mszGroups = (BYTE*) calloc(1, call->cBytes + 4); +static void smartcard_trace_read_cache_w_call(SMARTCARD_DEVICE* smartcard, + const ReadCacheW_Call* call) +{ + char* tmp = NULL; + char buffer[1024]; + WINPR_UNUSED(smartcard); + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) + return; - if (!call->mszGroups) - { - WLog_WARN(TAG, "ListReaders_Call out of memory error (mszGroups)"); - return STATUS_NO_MEMORY; - } + WLog_LVL(TAG, g_LogLevel, "GetTransmitCount_Call {"); - Stream_Read(s, call->mszGroups, call->cBytes); - smartcard_unpack_read_size_align(smartcard, s, call->cBytes, 4); - } + ConvertFromUnicode(CP_UTF8, 0, call->szLookupName, -1, &tmp, 0, NULL, NULL); + WLog_LVL(TAG, g_LogLevel, " szLookupName=%s", tmp); + free(tmp); + smartcard_log_context(TAG, &call->Common.hContext); + WLog_DBG( + TAG, "..CardIdentifier=%s", + smartcard_array_dump(call->Common.CardIdentifier, sizeof(UUID), buffer, sizeof(buffer))); + WLog_LVL(TAG, g_LogLevel, " FreshnessCounter=%" PRIu32, call->Common.FreshnessCounter); + WLog_LVL(TAG, g_LogLevel, " fPbDataIsNULL=%" PRId32, call->Common.fPbDataIsNULL); + WLog_LVL(TAG, g_LogLevel, " cbDataLen=%" PRIu32, call->Common.cbDataLen); - return SCARD_S_SUCCESS; + WLog_LVL(TAG, g_LogLevel, "}"); } -void smartcard_trace_list_readers_call(SMARTCARD_DEVICE* smartcard, ListReaders_Call* call, - BOOL unicode) +static void smartcard_trace_transmit_call(SMARTCARD_DEVICE* smartcard, const Transmit_Call* call) { - BYTE* pb; - char* mszGroupsA = NULL; + UINT32 cbExtraBytes; + BYTE* pbExtraBytes; + WINPR_UNUSED(smartcard); - if (!WLog_IsLevelActive(WLog_Get(TAG), WLOG_DEBUG)) + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) return; - if (unicode) - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) call->mszGroups, call->cBytes / 2, &mszGroupsA, 0, NULL, - NULL); + WLog_LVL(TAG, g_LogLevel, "Transmit_Call {"); + smartcard_log_context(TAG, &call->hContext); + smartcard_log_redir_handle(TAG, &call->hCard); + + if (call->pioSendPci) + { + cbExtraBytes = (UINT32)(call->pioSendPci->cbPciLength - sizeof(SCARD_IO_REQUEST)); + pbExtraBytes = &((BYTE*)call->pioSendPci)[sizeof(SCARD_IO_REQUEST)]; + WLog_LVL(TAG, g_LogLevel, "pioSendPci: dwProtocol: %" PRIu32 " cbExtraBytes: %" PRIu32 "", + call->pioSendPci->dwProtocol, cbExtraBytes); + + if (cbExtraBytes) + { + char buffer[1024]; + WLog_LVL(TAG, g_LogLevel, "pbExtraBytes: %s", + smartcard_array_dump(pbExtraBytes, cbExtraBytes, buffer, sizeof(buffer))); + } + } + else + { + WLog_LVL(TAG, g_LogLevel, "pioSendPci: null"); + } - WLog_DBG(TAG, "ListReaders%s_Call {", unicode ? "W" : "A"); - pb = (BYTE*) & (call->hContext.pbContext); + WLog_LVL(TAG, g_LogLevel, "cbSendLength: %" PRIu32 "", call->cbSendLength); - if (call->hContext.cbContext > 4) + if (call->pbSendBuffer) { - WLog_DBG(TAG, - "hContext: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], pb[4], pb[5], pb[6], pb[7], call->hContext.cbContext); + char buffer[1024]; + WLog_DBG( + TAG, "pbSendBuffer: %s", + smartcard_array_dump(call->pbSendBuffer, call->cbSendLength, buffer, sizeof(buffer))); } else { - WLog_DBG(TAG, "hContext: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], call->hContext.cbContext); + WLog_LVL(TAG, g_LogLevel, "pbSendBuffer: null"); } - WLog_DBG(TAG, - "cBytes: %"PRIu32" mszGroups: %s fmszReadersIsNULL: %"PRId32" cchReaders: 0x%08"PRIX32"", - call->cBytes, mszGroupsA, call->fmszReadersIsNULL, call->cchReaders); - WLog_DBG(TAG, "}"); + if (call->pioRecvPci) + { + cbExtraBytes = (UINT32)(call->pioRecvPci->cbPciLength - sizeof(SCARD_IO_REQUEST)); + pbExtraBytes = &((BYTE*)call->pioRecvPci)[sizeof(SCARD_IO_REQUEST)]; + WLog_LVL(TAG, g_LogLevel, "pioRecvPci: dwProtocol: %" PRIu32 " cbExtraBytes: %" PRIu32 "", + call->pioRecvPci->dwProtocol, cbExtraBytes); - if (unicode) - free(mszGroupsA); + if (cbExtraBytes) + { + char buffer[1024]; + WLog_LVL(TAG, g_LogLevel, "pbExtraBytes: %s", + smartcard_array_dump(pbExtraBytes, cbExtraBytes, buffer, sizeof(buffer))); + } + } + else + { + WLog_LVL(TAG, g_LogLevel, "pioRecvPci: null"); + } + + WLog_LVL(TAG, g_LogLevel, "fpbRecvBufferIsNULL: %" PRId32 " cbRecvLength: %" PRIu32 "", + call->fpbRecvBufferIsNULL, call->cbRecvLength); + WLog_LVL(TAG, g_LogLevel, "}"); } -LONG smartcard_pack_list_readers_return(SMARTCARD_DEVICE* smartcard, wStream* s, - ListReaders_Return* ret) +static void smartcard_trace_locate_cards_by_atr_w_call(SMARTCARD_DEVICE* smartcard, + const LocateCardsByATRW_Call* call) { - UINT32 mszNdrPtr; - LONG error; - - if (ret->ReturnCode != SCARD_S_SUCCESS) - return ret->ReturnCode; + UINT32 index; + char* szEventState; + char* szCurrentState; - mszNdrPtr = (ret->cBytes) ? 0x00020008 : 0; + WINPR_UNUSED(smartcard); - if (!Stream_EnsureRemainingCapacity(s, ret->cBytes + 32)) - { - WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); - return SCARD_F_INTERNAL_ERROR; - } + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) + return; - Stream_Write_UINT32(s, ret->cBytes); /* cBytes (4 bytes) */ - Stream_Write_UINT32(s, mszNdrPtr); /* mszNdrPtr (4 bytes) */ + WLog_LVL(TAG, g_LogLevel, "LocateCardsByATRW_Call {"); + smartcard_log_context(TAG, &call->hContext); - if (mszNdrPtr) + for (index = 0; index < call->cReaders; index++) { - Stream_Write_UINT32(s, ret->cBytes); /* mszNdrLen (4 bytes) */ + char buffer[1024]; + char* tmp = NULL; + const LPSCARD_READERSTATEW readerState = + (const LPSCARD_READERSTATEW)&call->rgReaderStates[index]; - if (ret->msz) - Stream_Write(s, ret->msz, ret->cBytes); - else - Stream_Zero(s, ret->cBytes); + ConvertFromUnicode(CP_UTF8, 0, readerState->szReader, -1, &tmp, 0, NULL, NULL); + WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: szReader: %s cbAtr: %" PRIu32 "", index, tmp, + readerState->cbAtr); + szCurrentState = SCardGetReaderStateString(readerState->dwCurrentState); + szEventState = SCardGetReaderStateString(readerState->dwEventState); + WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: dwCurrentState: %s (0x%08" PRIX32 ")", index, + szCurrentState, readerState->dwCurrentState); + WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: dwEventState: %s (0x%08" PRIX32 ")", index, + szEventState, readerState->dwEventState); - if ((error = smartcard_pack_write_size_align(smartcard, s, ret->cBytes, 4))) - { - WLog_ERR(TAG, "smartcard_pack_write_size_align failed with error %"PRId32"", error); - return error; - } + WLog_DBG( + TAG, "\t[%" PRIu32 "]: cbAtr: %" PRIu32 " rgbAtr: %s", index, readerState->cbAtr, + smartcard_array_dump(readerState->rgbAtr, readerState->cbAtr, buffer, sizeof(buffer))); + + free(szCurrentState); + free(szEventState); + free(tmp); } - return SCARD_S_SUCCESS; + WLog_LVL(TAG, g_LogLevel, "}"); } -void smartcard_trace_list_readers_return(SMARTCARD_DEVICE* smartcard, ListReaders_Return* ret, - BOOL unicode) +static void smartcard_trace_transmit_return(SMARTCARD_DEVICE* smartcard, const Transmit_Return* ret) { - int index; - size_t length; - char* mszA = NULL; + UINT32 cbExtraBytes; + BYTE* pbExtraBytes; + WINPR_UNUSED(smartcard); - if (!WLog_IsLevelActive(WLog_Get(TAG), WLOG_DEBUG)) + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) return; - WLog_DBG(TAG, "ListReaders%s_Return {", unicode ? "W" : "A"); - WLog_DBG(TAG, "ReturnCode: %s (0x%08"PRIX32")", + WLog_LVL(TAG, g_LogLevel, "Transmit_Return {"); + WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); - if (ret->ReturnCode != SCARD_S_SUCCESS) - { - WLog_DBG(TAG, "}"); - return; - } - - if (unicode) + if (ret->pioRecvPci) { - length = ret->cBytes / 2; + cbExtraBytes = (UINT32)(ret->pioRecvPci->cbPciLength - sizeof(SCARD_IO_REQUEST)); + pbExtraBytes = &((BYTE*)ret->pioRecvPci)[sizeof(SCARD_IO_REQUEST)]; + WLog_LVL(TAG, g_LogLevel, " pioRecvPci: dwProtocol: %" PRIu32 " cbExtraBytes: %" PRIu32 "", + ret->pioRecvPci->dwProtocol, cbExtraBytes); - if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) ret->msz, (int)length, - &mszA, 0, NULL, NULL) < 1) + if (cbExtraBytes) { - WLog_ERR(TAG, "ConvertFromUnicode failed"); - return; + char buffer[1024]; + WLog_LVL(TAG, g_LogLevel, " pbExtraBytes: %s", + smartcard_array_dump(pbExtraBytes, cbExtraBytes, buffer, sizeof(buffer))); } } else { - length = ret->cBytes; - mszA = (char*) malloc(length); + WLog_LVL(TAG, g_LogLevel, " pioRecvPci: null"); + } - if (!mszA) - { - WLog_ERR(TAG, "malloc failed!"); - return; - } + WLog_LVL(TAG, g_LogLevel, " cbRecvLength: %" PRIu32 "", ret->cbRecvLength); - CopyMemory(mszA, ret->msz, ret->cBytes); + if (ret->pbRecvBuffer) + { + char buffer[1024]; + WLog_DBG( + TAG, " pbRecvBuffer: %s", + smartcard_array_dump(ret->pbRecvBuffer, ret->cbRecvLength, buffer, sizeof(buffer))); } - - for (index = 0; index < length - 1; index++) + else { - if (mszA[index] == '\0') - mszA[index] = ','; + WLog_LVL(TAG, g_LogLevel, " pbRecvBuffer: null"); } - WLog_DBG(TAG, "cBytes: %"PRIu32" msz: %s", ret->cBytes, mszA); - WLog_DBG(TAG, "}"); - free(mszA); + WLog_LVL(TAG, g_LogLevel, "}"); } -LONG smartcard_unpack_connect_common(SMARTCARD_DEVICE* smartcard, wStream* s, - Connect_Common* common) +static void smartcard_trace_control_return(SMARTCARD_DEVICE* smartcard, const Control_Return* ret) { - LONG status; + WINPR_UNUSED(smartcard); - if (Stream_GetRemainingLength(s) < 8) + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) + return; + + WLog_LVL(TAG, g_LogLevel, "Control_Return {"); + WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", + SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); + WLog_LVL(TAG, g_LogLevel, " cbOutBufferSize: %" PRIu32 "", ret->cbOutBufferSize); + + if (ret->pvOutBuffer) { - WLog_WARN(TAG, "Connect_Common is too short: %"PRIuz"", - Stream_GetRemainingLength(s)); - return STATUS_BUFFER_TOO_SMALL; + char buffer[1024]; + WLog_DBG( + TAG, "pvOutBuffer: %s", + smartcard_array_dump(ret->pvOutBuffer, ret->cbOutBufferSize, buffer, sizeof(buffer))); } - - if ((status = smartcard_unpack_redir_scard_context(smartcard, s, &(common->hContext)))) + else { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_context failed with error %"PRId32"", status); - return status; + WLog_LVL(TAG, g_LogLevel, "pvOutBuffer: null"); } - Stream_Read_UINT32(s, common->dwShareMode); /* dwShareMode (4 bytes) */ - Stream_Read_UINT32(s, common->dwPreferredProtocols); /* dwPreferredProtocols (4 bytes) */ - return SCARD_S_SUCCESS; + WLog_LVL(TAG, g_LogLevel, "}"); } -LONG smartcard_unpack_connect_a_call(SMARTCARD_DEVICE* smartcard, wStream* s, ConnectA_Call* call) +static void smartcard_trace_control_call(SMARTCARD_DEVICE* smartcard, const Control_Call* call) { - LONG status; - UINT32 count; - call->szReader = NULL; + WINPR_UNUSED(smartcard); - if (Stream_GetRemainingLength(s) < 4) - { - WLog_WARN(TAG, "ConnectA_Call is too short: %"PRIuz"", - Stream_GetRemainingLength(s)); - return STATUS_BUFFER_TOO_SMALL; - } + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) + return; + + WLog_LVL(TAG, g_LogLevel, "Control_Call {"); + smartcard_log_context(TAG, &call->hContext); + smartcard_log_redir_handle(TAG, &call->hCard); - Stream_Seek_UINT32(s); /* szReaderNdrPtr (4 bytes) */ + WLog_LVL(TAG, g_LogLevel, + "dwControlCode: 0x%08" PRIX32 " cbInBufferSize: %" PRIu32 + " fpvOutBufferIsNULL: %" PRId32 " cbOutBufferSize: %" PRIu32 "", + call->dwControlCode, call->cbInBufferSize, call->fpvOutBufferIsNULL, + call->cbOutBufferSize); - if ((status = smartcard_unpack_connect_common(smartcard, s, &(call->Common)))) + if (call->pvInBuffer) { - WLog_ERR(TAG, "smartcard_unpack_connect_common failed with error %"PRId32"", status); - return status; + char buffer[1024]; + WLog_DBG( + TAG, "pbInBuffer: %s", + smartcard_array_dump(call->pvInBuffer, call->cbInBufferSize, buffer, sizeof(buffer))); } - - /* szReader */ - Stream_Seek_UINT32(s); /* NdrMaxCount (4 bytes) */ - Stream_Seek_UINT32(s); /* NdrOffset (4 bytes) */ - Stream_Read_UINT32(s, count); /* NdrActualCount (4 bytes) */ - call->szReader = (unsigned char*) malloc(count + 1); - - if (!call->szReader) + else { - WLog_WARN(TAG, "ConnectA_Call out of memory error (call->szReader)"); - return STATUS_NO_MEMORY; + WLog_LVL(TAG, g_LogLevel, "pvInBuffer: null"); } - Stream_Read(s, call->szReader, count); - smartcard_unpack_read_size_align(smartcard, s, count, 4); - call->szReader[count] = '\0'; + WLog_LVL(TAG, g_LogLevel, "}"); +} - if ((status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->Common.hContext)))) - WLog_ERR(TAG, "smartcard_unpack_redir_scard_context_ref failed with error %"PRId32"", status); +static void smartcard_trace_set_attrib_call(SMARTCARD_DEVICE* smartcard, const SetAttrib_Call* call) +{ + char buffer[8192]; + WINPR_UNUSED(smartcard); - return status; + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) + return; + + WLog_LVL(TAG, g_LogLevel, "GetAttrib_Call {"); + smartcard_log_context(TAG, &call->hContext); + smartcard_log_redir_handle(TAG, &call->hCard); + WLog_LVL(TAG, g_LogLevel, "dwAttrId: 0x%08" PRIX32, call->dwAttrId); + WLog_LVL(TAG, g_LogLevel, "cbAttrLen: 0x%08" PRId32, call->cbAttrLen); + WLog_LVL(TAG, g_LogLevel, "pbAttr: %s", + smartcard_array_dump(call->pbAttr, call->cbAttrLen, buffer, sizeof(buffer))); + WLog_LVL(TAG, g_LogLevel, "}"); } -void smartcard_trace_connect_a_call(SMARTCARD_DEVICE* smartcard, ConnectA_Call* call) +static void smartcard_trace_get_attrib_return(SMARTCARD_DEVICE* smartcard, + const GetAttrib_Return* ret, DWORD dwAttrId) { - BYTE* pb; + WINPR_UNUSED(smartcard); - if (!WLog_IsLevelActive(WLog_Get(TAG), WLOG_DEBUG)) + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) return; - WLog_DBG(TAG, "ConnectA_Call {"); - pb = (BYTE*) & (call->Common.hContext.pbContext); + WLog_LVL(TAG, g_LogLevel, "GetAttrib_Return {"); + WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", + SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); + WLog_LVL(TAG, g_LogLevel, " dwAttrId: %s (0x%08" PRIX32 ") cbAttrLen: 0x%08" PRIX32 "", + SCardGetAttributeString(dwAttrId), dwAttrId, ret->cbAttrLen); - if (call->Common.hContext.cbContext > 4) + if (dwAttrId == SCARD_ATTR_VENDOR_NAME) { - WLog_DBG(TAG, - "hContext: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], pb[4], pb[5], pb[6], pb[7], call->Common.hContext.cbContext); + WLog_LVL(TAG, g_LogLevel, " pbAttr: %.*s", ret->cbAttrLen, (char*)ret->pbAttr); } - else + else if (dwAttrId == SCARD_ATTR_CURRENT_PROTOCOL_TYPE) { - WLog_DBG(TAG, "hContext: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], call->Common.hContext.cbContext); + union { + BYTE* pb; + DWORD* pd; + } attr; + attr.pb = ret->pbAttr; + WLog_LVL(TAG, g_LogLevel, " dwProtocolType: %s (0x%08" PRIX32 ")", + SCardGetProtocolString(*attr.pd), *attr.pd); } - WLog_DBG(TAG, - "szReader: %s dwShareMode: %s (0x%08"PRIX32") dwPreferredProtocols: %s (0x%08"PRIX32")", - call->szReader, SCardGetShareModeString(call->Common.dwShareMode), call->Common.dwShareMode, - SCardGetProtocolString(call->Common.dwPreferredProtocols), call->Common.dwPreferredProtocols); - WLog_DBG(TAG, "}"); + WLog_LVL(TAG, g_LogLevel, "}"); } -LONG smartcard_unpack_connect_w_call(SMARTCARD_DEVICE* smartcard, wStream* s, ConnectW_Call* call) +static void smartcard_trace_get_attrib_call(SMARTCARD_DEVICE* smartcard, const GetAttrib_Call* call) { - LONG status; - UINT32 count; - call->szReader = NULL; + WINPR_UNUSED(smartcard); - if (Stream_GetRemainingLength(s) < 4) - { - WLog_WARN(TAG, "ConnectW_Call is too short: %"PRIuz"", - Stream_GetRemainingLength(s)); - return STATUS_BUFFER_TOO_SMALL; - } - - Stream_Seek_UINT32(s); /* szReaderNdrPtr (4 bytes) */ + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) + return; - if ((status = smartcard_unpack_connect_common(smartcard, s, &(call->Common)))) - { - WLog_ERR(TAG, "smartcard_unpack_connect_common failed with error %"PRId32"", status); - return status; - } + WLog_LVL(TAG, g_LogLevel, "GetAttrib_Call {"); + smartcard_log_context(TAG, &call->hContext); + smartcard_log_redir_handle(TAG, &call->hCard); - /* szReader */ - Stream_Seek_UINT32(s); /* NdrMaxCount (4 bytes) */ - Stream_Seek_UINT32(s); /* NdrOffset (4 bytes) */ - Stream_Read_UINT32(s, count); /* NdrActualCount (4 bytes) */ - call->szReader = (WCHAR*) calloc((count + 1), 2); + WLog_LVL(TAG, g_LogLevel, + "dwAttrId: %s (0x%08" PRIX32 ") fpbAttrIsNULL: %" PRId32 " cbAttrLen: 0x%08" PRIX32 "", + SCardGetAttributeString(call->dwAttrId), call->dwAttrId, call->fpbAttrIsNULL, + call->cbAttrLen); + WLog_LVL(TAG, g_LogLevel, "}"); +} - if (!call->szReader) - { - WLog_WARN(TAG, "ConnectW_Call out of memory error (call->szReader)"); - return STATUS_NO_MEMORY; - } +static void smartcard_trace_status_call(SMARTCARD_DEVICE* smartcard, const Status_Call* call, + BOOL unicode) +{ + WINPR_UNUSED(smartcard); - Stream_Read(s, call->szReader, (count * 2)); - smartcard_unpack_read_size_align(smartcard, s, (count * 2), 4); - call->szReader[count] = '\0'; + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) + return; - if ((status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->Common.hContext)))) - WLog_ERR(TAG, "smartcard_unpack_redir_scard_context_ref failed with error %"PRId32"", status); + WLog_LVL(TAG, g_LogLevel, "Status%s_Call {", unicode ? "W" : "A"); + smartcard_log_context(TAG, &call->hContext); + smartcard_log_redir_handle(TAG, &call->hCard); - return status; + WLog_LVL(TAG, g_LogLevel, + "fmszReaderNamesIsNULL: %" PRId32 " cchReaderLen: %" PRIu32 " cbAtrLen: %" PRIu32 "", + call->fmszReaderNamesIsNULL, call->cchReaderLen, call->cbAtrLen); + WLog_LVL(TAG, g_LogLevel, "}"); } -void smartcard_trace_connect_w_call(SMARTCARD_DEVICE* smartcard, ConnectW_Call* call) +static void smartcard_trace_status_return(SMARTCARD_DEVICE* smartcard, const Status_Return* ret, + BOOL unicode) { - BYTE* pb; - char* szReaderA = NULL; + char* mszReaderNamesA = NULL; + char buffer[1024]; + + WINPR_UNUSED(smartcard); - if (!WLog_IsLevelActive(WLog_Get(TAG), WLOG_DEBUG)) + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) return; - ConvertFromUnicode(CP_UTF8, 0, call->szReader, -1, &szReaderA, 0, NULL, NULL); - WLog_DBG(TAG, "ConnectW_Call {"); - pb = (BYTE*) & (call->Common.hContext.pbContext); + mszReaderNamesA = smartcard_convert_string_list(ret->mszReaderNames, ret->cBytes, unicode); - if (call->Common.hContext.cbContext > 4) - { - WLog_DBG(TAG, - "hContext: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], pb[4], pb[5], pb[6], pb[7], call->Common.hContext.cbContext); - } - else - { - WLog_DBG(TAG, "hContext: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], call->Common.hContext.cbContext); - } + WLog_LVL(TAG, g_LogLevel, "Status%s_Return {", unicode ? "W" : "A"); + WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", + SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); + WLog_LVL(TAG, g_LogLevel, " dwState: %s (0x%08" PRIX32 ") dwProtocol: %s (0x%08" PRIX32 ")", + SCardGetCardStateString(ret->dwState), ret->dwState, + SCardGetProtocolString(ret->dwProtocol), ret->dwProtocol); - WLog_DBG(TAG, - "szReader: %s dwShareMode: %s (0x%08"PRIX32") dwPreferredProtocols: %s (0x%08"PRIX32")", - szReaderA, SCardGetShareModeString(call->Common.dwShareMode), call->Common.dwShareMode, - SCardGetProtocolString(call->Common.dwPreferredProtocols), call->Common.dwPreferredProtocols); - WLog_DBG(TAG, "}"); - free(szReaderA); + WLog_LVL(TAG, g_LogLevel, " cBytes: %" PRIu32 " mszReaderNames: %s", ret->cBytes, + mszReaderNamesA); + + WLog_LVL(TAG, g_LogLevel, " cbAtrLen: %" PRIu32 " pbAtr: %s", ret->cbAtrLen, + smartcard_array_dump(ret->pbAtr, ret->cbAtrLen, buffer, sizeof(buffer))); + WLog_LVL(TAG, g_LogLevel, "}"); + free(mszReaderNamesA); } -LONG smartcard_pack_connect_return(SMARTCARD_DEVICE* smartcard, wStream* s, Connect_Return* ret) +static void smartcard_trace_state_return(SMARTCARD_DEVICE* smartcard, const State_Return* ret) { - LONG status; + char buffer[1024]; - if ((status = smartcard_pack_redir_scard_context(smartcard, s, &(ret->hContext)))) - { - WLog_ERR(TAG, "smartcard_pack_redir_scard_context failed with error %"PRId32"", status); - return status; - } + WINPR_UNUSED(smartcard); - if ((status = smartcard_pack_redir_scard_handle(smartcard, s, &(ret->hCard)))) - { - WLog_ERR(TAG, "smartcard_pack_redir_scard_handle failed with error %"PRId32"", status); - return status; - } + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) + return; - Stream_Write_UINT32(s, ret->dwActiveProtocol); /* dwActiveProtocol (4 bytes) */ + WLog_LVL(TAG, g_LogLevel, "Reconnect_Return {"); + WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", + SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); + WLog_LVL(TAG, g_LogLevel, " dwState: %s (0x%08" PRIX32 ")", ret->dwState); + WLog_LVL(TAG, g_LogLevel, " dwProtocol: %s (0x%08" PRIX32 ")", ret->dwProtocol); + WLog_LVL(TAG, g_LogLevel, " cbAtrLen: %s (0x%08" PRIX32 ")", ret->cbAtrLen); + WLog_LVL(TAG, g_LogLevel, " rgAtr: %s", + smartcard_array_dump(ret->rgAtr, sizeof(ret->rgAtr), buffer, sizeof(buffer))); + WLog_LVL(TAG, g_LogLevel, "}"); +} - if ((status = smartcard_pack_redir_scard_context_ref(smartcard, s, &(ret->hContext)))) - { - WLog_ERR(TAG, "smartcard_pack_redir_scard_context_ref failed with error %"PRId32"", status); - return status; - } +static void smartcard_trace_reconnect_return(SMARTCARD_DEVICE* smartcard, + const Reconnect_Return* ret) +{ + WINPR_UNUSED(smartcard); - if ((status = smartcard_pack_redir_scard_handle_ref(smartcard, s, &(ret->hCard)))) - WLog_ERR(TAG, "smartcard_pack_redir_scard_handle_ref failed with error %"PRId32"", status); + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) + return; - return status; + WLog_LVL(TAG, g_LogLevel, "Reconnect_Return {"); + WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", + SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); + WLog_LVL(TAG, g_LogLevel, " dwActiveProtocol: %s (0x%08" PRIX32 ")", + SCardGetProtocolString(ret->dwActiveProtocol), ret->dwActiveProtocol); + WLog_LVL(TAG, g_LogLevel, "}"); } -void smartcard_trace_connect_return(SMARTCARD_DEVICE* smartcard, Connect_Return* ret) +static void smartcard_trace_connect_a_call(SMARTCARD_DEVICE* smartcard, const ConnectA_Call* call) { - BYTE* pb; + WINPR_UNUSED(smartcard); - if (!WLog_IsLevelActive(WLog_Get(TAG), WLOG_DEBUG)) + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) return; - WLog_DBG(TAG, "Connect_Return {"); - WLog_DBG(TAG, "ReturnCode: %s (0x%08"PRIX32")", - SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); - pb = (BYTE*) & (ret->hContext.pbContext); + WLog_LVL(TAG, g_LogLevel, "ConnectA_Call {"); + smartcard_log_context(TAG, &call->Common.hContext); - if (ret->hContext.cbContext > 4) - { - WLog_DBG(TAG, - "hContext: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], pb[4], pb[5], pb[6], pb[7], ret->hContext.cbContext); - } - else - { - WLog_DBG(TAG, "hContext: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], ret->hContext.cbContext); - } + WLog_LVL(TAG, g_LogLevel, + "szReader: %s dwShareMode: %s (0x%08" PRIX32 ") dwPreferredProtocols: %s (0x%08" PRIX32 + ")", + call->szReader, SCardGetShareModeString(call->Common.dwShareMode), + call->Common.dwShareMode, SCardGetProtocolString(call->Common.dwPreferredProtocols), + call->Common.dwPreferredProtocols); + WLog_LVL(TAG, g_LogLevel, "}"); +} - pb = (BYTE*) & (ret->hCard.pbHandle); +static void smartcard_trace_connect_w_call(SMARTCARD_DEVICE* smartcard, const ConnectW_Call* call) +{ + char* szReaderA = NULL; + WINPR_UNUSED(smartcard); - if (ret->hCard.cbHandle > 4) - { - WLog_DBG(TAG, - "hCard: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], pb[4], pb[5], pb[6], pb[7], ret->hCard.cbHandle); - } - else - { - WLog_DBG(TAG, "hCard: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], ret->hCard.cbHandle); - } + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) + return; - WLog_DBG(TAG, "dwActiveProtocol: %s (0x%08"PRIX32")", - SCardGetProtocolString(ret->dwActiveProtocol), ret->dwActiveProtocol); - WLog_DBG(TAG, "}"); + ConvertFromUnicode(CP_UTF8, 0, call->szReader, -1, &szReaderA, 0, NULL, NULL); + WLog_LVL(TAG, g_LogLevel, "ConnectW_Call {"); + smartcard_log_context(TAG, &call->Common.hContext); + + WLog_LVL(TAG, g_LogLevel, + "szReader: %s dwShareMode: %s (0x%08" PRIX32 ") dwPreferredProtocols: %s (0x%08" PRIX32 + ")", + szReaderA, SCardGetShareModeString(call->Common.dwShareMode), call->Common.dwShareMode, + SCardGetProtocolString(call->Common.dwPreferredProtocols), + call->Common.dwPreferredProtocols); + WLog_LVL(TAG, g_LogLevel, "}"); + free(szReaderA); } -LONG smartcard_unpack_reconnect_call(SMARTCARD_DEVICE* smartcard, wStream* s, Reconnect_Call* call) +static void smartcard_trace_hcard_and_disposition_call(SMARTCARD_DEVICE* smartcard, + const HCardAndDisposition_Call* call, + const char* name) { - LONG status; + WINPR_UNUSED(smartcard); - if ((status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext)))) - { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_context failed with error %"PRId32"", status); - return status; - } + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) + return; - if ((status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->hCard)))) - { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_handle failed with error %"PRId32"", status); - return status; - } + WLog_LVL(TAG, g_LogLevel, "%s_Call {", name); + smartcard_log_context(TAG, &call->hContext); + smartcard_log_redir_handle(TAG, &call->hCard); - if (Stream_GetRemainingLength(s) < 12) - { - WLog_WARN(TAG, "Reconnect_Call is too short: %"PRIuz"", - Stream_GetRemainingLength(s)); - return STATUS_BUFFER_TOO_SMALL; - } + WLog_LVL(TAG, g_LogLevel, "dwDisposition: %s (0x%08" PRIX32 ")", + SCardGetDispositionString(call->dwDisposition), call->dwDisposition); + WLog_LVL(TAG, g_LogLevel, "}"); +} - Stream_Read_UINT32(s, call->dwShareMode); /* dwShareMode (4 bytes) */ - Stream_Read_UINT32(s, call->dwPreferredProtocols); /* dwPreferredProtocols (4 bytes) */ - Stream_Read_UINT32(s, call->dwInitialization); /* dwInitialization (4 bytes) */ +static void smartcard_trace_establish_context_call(SMARTCARD_DEVICE* smartcard, + const EstablishContext_Call* call) +{ + WINPR_UNUSED(smartcard); - if ((status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->hContext)))) - { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_context_ref failed with error %"PRId32"", status); - return status; - } + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) + return; - if ((status = smartcard_unpack_redir_scard_handle_ref(smartcard, s, &(call->hCard)))) - WLog_ERR(TAG, "smartcard_unpack_redir_scard_handle_ref failed with error %"PRId32"", status); + WLog_LVL(TAG, g_LogLevel, "EstablishContext_Call {"); + WLog_LVL(TAG, g_LogLevel, "dwScope: %s (0x%08" PRIX32 ")", SCardGetScopeString(call->dwScope), + call->dwScope); + WLog_LVL(TAG, g_LogLevel, "}"); +} - return status; +static void smartcard_trace_establish_context_return(SMARTCARD_DEVICE* smartcard, + const EstablishContext_Return* ret) +{ + WINPR_UNUSED(smartcard); + + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) + return; + + WLog_LVL(TAG, g_LogLevel, "EstablishContext_Return {"); + WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", + SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); + smartcard_log_context(TAG, &ret->hContext); + + WLog_LVL(TAG, g_LogLevel, "}"); } -void smartcard_trace_reconnect_call(SMARTCARD_DEVICE* smartcard, Reconnect_Call* call) +void smartcard_trace_long_return(SMARTCARD_DEVICE* smartcard, const Long_Return* ret, + const char* name) { - BYTE* pb; + WINPR_UNUSED(smartcard); - if (!WLog_IsLevelActive(WLog_Get(TAG), WLOG_DEBUG)) + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) return; - WLog_DBG(TAG, "Reconnect_Call {"); - pb = (BYTE*) & (call->hContext.pbContext); + WLog_LVL(TAG, g_LogLevel, "%s_Return {", name); + WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", + SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); + WLog_LVL(TAG, g_LogLevel, "}"); +} - if (call->hContext.cbContext > 4) - { - WLog_DBG(TAG, - "hContext: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], pb[4], pb[5], pb[6], pb[7], call->hContext.cbContext); - } - else - { - WLog_DBG(TAG, "hContext: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], call->hContext.cbContext); - } +static void smartcard_trace_connect_return(SMARTCARD_DEVICE* smartcard, const Connect_Return* ret) +{ + WINPR_UNUSED(smartcard); - pb = (BYTE*) & (call->hCard.pbHandle); + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) + return; - if (call->hCard.cbHandle > 4) - { - WLog_DBG(TAG, - "hCard: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], pb[4], pb[5], pb[6], pb[7], call->hCard.cbHandle); - } - else - { - WLog_DBG(TAG, "hCard: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], call->hCard.cbHandle); - } + WLog_LVL(TAG, g_LogLevel, "Connect_Return {"); + WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", + SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); + smartcard_log_context(TAG, &ret->hContext); + smartcard_log_redir_handle(TAG, &ret->hCard); + + WLog_LVL(TAG, g_LogLevel, " dwActiveProtocol: %s (0x%08" PRIX32 ")", + SCardGetProtocolString(ret->dwActiveProtocol), ret->dwActiveProtocol); + WLog_LVL(TAG, g_LogLevel, "}"); +} + +void smartcard_trace_reconnect_call(SMARTCARD_DEVICE* smartcard, const Reconnect_Call* call) +{ + WINPR_UNUSED(smartcard); + + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) + return; - WLog_DBG(TAG, - "dwShareMode: %s (0x%08"PRIX32") dwPreferredProtocols: %s (0x%08"PRIX32") dwInitialization: %s (0x%08"PRIX32")", + WLog_LVL(TAG, g_LogLevel, "Reconnect_Call {"); + smartcard_log_context(TAG, &call->hContext); + smartcard_log_redir_handle(TAG, &call->hCard); + + WLog_LVL(TAG, g_LogLevel, + "dwShareMode: %s (0x%08" PRIX32 ") dwPreferredProtocols: %s (0x%08" PRIX32 + ") dwInitialization: %s (0x%08" PRIX32 ")", SCardGetShareModeString(call->dwShareMode), call->dwShareMode, SCardGetProtocolString(call->dwPreferredProtocols), call->dwPreferredProtocols, SCardGetDispositionString(call->dwInitialization), call->dwInitialization); - WLog_DBG(TAG, "}"); + WLog_LVL(TAG, g_LogLevel, "}"); } -LONG smartcard_pack_reconnect_return(SMARTCARD_DEVICE* smartcard, wStream* s, Reconnect_Return* ret) +static void smartcard_trace_device_type_id_return(SMARTCARD_DEVICE* smartcard, + const GetDeviceTypeId_Return* ret) { - Stream_Write_UINT32(s, ret->dwActiveProtocol); /* dwActiveProtocol (4 bytes) */ - return SCARD_S_SUCCESS; -} + WINPR_UNUSED(smartcard); -void smartcard_trace_reconnect_return(SMARTCARD_DEVICE* smartcard, Reconnect_Return* ret) -{ - if (!WLog_IsLevelActive(WLog_Get(TAG), WLOG_DEBUG)) + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) return; - WLog_DBG(TAG, "Reconnect_Return {"); - WLog_DBG(TAG, "ReturnCode: %s (0x%08"PRIX32")", + WLog_LVL(TAG, g_LogLevel, "GetDeviceTypeId_Return {"); + WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); - WLog_DBG(TAG, "dwActiveProtocol: %s (0x%08"PRIX32")", - SCardGetProtocolString(ret->dwActiveProtocol), ret->dwActiveProtocol); - WLog_DBG(TAG, "}"); + WLog_LVL(TAG, g_LogLevel, " dwDeviceId=%08" PRIx32, ret->dwDeviceId); + + WLog_LVL(TAG, g_LogLevel, "}"); } -LONG smartcard_unpack_hcard_and_disposition_call(SMARTCARD_DEVICE* smartcard, wStream* s, - HCardAndDisposition_Call* call) +static LONG smartcard_unpack_common_context_and_string_a(SMARTCARD_DEVICE* smartcard, wStream* s, + REDIR_SCARDCONTEXT* phContext, + CHAR** pszReaderName) { LONG status; + UINT32 index = 0; + status = smartcard_unpack_redir_scard_context(smartcard, s, phContext, &index); + if (status != SCARD_S_SUCCESS) + return status; - if ((status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext)))) - { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_context failed with error %"PRId32"", status); + if (!smartcard_ndr_pointer_read(s, &index, NULL)) + return ERROR_INVALID_DATA; + + status = smartcard_unpack_redir_scard_context_ref(smartcard, s, phContext); + if (status != SCARD_S_SUCCESS) return status; - } - if ((status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->hCard)))) - { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_handle failed with error %"PRId32"", status); + status = smartcard_ndr_read_a(s, pszReaderName, NDR_PTR_FULL); + if (status != SCARD_S_SUCCESS) return status; - } - if (Stream_GetRemainingLength(s) < 4) - { - WLog_WARN(TAG, "HCardAndDisposition_Call is too short: %"PRIuz"", - Stream_GetRemainingLength(s)); - return STATUS_BUFFER_TOO_SMALL; - } + smartcard_trace_context_and_string_call_a(__FUNCTION__, phContext, *pszReaderName); + return SCARD_S_SUCCESS; +} - Stream_Read_UINT32(s, call->dwDisposition); /* dwDisposition (4 bytes) */ +static LONG smartcard_unpack_common_context_and_string_w(SMARTCARD_DEVICE* smartcard, wStream* s, + REDIR_SCARDCONTEXT* phContext, + WCHAR** pszReaderName) +{ + LONG status; + UINT32 index = 0; - if ((status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->hContext)))) - { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_context_ref failed with error %"PRId32"", status); + status = smartcard_unpack_redir_scard_context(smartcard, s, phContext, &index); + if (status != SCARD_S_SUCCESS) return status; - } - if ((status = smartcard_unpack_redir_scard_handle_ref(smartcard, s, &(call->hCard)))) - WLog_ERR(TAG, "smartcard_unpack_redir_scard_handle_ref failed with error %"PRId32"", status); + if (!smartcard_ndr_pointer_read(s, &index, NULL)) + return ERROR_INVALID_DATA; - return status; + status = smartcard_unpack_redir_scard_context_ref(smartcard, s, phContext); + if (status != SCARD_S_SUCCESS) + return status; + + status = smartcard_ndr_read_w(s, pszReaderName, NDR_PTR_FULL); + if (status != SCARD_S_SUCCESS) + return status; + + smartcard_trace_context_and_string_call_w(__FUNCTION__, phContext, *pszReaderName); + return SCARD_S_SUCCESS; } -void smartcard_trace_hcard_and_disposition_call(SMARTCARD_DEVICE* smartcard, - HCardAndDisposition_Call* call, const char* name) +LONG smartcard_unpack_common_type_header(SMARTCARD_DEVICE* smartcard, wStream* s) { - BYTE* pb; + UINT8 version; + UINT32 filler; + UINT8 endianness; + UINT16 commonHeaderLength; + WINPR_UNUSED(smartcard); - if (!WLog_IsLevelActive(WLog_Get(TAG), WLOG_DEBUG)) - return; + if (Stream_GetRemainingLength(s) < 8) + { + WLog_WARN(TAG, "CommonTypeHeader is too short: %" PRIuz "", Stream_GetRemainingLength(s)); + return STATUS_BUFFER_TOO_SMALL; + } - WLog_DBG(TAG, "%s_Call {", name); - pb = (BYTE*) & (call->hContext.pbContext); + /* Process CommonTypeHeader */ + Stream_Read_UINT8(s, version); /* Version (1 byte) */ + Stream_Read_UINT8(s, endianness); /* Endianness (1 byte) */ + Stream_Read_UINT16(s, commonHeaderLength); /* CommonHeaderLength (2 bytes) */ + Stream_Read_UINT32(s, filler); /* Filler (4 bytes), should be 0xCCCCCCCC */ - if (call->hContext.cbContext > 4) + if (version != 1) { - WLog_DBG(TAG, - "hContext: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], pb[4], pb[5], pb[6], pb[7], call->hContext.cbContext); + WLog_WARN(TAG, "Unsupported CommonTypeHeader Version %" PRIu8 "", version); + return STATUS_INVALID_PARAMETER; } - else + + if (endianness != 0x10) { - WLog_DBG(TAG, "hContext: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], call->hContext.cbContext); + WLog_WARN(TAG, "Unsupported CommonTypeHeader Endianness %" PRIu8 "", endianness); + return STATUS_INVALID_PARAMETER; } - pb = (BYTE*) & (call->hCard.pbHandle); - - if (call->hCard.cbHandle > 4) + if (commonHeaderLength != 8) { - WLog_DBG(TAG, - "hCard: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], pb[4], pb[5], pb[6], pb[7], call->hCard.cbHandle); + WLog_WARN(TAG, "Unsupported CommonTypeHeader CommonHeaderLength %" PRIu16 "", + commonHeaderLength); + return STATUS_INVALID_PARAMETER; } - else + + if (filler != 0xCCCCCCCC) { - WLog_DBG(TAG, "hCard: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], call->hCard.cbHandle); + WLog_WARN(TAG, "Unexpected CommonTypeHeader Filler 0x%08" PRIX32 "", filler); + return STATUS_INVALID_PARAMETER; } - WLog_DBG(TAG, "dwDisposition: %s (0x%08"PRIX32")", - SCardGetDispositionString(call->dwDisposition), call->dwDisposition); - WLog_DBG(TAG, "}"); + return SCARD_S_SUCCESS; } -LONG smartcard_unpack_get_status_change_a_call(SMARTCARD_DEVICE* smartcard, wStream* s, - GetStatusChangeA_Call* call) +void smartcard_pack_common_type_header(SMARTCARD_DEVICE* smartcard, wStream* s) { - UINT32 index; - UINT32 count; - LONG status; - UINT32 offset; - UINT32 maxCount; - UINT32 szReaderNdrPtr; - UINT32 rgReaderStatesNdrPtr; - LPSCARD_READERSTATEA readerState; - call->rgReaderStates = NULL; + WINPR_UNUSED(smartcard); + Stream_Write_UINT8(s, 1); /* Version (1 byte) */ + Stream_Write_UINT8(s, 0x10); /* Endianness (1 byte) */ + Stream_Write_UINT16(s, 8); /* CommonHeaderLength (2 bytes) */ + Stream_Write_UINT32(s, 0xCCCCCCCC); /* Filler (4 bytes), should be 0xCCCCCCCC */ +} - if ((status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext)))) - { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_context failed with error %"PRId32"", status); - return status; - } +LONG smartcard_unpack_private_type_header(SMARTCARD_DEVICE* smartcard, wStream* s) +{ + UINT32 filler; + UINT32 objectBufferLength; + WINPR_UNUSED(smartcard); - if (Stream_GetRemainingLength(s) < 12) + if (Stream_GetRemainingLength(s) < 8) { - WLog_WARN(TAG, "GetStatusChangeA_Call is too short: %"PRIuz"", - Stream_GetRemainingLength(s)); + WLog_WARN(TAG, "PrivateTypeHeader is too short: %" PRIuz "", Stream_GetRemainingLength(s)); return STATUS_BUFFER_TOO_SMALL; } - Stream_Read_UINT32(s, call->dwTimeOut); /* dwTimeOut (4 bytes) */ - Stream_Read_UINT32(s, call->cReaders); /* cReaders (4 bytes) */ - Stream_Read_UINT32(s, rgReaderStatesNdrPtr); /* rgReaderStatesNdrPtr (4 bytes) */ + Stream_Read_UINT32(s, objectBufferLength); /* ObjectBufferLength (4 bytes) */ + Stream_Read_UINT32(s, filler); /* Filler (4 bytes), should be 0x00000000 */ - if ((status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->hContext)))) + if (filler != 0x00000000) { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_context_ref failed with error %"PRId32"", status); - return status; + WLog_WARN(TAG, "Unexpected PrivateTypeHeader Filler 0x%08" PRIX32 "", filler); + return STATUS_INVALID_PARAMETER; } - if (Stream_GetRemainingLength(s) < 4) + if (objectBufferLength != Stream_GetRemainingLength(s)) { - WLog_WARN(TAG, "GetStatusChangeA_Call is too short: %"PRIuz"", - Stream_GetRemainingLength(s)); - return STATUS_BUFFER_TOO_SMALL; + WLog_WARN(TAG, + "PrivateTypeHeader ObjectBufferLength mismatch: Actual: %" PRIu32 + ", Expected: %" PRIuz "", + objectBufferLength, Stream_GetRemainingLength(s)); + return STATUS_INVALID_PARAMETER; + } + + return SCARD_S_SUCCESS; +} + +void smartcard_pack_private_type_header(SMARTCARD_DEVICE* smartcard, wStream* s, + UINT32 objectBufferLength) +{ + WINPR_UNUSED(smartcard); + Stream_Write_UINT32(s, objectBufferLength); /* ObjectBufferLength (4 bytes) */ + Stream_Write_UINT32(s, 0x00000000); /* Filler (4 bytes), should be 0x00000000 */ +} + +LONG smartcard_unpack_read_size_align(SMARTCARD_DEVICE* smartcard, wStream* s, size_t size, + UINT32 alignment) +{ + size_t pad; + WINPR_UNUSED(smartcard); + pad = size; + size = (size + alignment - 1) & ~(alignment - 1); + pad = size - pad; + + if (pad) + Stream_Seek(s, pad); + + return (LONG)pad; +} + +LONG smartcard_pack_write_size_align(SMARTCARD_DEVICE* smartcard, wStream* s, size_t size, + UINT32 alignment) +{ + size_t pad; + WINPR_UNUSED(smartcard); + pad = size; + size = (size + alignment - 1) & ~(alignment - 1); + pad = size - pad; + + if (pad) + { + if (!Stream_EnsureRemainingCapacity(s, pad)) + { + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + return SCARD_F_INTERNAL_ERROR; + } + + Stream_Zero(s, pad); } - Stream_Read_UINT32(s, count); /* NdrCount (4 bytes) */ + return SCARD_S_SUCCESS; +} + +SCARDCONTEXT smartcard_scard_context_native_from_redir(SMARTCARD_DEVICE* smartcard, + REDIR_SCARDCONTEXT* context) +{ + SCARDCONTEXT hContext = { 0 }; + WINPR_UNUSED(smartcard); - if (count != call->cReaders) + if ((context->cbContext != sizeof(ULONG_PTR)) && (context->cbContext != 0)) { WLog_WARN(TAG, - "GetStatusChangeA_Call unexpected reader count: Actual: %"PRIu32", Expected: %"PRIu32"", - count, call->cReaders); - return STATUS_INVALID_PARAMETER; + "REDIR_SCARDCONTEXT does not match native size: Actual: %" PRIu32 + ", Expected: %" PRIuz "", + context->cbContext, sizeof(ULONG_PTR)); + return 0; } - if (call->cReaders > 0) + if (context->cbContext) + CopyMemory(&hContext, &(context->pbContext), context->cbContext); + + return hContext; +} + +void smartcard_scard_context_native_to_redir(SMARTCARD_DEVICE* smartcard, + REDIR_SCARDCONTEXT* context, SCARDCONTEXT hContext) +{ + WINPR_UNUSED(smartcard); + ZeroMemory(context, sizeof(REDIR_SCARDCONTEXT)); + context->cbContext = sizeof(ULONG_PTR); + CopyMemory(&(context->pbContext), &hContext, context->cbContext); +} + +SCARDHANDLE smartcard_scard_handle_native_from_redir(SMARTCARD_DEVICE* smartcard, + REDIR_SCARDHANDLE* handle) +{ + SCARDHANDLE hCard = 0; + WINPR_UNUSED(smartcard); + + if (handle->cbHandle != sizeof(ULONG_PTR)) { - call->rgReaderStates = (LPSCARD_READERSTATEA) calloc(call->cReaders, sizeof(SCARD_READERSTATEA)); + WLog_WARN(TAG, + "REDIR_SCARDHANDLE does not match native size: Actual: %" PRIu32 + ", Expected: %" PRIuz "", + handle->cbHandle, sizeof(ULONG_PTR)); + return 0; + } - if (!call->rgReaderStates) - { - WLog_WARN(TAG, "GetStatusChangeA_Call out of memory error (call->rgReaderStates)"); - return STATUS_NO_MEMORY; - } + if (handle->cbHandle) + CopyMemory(&hCard, &(handle->pbHandle), handle->cbHandle); - for (index = 0; index < call->cReaders; index++) - { - readerState = &call->rgReaderStates[index]; + return hCard; +} - if (Stream_GetRemainingLength(s) < 52) - { - WLog_WARN(TAG, "GetStatusChangeA_Call is too short: %"PRIuz"", - Stream_GetRemainingLength(s)); - return STATUS_BUFFER_TOO_SMALL; - } +void smartcard_scard_handle_native_to_redir(SMARTCARD_DEVICE* smartcard, REDIR_SCARDHANDLE* handle, + SCARDHANDLE hCard) +{ + WINPR_UNUSED(smartcard); + ZeroMemory(handle, sizeof(REDIR_SCARDHANDLE)); + handle->cbHandle = sizeof(ULONG_PTR); + CopyMemory(&(handle->pbHandle), &hCard, handle->cbHandle); +} - Stream_Read_UINT32(s, szReaderNdrPtr); /* szReaderNdrPtr (4 bytes) */ - Stream_Read_UINT32(s, readerState->dwCurrentState); /* dwCurrentState (4 bytes) */ - Stream_Read_UINT32(s, readerState->dwEventState); /* dwEventState (4 bytes) */ - Stream_Read_UINT32(s, readerState->cbAtr); /* cbAtr (4 bytes) */ - Stream_Read(s, readerState->rgbAtr, 32); /* rgbAtr [0..32] (32 bytes) */ - Stream_Seek(s, 4); /* rgbAtr [32..36] (4 bytes) */ - } +LONG smartcard_unpack_redir_scard_context_(SMARTCARD_DEVICE* smartcard, wStream* s, + REDIR_SCARDCONTEXT* context, UINT32* index, + const char* file, const char* function, int line) +{ + UINT32 pbContextNdrPtr; + WINPR_UNUSED(smartcard); + WINPR_UNUSED(file); - for (index = 0; index < call->cReaders; index++) - { - readerState = &call->rgReaderStates[index]; + ZeroMemory(context, sizeof(REDIR_SCARDCONTEXT)); - if (Stream_GetRemainingLength(s) < 12) - { - WLog_WARN(TAG, "GetStatusChangeA_Call is too short: %"PRIuz"", - Stream_GetRemainingLength(s)); - return STATUS_BUFFER_TOO_SMALL; - } + if (Stream_GetRemainingLength(s) < 4) + { + WLog_WARN(TAG, "REDIR_SCARDCONTEXT is too short: %" PRIuz "", Stream_GetRemainingLength(s)); + return STATUS_BUFFER_TOO_SMALL; + } - Stream_Read_UINT32(s, maxCount); /* NdrMaxCount (4 bytes) */ - Stream_Read_UINT32(s, offset); /* NdrOffset (4 bytes) */ - Stream_Read_UINT32(s, count); /* NdrActualCount (4 bytes) */ + Stream_Read_UINT32(s, context->cbContext); /* cbContext (4 bytes) */ - if (Stream_GetRemainingLength(s) < count) - { - WLog_WARN(TAG, "GetStatusChangeA_Call is too short: %"PRIuz"", - Stream_GetRemainingLength(s)); - return STATUS_BUFFER_TOO_SMALL; - } + if (Stream_GetRemainingLength(s) < context->cbContext) + { + WLog_WARN(TAG, "REDIR_SCARDCONTEXT is too short: Actual: %" PRIuz ", Expected: %" PRIu32 "", + Stream_GetRemainingLength(s), context->cbContext); + return STATUS_BUFFER_TOO_SMALL; + } - readerState->szReader = (LPCSTR) malloc(count + 1); + if ((context->cbContext != 0) && (context->cbContext != 4) && (context->cbContext != 8)) + { + WLog_WARN(TAG, "REDIR_SCARDCONTEXT length is not 0, 4 or 8: %" PRIu32 "", + context->cbContext); + return STATUS_INVALID_PARAMETER; + } - if (!readerState->szReader) - { - WLog_WARN(TAG, "GetStatusChangeA_Call out of memory error (readerState->szReader)"); - return STATUS_NO_MEMORY; - } + if (!smartcard_ndr_pointer_read_(s, index, &pbContextNdrPtr, file, function, line)) + return ERROR_INVALID_DATA; - Stream_Read(s, (void*) readerState->szReader, count); - smartcard_unpack_read_size_align(smartcard, s, count, 4); - ((char*) readerState->szReader)[count] = '\0'; + if (((context->cbContext == 0) && pbContextNdrPtr) || + ((context->cbContext != 0) && !pbContextNdrPtr)) + { + WLog_WARN(TAG, + "REDIR_SCARDCONTEXT cbContext (%" PRIu32 ") pbContextNdrPtr (%" PRIu32 + ") inconsistency", + context->cbContext, pbContextNdrPtr); + return STATUS_INVALID_PARAMETER; + } - if (!readerState->szReader) - { - WLog_WARN(TAG, "GetStatusChangeA_Call null reader name"); - return STATUS_INVALID_PARAMETER; - } - } + if (context->cbContext > Stream_GetRemainingLength(s)) + { + WLog_WARN(TAG, "REDIR_SCARDCONTEXT is too long: Actual: %" PRIuz ", Expected: %" PRIu32 "", + Stream_GetRemainingLength(s), context->cbContext); + return STATUS_INVALID_PARAMETER; } return SCARD_S_SUCCESS; } -void smartcard_trace_get_status_change_a_call(SMARTCARD_DEVICE* smartcard, - GetStatusChangeA_Call* call) +LONG smartcard_pack_redir_scard_context(SMARTCARD_DEVICE* smartcard, wStream* s, + const REDIR_SCARDCONTEXT* context, DWORD* index) { - BYTE* pb; - UINT32 index; - char* szEventState; - char* szCurrentState; - LPSCARD_READERSTATEA readerState; + const UINT32 pbContextNdrPtr = 0x00020000 + *index * 4; + WINPR_UNUSED(smartcard); - if (!WLog_IsLevelActive(WLog_Get(TAG), WLOG_DEBUG)) - return; + if (context->cbContext != 0) + { + Stream_Write_UINT32(s, context->cbContext); /* cbContext (4 bytes) */ + Stream_Write_UINT32(s, pbContextNdrPtr); /* pbContextNdrPtr (4 bytes) */ + *index = *index + 1; + } + else + Stream_Zero(s, 8); + + return SCARD_S_SUCCESS; +} + +LONG smartcard_unpack_redir_scard_context_ref(SMARTCARD_DEVICE* smartcard, wStream* s, + REDIR_SCARDCONTEXT* context) +{ + UINT32 length; + WINPR_UNUSED(smartcard); + + if (context->cbContext == 0) + return SCARD_S_SUCCESS; - WLog_DBG(TAG, "GetStatusChangeA_Call {"); - pb = (BYTE*) & (call->hContext.pbContext); + if (Stream_GetRemainingLength(s) < 4) + { + WLog_WARN(TAG, "REDIR_SCARDCONTEXT is too short: Actual: %" PRIuz ", Expected: 4", + Stream_GetRemainingLength(s)); + return STATUS_BUFFER_TOO_SMALL; + } - if (call->hContext.cbContext > 4) + Stream_Read_UINT32(s, length); /* Length (4 bytes) */ + + if (length != context->cbContext) + { + WLog_WARN(TAG, "REDIR_SCARDCONTEXT length (%" PRIu32 ") cbContext (%" PRIu32 ") mismatch", + length, context->cbContext); + return STATUS_INVALID_PARAMETER; + } + + if ((context->cbContext != 0) && (context->cbContext != 4) && (context->cbContext != 8)) + { + WLog_WARN(TAG, "REDIR_SCARDCONTEXT length is not 4 or 8: %" PRIu32 "", context->cbContext); + return STATUS_INVALID_PARAMETER; + } + + if (Stream_GetRemainingLength(s) < context->cbContext) { - WLog_DBG(TAG, - "hContext: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], pb[4], pb[5], pb[6], pb[7], call->hContext.cbContext); + WLog_WARN(TAG, "REDIR_SCARDCONTEXT is too short: Actual: %" PRIuz ", Expected: %" PRIu32 "", + Stream_GetRemainingLength(s), context->cbContext); + return STATUS_BUFFER_TOO_SMALL; } + + if (context->cbContext) + Stream_Read(s, &(context->pbContext), context->cbContext); else + ZeroMemory(&(context->pbContext), sizeof(context->pbContext)); + + return SCARD_S_SUCCESS; +} + +LONG smartcard_pack_redir_scard_context_ref(SMARTCARD_DEVICE* smartcard, wStream* s, + const REDIR_SCARDCONTEXT* context) +{ + WINPR_UNUSED(smartcard); + Stream_Write_UINT32(s, context->cbContext); /* Length (4 bytes) */ + + if (context->cbContext) { - WLog_DBG(TAG, "hContext: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], call->hContext.cbContext); + Stream_Write(s, &(context->pbContext), context->cbContext); } - WLog_DBG(TAG, "dwTimeOut: 0x%08"PRIX32" cReaders: %"PRIu32"", - call->dwTimeOut, call->cReaders); + return SCARD_S_SUCCESS; +} - for (index = 0; index < call->cReaders; index++) +LONG smartcard_unpack_redir_scard_handle_(SMARTCARD_DEVICE* smartcard, wStream* s, + REDIR_SCARDHANDLE* handle, UINT32* index, + const char* file, const char* function, int line) +{ + WINPR_UNUSED(smartcard); + ZeroMemory(handle, sizeof(REDIR_SCARDHANDLE)); + + if (Stream_GetRemainingLength(s) < 4) { - readerState = &call->rgReaderStates[index]; - WLog_DBG(TAG, "\t[%"PRIu32"]: szReader: %s cbAtr: %"PRIu32"", - index, readerState->szReader, readerState->cbAtr); - szCurrentState = SCardGetReaderStateString(readerState->dwCurrentState); - szEventState = SCardGetReaderStateString(readerState->dwEventState); - WLog_DBG(TAG, "\t[%"PRIu32"]: dwCurrentState: %s (0x%08"PRIX32")", - index, szCurrentState, readerState->dwCurrentState); - WLog_DBG(TAG, "\t[%"PRIu32"]: dwEventState: %s (0x%08"PRIX32")", - index, szEventState, readerState->dwEventState); - free(szCurrentState); - free(szEventState); + WLog_WARN(TAG, "SCARDHANDLE is too short: %" PRIuz "", Stream_GetRemainingLength(s)); + return STATUS_BUFFER_TOO_SMALL; + } + + Stream_Read_UINT32(s, handle->cbHandle); /* Length (4 bytes) */ + + if ((Stream_GetRemainingLength(s) < handle->cbHandle) || (!handle->cbHandle)) + { + WLog_WARN(TAG, "SCARDHANDLE is too short: Actual: %" PRIuz ", Expected: %" PRIu32 "", + Stream_GetRemainingLength(s), handle->cbHandle); + return STATUS_BUFFER_TOO_SMALL; } - WLog_DBG(TAG, "}"); + if (!smartcard_ndr_pointer_read_(s, index, NULL, file, function, line)) + return ERROR_INVALID_DATA; + + return SCARD_S_SUCCESS; } -LONG smartcard_unpack_get_status_change_w_call(SMARTCARD_DEVICE* smartcard, wStream* s, - GetStatusChangeW_Call* call) +LONG smartcard_pack_redir_scard_handle(SMARTCARD_DEVICE* smartcard, wStream* s, + const REDIR_SCARDHANDLE* handle, DWORD* index) { - UINT32 index; - UINT32 count; - LONG status; - UINT32 offset; - UINT32 maxCount; - UINT32 szReaderNdrPtr; - UINT32 rgReaderStatesNdrPtr; - LPSCARD_READERSTATEW readerState; - call->rgReaderStates = NULL; + const UINT32 pbContextNdrPtr = 0x00020000 + *index * 4; + WINPR_UNUSED(smartcard); - if ((status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext)))) + if (handle->cbHandle != 0) { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_context failed with error %"PRId32"", status); - return status; + Stream_Write_UINT32(s, handle->cbHandle); /* cbContext (4 bytes) */ + Stream_Write_UINT32(s, pbContextNdrPtr); /* pbContextNdrPtr (4 bytes) */ + *index = *index + 1; } + else + Stream_Zero(s, 8); + return SCARD_S_SUCCESS; +} - if (Stream_GetRemainingLength(s) < 12) +LONG smartcard_unpack_redir_scard_handle_ref(SMARTCARD_DEVICE* smartcard, wStream* s, + REDIR_SCARDHANDLE* handle) +{ + UINT32 length; + WINPR_UNUSED(smartcard); + + if (Stream_GetRemainingLength(s) < 4) { - WLog_WARN(TAG, "GetStatusChangeW_Call is too short: %"PRIuz"", + WLog_WARN(TAG, "REDIR_SCARDHANDLE is too short: Actual: %" PRIuz ", Expected: 4", Stream_GetRemainingLength(s)); return STATUS_BUFFER_TOO_SMALL; } - Stream_Read_UINT32(s, call->dwTimeOut); /* dwTimeOut (4 bytes) */ - Stream_Read_UINT32(s, call->cReaders); /* cReaders (4 bytes) */ - Stream_Read_UINT32(s, rgReaderStatesNdrPtr); /* rgReaderStatesNdrPtr (4 bytes) */ + Stream_Read_UINT32(s, length); /* Length (4 bytes) */ - if ((status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->hContext)))) + if (length != handle->cbHandle) { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_context_ref failed with error %"PRId32"", status); - return status; + WLog_WARN(TAG, "REDIR_SCARDHANDLE length (%" PRIu32 ") cbHandle (%" PRIu32 ") mismatch", + length, handle->cbHandle); + return STATUS_INVALID_PARAMETER; } + if ((handle->cbHandle != 4) && (handle->cbHandle != 8)) + { + WLog_WARN(TAG, "REDIR_SCARDHANDLE length is not 4 or 8: %" PRIu32 "", handle->cbHandle); + return STATUS_INVALID_PARAMETER; + } + + if ((Stream_GetRemainingLength(s) < handle->cbHandle) || (!handle->cbHandle)) + { + WLog_WARN(TAG, "REDIR_SCARDHANDLE is too short: Actual: %" PRIuz ", Expected: %" PRIu32 "", + Stream_GetRemainingLength(s), handle->cbHandle); + return STATUS_BUFFER_TOO_SMALL; + } + + if (handle->cbHandle) + Stream_Read(s, &(handle->pbHandle), handle->cbHandle); + + return SCARD_S_SUCCESS; +} + +LONG smartcard_pack_redir_scard_handle_ref(SMARTCARD_DEVICE* smartcard, wStream* s, + const REDIR_SCARDHANDLE* handle) +{ + WINPR_UNUSED(smartcard); + Stream_Write_UINT32(s, handle->cbHandle); /* Length (4 bytes) */ + + if (handle->cbHandle) + Stream_Write(s, &(handle->pbHandle), handle->cbHandle); + + return SCARD_S_SUCCESS; +} + +LONG smartcard_unpack_establish_context_call(SMARTCARD_DEVICE* smartcard, wStream* s, + EstablishContext_Call* call) +{ + WINPR_UNUSED(smartcard); + if (Stream_GetRemainingLength(s) < 4) { - WLog_WARN(TAG, "GetStatusChangeW_Call is too short: %"PRIuz"", + WLog_WARN(TAG, "EstablishContext_Call is too short: Actual: %" PRIuz ", Expected: 4", Stream_GetRemainingLength(s)); return STATUS_BUFFER_TOO_SMALL; } - Stream_Seek_UINT32(s); /* NdrConformant (4 bytes) */ + Stream_Read_UINT32(s, call->dwScope); /* dwScope (4 bytes) */ + smartcard_trace_establish_context_call(smartcard, call); + return SCARD_S_SUCCESS; +} + +LONG smartcard_pack_establish_context_return(SMARTCARD_DEVICE* smartcard, wStream* s, + const EstablishContext_Return* ret) +{ + LONG status; + DWORD index = 0; + + smartcard_trace_establish_context_return(smartcard, ret); + if (ret->ReturnCode != SCARD_S_SUCCESS) + return ret->ReturnCode; + + if ((status = smartcard_pack_redir_scard_context(smartcard, s, &(ret->hContext), &index))) + return status; + + return smartcard_pack_redir_scard_context_ref(smartcard, s, &(ret->hContext)); +} + +LONG smartcard_unpack_context_call(SMARTCARD_DEVICE* smartcard, wStream* s, Context_Call* call, + const char* name) +{ + LONG status; + UINT32 index = 0; + + status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext), &index); + if (status != SCARD_S_SUCCESS) + return status; + + if ((status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->hContext)))) + WLog_ERR(TAG, "smartcard_unpack_redir_scard_context_ref failed with error %" PRId32 "", + status); + + smartcard_trace_context_call(smartcard, call, name); + return status; +} + +LONG smartcard_unpack_list_reader_groups_call(SMARTCARD_DEVICE* smartcard, wStream* s, + ListReaderGroups_Call* call, BOOL unicode) +{ + LONG status; + UINT32 index = 0; + status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext), &index); - if (call->cReaders > 0) + if (status != SCARD_S_SUCCESS) + return status; + + if (Stream_GetRemainingLength(s) < 8) { - call->rgReaderStates = (LPSCARD_READERSTATEW) calloc(call->cReaders, sizeof(SCARD_READERSTATEW)); + WLog_WARN(TAG, "ListReaderGroups_Call is too short: %" PRIdz, Stream_GetRemainingLength(s)); + return STATUS_BUFFER_TOO_SMALL; + } - if (!call->rgReaderStates) - { - WLog_WARN(TAG, "GetStatusChangeW_Call out of memory error (call->rgReaderStates)"); - return STATUS_NO_MEMORY; - } + Stream_Read_INT32(s, call->fmszGroupsIsNULL); /* fmszGroupsIsNULL (4 bytes) */ + Stream_Read_UINT32(s, call->cchGroups); /* cchGroups (4 bytes) */ + status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->hContext)); - for (index = 0; index < call->cReaders; index++) - { - readerState = &call->rgReaderStates[index]; + if (status != SCARD_S_SUCCESS) + return status; - if (Stream_GetRemainingLength(s) < 52) - { - WLog_WARN(TAG, "GetStatusChangeW_Call is too short: %"PRIuz"", - Stream_GetRemainingLength(s)); - return STATUS_BUFFER_TOO_SMALL; - } + smartcard_trace_list_reader_groups_call(smartcard, call, unicode); + return SCARD_S_SUCCESS; +} - Stream_Read_UINT32(s, szReaderNdrPtr); /* (4 bytes) */ - Stream_Read_UINT32(s, readerState->dwCurrentState); /* dwCurrentState (4 bytes) */ - Stream_Read_UINT32(s, readerState->dwEventState); /* dwEventState (4 bytes) */ - Stream_Read_UINT32(s, readerState->cbAtr); /* cbAtr (4 bytes) */ - Stream_Read(s, readerState->rgbAtr, 32); /* rgbAtr [0..32] (32 bytes) */ - Stream_Seek(s, 4); /* rgbAtr [32..36] (4 bytes) */ - } +LONG smartcard_pack_list_reader_groups_return(SMARTCARD_DEVICE* smartcard, wStream* s, + const ListReaderGroups_Return* ret, BOOL unicode) +{ + DWORD index = 0; + UINT32 size = unicode ? sizeof(WCHAR) : sizeof(CHAR); + size *= ret->cBytes; - for (index = 0; index < call->cReaders; index++) - { - readerState = &call->rgReaderStates[index]; + smartcard_trace_list_reader_groups_return(smartcard, ret, unicode); + if (ret->ReturnCode != SCARD_S_SUCCESS) + return ret->ReturnCode; - if (Stream_GetRemainingLength(s) < 12) - { - WLog_WARN(TAG, "GetStatusChangeW_Call is too short: %"PRIuz"", - Stream_GetRemainingLength(s)); - return STATUS_BUFFER_TOO_SMALL; - } + if (!Stream_EnsureRemainingCapacity(s, 4)) + return SCARD_E_NO_MEMORY; - Stream_Read_UINT32(s, maxCount); /* NdrMaxCount (4 bytes) */ - Stream_Read_UINT32(s, offset); /* NdrOffset (4 bytes) */ - Stream_Read_UINT32(s, count); /* NdrActualCount (4 bytes) */ + Stream_Write_UINT32(s, size); /* cBytes (4 bytes) */ + if (!smartcard_ndr_pointer_write(s, &index, size)) + return SCARD_E_NO_MEMORY; - if (Stream_GetRemainingLength(s) < (count * 2)) - { - WLog_WARN(TAG, "GetStatusChangeW_Call is too short: %"PRIuz"", - Stream_GetRemainingLength(s)); - return STATUS_BUFFER_TOO_SMALL; - } + return smartcard_ndr_write(s, ret->msz, size, 1, NDR_PTR_SIMPLE); +} - readerState->szReader = (WCHAR*) calloc((count + 1), 2); +LONG smartcard_unpack_list_readers_call(SMARTCARD_DEVICE* smartcard, wStream* s, + ListReaders_Call* call, BOOL unicode) +{ + LONG status; + UINT32 index = 0; + UINT32 mszGroupsNdrPtr; + call->mszGroups = NULL; - if (!readerState->szReader) - { - WLog_WARN(TAG, "GetStatusChangeW_Call out of memory error (readerState->szReader)"); - return STATUS_NO_MEMORY; - } + status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext), &index); + if (status != SCARD_S_SUCCESS) + return status; - Stream_Read(s, (void*) readerState->szReader, (count * 2)); - smartcard_unpack_read_size_align(smartcard, s, (count * 2), 4); - ((WCHAR*) readerState->szReader)[count] = '\0'; + if (Stream_GetRemainingLength(s) < 16) + { + WLog_WARN(TAG, "ListReaders_Call is too short: %" PRIuz "", Stream_GetRemainingLength(s)); + return STATUS_BUFFER_TOO_SMALL; + } - if (!readerState->szReader) - { - WLog_WARN(TAG, "GetStatusChangeW_Call null reader name"); - return STATUS_INVALID_PARAMETER; - } - } + Stream_Read_UINT32(s, call->cBytes); /* cBytes (4 bytes) */ + if (!smartcard_ndr_pointer_read(s, &index, &mszGroupsNdrPtr)) + return ERROR_INVALID_DATA; + Stream_Read_INT32(s, call->fmszReadersIsNULL); /* fmszReadersIsNULL (4 bytes) */ + Stream_Read_UINT32(s, call->cchReaders); /* cchReaders (4 bytes) */ + + if ((status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->hContext)))) + return status; + + if (mszGroupsNdrPtr) + { + status = smartcard_ndr_read(s, &call->mszGroups, call->cBytes, 1, NDR_PTR_SIMPLE); + if (status != SCARD_S_SUCCESS) + return status; } + smartcard_trace_list_readers_call(smartcard, call, unicode); return SCARD_S_SUCCESS; } -void smartcard_trace_get_status_change_w_call(SMARTCARD_DEVICE* smartcard, - GetStatusChangeW_Call* call) +LONG smartcard_pack_list_readers_return(SMARTCARD_DEVICE* smartcard, wStream* s, + const ListReaders_Return* ret, BOOL unicode) { - BYTE* pb; - UINT32 index; - char* szEventState; - char* szCurrentState; - LPSCARD_READERSTATEW readerState; + DWORD index = 0; + UINT32 size = unicode ? sizeof(WCHAR) : sizeof(CHAR); - if (!WLog_IsLevelActive(WLog_Get(TAG), WLOG_DEBUG)) - return; + size *= ret->cBytes; - WLog_DBG(TAG, "GetStatusChangeW_Call {"); - pb = (BYTE*) & (call->hContext.pbContext); + smartcard_trace_list_readers_return(smartcard, ret, unicode); + if (ret->ReturnCode != SCARD_S_SUCCESS) + return ret->ReturnCode; - if (call->hContext.cbContext > 4) + if (!Stream_EnsureRemainingCapacity(s, 4)) { - WLog_DBG(TAG, - "hContext: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], pb[4], pb[5], pb[6], pb[7], call->hContext.cbContext); + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + return SCARD_F_INTERNAL_ERROR; } - else + + Stream_Write_UINT32(s, size); /* cBytes (4 bytes) */ + if (!smartcard_ndr_pointer_write(s, &index, size)) + return SCARD_E_NO_MEMORY; + + return smartcard_ndr_write(s, ret->msz, size, 1, NDR_PTR_SIMPLE); +} + +static LONG smartcard_unpack_connect_common(SMARTCARD_DEVICE* smartcard, wStream* s, + Connect_Common* common, UINT32* index) +{ + LONG status; + + status = smartcard_unpack_redir_scard_context(smartcard, s, &(common->hContext), index); + if (status != SCARD_S_SUCCESS) + return status; + + if (Stream_GetRemainingLength(s) < 8) { - WLog_DBG(TAG, "hContext: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], call->hContext.cbContext); + WLog_WARN(TAG, "Connect_Common is too short: %" PRIuz "", Stream_GetRemainingLength(s)); + return STATUS_BUFFER_TOO_SMALL; } - WLog_DBG(TAG, "dwTimeOut: 0x%08"PRIX32" cReaders: %"PRIu32"", - call->dwTimeOut, call->cReaders); + Stream_Read_UINT32(s, common->dwShareMode); /* dwShareMode (4 bytes) */ + Stream_Read_UINT32(s, common->dwPreferredProtocols); /* dwPreferredProtocols (4 bytes) */ + return SCARD_S_SUCCESS; +} - for (index = 0; index < call->cReaders; index++) +LONG smartcard_unpack_connect_a_call(SMARTCARD_DEVICE* smartcard, wStream* s, ConnectA_Call* call) +{ + LONG status; + UINT32 index = 0; + call->szReader = NULL; + + if (!smartcard_ndr_pointer_read(s, &index, NULL)) + return ERROR_INVALID_DATA; + + if ((status = smartcard_unpack_connect_common(smartcard, s, &(call->Common), &index))) { - char* szReaderA = NULL; - readerState = &call->rgReaderStates[index]; - ConvertFromUnicode(CP_UTF8, 0, readerState->szReader, -1, &szReaderA, 0, NULL, NULL); - WLog_DBG(TAG, "\t[%"PRIu32"]: szReader: %s cbAtr: %"PRIu32"", - index, szReaderA, readerState->cbAtr); - szCurrentState = SCardGetReaderStateString(readerState->dwCurrentState); - szEventState = SCardGetReaderStateString(readerState->dwEventState); - WLog_DBG(TAG, "\t[%"PRIu32"]: dwCurrentState: %s (0x%08"PRIX32")", - index, szCurrentState, readerState->dwCurrentState); - WLog_DBG(TAG, "\t[%"PRIu32"]: dwEventState: %s (0x%08"PRIX32")", - index, szEventState, readerState->dwEventState); - free(szCurrentState); - free(szEventState); - free(szReaderA); + WLog_ERR(TAG, "smartcard_unpack_connect_common failed with error %" PRId32 "", status); + return status; } - WLog_DBG(TAG, "}"); + status = smartcard_ndr_read_a(s, &call->szReader, NDR_PTR_FULL); + if (status != SCARD_S_SUCCESS) + return status; + + if ((status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->Common.hContext)))) + WLog_ERR(TAG, "smartcard_unpack_redir_scard_context_ref failed with error %" PRId32 "", + status); + + smartcard_trace_connect_a_call(smartcard, call); + return status; } -LONG smartcard_pack_get_status_change_return(SMARTCARD_DEVICE* smartcard, wStream* s, - GetStatusChange_Return* ret) +LONG smartcard_unpack_connect_w_call(SMARTCARD_DEVICE* smartcard, wStream* s, ConnectW_Call* call) { - UINT32 index; - ReaderState_Return* rgReaderState; - Stream_Write_UINT32(s, ret->cReaders); /* cReaders (4 bytes) */ - Stream_Write_UINT32(s, 0x00020100); /* rgReaderStatesNdrPtr (4 bytes) */ - Stream_Write_UINT32(s, ret->cReaders); /* rgReaderStatesNdrCount (4 bytes) */ + LONG status; + UINT32 index = 0; - for (index = 0; index < ret->cReaders; index++) + call->szReader = NULL; + + if (!smartcard_ndr_pointer_read(s, &index, NULL)) + return ERROR_INVALID_DATA; + + if ((status = smartcard_unpack_connect_common(smartcard, s, &(call->Common), &index))) { - rgReaderState = &(ret->rgReaderStates[index]); - Stream_Write_UINT32(s, rgReaderState->dwCurrentState); /* dwCurrentState (4 bytes) */ - Stream_Write_UINT32(s, rgReaderState->dwEventState); /* dwEventState (4 bytes) */ - Stream_Write_UINT32(s, rgReaderState->cbAtr); /* cbAtr (4 bytes) */ - Stream_Write(s, rgReaderState->rgbAtr, 32); /* rgbAtr [0..32] (32 bytes) */ - Stream_Zero(s, 4); /* rgbAtr [32..36] (32 bytes) */ + WLog_ERR(TAG, "smartcard_unpack_connect_common failed with error %" PRId32 "", status); + return status; } - return SCARD_S_SUCCESS; + status = smartcard_ndr_read_w(s, &call->szReader, NDR_PTR_FULL); + if (status != SCARD_S_SUCCESS) + return status; + + if ((status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->Common.hContext)))) + WLog_ERR(TAG, "smartcard_unpack_redir_scard_context_ref failed with error %" PRId32 "", + status); + + smartcard_trace_connect_w_call(smartcard, call); + return status; } -void smartcard_trace_get_status_change_return(SMARTCARD_DEVICE* smartcard, - GetStatusChange_Return* ret, BOOL unicode) -{ - UINT32 index; - char* rgbAtr; - char* szEventState; - char* szCurrentState; - ReaderState_Return* rgReaderState; +LONG smartcard_pack_connect_return(SMARTCARD_DEVICE* smartcard, wStream* s, + const Connect_Return* ret) +{ + LONG status; + DWORD index = 0; + + smartcard_trace_connect_return(smartcard, ret); + if (ret->ReturnCode != SCARD_S_SUCCESS) + return ret->ReturnCode; - if (!WLog_IsLevelActive(WLog_Get(TAG), WLOG_DEBUG)) - return; + status = smartcard_pack_redir_scard_context(smartcard, s, &ret->hContext, &index); + if (status != SCARD_S_SUCCESS) + return status; - WLog_DBG(TAG, "GetStatusChange%s_Return {", unicode ? "W" : "A"); - WLog_DBG(TAG, "ReturnCode: %s (0x%08"PRIX32")", - SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); - WLog_DBG(TAG, "cReaders: %"PRIu32"", ret->cReaders); + status = smartcard_pack_redir_scard_handle(smartcard, s, &ret->hCard, &index); + if (status != SCARD_S_SUCCESS) + return status; - for (index = 0; index < ret->cReaders; index++) - { - rgReaderState = &(ret->rgReaderStates[index]); - szCurrentState = SCardGetReaderStateString(rgReaderState->dwCurrentState); - szEventState = SCardGetReaderStateString(rgReaderState->dwEventState); - rgbAtr = winpr_BinToHexString((BYTE*) & (rgReaderState->rgbAtr), rgReaderState->cbAtr, FALSE); - WLog_DBG(TAG, "\t[%"PRIu32"]: dwCurrentState: %s (0x%08"PRIX32")", - index, szCurrentState, rgReaderState->dwCurrentState); - WLog_DBG(TAG, "\t[%"PRIu32"]: dwEventState: %s (0x%08"PRIX32")", - index, szEventState, rgReaderState->dwEventState); - WLog_DBG(TAG, "\t[%"PRIu32"]: cbAtr: %"PRIu32" rgbAtr: %s", - index, rgReaderState->cbAtr, rgbAtr); - free(szCurrentState); - free(szEventState); - free(rgbAtr); - } + if (!Stream_EnsureRemainingCapacity(s, 4)) + return SCARD_E_NO_MEMORY; - WLog_DBG(TAG, "}"); + Stream_Write_UINT32(s, ret->dwActiveProtocol); /* dwActiveProtocol (4 bytes) */ + status = smartcard_pack_redir_scard_context_ref(smartcard, s, &ret->hContext); + if (status != SCARD_S_SUCCESS) + return status; + return smartcard_pack_redir_scard_handle_ref(smartcard, s, &(ret->hCard)); } -LONG smartcard_unpack_state_call(SMARTCARD_DEVICE* smartcard, wStream* s, State_Call* call) +LONG smartcard_unpack_reconnect_call(SMARTCARD_DEVICE* smartcard, wStream* s, Reconnect_Call* call) { LONG status; + UINT32 index = 0; - if ((status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext)))) - { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_context failed with error %"PRId32"", status); + status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext), &index); + if (status != SCARD_S_SUCCESS) return status; - } - if ((status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->hCard)))) - { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_handle failed with error %"PRId32"", status); + status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->hCard), &index); + if (status != SCARD_S_SUCCESS) return status; - } - if (Stream_GetRemainingLength(s) < 8) + if (Stream_GetRemainingLength(s) < 12) { - WLog_WARN(TAG, "State_Call is too short: %"PRIuz"", - Stream_GetRemainingLength(s)); + WLog_WARN(TAG, "Reconnect_Call is too short: %" PRIuz "", Stream_GetRemainingLength(s)); return STATUS_BUFFER_TOO_SMALL; } - Stream_Read_UINT32(s, call->fpbAtrIsNULL); /* fpbAtrIsNULL (4 bytes) */ - Stream_Read_UINT32(s, call->cbAtrLen); /* cbAtrLen (4 bytes) */ + Stream_Read_UINT32(s, call->dwShareMode); /* dwShareMode (4 bytes) */ + Stream_Read_UINT32(s, call->dwPreferredProtocols); /* dwPreferredProtocols (4 bytes) */ + Stream_Read_UINT32(s, call->dwInitialization); /* dwInitialization (4 bytes) */ if ((status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->hContext)))) { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_context_ref failed with error %"PRId32"", status); + WLog_ERR(TAG, "smartcard_unpack_redir_scard_context_ref failed with error %" PRId32 "", + status); return status; } if ((status = smartcard_unpack_redir_scard_handle_ref(smartcard, s, &(call->hCard)))) - WLog_ERR(TAG, "smartcard_unpack_redir_scard_handle_ref failed with error %"PRId32"", status); + WLog_ERR(TAG, "smartcard_unpack_redir_scard_handle_ref failed with error %" PRId32 "", + status); + smartcard_trace_reconnect_call(smartcard, call); return status; } -LONG smartcard_pack_state_return(SMARTCARD_DEVICE* smartcard, wStream* s, State_Return* ret) +LONG smartcard_pack_reconnect_return(SMARTCARD_DEVICE* smartcard, wStream* s, + const Reconnect_Return* ret) { - LONG status; - Stream_Write_UINT32(s, ret->dwState); /* dwState (4 bytes) */ - Stream_Write_UINT32(s, ret->dwProtocol); /* dwProtocol (4 bytes) */ - Stream_Write_UINT32(s, ret->cbAtrLen); /* cbAtrLen (4 bytes) */ - Stream_Write_UINT32(s, 0x00020020); /* rgAtrNdrPtr (4 bytes) */ - Stream_Write_UINT32(s, ret->cbAtrLen); /* rgAtrLength (4 bytes) */ - Stream_Write(s, ret->rgAtr, ret->cbAtrLen); /* rgAtr */ - - if ((status = smartcard_pack_write_size_align(smartcard, s, ret->cbAtrLen, 4))) - WLog_ERR(TAG, "smartcard_pack_write_size_align failed with error %"PRId32"", status); + smartcard_trace_reconnect_return(smartcard, ret); + if (ret->ReturnCode != SCARD_S_SUCCESS) + return ret->ReturnCode; - return status; + if (!Stream_EnsureRemainingCapacity(s, 4)) + return SCARD_E_NO_MEMORY; + Stream_Write_UINT32(s, ret->dwActiveProtocol); /* dwActiveProtocol (4 bytes) */ + return SCARD_S_SUCCESS; } -LONG smartcard_unpack_status_call(SMARTCARD_DEVICE* smartcard, wStream* s, Status_Call* call) +LONG smartcard_unpack_hcard_and_disposition_call(SMARTCARD_DEVICE* smartcard, wStream* s, + HCardAndDisposition_Call* call, const char* name) { LONG status; + UINT32 index = 0; - if ((status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext)))) - { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_context failed with error %"PRId32"", status); + status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext), &index); + if (status != SCARD_S_SUCCESS) return status; - } - if ((status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->hCard)))) - { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_handle failed with error %"PRId32"", status); + status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->hCard), &index); + if (status != SCARD_S_SUCCESS) return status; - } - if (Stream_GetRemainingLength(s) < 12) + if (Stream_GetRemainingLength(s) < 4) { - WLog_WARN(TAG, "Status_Call is too short: %"PRIuz"", + WLog_WARN(TAG, "HCardAndDisposition_Call is too short: %" PRIuz "", Stream_GetRemainingLength(s)); return STATUS_BUFFER_TOO_SMALL; } - Stream_Read_UINT32(s, call->fmszReaderNamesIsNULL); /* fmszReaderNamesIsNULL (4 bytes) */ - Stream_Read_UINT32(s, call->cchReaderLen); /* cchReaderLen (4 bytes) */ - Stream_Read_UINT32(s, call->cbAtrLen); /* cbAtrLen (4 bytes) */ + Stream_Read_UINT32(s, call->dwDisposition); /* dwDisposition (4 bytes) */ if ((status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->hContext)))) - { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_context_ref failed with error %"PRId32"", status); return status; - } if ((status = smartcard_unpack_redir_scard_handle_ref(smartcard, s, &(call->hCard)))) - WLog_ERR(TAG, "smartcard_unpack_redir_scard_handle_ref failed with error %"PRId32"", status); + return status; + smartcard_trace_hcard_and_disposition_call(smartcard, call, name); return status; } -void smartcard_trace_status_call(SMARTCARD_DEVICE* smartcard, Status_Call* call, BOOL unicode) +static void smartcard_trace_get_status_change_a_call(SMARTCARD_DEVICE* smartcard, + const GetStatusChangeA_Call* call) { - BYTE* pb; + UINT32 index; + char* szEventState; + char* szCurrentState; + LPSCARD_READERSTATEA readerState; + WINPR_UNUSED(smartcard); - if (!WLog_IsLevelActive(WLog_Get(TAG), WLOG_DEBUG)) + if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) return; - WLog_DBG(TAG, "Status%s_Call {", unicode ? "W" : "A"); - pb = (BYTE*) & (call->hContext.pbContext); - - if (call->hContext.cbContext > 4) - { - WLog_DBG(TAG, - "hContext: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], pb[4], pb[5], pb[6], pb[7], call->hContext.cbContext); - } - else - { - WLog_DBG(TAG, "hContext: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], call->hContext.cbContext); - } + WLog_LVL(TAG, g_LogLevel, "GetStatusChangeA_Call {"); + smartcard_log_context(TAG, &call->hContext); - pb = (BYTE*) & (call->hCard.pbHandle); + WLog_LVL(TAG, g_LogLevel, "dwTimeOut: 0x%08" PRIX32 " cReaders: %" PRIu32 "", call->dwTimeOut, + call->cReaders); - if (call->hCard.cbHandle > 4) - { - WLog_DBG(TAG, - "hCard: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], pb[4], pb[5], pb[6], pb[7], call->hCard.cbHandle); - } - else + for (index = 0; index < call->cReaders; index++) { - WLog_DBG(TAG, "hCard: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], call->hCard.cbHandle); + readerState = &call->rgReaderStates[index]; + WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: szReader: %s cbAtr: %" PRIu32 "", index, + readerState->szReader, readerState->cbAtr); + szCurrentState = SCardGetReaderStateString(readerState->dwCurrentState); + szEventState = SCardGetReaderStateString(readerState->dwEventState); + WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: dwCurrentState: %s (0x%08" PRIX32 ")", index, + szCurrentState, readerState->dwCurrentState); + WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: dwEventState: %s (0x%08" PRIX32 ")", index, + szEventState, readerState->dwEventState); + free(szCurrentState); + free(szEventState); } - WLog_DBG(TAG, "fmszReaderNamesIsNULL: %"PRId32" cchReaderLen: %"PRIu32" cbAtrLen: %"PRIu32"", - call->fmszReaderNamesIsNULL, call->cchReaderLen, call->cbAtrLen); - WLog_DBG(TAG, "}"); + WLog_LVL(TAG, g_LogLevel, "}"); } -LONG smartcard_pack_status_return(SMARTCARD_DEVICE* smartcard, wStream* s, Status_Return* ret) +static LONG smartcard_unpack_reader_state_a(wStream* s, LPSCARD_READERSTATEA* ppcReaders, + UINT32 cReaders, UINT32* ptrIndex) { - LONG status; + UINT32 index, len; + LONG status = ERROR_INVALID_DATA; + LPSCARD_READERSTATEA rgReaderStates; + + if (Stream_GetRemainingLength(s) < 4) + return status; - if (!Stream_EnsureRemainingCapacity(s, ret->cBytes + 64)) + Stream_Read_UINT32(s, len); + if (len != cReaders) { - WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); - return SCARD_F_INTERNAL_ERROR; + WLog_ERR(TAG, "Count mismatch when reading LPSCARD_READERSTATEA"); + return status; } + rgReaderStates = (LPSCARD_READERSTATEA)calloc(cReaders, sizeof(SCARD_READERSTATEA)); - Stream_Write_UINT32(s, ret->cBytes); /* cBytes (4 bytes) */ - Stream_Write_UINT32(s, 0x00020010); /* mszReaderNamesNdrPtr (4 bytes) */ - Stream_Write_UINT32(s, ret->dwState); /* dwState (4 bytes) */ - Stream_Write_UINT32(s, ret->dwProtocol); /* dwProtocol (4 bytes) */ - Stream_Write(s, ret->pbAtr, 32); /* pbAtr (32 bytes) */ - Stream_Write_UINT32(s, ret->cbAtrLen); /* cbAtrLen (4 bytes) */ - Stream_Write_UINT32(s, ret->cBytes); /* mszReaderNamesNdrLen (4 bytes) */ + if (!rgReaderStates) + return STATUS_NO_MEMORY; - if (ret->mszReaderNames) - Stream_Write(s, ret->mszReaderNames, ret->cBytes); - else - Stream_Zero(s, ret->cBytes); + for (index = 0; index < cReaders; index++) + { + LPSCARD_READERSTATEA readerState = &rgReaderStates[index]; - if ((status = smartcard_pack_write_size_align(smartcard, s, ret->cBytes, 4))) - WLog_ERR(TAG, "smartcard_pack_write_size_align failed with error %"PRId32"", status); + if (Stream_GetRemainingLength(s) < 52) + { + WLog_WARN(TAG, "GetStatusChangeA_Call is too short: %" PRIuz "", + Stream_GetRemainingLength(s)); + goto fail; + } - return status; -} + if (!smartcard_ndr_pointer_read(s, ptrIndex, NULL)) + goto fail; + Stream_Read_UINT32(s, readerState->dwCurrentState); /* dwCurrentState (4 bytes) */ + Stream_Read_UINT32(s, readerState->dwEventState); /* dwEventState (4 bytes) */ + Stream_Read_UINT32(s, readerState->cbAtr); /* cbAtr (4 bytes) */ + Stream_Read(s, readerState->rgbAtr, 36); /* rgbAtr [0..36] (36 bytes) */ + } -void smartcard_trace_status_return(SMARTCARD_DEVICE* smartcard, Status_Return* ret, BOOL unicode) -{ - int index; - size_t length; - char* pbAtr = NULL; - char* mszReaderNamesA = NULL; + for (index = 0; index < cReaders; index++) + { + LPSCARD_READERSTATEA readerState = &rgReaderStates[index]; - if (!WLog_IsLevelActive(WLog_Get(TAG), WLOG_DEBUG)) - return; + status = smartcard_ndr_read_a(s, &readerState->szReader, NDR_PTR_FULL); + if (status != SCARD_S_SUCCESS) + goto fail; + } - if (ret->mszReaderNames) + *ppcReaders = rgReaderStates; + return SCARD_S_SUCCESS; +fail: + if (rgReaderStates) { - if (unicode) + for (index = 0; index < cReaders; index++) { - length = ret->cBytes / 2; - - if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) ret->mszReaderNames, (int) length, - &mszReaderNamesA, 0, NULL, NULL) < 1) - { - WLog_ERR(TAG, "ConvertFromUnicode failed"); - return; - } + LPSCARD_READERSTATEA readerState = &rgReaderStates[index]; + free(readerState->szReader); } - else - { - length = (int) ret->cBytes; - mszReaderNamesA = (char*) malloc(length); + } + free(rgReaderStates); + return status; +} - if (!mszReaderNamesA) - { - WLog_ERR(TAG, "malloc failed!"); - return; - } +static LONG smartcard_unpack_reader_state_w(wStream* s, LPSCARD_READERSTATEW* ppcReaders, + UINT32 cReaders, UINT32* ptrIndex) +{ + UINT32 index, len; + LONG status = ERROR_INVALID_DATA; + LPSCARD_READERSTATEW rgReaderStates; - CopyMemory(mszReaderNamesA, ret->mszReaderNames, ret->cBytes); - } + if (Stream_GetRemainingLength(s) < 4) + return status; + + Stream_Read_UINT32(s, len); + if (len != cReaders) + { + WLog_ERR(TAG, "Count mismatch when reading LPSCARD_READERSTATEW"); + return status; } - else - length = 0; - if (length > 2) + rgReaderStates = (LPSCARD_READERSTATEW)calloc(cReaders, sizeof(SCARD_READERSTATEW)); + + if (!rgReaderStates) + return STATUS_NO_MEMORY; + + for (index = 0; index < cReaders; index++) { - for (index = 0; index < length - 2; index++) + LPSCARD_READERSTATEW readerState = &rgReaderStates[index]; + + if (Stream_GetRemainingLength(s) < 52) { - if (mszReaderNamesA[index] == '\0') - mszReaderNamesA[index] = ','; + WLog_WARN(TAG, "GetStatusChangeA_Call is too short: %" PRIuz "", + Stream_GetRemainingLength(s)); + goto fail; } - } - pbAtr = winpr_BinToHexString(ret->pbAtr, ret->cbAtrLen, FALSE); - WLog_DBG(TAG, "Status%s_Return {", unicode ? "W" : "A"); - WLog_DBG(TAG, "ReturnCode: %s (0x%08"PRIX32")", - SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); - WLog_DBG(TAG, "dwState: %s (0x%08"PRIX32") dwProtocol: %s (0x%08"PRIX32")", - SCardGetCardStateString(ret->dwState), ret->dwState, - SCardGetProtocolString(ret->dwProtocol), ret->dwProtocol); + if (!smartcard_ndr_pointer_read(s, ptrIndex, NULL)) + goto fail; + Stream_Read_UINT32(s, readerState->dwCurrentState); /* dwCurrentState (4 bytes) */ + Stream_Read_UINT32(s, readerState->dwEventState); /* dwEventState (4 bytes) */ + Stream_Read_UINT32(s, readerState->cbAtr); /* cbAtr (4 bytes) */ + Stream_Read(s, readerState->rgbAtr, 36); /* rgbAtr [0..36] (36 bytes) */ + } - if (mszReaderNamesA) + for (index = 0; index < cReaders; index++) { - WLog_DBG(TAG, "cBytes: %"PRIu32" mszReaderNames: %s", - ret->cBytes, mszReaderNamesA); + LPSCARD_READERSTATEW readerState = &rgReaderStates[index]; + + status = smartcard_ndr_read_w(s, &readerState->szReader, NDR_PTR_FULL); + if (status != SCARD_S_SUCCESS) + goto fail; } - WLog_DBG(TAG, "cbAtrLen: %"PRIu32" pbAtr: %s", ret->cbAtrLen, pbAtr); - WLog_DBG(TAG, "}"); - free(mszReaderNamesA); - free(pbAtr); + *ppcReaders = rgReaderStates; + return SCARD_S_SUCCESS; +fail: + if (rgReaderStates) + { + for (index = 0; index < cReaders; index++) + { + LPSCARD_READERSTATEW readerState = &rgReaderStates[index]; + free(readerState->szReader); + } + } + free(rgReaderStates); + return status; } -LONG smartcard_unpack_get_attrib_call(SMARTCARD_DEVICE* smartcard, wStream* s, GetAttrib_Call* call) +/******************************************************************************/ +/************************************* End Trace Functions ********************/ +/******************************************************************************/ + +LONG smartcard_unpack_get_status_change_a_call(SMARTCARD_DEVICE* smartcard, wStream* s, + GetStatusChangeA_Call* call) { LONG status; + UINT32 ndrPtr; + UINT32 index = 0; + call->rgReaderStates = NULL; - if ((status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext)))) - { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_context failed with error %"PRId32"", status); - return status; - } - - if ((status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->hCard)))) - { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_handle failed with error %"PRId32"", status); + status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext), &index); + if (status != SCARD_S_SUCCESS) return status; - } if (Stream_GetRemainingLength(s) < 12) { - WLog_WARN(TAG, "GetAttrib_Call is too short: %"PRIuz"", + WLog_WARN(TAG, "GetStatusChangeA_Call is too short: %" PRIuz "", Stream_GetRemainingLength(s)); return STATUS_BUFFER_TOO_SMALL; } - Stream_Read_UINT32(s, call->dwAttrId); /* dwAttrId (4 bytes) */ - Stream_Read_UINT32(s, call->fpbAttrIsNULL); /* fpbAttrIsNULL (4 bytes) */ - Stream_Read_UINT32(s, call->cbAttrLen); /* cbAttrLen (4 bytes) */ + Stream_Read_UINT32(s, call->dwTimeOut); /* dwTimeOut (4 bytes) */ + Stream_Read_UINT32(s, call->cReaders); /* cReaders (4 bytes) */ + if (!smartcard_ndr_pointer_read(s, &index, &ndrPtr)) + return ERROR_INVALID_DATA; if ((status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->hContext)))) - { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_context_ref failed with error %"PRId32"", status); return status; - } - if ((status = smartcard_unpack_redir_scard_handle_ref(smartcard, s, &(call->hCard)))) - WLog_ERR(TAG, "smartcard_unpack_redir_scard_handle_ref failed with error %"PRId32"", status); + if (ndrPtr) + { + status = smartcard_unpack_reader_state_a(s, &call->rgReaderStates, call->cReaders, &index); + if (status != SCARD_S_SUCCESS) + return status; + } - return status; + smartcard_trace_get_status_change_a_call(smartcard, call); + return SCARD_S_SUCCESS; } -void smartcard_trace_get_attrib_call(SMARTCARD_DEVICE* smartcard, GetAttrib_Call* call) +LONG smartcard_unpack_get_status_change_w_call(SMARTCARD_DEVICE* smartcard, wStream* s, + GetStatusChangeW_Call* call) { - BYTE* pb; + UINT32 ndrPtr; + LONG status; + UINT32 index = 0; - if (!WLog_IsLevelActive(WLog_Get(TAG), WLOG_DEBUG)) - return; + call->rgReaderStates = NULL; - WLog_DBG(TAG, "GetAttrib_Call {"); - pb = (BYTE*) & (call->hContext.pbContext); + status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext), &index); + if (status != SCARD_S_SUCCESS) + return status; - if (call->hContext.cbContext > 4) - { - WLog_DBG(TAG, - "hContext: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], pb[4], pb[5], pb[6], pb[7], call->hContext.cbContext); - } - else + if (Stream_GetRemainingLength(s) < 12) { - WLog_DBG(TAG, "hContext: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], call->hContext.cbContext); + WLog_WARN(TAG, "GetStatusChangeW_Call is too short: %" PRIuz "", + Stream_GetRemainingLength(s)); + return STATUS_BUFFER_TOO_SMALL; } - pb = (BYTE*) & (call->hCard.pbHandle); + Stream_Read_UINT32(s, call->dwTimeOut); /* dwTimeOut (4 bytes) */ + Stream_Read_UINT32(s, call->cReaders); /* cReaders (4 bytes) */ + if (!smartcard_ndr_pointer_read(s, &index, &ndrPtr)) + return ERROR_INVALID_DATA; - if (call->hCard.cbHandle > 4) - { - WLog_DBG(TAG, - "hCard: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], pb[4], pb[5], pb[6], pb[7], call->hCard.cbHandle); - } - else + if ((status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->hContext)))) + return status; + + if (ndrPtr) { - WLog_DBG(TAG, "hCard: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], call->hCard.cbHandle); + status = smartcard_unpack_reader_state_w(s, &call->rgReaderStates, call->cReaders, &index); + if (status != SCARD_S_SUCCESS) + return status; } - WLog_DBG(TAG, "dwAttrId: %s (0x%08"PRIX32") fpbAttrIsNULL: %"PRId32" cbAttrLen: 0x%08"PRIX32"", - SCardGetAttributeString(call->dwAttrId), call->dwAttrId, call->fpbAttrIsNULL, call->cbAttrLen); - WLog_DBG(TAG, "}"); + smartcard_trace_get_status_change_w_call(smartcard, call); + return SCARD_S_SUCCESS; } -LONG smartcard_pack_get_attrib_return(SMARTCARD_DEVICE* smartcard, wStream* s, - GetAttrib_Return* ret) +LONG smartcard_pack_get_status_change_return(SMARTCARD_DEVICE* smartcard, wStream* s, + const GetStatusChange_Return* ret, BOOL unicode) +{ + UINT32 index = 0; + + smartcard_trace_get_status_change_return(smartcard, ret, unicode); + if (ret->ReturnCode != SCARD_S_SUCCESS) + return ret->ReturnCode; + + if (!Stream_EnsureRemainingCapacity(s, 4)) + return SCARD_E_NO_MEMORY; + + Stream_Write_UINT32(s, ret->cReaders); /* cReaders (4 bytes) */ + if (!smartcard_ndr_pointer_write(s, &index, ret->cReaders)) + return SCARD_E_NO_MEMORY; + return smartcard_ndr_write_state(s, ret->rgReaderStates, ret->cReaders, NDR_PTR_SIMPLE); +} + +LONG smartcard_unpack_state_call(SMARTCARD_DEVICE* smartcard, wStream* s, State_Call* call) { LONG status; + UINT32 index = 0; + + status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext), &index); + if (status != SCARD_S_SUCCESS) + return status; + + status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->hCard), &index); + if (status != SCARD_S_SUCCESS) + return status; - if (!Stream_EnsureRemainingCapacity(s, ret->cbAttrLen + 32)) + if (Stream_GetRemainingLength(s) < 8) { - WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); - return SCARD_F_INTERNAL_ERROR; + WLog_WARN(TAG, "State_Call is too short: %" PRIuz "", Stream_GetRemainingLength(s)); + return STATUS_BUFFER_TOO_SMALL; } - Stream_Write_UINT32(s, ret->cbAttrLen); /* cbAttrLen (4 bytes) */ - Stream_Write_UINT32(s, 0x00020080); /* pbAttrNdrPtr (4 bytes) */ - Stream_Write_UINT32(s, ret->cbAttrLen); /* pbAttrNdrCount (4 bytes) */ + Stream_Read_INT32(s, call->fpbAtrIsNULL); /* fpbAtrIsNULL (4 bytes) */ + Stream_Read_UINT32(s, call->cbAtrLen); /* cbAtrLen (4 bytes) */ - if (!ret->pbAttr) - Stream_Zero(s, ret->cbAttrLen); /* pbAttr */ - else - Stream_Write(s, ret->pbAttr, ret->cbAttrLen); /* pbAttr */ + if ((status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->hContext)))) + return status; - if ((status = smartcard_pack_write_size_align(smartcard, s, ret->cbAttrLen, 4))) - WLog_ERR(TAG, "smartcard_pack_write_size_align failed with error %"PRId32"", status); + if ((status = smartcard_unpack_redir_scard_handle_ref(smartcard, s, &(call->hCard)))) + return status; return status; } -void smartcard_trace_get_attrib_return(SMARTCARD_DEVICE* smartcard, GetAttrib_Return* ret, - DWORD dwAttrId) +LONG smartcard_pack_state_return(SMARTCARD_DEVICE* smartcard, wStream* s, const State_Return* ret) { - if (!WLog_IsLevelActive(WLog_Get(TAG), WLOG_DEBUG)) - return; - - WLog_DBG(TAG, "GetAttrib_Return {"); - WLog_DBG(TAG, "ReturnCode: %s (0x%08"PRIX32")", - SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); - WLog_DBG(TAG, "dwAttrId: %s (0x%08"PRIX32") cbAttrLen: 0x%08"PRIX32"", - SCardGetAttributeString(dwAttrId), dwAttrId, ret->cbAttrLen); + DWORD index = 0; - if (dwAttrId == SCARD_ATTR_VENDOR_NAME) - { - WLog_DBG(TAG, "pbAttr: %.*s", ret->cbAttrLen, (char*) ret->pbAttr); - } - else if (dwAttrId == SCARD_ATTR_CURRENT_PROTOCOL_TYPE) - { - UINT32 dwProtocolType = *((UINT32*) ret->pbAttr); - WLog_DBG(TAG, "dwProtocolType: %s (0x%08"PRIX32")", - SCardGetProtocolString(dwProtocolType), dwProtocolType); - } + smartcard_trace_state_return(smartcard, ret); + if (ret->ReturnCode != SCARD_S_SUCCESS) + return ret->ReturnCode; - WLog_DBG(TAG, "}"); + Stream_Write_UINT32(s, ret->dwState); /* dwState (4 bytes) */ + Stream_Write_UINT32(s, ret->dwProtocol); /* dwProtocol (4 bytes) */ + Stream_Write_UINT32(s, ret->cbAtrLen); /* cbAtrLen (4 bytes) */ + if (!smartcard_ndr_pointer_write(s, &index, ret->cbAtrLen)) + return SCARD_E_NO_MEMORY; + return smartcard_ndr_write(s, ret->rgAtr, ret->cbAtrLen, 1, NDR_PTR_SIMPLE); } -LONG smartcard_unpack_control_call(SMARTCARD_DEVICE* smartcard, wStream* s, Control_Call* call) +LONG smartcard_unpack_status_call(SMARTCARD_DEVICE* smartcard, wStream* s, Status_Call* call, + BOOL unicode) { LONG status; - UINT32 length; - call->pvInBuffer = NULL; - - if ((status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext)))) - { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_context failed with error %"PRId32"", status); + UINT32 index = 0; + status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext), &index); + if (status != SCARD_S_SUCCESS) return status; - } - if ((status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->hCard)))) - { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_handle failed with error %"PRId32"", status); + status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->hCard), &index); + if (status != SCARD_S_SUCCESS) return status; - } - if (Stream_GetRemainingLength(s) < 20) + if (Stream_GetRemainingLength(s) < 12) { - WLog_WARN(TAG, "Control_Call is too short: %"PRIuz"", - Stream_GetRemainingLength(s)); + WLog_WARN(TAG, "Status_Call is too short: %" PRIuz "", Stream_GetRemainingLength(s)); return STATUS_BUFFER_TOO_SMALL; } - Stream_Read_UINT32(s, call->dwControlCode); /* dwControlCode (4 bytes) */ - Stream_Read_UINT32(s, call->cbInBufferSize); /* cbInBufferSize (4 bytes) */ - Stream_Seek_UINT32(s); /* pvInBufferNdrPtr (4 bytes) */ - Stream_Read_UINT32(s, call->fpvOutBufferIsNULL); /* fpvOutBufferIsNULL (4 bytes) */ - Stream_Read_UINT32(s, call->cbOutBufferSize); /* cbOutBufferSize (4 bytes) */ + Stream_Read_INT32(s, call->fmszReaderNamesIsNULL); /* fmszReaderNamesIsNULL (4 bytes) */ + Stream_Read_UINT32(s, call->cchReaderLen); /* cchReaderLen (4 bytes) */ + Stream_Read_UINT32(s, call->cbAtrLen); /* cbAtrLen (4 bytes) */ if ((status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->hContext)))) - { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_context_ref failed with error %"PRId32"", status); return status; - } if ((status = smartcard_unpack_redir_scard_handle_ref(smartcard, s, &(call->hCard)))) - { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_context_ref failed with error %"PRId32"", status); return status; - } - if (call->cbInBufferSize) - { - if (Stream_GetRemainingLength(s) < 4) - { - WLog_WARN(TAG, "Control_Call is too short: %"PRIuz"", - Stream_GetRemainingLength(s)); - return STATUS_BUFFER_TOO_SMALL; - } + smartcard_trace_status_call(smartcard, call, unicode); + return status; +} - Stream_Read_UINT32(s, length); /* Length (4 bytes) */ +LONG smartcard_pack_status_return(SMARTCARD_DEVICE* smartcard, wStream* s, const Status_Return* ret, + BOOL unicode) +{ + DWORD index = 0; + UINT32 size = unicode ? sizeof(WCHAR) : sizeof(CHAR); + size *= ret->cBytes; - if (Stream_GetRemainingLength(s) < length) - { - WLog_WARN(TAG, "Control_Call is too short: %"PRIuz"", - Stream_GetRemainingLength(s)); - return STATUS_BUFFER_TOO_SMALL; - } + smartcard_trace_status_return(smartcard, ret, unicode); + if (ret->ReturnCode != SCARD_S_SUCCESS) + return ret->ReturnCode; - call->pvInBuffer = (BYTE*) malloc(length); + if (!Stream_EnsureRemainingCapacity(s, 4)) + return SCARD_F_INTERNAL_ERROR; - if (!call->pvInBuffer) - { - WLog_WARN(TAG, "Control_Call out of memory error (call->pvInBuffer)"); - return STATUS_NO_MEMORY; - } + Stream_Write_UINT32(s, size); /* cBytes (4 bytes) */ + if (!smartcard_ndr_pointer_write(s, &index, size)) + return SCARD_E_NO_MEMORY; + + if (!Stream_EnsureRemainingCapacity(s, 44)) + return SCARD_F_INTERNAL_ERROR; + + Stream_Write_UINT32(s, ret->dwState); /* dwState (4 bytes) */ + Stream_Write_UINT32(s, ret->dwProtocol); /* dwProtocol (4 bytes) */ + Stream_Write(s, ret->pbAtr, sizeof(ret->pbAtr)); /* pbAtr (32 bytes) */ + Stream_Write_UINT32(s, ret->cbAtrLen); /* cbAtrLen (4 bytes) */ + return smartcard_ndr_write(s, ret->mszReaderNames, size, 1, NDR_PTR_SIMPLE); +} + +LONG smartcard_unpack_get_attrib_call(SMARTCARD_DEVICE* smartcard, wStream* s, GetAttrib_Call* call) +{ + LONG status; + UINT32 index = 0; + + status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext), &index); + if (status != SCARD_S_SUCCESS) + return status; + + status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->hCard), &index); + if (status != SCARD_S_SUCCESS) + return status; + + if (Stream_GetRemainingLength(s) < 12) + { + WLog_WARN(TAG, "GetAttrib_Call is too short: %" PRIuz "", Stream_GetRemainingLength(s)); + return STATUS_BUFFER_TOO_SMALL; + } + + Stream_Read_UINT32(s, call->dwAttrId); /* dwAttrId (4 bytes) */ + Stream_Read_INT32(s, call->fpbAttrIsNULL); /* fpbAttrIsNULL (4 bytes) */ + Stream_Read_UINT32(s, call->cbAttrLen); /* cbAttrLen (4 bytes) */ + + if ((status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->hContext)))) + return status; - call->cbInBufferSize = length; - Stream_Read(s, call->pvInBuffer, length); - } + if ((status = smartcard_unpack_redir_scard_handle_ref(smartcard, s, &(call->hCard)))) + return status; - return SCARD_S_SUCCESS; + smartcard_trace_get_attrib_call(smartcard, call); + return status; } -void smartcard_trace_control_call(SMARTCARD_DEVICE* smartcard, Control_Call* call) +LONG smartcard_pack_get_attrib_return(SMARTCARD_DEVICE* smartcard, wStream* s, + const GetAttrib_Return* ret, DWORD dwAttrId) { - BYTE* pb; + DWORD index = 0; + smartcard_trace_get_attrib_return(smartcard, ret, dwAttrId); + if (ret->ReturnCode != SCARD_S_SUCCESS) + return ret->ReturnCode; - if (!WLog_IsLevelActive(WLog_Get(TAG), WLOG_DEBUG)) - return; + if (!Stream_EnsureRemainingCapacity(s, 4)) + return SCARD_F_INTERNAL_ERROR; - WLog_DBG(TAG, "Control_Call {"); - pb = (BYTE*) & (call->hContext.pbContext); + Stream_Write_UINT32(s, ret->cbAttrLen); /* cbAttrLen (4 bytes) */ + if (!smartcard_ndr_pointer_write(s, &index, ret->cbAttrLen)) + return SCARD_E_NO_MEMORY; - if (call->hContext.cbContext > 4) - { - WLog_DBG(TAG, - "hContext: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], pb[4], pb[5], pb[6], pb[7], call->hContext.cbContext); - } - else - { - WLog_DBG(TAG, "hContext: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], call->hContext.cbContext); - } + return smartcard_ndr_write(s, ret->pbAttr, ret->cbAttrLen, 1, NDR_PTR_SIMPLE); +} - pb = (BYTE*) & (call->hCard.pbHandle); +LONG smartcard_unpack_control_call(SMARTCARD_DEVICE* smartcard, wStream* s, Control_Call* call) +{ + LONG status; + UINT32 index = 0; + UINT32 pvInBufferNdrPtr; - if (call->hCard.cbHandle > 4) - { - WLog_DBG(TAG, - "hCard: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], pb[4], pb[5], pb[6], pb[7], call->hCard.cbHandle); - } - else - { - WLog_DBG(TAG, "hCard: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], call->hCard.cbHandle); - } + call->pvInBuffer = NULL; - WLog_DBG(TAG, - "dwControlCode: 0x%08"PRIX32" cbInBufferSize: %"PRIu32" fpvOutBufferIsNULL: %"PRId32" cbOutBufferSize: %"PRIu32"", - call->dwControlCode, call->cbInBufferSize, call->fpvOutBufferIsNULL, call->cbOutBufferSize); + status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext), &index); + if (status != SCARD_S_SUCCESS) + return status; - if (call->pvInBuffer) - { - char* szInBuffer = winpr_BinToHexString(call->pvInBuffer, call->cbInBufferSize, TRUE); - WLog_DBG(TAG, "pbInBuffer: %s", szInBuffer); - free(szInBuffer); - } - else + status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->hCard), &index); + if (status != SCARD_S_SUCCESS) + return status; + + if (Stream_GetRemainingLength(s) < 20) { - WLog_DBG(TAG, "pvInBuffer: null"); + WLog_WARN(TAG, "Control_Call is too short: %" PRIuz "", Stream_GetRemainingLength(s)); + return STATUS_BUFFER_TOO_SMALL; } - WLog_DBG(TAG, "}"); -} - -LONG smartcard_pack_control_return(SMARTCARD_DEVICE* smartcard, wStream* s, Control_Return* ret) -{ - LONG error; + Stream_Read_UINT32(s, call->dwControlCode); /* dwControlCode (4 bytes) */ + Stream_Read_UINT32(s, call->cbInBufferSize); /* cbInBufferSize (4 bytes) */ + if (!smartcard_ndr_pointer_read(s, &index, &pvInBufferNdrPtr)) /* pvInBufferNdrPtr (4 bytes) */ + return ERROR_INVALID_DATA; + Stream_Read_INT32(s, call->fpvOutBufferIsNULL); /* fpvOutBufferIsNULL (4 bytes) */ + Stream_Read_UINT32(s, call->cbOutBufferSize); /* cbOutBufferSize (4 bytes) */ - if (!Stream_EnsureRemainingCapacity(s, ret->cbOutBufferSize + 32)) - { - WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); - return SCARD_F_INTERNAL_ERROR; - } + if ((status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->hContext)))) + return status; - Stream_Write_UINT32(s, ret->cbOutBufferSize); /* cbOutBufferSize (4 bytes) */ - Stream_Write_UINT32(s, 0x00020040); /* pvOutBufferPointer (4 bytes) */ - Stream_Write_UINT32(s, ret->cbOutBufferSize); /* pvOutBufferLength (4 bytes) */ + if ((status = smartcard_unpack_redir_scard_handle_ref(smartcard, s, &(call->hCard)))) + return status; - if (ret->cbOutBufferSize > 0) + if (pvInBufferNdrPtr) { - Stream_Write(s, ret->pvOutBuffer, ret->cbOutBufferSize); /* pvOutBuffer */ - - if ((error = smartcard_pack_write_size_align(smartcard, s, ret->cbOutBufferSize, 4))) - { - WLog_ERR(TAG, "smartcard_pack_write_size_align failed with error %"PRId32"", error); - return error; - } + status = smartcard_ndr_read(s, &call->pvInBuffer, call->cbInBufferSize, 1, NDR_PTR_SIMPLE); + if (status != SCARD_S_SUCCESS) + return status; } + smartcard_trace_control_call(smartcard, call); return SCARD_S_SUCCESS; } -void smartcard_trace_control_return(SMARTCARD_DEVICE* smartcard, Control_Return* ret) +LONG smartcard_pack_control_return(SMARTCARD_DEVICE* smartcard, wStream* s, + const Control_Return* ret) { - if (!WLog_IsLevelActive(WLog_Get(TAG), WLOG_DEBUG)) - return; + DWORD index = 0; - WLog_DBG(TAG, "Control_Return {"); - WLog_DBG(TAG, "ReturnCode: %s (0x%08"PRIX32")", - SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); - WLog_DBG(TAG, "cbOutBufferSize: %"PRIu32"", ret->cbOutBufferSize); + smartcard_trace_control_return(smartcard, ret); + if (ret->ReturnCode != SCARD_S_SUCCESS) + return ret->ReturnCode; - if (ret->pvOutBuffer) - { - char* szOutBuffer = winpr_BinToHexString(ret->pvOutBuffer, ret->cbOutBufferSize, TRUE); - WLog_DBG(TAG, "pvOutBuffer: %s", szOutBuffer); - free(szOutBuffer); - } - else - { - WLog_DBG(TAG, "pvOutBuffer: null"); - } + if (!Stream_EnsureRemainingCapacity(s, 4)) + return SCARD_F_INTERNAL_ERROR; + + Stream_Write_UINT32(s, ret->cbOutBufferSize); /* cbOutBufferSize (4 bytes) */ + if (!smartcard_ndr_pointer_write(s, &index, ret->cbOutBufferSize)) + return SCARD_E_NO_MEMORY; - WLog_DBG(TAG, "}"); + return smartcard_ndr_write(s, ret->pvOutBuffer, ret->cbOutBufferSize, 1, NDR_PTR_SIMPLE); } LONG smartcard_unpack_transmit_call(SMARTCARD_DEVICE* smartcard, wStream* s, Transmit_Call* call) @@ -2244,75 +2808,77 @@ LONG smartcard_unpack_transmit_call(SMARTCARD_DEVICE* smartcard, wStream* s, Tra UINT32 pioRecvPciNdrPtr; SCardIO_Request ioSendPci; SCardIO_Request ioRecvPci; + UINT32 index = 0; call->pioSendPci = NULL; call->pioRecvPci = NULL; call->pbSendBuffer = NULL; - if ((status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext)))) - { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_context failed with error %"PRId32"", status); + status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext), &index); + if (status != SCARD_S_SUCCESS) return status; - } - if ((status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->hCard)))) - { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_handle failed with error %"PRId32"", status); + status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->hCard), &index); + if (status != SCARD_S_SUCCESS) return status; - } if (Stream_GetRemainingLength(s) < 32) { - WLog_WARN(TAG, "Transmit_Call is too short: Actual: %"PRIuz", Expected: 32", + WLog_WARN(TAG, "Transmit_Call is too short: Actual: %" PRIuz ", Expected: 32", Stream_GetRemainingLength(s)); return STATUS_BUFFER_TOO_SMALL; } - Stream_Read_UINT32(s, ioSendPci.dwProtocol); /* dwProtocol (4 bytes) */ - Stream_Read_UINT32(s, ioSendPci.cbExtraBytes); /* cbExtraBytes (4 bytes) */ - Stream_Read_UINT32(s, pbExtraBytesNdrPtr); /* pbExtraBytesNdrPtr (4 bytes) */ - Stream_Read_UINT32(s, call->cbSendLength); /* cbSendLength (4 bytes) */ - Stream_Read_UINT32(s, pbSendBufferNdrPtr); /* pbSendBufferNdrPtr (4 bytes) */ - Stream_Read_UINT32(s, pioRecvPciNdrPtr); /* pioRecvPciNdrPtr (4 bytes) */ - Stream_Read_UINT32(s, call->fpbRecvBufferIsNULL); /* fpbRecvBufferIsNULL (4 bytes) */ - Stream_Read_UINT32(s, call->cbRecvLength); /* cbRecvLength (4 bytes) */ + Stream_Read_UINT32(s, ioSendPci.dwProtocol); /* dwProtocol (4 bytes) */ + Stream_Read_UINT32(s, ioSendPci.cbExtraBytes); /* cbExtraBytes (4 bytes) */ + if (!smartcard_ndr_pointer_read(s, &index, + &pbExtraBytesNdrPtr)) /* pbExtraBytesNdrPtr (4 bytes) */ + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, call->cbSendLength); /* cbSendLength (4 bytes) */ + if (!smartcard_ndr_pointer_read(s, &index, + &pbSendBufferNdrPtr)) /* pbSendBufferNdrPtr (4 bytes) */ + return ERROR_INVALID_DATA; + + if (!smartcard_ndr_pointer_read(s, &index, &pioRecvPciNdrPtr)) /* pioRecvPciNdrPtr (4 bytes) */ + return ERROR_INVALID_DATA; + + Stream_Read_INT32(s, call->fpbRecvBufferIsNULL); /* fpbRecvBufferIsNULL (4 bytes) */ + Stream_Read_UINT32(s, call->cbRecvLength); /* cbRecvLength (4 bytes) */ if (ioSendPci.cbExtraBytes > 1024) { - WLog_WARN(TAG, "Transmit_Call ioSendPci.cbExtraBytes is out of bounds: %"PRIu32" (max: 1024)", + WLog_WARN(TAG, + "Transmit_Call ioSendPci.cbExtraBytes is out of bounds: %" PRIu32 " (max: 1024)", ioSendPci.cbExtraBytes); return STATUS_INVALID_PARAMETER; } if (call->cbSendLength > 66560) { - WLog_WARN(TAG, "Transmit_Call cbSendLength is out of bounds: %"PRIu32" (max: 66560)", + WLog_WARN(TAG, "Transmit_Call cbSendLength is out of bounds: %" PRIu32 " (max: 66560)", ioSendPci.cbExtraBytes); return STATUS_INVALID_PARAMETER; } if ((status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->hContext)))) - { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_context_ref failed with error %"PRId32"", status); return status; - } if ((status = smartcard_unpack_redir_scard_handle_ref(smartcard, s, &(call->hCard)))) - { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_handle_ref failed with error %"PRId32"", status); return status; - } if (ioSendPci.cbExtraBytes && !pbExtraBytesNdrPtr) { - WLog_WARN(TAG, "Transmit_Call ioSendPci.cbExtraBytes is non-zero but pbExtraBytesNdrPtr is null"); + WLog_WARN( + TAG, "Transmit_Call ioSendPci.cbExtraBytes is non-zero but pbExtraBytesNdrPtr is null"); return STATUS_INVALID_PARAMETER; } if (pbExtraBytesNdrPtr) { + // TODO: Use unified pointer reading if (Stream_GetRemainingLength(s) < 4) { - WLog_WARN(TAG, "Transmit_Call is too short: %"PRIuz" (ioSendPci.pbExtraBytes)", + WLog_WARN(TAG, "Transmit_Call is too short: %" PRIuz " (ioSendPci.pbExtraBytes)", Stream_GetRemainingLength(s)); return STATUS_BUFFER_TOO_SMALL; } @@ -2322,13 +2888,15 @@ LONG smartcard_unpack_transmit_call(SMARTCARD_DEVICE* smartcard, wStream* s, Tra if (Stream_GetRemainingLength(s) < ioSendPci.cbExtraBytes) { WLog_WARN(TAG, - "Transmit_Call is too short: Actual: %"PRIuz", Expected: %"PRIu32" (ioSendPci.cbExtraBytes)", + "Transmit_Call is too short: Actual: %" PRIuz ", Expected: %" PRIu32 + " (ioSendPci.cbExtraBytes)", Stream_GetRemainingLength(s), ioSendPci.cbExtraBytes); return STATUS_BUFFER_TOO_SMALL; } ioSendPci.pbExtraBytes = Stream_Pointer(s); - call->pioSendPci = (LPSCARD_IO_REQUEST) malloc(sizeof(SCARD_IO_REQUEST) + ioSendPci.cbExtraBytes); + call->pioSendPci = + (LPSCARD_IO_REQUEST)malloc(sizeof(SCARD_IO_REQUEST) + ioSendPci.cbExtraBytes); if (!call->pioSendPci) { @@ -2338,13 +2906,13 @@ LONG smartcard_unpack_transmit_call(SMARTCARD_DEVICE* smartcard, wStream* s, Tra call->pioSendPci->dwProtocol = ioSendPci.dwProtocol; call->pioSendPci->cbPciLength = (DWORD)(ioSendPci.cbExtraBytes + sizeof(SCARD_IO_REQUEST)); - pbExtraBytes = &((BYTE*) call->pioSendPci)[sizeof(SCARD_IO_REQUEST)]; + pbExtraBytes = &((BYTE*)call->pioSendPci)[sizeof(SCARD_IO_REQUEST)]; Stream_Read(s, pbExtraBytes, ioSendPci.cbExtraBytes); smartcard_unpack_read_size_align(smartcard, s, ioSendPci.cbExtraBytes, 4); } else { - call->pioSendPci = (LPSCARD_IO_REQUEST) calloc(1, sizeof(SCARD_IO_REQUEST)); + call->pioSendPci = (LPSCARD_IO_REQUEST)calloc(1, sizeof(SCARD_IO_REQUEST)); if (!call->pioSendPci) { @@ -2358,66 +2926,40 @@ LONG smartcard_unpack_transmit_call(SMARTCARD_DEVICE* smartcard, wStream* s, Tra if (pbSendBufferNdrPtr) { - if (Stream_GetRemainingLength(s) < 4) - { - WLog_WARN(TAG, "Transmit_Call is too short: %"PRIuz"", - Stream_GetRemainingLength(s)); - return STATUS_BUFFER_TOO_SMALL; - } - - Stream_Read_UINT32(s, length); /* Length (4 bytes) */ - - if (length != call->cbSendLength) - { - WLog_WARN(TAG, - "Transmit_Call unexpected length: Actual: %"PRIu32", Expected: %"PRIu32" (cbSendLength)", - length, call->cbSendLength); - return STATUS_INVALID_PARAMETER; - } - - if (Stream_GetRemainingLength(s) < call->cbSendLength) - { - WLog_WARN(TAG, "Transmit_Call is too short: Actual: %"PRIuz", Expected: %"PRIu32" (cbSendLength)", - Stream_GetRemainingLength(s), call->cbSendLength); - return STATUS_BUFFER_TOO_SMALL; - } - - call->pbSendBuffer = (BYTE*) malloc(call->cbSendLength); - - if (!call->pbSendBuffer) - { - WLog_WARN(TAG, "Transmit_Call out of memory error (pbSendBuffer)"); - return STATUS_NO_MEMORY; - } - - Stream_Read(s, call->pbSendBuffer, call->cbSendLength); - smartcard_unpack_read_size_align(smartcard, s, call->cbSendLength, 4); + status = smartcard_ndr_read(s, &call->pbSendBuffer, call->cbSendLength, 1, NDR_PTR_SIMPLE); + if (status != SCARD_S_SUCCESS) + return status; } if (pioRecvPciNdrPtr) { if (Stream_GetRemainingLength(s) < 12) { - WLog_WARN(TAG, "Transmit_Call is too short: Actual: %"PRIuz", Expected: 12", + WLog_WARN(TAG, "Transmit_Call is too short: Actual: %" PRIuz ", Expected: 12", Stream_GetRemainingLength(s)); return STATUS_BUFFER_TOO_SMALL; } - Stream_Read_UINT32(s, ioRecvPci.dwProtocol); /* dwProtocol (4 bytes) */ + Stream_Read_UINT32(s, ioRecvPci.dwProtocol); /* dwProtocol (4 bytes) */ Stream_Read_UINT32(s, ioRecvPci.cbExtraBytes); /* cbExtraBytes (4 bytes) */ - Stream_Read_UINT32(s, pbExtraBytesNdrPtr); /* pbExtraBytesNdrPtr (4 bytes) */ + if (!smartcard_ndr_pointer_read(s, &index, + &pbExtraBytesNdrPtr)) /* pbExtraBytesNdrPtr (4 bytes) */ + return ERROR_INVALID_DATA; if (ioRecvPci.cbExtraBytes && !pbExtraBytesNdrPtr) { - WLog_WARN(TAG, "Transmit_Call ioRecvPci.cbExtraBytes is non-zero but pbExtraBytesNdrPtr is null"); + WLog_WARN( + TAG, + "Transmit_Call ioRecvPci.cbExtraBytes is non-zero but pbExtraBytesNdrPtr is null"); return STATUS_INVALID_PARAMETER; } if (pbExtraBytesNdrPtr) { + // TODO: Unify ndr pointer reading if (Stream_GetRemainingLength(s) < 4) { - WLog_WARN(TAG, "Transmit_Call is too short: %"PRIuz" (ioRecvPci.pbExtraBytes)", + WLog_WARN(TAG, "Transmit_Call is too short: %" PRIuz " (ioRecvPci.pbExtraBytes)", Stream_GetRemainingLength(s)); return STATUS_BUFFER_TOO_SMALL; } @@ -2426,7 +2968,9 @@ LONG smartcard_unpack_transmit_call(SMARTCARD_DEVICE* smartcard, wStream* s, Tra if (ioRecvPci.cbExtraBytes > 1024) { - WLog_WARN(TAG, "Transmit_Call ioRecvPci.cbExtraBytes is out of bounds: %"PRIu32" (max: 1024)", + WLog_WARN(TAG, + "Transmit_Call ioRecvPci.cbExtraBytes is out of bounds: %" PRIu32 + " (max: 1024)", ioRecvPci.cbExtraBytes); return STATUS_INVALID_PARAMETER; } @@ -2434,7 +2978,8 @@ LONG smartcard_unpack_transmit_call(SMARTCARD_DEVICE* smartcard, wStream* s, Tra if (length != ioRecvPci.cbExtraBytes) { WLog_WARN(TAG, - "Transmit_Call unexpected length: Actual: %"PRIu32", Expected: %"PRIu32" (ioRecvPci.cbExtraBytes)", + "Transmit_Call unexpected length: Actual: %" PRIu32 ", Expected: %" PRIu32 + " (ioRecvPci.cbExtraBytes)", length, ioRecvPci.cbExtraBytes); return STATUS_INVALID_PARAMETER; } @@ -2442,13 +2987,15 @@ LONG smartcard_unpack_transmit_call(SMARTCARD_DEVICE* smartcard, wStream* s, Tra if (Stream_GetRemainingLength(s) < ioRecvPci.cbExtraBytes) { WLog_WARN(TAG, - "Transmit_Call is too short: Actual: %"PRIuz", Expected: %"PRIu32" (ioRecvPci.cbExtraBytes)", + "Transmit_Call is too short: Actual: %" PRIuz ", Expected: %" PRIu32 + " (ioRecvPci.cbExtraBytes)", Stream_GetRemainingLength(s), ioRecvPci.cbExtraBytes); return STATUS_BUFFER_TOO_SMALL; } ioRecvPci.pbExtraBytes = Stream_Pointer(s); - call->pioRecvPci = (LPSCARD_IO_REQUEST) malloc(sizeof(SCARD_IO_REQUEST) + ioRecvPci.cbExtraBytes); + call->pioRecvPci = + (LPSCARD_IO_REQUEST)malloc(sizeof(SCARD_IO_REQUEST) + ioRecvPci.cbExtraBytes); if (!call->pioRecvPci) { @@ -2457,14 +3004,15 @@ LONG smartcard_unpack_transmit_call(SMARTCARD_DEVICE* smartcard, wStream* s, Tra } call->pioRecvPci->dwProtocol = ioRecvPci.dwProtocol; - call->pioRecvPci->cbPciLength = (DWORD)(ioRecvPci.cbExtraBytes + sizeof(SCARD_IO_REQUEST)); - pbExtraBytes = &((BYTE*) call->pioRecvPci)[sizeof(SCARD_IO_REQUEST)]; + call->pioRecvPci->cbPciLength = + (DWORD)(ioRecvPci.cbExtraBytes + sizeof(SCARD_IO_REQUEST)); + pbExtraBytes = &((BYTE*)call->pioRecvPci)[sizeof(SCARD_IO_REQUEST)]; Stream_Read(s, pbExtraBytes, ioRecvPci.cbExtraBytes); smartcard_unpack_read_size_align(smartcard, s, ioRecvPci.cbExtraBytes, 4); } else { - call->pioRecvPci = (LPSCARD_IO_REQUEST) calloc(1, sizeof(SCARD_IO_REQUEST)); + call->pioRecvPci = (LPSCARD_IO_REQUEST)calloc(1, sizeof(SCARD_IO_REQUEST)); if (!call->pioRecvPci) { @@ -2477,446 +3025,724 @@ LONG smartcard_unpack_transmit_call(SMARTCARD_DEVICE* smartcard, wStream* s, Tra } } + smartcard_trace_transmit_call(smartcard, call); return SCARD_S_SUCCESS; } -void smartcard_trace_transmit_call(SMARTCARD_DEVICE* smartcard, Transmit_Call* call) +LONG smartcard_pack_transmit_return(SMARTCARD_DEVICE* smartcard, wStream* s, + const Transmit_Return* ret) { - BYTE* pb; - UINT32 cbExtraBytes; - BYTE* pbExtraBytes; + DWORD index = 0; + LONG error; + UINT32 cbRecvLength = ret->cbRecvLength; + UINT32 cbRecvPci = ret->pioRecvPci ? ret->pioRecvPci->cbPciLength : 0; - if (!WLog_IsLevelActive(WLog_Get(TAG), WLOG_DEBUG)) - return; + smartcard_trace_transmit_return(smartcard, ret); + if (ret->ReturnCode != SCARD_S_SUCCESS) + return ret->ReturnCode; - WLog_DBG(TAG, "Transmit_Call {"); - pb = (BYTE*) & (call->hContext.pbContext); + if (!ret->pbRecvBuffer) + cbRecvLength = 0; + + if (!smartcard_ndr_pointer_write(s, &index, cbRecvPci)) + return SCARD_E_NO_MEMORY; + if (!Stream_EnsureRemainingCapacity(s, 4)) + return SCARD_E_NO_MEMORY; + Stream_Write_UINT32(s, cbRecvLength); /* cbRecvLength (4 bytes) */ + if (!smartcard_ndr_pointer_write(s, &index, cbRecvLength)) + return SCARD_E_NO_MEMORY; - if (call->hContext.cbContext > 4) + if (ret->pioRecvPci) { - WLog_DBG(TAG, - "hContext: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], pb[4], pb[5], pb[6], pb[7], call->hContext.cbContext); + UINT32 cbExtraBytes = (UINT32)(ret->pioRecvPci->cbPciLength - sizeof(SCARD_IO_REQUEST)); + BYTE* pbExtraBytes = &((BYTE*)ret->pioRecvPci)[sizeof(SCARD_IO_REQUEST)]; + + if (!Stream_EnsureRemainingCapacity(s, cbExtraBytes + 16)) + { + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + return SCARD_F_INTERNAL_ERROR; + } + + Stream_Write_UINT32(s, ret->pioRecvPci->dwProtocol); /* dwProtocol (4 bytes) */ + Stream_Write_UINT32(s, cbExtraBytes); /* cbExtraBytes (4 bytes) */ + if (!smartcard_ndr_pointer_write(s, &index, cbExtraBytes)) + return SCARD_E_NO_MEMORY; + error = smartcard_ndr_write(s, pbExtraBytes, cbExtraBytes, 1, NDR_PTR_SIMPLE); + if (error) + return error; } - else + + return smartcard_ndr_write(s, ret->pbRecvBuffer, ret->cbRecvLength, 1, NDR_PTR_SIMPLE); +} + +LONG smartcard_unpack_locate_cards_by_atr_a_call(SMARTCARD_DEVICE* smartcard, wStream* s, + LocateCardsByATRA_Call* call) +{ + LONG status; + UINT32 rgReaderStatesNdrPtr; + UINT32 rgAtrMasksNdrPtr; + UINT32 index = 0; + call->rgReaderStates = NULL; + + status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext), &index); + if (status != SCARD_S_SUCCESS) + return status; + + if (Stream_GetRemainingLength(s) < 16) { - WLog_DBG(TAG, "hContext: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], call->hContext.cbContext); + WLog_WARN(TAG, "LocateCardsByATRA_Call is too short: %" PRIuz "", + Stream_GetRemainingLength(s)); + return STATUS_BUFFER_TOO_SMALL; } - pb = (BYTE*) & (call->hCard.pbHandle); + Stream_Read_UINT32(s, call->cAtrs); + if (!smartcard_ndr_pointer_read(s, &index, &rgAtrMasksNdrPtr)) + return ERROR_INVALID_DATA; + Stream_Read_UINT32(s, call->cReaders); /* cReaders (4 bytes) */ + if (!smartcard_ndr_pointer_read(s, &index, &rgReaderStatesNdrPtr)) + return ERROR_INVALID_DATA; + + if ((status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->hContext)))) + return status; - if (call->hCard.cbHandle > 4) + if ((rgAtrMasksNdrPtr && !call->cAtrs) || (!rgAtrMasksNdrPtr && call->cAtrs)) { - WLog_DBG(TAG, - "hCard: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], pb[4], pb[5], pb[6], pb[7], call->hCard.cbHandle); + WLog_WARN(TAG, + "LocateCardsByATRA_Call rgAtrMasksNdrPtr (0x%08" PRIX32 + ") and cAtrs (0x%08" PRIX32 ") inconsistency", + rgAtrMasksNdrPtr, call->cAtrs); + return STATUS_INVALID_PARAMETER; } - else + + if (rgAtrMasksNdrPtr) { - WLog_DBG(TAG, "hCard: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], call->hCard.cbHandle); + status = smartcard_ndr_read_atrmask(s, &call->rgAtrMasks, call->cAtrs, NDR_PTR_SIMPLE); + if (status != SCARD_S_SUCCESS) + return status; } - if (call->pioSendPci) + if (rgReaderStatesNdrPtr) { - cbExtraBytes = (UINT32)(call->pioSendPci->cbPciLength - sizeof(SCARD_IO_REQUEST)); - pbExtraBytes = &((BYTE*) call->pioSendPci)[sizeof(SCARD_IO_REQUEST)]; - WLog_DBG(TAG, "pioSendPci: dwProtocol: %"PRIu32" cbExtraBytes: %"PRIu32"", - call->pioSendPci->dwProtocol, cbExtraBytes); + status = smartcard_unpack_reader_state_a(s, &call->rgReaderStates, call->cReaders, &index); + if (status != SCARD_S_SUCCESS) + return status; + } - if (cbExtraBytes) - { - char* szExtraBytes = winpr_BinToHexString(pbExtraBytes, cbExtraBytes, TRUE); - WLog_DBG(TAG, "pbExtraBytes: %s", szExtraBytes); - free(szExtraBytes); - } + smartcard_trace_locate_cards_by_atr_a_call(smartcard, call); + return SCARD_S_SUCCESS; +} + +LONG smartcard_unpack_context_and_two_strings_a_call(SMARTCARD_DEVICE* smartcard, wStream* s, + ContextAndTwoStringA_Call* call) +{ + LONG status; + UINT32 sz1NdrPtr, sz2NdrPtr; + UINT32 index = 0; + + status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext), &index); + if (status != SCARD_S_SUCCESS) + return status; + + if (!smartcard_ndr_pointer_read(s, &index, &sz1NdrPtr)) + return ERROR_INVALID_DATA; + if (!smartcard_ndr_pointer_read(s, &index, &sz2NdrPtr)) + return ERROR_INVALID_DATA; + + status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &call->hContext); + if (status != SCARD_S_SUCCESS) + return status; + + if (sz1NdrPtr) + { + status = smartcard_ndr_read_a(s, &call->sz1, NDR_PTR_FULL); + if (status != SCARD_S_SUCCESS) + return status; } - else + if (sz2NdrPtr) + { + status = smartcard_ndr_read_a(s, &call->sz2, NDR_PTR_FULL); + if (status != SCARD_S_SUCCESS) + return status; + } + smartcard_trace_context_and_two_strings_a_call(smartcard, call); + return SCARD_S_SUCCESS; +} + +LONG smartcard_unpack_context_and_two_strings_w_call(SMARTCARD_DEVICE* smartcard, wStream* s, + ContextAndTwoStringW_Call* call) +{ + LONG status; + UINT32 sz1NdrPtr, sz2NdrPtr; + UINT32 index = 0; + status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext), &index); + if (status != SCARD_S_SUCCESS) + return status; + + if (!smartcard_ndr_pointer_read(s, &index, &sz1NdrPtr)) + return ERROR_INVALID_DATA; + if (!smartcard_ndr_pointer_read(s, &index, &sz2NdrPtr)) + return ERROR_INVALID_DATA; + + status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &call->hContext); + if (status != SCARD_S_SUCCESS) + return status; + + if (sz1NdrPtr) + { + status = smartcard_ndr_read_w(s, &call->sz1, NDR_PTR_FULL); + if (status != SCARD_S_SUCCESS) + return status; + } + if (sz2NdrPtr) + { + status = smartcard_ndr_read_w(s, &call->sz2, NDR_PTR_FULL); + if (status != SCARD_S_SUCCESS) + return status; + } + smartcard_trace_context_and_two_strings_w_call(smartcard, call); + return SCARD_S_SUCCESS; +} + +LONG smartcard_unpack_locate_cards_a_call(SMARTCARD_DEVICE* smartcard, wStream* s, + LocateCardsA_Call* call) +{ + LONG status; + UINT32 sz1NdrPtr, sz2NdrPtr; + UINT32 index = 0; + status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext), &index); + if (status != SCARD_S_SUCCESS) + return status; + + if (Stream_GetRemainingLength(s) < 16) { - WLog_DBG(TAG, "pioSendPci: null"); + WLog_WARN(TAG, "%s is too short: %" PRIuz "", __FUNCTION__, Stream_GetRemainingLength(s)); + return STATUS_BUFFER_TOO_SMALL; + } + Stream_Read_UINT32(s, call->cBytes); + if (!smartcard_ndr_pointer_read(s, &index, &sz1NdrPtr)) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, call->cReaders); + if (!smartcard_ndr_pointer_read(s, &index, &sz2NdrPtr)) + return ERROR_INVALID_DATA; + + if (sz1NdrPtr) + { + status = + smartcard_ndr_read_fixed_string_a(s, &call->mszCards, call->cBytes, NDR_PTR_SIMPLE); + if (status != SCARD_S_SUCCESS) + return status; + } + if (sz2NdrPtr) + { + status = smartcard_unpack_reader_state_a(s, &call->rgReaderStates, call->cReaders, &index); + if (status != SCARD_S_SUCCESS) + return status; + } + smartcard_trace_locate_cards_a_call(smartcard, call); + return SCARD_S_SUCCESS; +} + +LONG smartcard_unpack_locate_cards_w_call(SMARTCARD_DEVICE* smartcard, wStream* s, + LocateCardsW_Call* call) +{ + LONG status; + UINT32 sz1NdrPtr, sz2NdrPtr; + UINT32 index = 0; + + status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext), &index); + if (status != SCARD_S_SUCCESS) + return status; + + if (Stream_GetRemainingLength(s) < 16) + { + WLog_WARN(TAG, "%s is too short: %" PRIuz "", __FUNCTION__, Stream_GetRemainingLength(s)); + return STATUS_BUFFER_TOO_SMALL; + } + Stream_Read_UINT32(s, call->cBytes); + if (!smartcard_ndr_pointer_read(s, &index, &sz1NdrPtr)) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, call->cReaders); + if (!smartcard_ndr_pointer_read(s, &index, &sz2NdrPtr)) + return ERROR_INVALID_DATA; + + if (sz1NdrPtr) + { + status = + smartcard_ndr_read_fixed_string_w(s, &call->mszCards, call->cBytes, NDR_PTR_SIMPLE); + if (status != SCARD_S_SUCCESS) + return status; + } + if (sz2NdrPtr) + { + status = smartcard_unpack_reader_state_w(s, &call->rgReaderStates, call->cReaders, &index); + if (status != SCARD_S_SUCCESS) + return status; + } + smartcard_trace_locate_cards_w_call(smartcard, call); + return SCARD_S_SUCCESS; +} + +LONG smartcard_unpack_set_attrib_call(SMARTCARD_DEVICE* smartcard, wStream* s, SetAttrib_Call* call) +{ + LONG status; + UINT32 index = 0; + UINT32 ndrPtr; + + status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext), &index); + if (status != SCARD_S_SUCCESS) + return status; + status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->hCard), &index); + if (status != SCARD_S_SUCCESS) + return status; + + if (Stream_GetRemainingLength(s) < 12) + return STATUS_BUFFER_TOO_SMALL; + Stream_Read_UINT32(s, call->dwAttrId); + Stream_Read_UINT32(s, call->cbAttrLen); + + if ((status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->hContext)))) + return status; + + if ((status = smartcard_unpack_redir_scard_handle_ref(smartcard, s, &(call->hCard)))) + return status; + + if (!smartcard_ndr_pointer_read(s, &index, &ndrPtr)) + return ERROR_INVALID_DATA; + + if (ndrPtr) + { + // TODO: call->cbAttrLen was larger than the pointer value. + // TODO: Maybe need to refine the checks? + status = smartcard_ndr_read(s, &call->pbAttr, 0, 1, NDR_PTR_SIMPLE); + if (status != SCARD_S_SUCCESS) + return status; + } + smartcard_trace_set_attrib_call(smartcard, call); + return SCARD_S_SUCCESS; +} + +LONG smartcard_unpack_locate_cards_by_atr_w_call(SMARTCARD_DEVICE* smartcard, wStream* s, + LocateCardsByATRW_Call* call) +{ + LONG status; + UINT32 rgReaderStatesNdrPtr; + UINT32 rgAtrMasksNdrPtr; + UINT32 index = 0; + call->rgReaderStates = NULL; + + status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext), &index); + if (status != SCARD_S_SUCCESS) + return status; + + if (Stream_GetRemainingLength(s) < 16) + { + WLog_WARN(TAG, "LocateCardsByATRW_Call is too short: %" PRIuz "", + Stream_GetRemainingLength(s)); + return STATUS_BUFFER_TOO_SMALL; } - WLog_DBG(TAG, "cbSendLength: %"PRIu32"", call->cbSendLength); + Stream_Read_UINT32(s, call->cAtrs); + if (!smartcard_ndr_pointer_read(s, &index, &rgAtrMasksNdrPtr)) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, call->cReaders); /* cReaders (4 bytes) */ + if (!smartcard_ndr_pointer_read(s, &index, &rgReaderStatesNdrPtr)) + return ERROR_INVALID_DATA; - if (call->pbSendBuffer) - { - char* szSendBuffer = winpr_BinToHexString(call->pbSendBuffer, call->cbSendLength, TRUE); - WLog_DBG(TAG, "pbSendBuffer: %s", szSendBuffer); - free(szSendBuffer); - } - else + if ((status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->hContext)))) + return status; + + if ((rgAtrMasksNdrPtr && !call->cAtrs) || (!rgAtrMasksNdrPtr && call->cAtrs)) { - WLog_DBG(TAG, "pbSendBuffer: null"); + WLog_WARN(TAG, + "LocateCardsByATRW_Call rgAtrMasksNdrPtr (0x%08" PRIX32 + ") and cAtrs (0x%08" PRIX32 ") inconsistency", + rgAtrMasksNdrPtr, call->cAtrs); + return STATUS_INVALID_PARAMETER; } - if (call->pioRecvPci) + if (rgAtrMasksNdrPtr) { - cbExtraBytes = (UINT32)(call->pioRecvPci->cbPciLength - sizeof(SCARD_IO_REQUEST)); - pbExtraBytes = &((BYTE*) call->pioRecvPci)[sizeof(SCARD_IO_REQUEST)]; - WLog_DBG(TAG, "pioRecvPci: dwProtocol: %"PRIu32" cbExtraBytes: %"PRIu32"", - call->pioRecvPci->dwProtocol, cbExtraBytes); - - if (cbExtraBytes) - { - char* szExtraBytes = winpr_BinToHexString(pbExtraBytes, cbExtraBytes, TRUE); - WLog_DBG(TAG, "pbExtraBytes: %s", szExtraBytes); - free(szExtraBytes); - } + status = smartcard_ndr_read_atrmask(s, &call->rgAtrMasks, call->cAtrs, NDR_PTR_SIMPLE); + if (status != SCARD_S_SUCCESS) + return status; } - else + + if (rgReaderStatesNdrPtr) { - WLog_DBG(TAG, "pioRecvPci: null"); + status = smartcard_unpack_reader_state_w(s, &call->rgReaderStates, call->cReaders, &index); + if (status != SCARD_S_SUCCESS) + return status; } - WLog_DBG(TAG, "fpbRecvBufferIsNULL: %"PRId32" cbRecvLength: %"PRIu32"", - call->fpbRecvBufferIsNULL, call->cbRecvLength); - WLog_DBG(TAG, "}"); + smartcard_trace_locate_cards_by_atr_w_call(smartcard, call); + return SCARD_S_SUCCESS; } -LONG smartcard_pack_transmit_return(SMARTCARD_DEVICE* smartcard, wStream* s, Transmit_Return* ret) +LONG smartcard_unpack_read_cache_a_call(SMARTCARD_DEVICE* smartcard, wStream* s, + ReadCacheA_Call* call) { - UINT32 cbExtraBytes; - BYTE* pbExtraBytes; - UINT32 pioRecvPciNdrPtr; - UINT32 pbRecvBufferNdrPtr; - UINT32 pbExtraBytesNdrPtr; - LONG error; - - if (!ret->pbRecvBuffer) - ret->cbRecvLength = 0; - - pioRecvPciNdrPtr = (ret->pioRecvPci) ? 0x00020000 : 0; - pbRecvBufferNdrPtr = (ret->pbRecvBuffer) ? 0x00020004 : 0; - Stream_Write_UINT32(s, pioRecvPciNdrPtr); /* pioRecvPciNdrPtr (4 bytes) */ - Stream_Write_UINT32(s, ret->cbRecvLength); /* cbRecvLength (4 bytes) */ - Stream_Write_UINT32(s, pbRecvBufferNdrPtr); /* pbRecvBufferNdrPtr (4 bytes) */ - - if (pioRecvPciNdrPtr) - { - cbExtraBytes = (UINT32)(ret->pioRecvPci->cbPciLength - sizeof(SCARD_IO_REQUEST)); - pbExtraBytes = &((BYTE*) ret->pioRecvPci)[sizeof(SCARD_IO_REQUEST)]; - pbExtraBytesNdrPtr = cbExtraBytes ? 0x00020008 : 0; + LONG status; + UINT32 mszNdrPtr; + UINT32 contextNdrPtr; + UINT32 index = 0; - if (!Stream_EnsureRemainingCapacity(s, cbExtraBytes + 16)) - { - WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); - return SCARD_F_INTERNAL_ERROR; - } + if (!smartcard_ndr_pointer_read(s, &index, &mszNdrPtr)) + return ERROR_INVALID_DATA; - Stream_Write_UINT32(s, ret->pioRecvPci->dwProtocol); /* dwProtocol (4 bytes) */ - Stream_Write_UINT32(s, cbExtraBytes); /* cbExtraBytes (4 bytes) */ - Stream_Write_UINT32(s, pbExtraBytesNdrPtr); /* pbExtraBytesNdrPtr (4 bytes) */ + status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->Common.hContext), &index); + if (status != SCARD_S_SUCCESS) + return status; - if (pbExtraBytesNdrPtr) - { - Stream_Write_UINT32(s, cbExtraBytes); /* Length (4 bytes) */ - Stream_Write(s, pbExtraBytes, cbExtraBytes); + if (!smartcard_ndr_pointer_read(s, &index, &contextNdrPtr)) + return ERROR_INVALID_DATA; - if ((error = smartcard_pack_write_size_align(smartcard, s, cbExtraBytes, 4))) - { - WLog_ERR(TAG, "smartcard_pack_write_size_align failed with error %"PRId32"!", error); - return error; - } - } - } + if (Stream_GetRemainingLength(s) < 12) + return STATUS_BUFFER_TOO_SMALL; + Stream_Read_UINT32(s, call->Common.FreshnessCounter); + Stream_Read_INT32(s, call->Common.fPbDataIsNULL); + Stream_Read_UINT32(s, call->Common.cbDataLen); - if (pbRecvBufferNdrPtr) + call->szLookupName = NULL; + if (mszNdrPtr) { - if (!Stream_EnsureRemainingCapacity(s, ret->cbRecvLength + 16)) - { - WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); - return SCARD_F_INTERNAL_ERROR; - } + status = smartcard_ndr_read_a(s, &call->szLookupName, NDR_PTR_FULL); + if (status != SCARD_S_SUCCESS) + return status; + } - Stream_Write_UINT32(s, ret->cbRecvLength); /* pbRecvBufferNdrLen (4 bytes) */ - Stream_Write(s, ret->pbRecvBuffer, ret->cbRecvLength); + status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &call->Common.hContext); + if (status != SCARD_S_SUCCESS) + return status; - if ((error = smartcard_pack_write_size_align(smartcard, s, ret->cbRecvLength, 4))) - { - WLog_ERR(TAG, "smartcard_pack_write_size_align failed with error %"PRId32"!", error); - return error; - } + if (contextNdrPtr) + { + status = smartcard_ndr_read_u(s, &call->Common.CardIdentifier); + if (status != SCARD_S_SUCCESS) + return status; } - + smartcard_trace_read_cache_a_call(smartcard, call); return SCARD_S_SUCCESS; } -void smartcard_trace_transmit_return(SMARTCARD_DEVICE* smartcard, Transmit_Return* ret) +LONG smartcard_unpack_read_cache_w_call(SMARTCARD_DEVICE* smartcard, wStream* s, + ReadCacheW_Call* call) { - UINT32 cbExtraBytes; - BYTE* pbExtraBytes; + LONG status; + UINT32 mszNdrPtr; + UINT32 contextNdrPtr; + UINT32 index = 0; - if (!WLog_IsLevelActive(WLog_Get(TAG), WLOG_DEBUG)) - return; + if (!smartcard_ndr_pointer_read(s, &index, &mszNdrPtr)) + return ERROR_INVALID_DATA; - WLog_DBG(TAG, "Transmit_Return {"); - WLog_DBG(TAG, "ReturnCode: %s (0x%08"PRIX32")", - SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); + status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->Common.hContext), &index); + if (status != SCARD_S_SUCCESS) + return status; - if (ret->pioRecvPci) - { - cbExtraBytes = (UINT32)(ret->pioRecvPci->cbPciLength - sizeof(SCARD_IO_REQUEST)); - pbExtraBytes = &((BYTE*) ret->pioRecvPci)[sizeof(SCARD_IO_REQUEST)]; - WLog_DBG(TAG, "pioRecvPci: dwProtocol: %"PRIu32" cbExtraBytes: %"PRIu32"", - ret->pioRecvPci->dwProtocol, cbExtraBytes); + if (!smartcard_ndr_pointer_read(s, &index, &contextNdrPtr)) + return ERROR_INVALID_DATA; - if (cbExtraBytes) - { - char* szExtraBytes = winpr_BinToHexString(pbExtraBytes, cbExtraBytes, TRUE); - WLog_DBG(TAG, "pbExtraBytes: %s", szExtraBytes); - free(szExtraBytes); - } - } - else + if (Stream_GetRemainingLength(s) < 12) + return STATUS_BUFFER_TOO_SMALL; + Stream_Read_UINT32(s, call->Common.FreshnessCounter); + Stream_Read_INT32(s, call->Common.fPbDataIsNULL); + Stream_Read_UINT32(s, call->Common.cbDataLen); + + call->szLookupName = NULL; + if (mszNdrPtr) { - WLog_DBG(TAG, "pioRecvPci: null"); + status = smartcard_ndr_read_w(s, &call->szLookupName, NDR_PTR_FULL); + if (status != SCARD_S_SUCCESS) + return status; } - WLog_DBG(TAG, "cbRecvLength: %"PRIu32"", ret->cbRecvLength); + status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &call->Common.hContext); + if (status != SCARD_S_SUCCESS) + return status; - if (ret->pbRecvBuffer) - { - char* szRecvBuffer = winpr_BinToHexString(ret->pbRecvBuffer, ret->cbRecvLength, TRUE); - WLog_DBG(TAG, "pbRecvBuffer: %s", szRecvBuffer); - free(szRecvBuffer); - } - else + if (contextNdrPtr) { - WLog_DBG(TAG, "pbRecvBuffer: null"); + status = smartcard_ndr_read_u(s, &call->Common.CardIdentifier); + if (status != SCARD_S_SUCCESS) + return status; } - - WLog_DBG(TAG, "}"); + smartcard_trace_read_cache_w_call(smartcard, call); + return SCARD_S_SUCCESS; } -LONG smartcard_unpack_locate_cards_by_atr_a_call(SMARTCARD_DEVICE* smartcard, wStream* s, - LocateCardsByATRA_Call* call) +LONG smartcard_unpack_write_cache_a_call(SMARTCARD_DEVICE* smartcard, wStream* s, + WriteCacheA_Call* call) { - UINT32 index; - UINT32 count; LONG status; - UINT32 offset; - UINT32 maxCount; - UINT32 szReaderNdrPtr; - UINT32 rgReaderStatesNdrPtr; - UINT32 rgAtrMasksNdrPtr; - LPSCARD_READERSTATEA readerState; - call->rgReaderStates = NULL; + UINT32 mszNdrPtr; + UINT32 contextNdrPtr; + UINT32 pbDataNdrPtr; + UINT32 index = 0; - if ((status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext)))) - { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_context failed with error %"PRId32"", status); + if (!smartcard_ndr_pointer_read(s, &index, &mszNdrPtr)) + return ERROR_INVALID_DATA; + + status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->Common.hContext), &index); + if (status != SCARD_S_SUCCESS) return status; - } - if (Stream_GetRemainingLength(s) < 16) - { - WLog_WARN(TAG, "LocateCardsByATRA_Call is too short: %"PRIuz"", - Stream_GetRemainingLength(s)); + if (!smartcard_ndr_pointer_read(s, &index, &contextNdrPtr)) + return ERROR_INVALID_DATA; + + if (Stream_GetRemainingLength(s) < 8) return STATUS_BUFFER_TOO_SMALL; - } - Stream_Read_UINT32(s, call->cAtrs); - Stream_Read_UINT32(s, rgAtrMasksNdrPtr); - Stream_Read_UINT32(s, call->cReaders); /* cReaders (4 bytes) */ - Stream_Read_UINT32(s, rgReaderStatesNdrPtr); /* rgReaderStatesNdrPtr (4 bytes) */ + Stream_Read_UINT32(s, call->Common.FreshnessCounter); + Stream_Read_UINT32(s, call->Common.cbDataLen); - if ((status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->hContext)))) + if (!smartcard_ndr_pointer_read(s, &index, &pbDataNdrPtr)) + return ERROR_INVALID_DATA; + + call->szLookupName = NULL; + if (mszNdrPtr) { - WLog_ERR(TAG, "smartcard_unpack_redir_scard_context_ref failed with error %"PRId32"", status); - return status; + status = smartcard_ndr_read_a(s, &call->szLookupName, NDR_PTR_FULL); + if (status != SCARD_S_SUCCESS) + return status; } - if (Stream_GetRemainingLength(s) < 4) + status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &call->Common.hContext); + if (status != SCARD_S_SUCCESS) + return status; + + call->Common.CardIdentifier = NULL; + if (contextNdrPtr) { - WLog_WARN(TAG, "LocateCardsByATRA_Call is too short: %"PRIuz"", - Stream_GetRemainingLength(s)); - return STATUS_BUFFER_TOO_SMALL; + status = smartcard_ndr_read_u(s, &call->Common.CardIdentifier); + if (status != SCARD_S_SUCCESS) + return status; } - if ((rgAtrMasksNdrPtr && !call->cAtrs) || (!rgAtrMasksNdrPtr && call->cAtrs)) + call->Common.pbData = NULL; + if (pbDataNdrPtr) { - WLog_WARN(TAG, - "LocateCardsByATRA_Call rgAtrMasksNdrPtr (0x%08"PRIX32") and cAtrs (0x%08"PRIX32") inconsistency", - rgAtrMasksNdrPtr, call->cAtrs); - return STATUS_INVALID_PARAMETER; + status = + smartcard_ndr_read(s, &call->Common.pbData, call->Common.cbDataLen, 1, NDR_PTR_SIMPLE); + if (status != SCARD_S_SUCCESS) + return status; } + smartcard_trace_write_cache_a_call(smartcard, call); + return SCARD_S_SUCCESS; +} - if (rgAtrMasksNdrPtr) - { - Stream_Read_UINT32(s, count); +LONG smartcard_unpack_write_cache_w_call(SMARTCARD_DEVICE* smartcard, wStream* s, + WriteCacheW_Call* call) +{ + LONG status; + UINT32 mszNdrPtr; + UINT32 contextNdrPtr; + UINT32 pbDataNdrPtr; + UINT32 index = 0; - if (count != call->cAtrs) - { - WLog_WARN(TAG, - "LocateCardsByATRA_Call NdrCount (0x%08"PRIX32") and cAtrs (0x%08"PRIX32") inconsistency", - count, call->cAtrs); - return STATUS_INVALID_PARAMETER; - } + if (!smartcard_ndr_pointer_read(s, &index, &mszNdrPtr)) + return ERROR_INVALID_DATA; - if (Stream_GetRemainingLength(s) < call->cAtrs) - { - WLog_WARN(TAG, "LocateCardsByATRA_Call is too short: Actual: %"PRIuz", Expected: %"PRIu32"", - Stream_GetRemainingLength(s), call->cAtrs); - return STATUS_BUFFER_TOO_SMALL; - } + status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->Common.hContext), &index); + if (status != SCARD_S_SUCCESS) + return status; - call->rgAtrMasks = (LocateCards_ATRMask*)calloc(call->cAtrs, sizeof(LocateCards_ATRMask)); + if (!smartcard_ndr_pointer_read(s, &index, &contextNdrPtr)) + return ERROR_INVALID_DATA; - if (!call->rgAtrMasks) - { - WLog_WARN(TAG, "LocateCardsByATRA_Call out of memory error (call->rgAtrMasks)"); - return STATUS_NO_MEMORY; - } + if (Stream_GetRemainingLength(s) < 8) + return STATUS_BUFFER_TOO_SMALL; + Stream_Read_UINT32(s, call->Common.FreshnessCounter); + Stream_Read_UINT32(s, call->Common.cbDataLen); - for (index = 0; index < call->cAtrs; index++) - { - Stream_Read_UINT32(s, call->rgAtrMasks[index].cbAtr); - Stream_Read(s, call->rgAtrMasks[index].rgbAtr, 36); - Stream_Read(s, call->rgAtrMasks[index].rgbMask, 36); - } + if (!smartcard_ndr_pointer_read(s, &index, &pbDataNdrPtr)) + return ERROR_INVALID_DATA; + + call->szLookupName = NULL; + if (mszNdrPtr) + { + status = smartcard_ndr_read_w(s, &call->szLookupName, NDR_PTR_FULL); + if (status != SCARD_S_SUCCESS) + return status; } - Stream_Read_UINT32(s, count); + status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &call->Common.hContext); + if (status != SCARD_S_SUCCESS) + return status; - if (count != call->cReaders) + call->Common.CardIdentifier = NULL; + if (contextNdrPtr) { - WLog_WARN(TAG, - "GetStatusChangeA_Call unexpected reader count: Actual: %"PRIu32", Expected: %"PRIu32"", - count, call->cReaders); - return STATUS_INVALID_PARAMETER; + status = smartcard_ndr_read_u(s, &call->Common.CardIdentifier); + if (status != SCARD_S_SUCCESS) + return status; } - if (call->cReaders > 0) + call->Common.pbData = NULL; + if (pbDataNdrPtr) { - call->rgReaderStates = (ReaderStateA*)calloc(call->cReaders, sizeof(ReaderStateA)); + status = + smartcard_ndr_read(s, &call->Common.pbData, call->Common.cbDataLen, 1, NDR_PTR_SIMPLE); + if (status != SCARD_S_SUCCESS) + return status; + } + smartcard_trace_write_cache_w_call(smartcard, call); + return status; +} - if (!call->rgReaderStates) - { - WLog_WARN(TAG, "LocateCardsByATRA_Call out of memory error (call->rgReaderStates)"); - return STATUS_NO_MEMORY; - } +LONG smartcard_unpack_get_transmit_count_call(SMARTCARD_DEVICE* smartcard, wStream* s, + GetTransmitCount_Call* call) +{ + LONG status; + UINT32 index = 0; - for (index = 0; index < call->cReaders; index++) - { - readerState = (LPSCARD_READERSTATEA) &call->rgReaderStates[index]; + status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext), &index); + if (status != SCARD_S_SUCCESS) + return status; - if (Stream_GetRemainingLength(s) < 52) - { - WLog_WARN(TAG, "LocateCardsByATRA_Call is too short: %"PRIuz"", - Stream_GetRemainingLength(s)); - return STATUS_BUFFER_TOO_SMALL; - } + status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->hCard), &index); + if (status != SCARD_S_SUCCESS) + return status; - Stream_Read_UINT32(s, szReaderNdrPtr); /* szReaderNdrPtr (4 bytes) */ - Stream_Read_UINT32(s, readerState->dwCurrentState); /* dwCurrentState (4 bytes) */ - Stream_Read_UINT32(s, readerState->dwEventState); /* dwEventState (4 bytes) */ - Stream_Read_UINT32(s, readerState->cbAtr); /* cbAtr (4 bytes) */ - Stream_Read(s, readerState->rgbAtr, 32); /* rgbAtr [0..32] (32 bytes) */ - Stream_Seek(s, 4); /* rgbAtr [32..36] (4 bytes) */ - } + if ((status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->hContext)))) + { + WLog_ERR(TAG, "smartcard_unpack_redir_scard_context_ref failed with error %" PRId32 "", + status); + return status; + } - for (index = 0; index < call->cReaders; index++) - { - readerState = (LPSCARD_READERSTATEA) &call->rgReaderStates[index]; + if ((status = smartcard_unpack_redir_scard_handle_ref(smartcard, s, &(call->hCard)))) + WLog_ERR(TAG, "smartcard_unpack_redir_scard_handle_ref failed with error %" PRId32 "", + status); - if (Stream_GetRemainingLength(s) < 12) - { - WLog_WARN(TAG, "GetStatusChangeA_Call is too short: %"PRIuz"", - Stream_GetRemainingLength(s)); - return STATUS_BUFFER_TOO_SMALL; - } + smartcard_trace_get_transmit_count_call(smartcard, call); + return status; +} - Stream_Read_UINT32(s, maxCount); /* NdrMaxCount (4 bytes) */ - Stream_Read_UINT32(s, offset); /* NdrOffset (4 bytes) */ - Stream_Read_UINT32(s, count); /* NdrActualCount (4 bytes) */ +LONG smartcard_unpack_get_reader_icon_call(SMARTCARD_DEVICE* smartcard, wStream* s, + GetReaderIcon_Call* call) +{ + return smartcard_unpack_common_context_and_string_w(smartcard, s, &call->hContext, + &call->szReaderName); +} - if (Stream_GetRemainingLength(s) < count) - { - WLog_WARN(TAG, "GetStatusChangeA_Call is too short: %"PRIuz"", - Stream_GetRemainingLength(s)); - return STATUS_BUFFER_TOO_SMALL; - } +LONG smartcard_unpack_context_and_string_a_call(SMARTCARD_DEVICE* smartcard, wStream* s, + ContextAndStringA_Call* call) +{ + return smartcard_unpack_common_context_and_string_a(smartcard, s, &call->hContext, &call->sz); +} - readerState->szReader = (LPCSTR) malloc(count + 1); +LONG smartcard_unpack_context_and_string_w_call(SMARTCARD_DEVICE* smartcard, wStream* s, + ContextAndStringW_Call* call) +{ + return smartcard_unpack_common_context_and_string_w(smartcard, s, &call->hContext, &call->sz); +} - if (!readerState->szReader) - { - WLog_WARN(TAG, "GetStatusChangeA_Call out of memory error (readerState->szReader)"); - return STATUS_NO_MEMORY; - } +LONG smartcard_unpack_get_device_type_id_call(SMARTCARD_DEVICE* smartcard, wStream* s, + GetDeviceTypeId_Call* call) +{ + return smartcard_unpack_common_context_and_string_w(smartcard, s, &call->hContext, + &call->szReaderName); +} - Stream_Read(s, (void*) readerState->szReader, count); - smartcard_unpack_read_size_align(smartcard, s, count, 4); - ((char*) readerState->szReader)[count] = '\0'; +LONG smartcard_pack_device_type_id_return(SMARTCARD_DEVICE* smartcard, wStream* s, + const GetDeviceTypeId_Return* ret) +{ + smartcard_trace_device_type_id_return(smartcard, ret); + if (ret->ReturnCode != SCARD_S_SUCCESS) + return ret->ReturnCode; - if (!readerState->szReader) - { - WLog_WARN(TAG, "GetStatusChangeA_Call null reader name"); - return STATUS_INVALID_PARAMETER; - } - } + if (!Stream_EnsureRemainingCapacity(s, 4)) + { + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + return SCARD_F_INTERNAL_ERROR; } + Stream_Write_UINT32(s, ret->dwDeviceId); /* cBytes (4 bytes) */ + return SCARD_S_SUCCESS; } -void smartcard_trace_locate_cards_by_atr_a_call(SMARTCARD_DEVICE* smartcard, - LocateCardsByATRA_Call* call) +LONG smartcard_pack_locate_cards_return(SMARTCARD_DEVICE* smartcard, wStream* s, + const LocateCards_Return* ret) { - BYTE* pb; - UINT32 index; - char* szEventState; - char* szCurrentState; - char* rgbAtr; - LPSCARD_READERSTATEA readerState; + DWORD index = 0; + smartcard_trace_locate_cards_return(smartcard, ret); + if (ret->ReturnCode != SCARD_S_SUCCESS) + return ret->ReturnCode; - if (!WLog_IsLevelActive(WLog_Get(TAG), WLOG_DEBUG)) - return; + if (!Stream_EnsureRemainingCapacity(s, 4)) + { + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + return SCARD_F_INTERNAL_ERROR; + } + + Stream_Write_UINT32(s, ret->cReaders); /* cBytes (4 cbDataLen) */ + if (!smartcard_ndr_pointer_write(s, &index, ret->cReaders)) + return SCARD_E_NO_MEMORY; - WLog_DBG(TAG, "LocateCardsByATRA_Call {"); - pb = (BYTE*) & (call->hContext.pbContext); + return smartcard_ndr_write_state(s, ret->rgReaderStates, ret->cReaders, NDR_PTR_SIMPLE); +} + +LONG smartcard_pack_get_reader_icon_return(SMARTCARD_DEVICE* smartcard, wStream* s, + const GetReaderIcon_Return* ret) +{ + DWORD index = 0; + smartcard_trace_get_reader_icon_return(smartcard, ret); + if (ret->ReturnCode != SCARD_S_SUCCESS) + return ret->ReturnCode; - if (call->hContext.cbContext > 4) + if (!Stream_EnsureRemainingCapacity(s, 4)) { - WLog_DBG(TAG, - "hContext: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], pb[4], pb[5], pb[6], pb[7], call->hContext.cbContext); + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + return SCARD_F_INTERNAL_ERROR; } - else + + Stream_Write_UINT32(s, ret->cbDataLen); /* cBytes (4 cbDataLen) */ + if (!smartcard_ndr_pointer_write(s, &index, ret->cbDataLen)) + return SCARD_E_NO_MEMORY; + + return smartcard_ndr_write(s, ret->pbData, ret->cbDataLen, 1, NDR_PTR_SIMPLE); +} + +LONG smartcard_pack_get_transmit_count_return(SMARTCARD_DEVICE* smartcard, wStream* s, + const GetTransmitCount_Return* ret) +{ + smartcard_trace_get_transmit_count_return(smartcard, ret); + if (ret->ReturnCode != SCARD_S_SUCCESS) + return ret->ReturnCode; + + if (!Stream_EnsureRemainingCapacity(s, 4)) { - WLog_DBG(TAG, "hContext: 0x%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8" (%"PRIu32")", - pb[0], pb[1], pb[2], pb[3], call->hContext.cbContext); + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + return SCARD_F_INTERNAL_ERROR; } - for (index = 0; index < call->cReaders; index++) - { - readerState = (LPSCARD_READERSTATEA) &call->rgReaderStates[index]; - WLog_DBG(TAG, "\t[%"PRIu32"]: szReader: %s cbAtr: %"PRIu32"", - index, readerState->szReader, readerState->cbAtr); - szCurrentState = SCardGetReaderStateString(readerState->dwCurrentState); - szEventState = SCardGetReaderStateString(readerState->dwEventState); - rgbAtr = winpr_BinToHexString((BYTE*) & (readerState->rgbAtr), readerState->cbAtr, FALSE); - WLog_DBG(TAG, "\t[%"PRIu32"]: dwCurrentState: %s (0x%08"PRIX32")", - index, szCurrentState, readerState->dwCurrentState); - WLog_DBG(TAG, "\t[%"PRIu32"]: dwEventState: %s (0x%08"PRIX32")", - index, szEventState, readerState->dwEventState); + Stream_Write_UINT32(s, ret->cTransmitCount); /* cBytes (4 cbDataLen) */ - if (rgbAtr) - { - WLog_DBG(TAG, "\t[%"PRIu32"]: cbAtr: %"PRIu32" rgbAtr: %s", - index, readerState->cbAtr, rgbAtr); - } - else - { - WLog_DBG(TAG, "\t[%"PRIu32"]: cbAtr: 0 rgbAtr: n/a", - index); - } + return SCARD_S_SUCCESS; +} - free(szCurrentState); - free(szEventState); - free(rgbAtr); +LONG smartcard_pack_read_cache_return(SMARTCARD_DEVICE* smartcard, wStream* s, + const ReadCache_Return* ret) +{ + DWORD index = 0; + + smartcard_trace_read_cache_return(smartcard, ret); + if (ret->ReturnCode != SCARD_S_SUCCESS) + return ret->ReturnCode; + + if (!Stream_EnsureRemainingCapacity(s, 4)) + { + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + return SCARD_F_INTERNAL_ERROR; } - WLog_DBG(TAG, "}"); + Stream_Write_UINT32(s, ret->cbDataLen); /* cBytes (4 cbDataLen) */ + if (!smartcard_ndr_pointer_write(s, &index, ret->cbDataLen)) + return SCARD_E_NO_MEMORY; + + return smartcard_ndr_write(s, ret->pbData, ret->cbDataLen, 1, NDR_PTR_SIMPLE); } diff --git a/channels/smartcard/client/smartcard_pack.h b/channels/smartcard/client/smartcard_pack.h index f7bc083..85cb91e 100644 --- a/channels/smartcard/client/smartcard_pack.h +++ b/channels/smartcard/client/smartcard_pack.h @@ -5,6 +5,8 @@ * Copyright 2014 Marc-Andre Moreau * Copyright 2015 Thincast Technologies GmbH * Copyright 2015 DI (FH) Martin Haimberger + * Copyright 2020 Armin Novak + * Copyright 2020 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. @@ -26,6 +28,8 @@ #include #include +#pragma pack(push, 1) + /* interface type_scard_pack */ /* [unique][version][uuid] */ @@ -68,7 +72,7 @@ typedef struct _Context_Call typedef struct _ContextAndStringA_Call { REDIR_SCARDCONTEXT hContext; - /* [string] */ unsigned char* sz; + /* [string] */ char* sz; } ContextAndStringA_Call; typedef struct _ContextAndStringW_Call @@ -80,8 +84,8 @@ typedef struct _ContextAndStringW_Call typedef struct _ContextAndTwoStringA_Call { REDIR_SCARDCONTEXT hContext; - /* [string] */ unsigned char* sz1; - /* [string] */ unsigned char* sz2; + /* [string] */ char* sz1; + /* [string] */ char* sz2; } ContextAndTwoStringA_Call; typedef struct _ContextAndTwoStringW_Call @@ -118,26 +122,6 @@ typedef struct _ListReaders_Call DWORD cchReaders; } ListReaders_Call; -typedef struct _ReaderState_Common_Call -{ - DWORD dwCurrentState; - DWORD dwEventState; - /* [range] */ DWORD cbAtr; - BYTE rgbAtr[36]; -} ReaderState_Common_Call; - -typedef struct _ReaderStateA -{ - /* [string] */ unsigned char* szReader; - ReaderState_Common_Call Common; -} ReaderStateA; - -typedef struct _ReaderStateW -{ - /* [string] */ WCHAR* szReader; - ReaderState_Common_Call Common; -} ReaderStateW; - typedef struct _ReaderState_Return { DWORD dwCurrentState; @@ -158,25 +142,25 @@ typedef struct _LocateCardsA_Call { REDIR_SCARDCONTEXT hContext; /* [range] */ DWORD cBytes; - /* [size_is] */ BYTE* mszCards; + /* [size_is] */ CHAR* mszCards; /* [range] */ DWORD cReaders; - /* [size_is] */ ReaderStateA* rgReaderStates; + /* [size_is] */ LPSCARD_READERSTATEA rgReaderStates; } LocateCardsA_Call; typedef struct _LocateCardsW_Call { REDIR_SCARDCONTEXT hContext; /* [range] */ DWORD cBytes; - /* [size_is] */ BYTE* mszCards; + /* [size_is] */ WCHAR* mszCards; /* [range] */ DWORD cReaders; - /* [size_is] */ ReaderStateW* rgReaderStates; + /* [size_is] */ LPSCARD_READERSTATEW rgReaderStates; } LocateCardsW_Call; typedef struct _LocateCards_ATRMask { /* [range] */ DWORD cbAtr; - BYTE rgbAtr[ 36 ]; - BYTE rgbMask[ 36 ]; + BYTE rgbAtr[36]; + BYTE rgbMask[36]; } LocateCards_ATRMask; typedef struct _LocateCardsByATRA_Call @@ -185,7 +169,7 @@ typedef struct _LocateCardsByATRA_Call /* [range] */ DWORD cAtrs; /* [size_is] */ LocateCards_ATRMask* rgAtrMasks; /* [range] */ DWORD cReaders; - /* [size_is] */ ReaderStateA* rgReaderStates; + /* [size_is] */ LPSCARD_READERSTATEA rgReaderStates; } LocateCardsByATRA_Call; typedef struct _LocateCardsByATRW_Call @@ -194,7 +178,7 @@ typedef struct _LocateCardsByATRW_Call /* [range] */ DWORD cAtrs; /* [size_is] */ LocateCards_ATRMask* rgAtrMasks; /* [range] */ DWORD cReaders; - /* [size_is] */ ReaderStateW* rgReaderStates; + /* [size_is] */ LPSCARD_READERSTATEW rgReaderStates; } LocateCardsByATRW_Call; typedef struct _GetStatusChange_Return @@ -214,6 +198,31 @@ typedef struct _GetStatusChangeW_Call /* [size_is] */ LPSCARD_READERSTATEW rgReaderStates; } GetStatusChangeW_Call; +typedef struct _GetReaderIcon_Call +{ + REDIR_SCARDCONTEXT hContext; + WCHAR* szReaderName; +} GetReaderIcon_Call; + +typedef struct _GetReaderIcon_Return +{ + LONG ReturnCode; + ULONG cbDataLen; + BYTE* pbData; +} GetReaderIcon_Return; + +typedef struct _GetDeviceTypeId_Call +{ + REDIR_SCARDCONTEXT hContext; + WCHAR* szReaderName; +} GetDeviceTypeId_Call; + +typedef struct _GetDeviceTypeId_Return +{ + LONG ReturnCode; + ULONG dwDeviceId; +} GetDeviceTypeId_Return; + typedef struct _Connect_Common { REDIR_SCARDCONTEXT hContext; @@ -223,7 +232,7 @@ typedef struct _Connect_Common typedef struct _ConnectA_Call { - /* [string] */ unsigned char* szReader; + /* [string] */ CHAR* szReader; Connect_Common Common; } ConnectA_Call; @@ -393,7 +402,7 @@ typedef struct _ReadCache_Common typedef struct _ReadCacheA_Call { - /* [string] */ unsigned char* szLookupName; + /* [string] */ char* szLookupName; ReadCache_Common Common; } ReadCacheA_Call; @@ -421,7 +430,7 @@ typedef struct _WriteCache_Common typedef struct _WriteCacheA_Call { - /* [string] */ unsigned char* szLookupName; + /* [string] */ char* szLookupName; WriteCache_Common Common; } WriteCacheA_Call; @@ -431,25 +440,27 @@ typedef struct _WriteCacheW_Call WriteCache_Common Common; } WriteCacheW_Call; -#define SMARTCARD_COMMON_TYPE_HEADER_LENGTH 8 -#define SMARTCARD_PRIVATE_TYPE_HEADER_LENGTH 8 +#pragma pack(pop) + +#define SMARTCARD_COMMON_TYPE_HEADER_LENGTH 8 +#define SMARTCARD_PRIVATE_TYPE_HEADER_LENGTH 8 #include "smartcard_main.h" -LONG smartcard_pack_write_size_align(SMARTCARD_DEVICE* smartcard, wStream* s, UINT32 size, +LONG smartcard_pack_write_size_align(SMARTCARD_DEVICE* smartcard, wStream* s, size_t size, UINT32 alignment); -LONG smartcard_unpack_read_size_align(SMARTCARD_DEVICE* smartcard, wStream* s, UINT32 size, +LONG smartcard_unpack_read_size_align(SMARTCARD_DEVICE* smartcard, wStream* s, size_t size, UINT32 alignment); SCARDCONTEXT smartcard_scard_context_native_from_redir(SMARTCARD_DEVICE* smartcard, - REDIR_SCARDCONTEXT* context); + REDIR_SCARDCONTEXT* context); void smartcard_scard_context_native_to_redir(SMARTCARD_DEVICE* smartcard, - REDIR_SCARDCONTEXT* context, SCARDCONTEXT hContext); + REDIR_SCARDCONTEXT* context, SCARDCONTEXT hContext); SCARDHANDLE smartcard_scard_handle_native_from_redir(SMARTCARD_DEVICE* smartcard, - REDIR_SCARDHANDLE* handle); + REDIR_SCARDHANDLE* handle); void smartcard_scard_handle_native_to_redir(SMARTCARD_DEVICE* smartcard, REDIR_SCARDHANDLE* handle, - SCARDHANDLE hCard); + SCARDHANDLE hCard); LONG smartcard_unpack_common_type_header(SMARTCARD_DEVICE* smartcard, wStream* s); void smartcard_pack_common_type_header(SMARTCARD_DEVICE* smartcard, wStream* s); @@ -458,132 +469,141 @@ LONG smartcard_unpack_private_type_header(SMARTCARD_DEVICE* smartcard, wStream* void smartcard_pack_private_type_header(SMARTCARD_DEVICE* smartcard, wStream* s, UINT32 objectBufferLength); -LONG smartcard_unpack_redir_scard_context(SMARTCARD_DEVICE* smartcard, wStream* s, - REDIR_SCARDCONTEXT* context); -LONG smartcard_pack_redir_scard_context(SMARTCARD_DEVICE* smartcard, wStream* s, - REDIR_SCARDCONTEXT* context); - -LONG smartcard_unpack_redir_scard_context_ref(SMARTCARD_DEVICE* smartcard, wStream* s, - REDIR_SCARDCONTEXT* context); -LONG smartcard_pack_redir_scard_context_ref(SMARTCARD_DEVICE* smartcard, wStream* s, - REDIR_SCARDCONTEXT* context); - -LONG smartcard_unpack_redir_scard_handle(SMARTCARD_DEVICE* smartcard, wStream* s, - REDIR_SCARDHANDLE* handle); -LONG smartcard_pack_redir_scard_handle(SMARTCARD_DEVICE* smartcard, wStream* s, - REDIR_SCARDHANDLE* handle); - -LONG smartcard_unpack_redir_scard_handle_ref(SMARTCARD_DEVICE* smartcard, wStream* s, - REDIR_SCARDHANDLE* handle); -LONG smartcard_pack_redir_scard_handle_ref(SMARTCARD_DEVICE* smartcard, wStream* s, - REDIR_SCARDHANDLE* handle); - LONG smartcard_unpack_establish_context_call(SMARTCARD_DEVICE* smartcard, wStream* s, - EstablishContext_Call* call); -void smartcard_trace_establish_context_call(SMARTCARD_DEVICE* smartcard, - EstablishContext_Call* call); + EstablishContext_Call* call); LONG smartcard_pack_establish_context_return(SMARTCARD_DEVICE* smartcard, wStream* s, - EstablishContext_Return* ret); -void smartcard_trace_establish_context_return(SMARTCARD_DEVICE* smartcard, - EstablishContext_Return* ret); + const EstablishContext_Return* ret); -LONG smartcard_unpack_context_call(SMARTCARD_DEVICE* smartcard, wStream* s, Context_Call* call); -void smartcard_trace_context_call(SMARTCARD_DEVICE* smartcard, Context_Call* call, - const char* name); +LONG smartcard_unpack_context_call(SMARTCARD_DEVICE* smartcard, wStream* s, Context_Call* call, + const char* name); -void smartcard_trace_long_return(SMARTCARD_DEVICE* smartcard, Long_Return* ret, const char* name); +void smartcard_trace_long_return(SMARTCARD_DEVICE* smartcard, const Long_Return* ret, + const char* name); LONG smartcard_unpack_list_reader_groups_call(SMARTCARD_DEVICE* smartcard, wStream* s, - ListReaderGroups_Call* call); -void smartcard_trace_list_reader_groups_call(SMARTCARD_DEVICE* smartcard, - ListReaderGroups_Call* call, BOOL unicode); + ListReaderGroups_Call* call, BOOL unicode); LONG smartcard_pack_list_reader_groups_return(SMARTCARD_DEVICE* smartcard, wStream* s, - ListReaderGroups_Return* ret); -void smartcard_trace_list_reader_groups_return(SMARTCARD_DEVICE* smartcard, - ListReaderGroups_Return* ret, BOOL unicode); + const ListReaderGroups_Return* ret, BOOL unicode); LONG smartcard_unpack_list_readers_call(SMARTCARD_DEVICE* smartcard, wStream* s, - ListReaders_Call* call); -void smartcard_trace_list_readers_call(SMARTCARD_DEVICE* smartcard, ListReaders_Call* call, - BOOL unicode); + ListReaders_Call* call, BOOL unicode); LONG smartcard_pack_list_readers_return(SMARTCARD_DEVICE* smartcard, wStream* s, - ListReaders_Return* ret); -void smartcard_trace_list_readers_return(SMARTCARD_DEVICE* smartcard, ListReaders_Return* ret, - BOOL unicode); + const ListReaders_Return* ret, BOOL unicode); + +LONG smartcard_unpack_context_and_two_strings_a_call(SMARTCARD_DEVICE* smartcard, wStream* s, + ContextAndTwoStringA_Call* call); + +LONG smartcard_unpack_context_and_two_strings_w_call(SMARTCARD_DEVICE* smartcard, wStream* s, + ContextAndTwoStringW_Call* call); + +LONG smartcard_unpack_context_and_string_a_call(SMARTCARD_DEVICE* smartcard, wStream* s, + ContextAndStringA_Call* call); + +LONG smartcard_unpack_context_and_string_w_call(SMARTCARD_DEVICE* smartcard, wStream* s, + ContextAndStringW_Call* call); + +LONG smartcard_unpack_locate_cards_a_call(SMARTCARD_DEVICE* smartcard, wStream* s, + LocateCardsA_Call* call); + +LONG smartcard_pack_locate_cards_return(SMARTCARD_DEVICE* smartcard, wStream* s, + const LocateCards_Return* ret); + +LONG smartcard_unpack_locate_cards_w_call(SMARTCARD_DEVICE* smartcard, wStream* s, + LocateCardsW_Call* call); + +LONG smartcard_pack_locate_cards_w_return(SMARTCARD_DEVICE* smartcard, wStream* s, + const LocateCardsW_Call* ret); LONG smartcard_unpack_connect_a_call(SMARTCARD_DEVICE* smartcard, wStream* s, ConnectA_Call* call); -void smartcard_trace_connect_a_call(SMARTCARD_DEVICE* smartcard, ConnectA_Call* call); LONG smartcard_unpack_connect_w_call(SMARTCARD_DEVICE* smartcard, wStream* s, ConnectW_Call* call); -void smartcard_trace_connect_w_call(SMARTCARD_DEVICE* smartcard, ConnectW_Call* call); -LONG smartcard_pack_connect_return(SMARTCARD_DEVICE* smartcard, wStream* s, Connect_Return* ret); -void smartcard_trace_connect_return(SMARTCARD_DEVICE* smartcard, Connect_Return* ret); +LONG smartcard_pack_connect_return(SMARTCARD_DEVICE* smartcard, wStream* s, + const Connect_Return* ret); LONG smartcard_unpack_reconnect_call(SMARTCARD_DEVICE* smartcard, wStream* s, Reconnect_Call* call); -void smartcard_trace_reconnect_call(SMARTCARD_DEVICE* smartcard, Reconnect_Call* call); LONG smartcard_pack_reconnect_return(SMARTCARD_DEVICE* smartcard, wStream* s, - Reconnect_Return* ret); -void smartcard_trace_reconnect_return(SMARTCARD_DEVICE* smartcard, Reconnect_Return* ret); + const Reconnect_Return* ret); LONG smartcard_unpack_hcard_and_disposition_call(SMARTCARD_DEVICE* smartcard, wStream* s, - HCardAndDisposition_Call* call); -void smartcard_trace_hcard_and_disposition_call(SMARTCARD_DEVICE* smartcard, - HCardAndDisposition_Call* call, const char* name); + HCardAndDisposition_Call* call, const char* name); LONG smartcard_unpack_get_status_change_a_call(SMARTCARD_DEVICE* smartcard, wStream* s, - GetStatusChangeA_Call* call); -void smartcard_trace_get_status_change_a_call(SMARTCARD_DEVICE* smartcard, - GetStatusChangeA_Call* call); + GetStatusChangeA_Call* call); LONG smartcard_unpack_get_status_change_w_call(SMARTCARD_DEVICE* smartcard, wStream* s, - GetStatusChangeW_Call* call); -void smartcard_trace_get_status_change_w_call(SMARTCARD_DEVICE* smartcard, - GetStatusChangeW_Call* call); + GetStatusChangeW_Call* call); LONG smartcard_pack_get_status_change_return(SMARTCARD_DEVICE* smartcard, wStream* s, - GetStatusChange_Return* ret); -void smartcard_trace_get_status_change_return(SMARTCARD_DEVICE* smartcard, - GetStatusChange_Return* ret, BOOL unicode); + const GetStatusChange_Return* ret, BOOL unicode); LONG smartcard_unpack_state_call(SMARTCARD_DEVICE* smartcard, wStream* s, State_Call* call); -LONG smartcard_pack_state_return(SMARTCARD_DEVICE* smartcard, wStream* s, State_Return* ret); +LONG smartcard_pack_state_return(SMARTCARD_DEVICE* smartcard, wStream* s, const State_Return* ret); -LONG smartcard_unpack_status_call(SMARTCARD_DEVICE* smartcard, wStream* s, Status_Call* call); -void smartcard_trace_status_call(SMARTCARD_DEVICE* smartcard, Status_Call* call, BOOL unicode); +LONG smartcard_unpack_status_call(SMARTCARD_DEVICE* smartcard, wStream* s, Status_Call* call, + BOOL unicode); -LONG smartcard_pack_status_return(SMARTCARD_DEVICE* smartcard, wStream* s, Status_Return* ret); -void smartcard_trace_status_return(SMARTCARD_DEVICE* smartcard, Status_Return* ret, BOOL unicode); +LONG smartcard_pack_status_return(SMARTCARD_DEVICE* smartcard, wStream* s, const Status_Return* ret, + BOOL unicode); LONG smartcard_unpack_get_attrib_call(SMARTCARD_DEVICE* smartcard, wStream* s, GetAttrib_Call* call); -void smartcard_trace_get_attrib_call(SMARTCARD_DEVICE* smartcard, GetAttrib_Call* call); LONG smartcard_pack_get_attrib_return(SMARTCARD_DEVICE* smartcard, wStream* s, - GetAttrib_Return* ret); -void smartcard_trace_get_attrib_return(SMARTCARD_DEVICE* smartcard, GetAttrib_Return* ret, - DWORD dwAttrId); + const GetAttrib_Return* ret, DWORD dwAttrId); + +LONG smartcard_unpack_set_attrib_call(SMARTCARD_DEVICE* smartcard, wStream* s, + SetAttrib_Call* call); LONG smartcard_unpack_control_call(SMARTCARD_DEVICE* smartcard, wStream* s, Control_Call* call); -void smartcard_trace_control_call(SMARTCARD_DEVICE* smartcard, Control_Call* call); -LONG smartcard_pack_control_return(SMARTCARD_DEVICE* smartcard, wStream* s, Control_Return* ret); -void smartcard_trace_control_return(SMARTCARD_DEVICE* smartcard, Control_Return* ret); +LONG smartcard_pack_control_return(SMARTCARD_DEVICE* smartcard, wStream* s, + const Control_Return* ret); LONG smartcard_unpack_transmit_call(SMARTCARD_DEVICE* smartcard, wStream* s, Transmit_Call* call); -void smartcard_trace_transmit_call(SMARTCARD_DEVICE* smartcard, Transmit_Call* call); -LONG smartcard_pack_transmit_return(SMARTCARD_DEVICE* smartcard, wStream* s, Transmit_Return* ret); -void smartcard_trace_transmit_return(SMARTCARD_DEVICE* smartcard, Transmit_Return* ret); +LONG smartcard_pack_transmit_return(SMARTCARD_DEVICE* smartcard, wStream* s, + const Transmit_Return* ret); LONG smartcard_unpack_locate_cards_by_atr_a_call(SMARTCARD_DEVICE* smartcard, wStream* s, - LocateCardsByATRA_Call* call); -void smartcard_trace_locate_cards_by_atr_a_call(SMARTCARD_DEVICE* smartcard, - LocateCardsByATRA_Call* call); + LocateCardsByATRA_Call* call); + +LONG smartcard_unpack_locate_cards_by_atr_w_call(SMARTCARD_DEVICE* smartcard, wStream* s, + LocateCardsByATRW_Call* call); + +LONG smartcard_unpack_read_cache_a_call(SMARTCARD_DEVICE* smartcard, wStream* s, + ReadCacheA_Call* call); + +LONG smartcard_unpack_read_cache_w_call(SMARTCARD_DEVICE* smartcard, wStream* s, + ReadCacheW_Call* call); + +LONG smartcard_pack_read_cache_return(SMARTCARD_DEVICE* smartcard, wStream* s, + const ReadCache_Return* ret); + +LONG smartcard_unpack_write_cache_a_call(SMARTCARD_DEVICE* smartcard, wStream* s, + WriteCacheA_Call* call); + +LONG smartcard_unpack_write_cache_w_call(SMARTCARD_DEVICE* smartcard, wStream* s, + WriteCacheW_Call* call); + +LONG smartcard_unpack_get_transmit_count_call(SMARTCARD_DEVICE* smartcard, wStream* s, + GetTransmitCount_Call* call); +LONG smartcard_pack_get_transmit_count_return(SMARTCARD_DEVICE* smartcard, wStream* s, + const GetTransmitCount_Return* call); + +LONG smartcard_unpack_get_reader_icon_call(SMARTCARD_DEVICE* smartcard, wStream* s, + GetReaderIcon_Call* call); +LONG smartcard_pack_get_reader_icon_return(SMARTCARD_DEVICE* smartcard, wStream* s, + const GetReaderIcon_Return* ret); + +LONG smartcard_unpack_get_device_type_id_call(SMARTCARD_DEVICE* smartcard, wStream* s, + GetDeviceTypeId_Call* call); +LONG smartcard_pack_device_type_id_return(SMARTCARD_DEVICE* smartcard, wStream* s, + const GetDeviceTypeId_Return* ret); #endif /* FREERDP_CHANNEL_SMARTCARD_CLIENT_PACK_H */ 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..41b5a21 100644 --- a/channels/sshagent/ChannelOptions.cmake +++ b/channels/sshagent/ChannelOptions.cmake @@ -4,10 +4,9 @@ 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/client/sshagent_main.c b/channels/sshagent/client/sshagent_main.c index 39d81aa..aa7e632 100644 --- a/channels/sshagent/client/sshagent_main.c +++ b/channels/sshagent/client/sshagent_main.c @@ -95,7 +95,6 @@ struct _SSHAGENT_PLUGIN rdpContext* rdpcontext; }; - /** * Function to open the connection to the sshagent * @@ -123,8 +122,7 @@ static int connect_to_sshagent(const char* udspath) if (rc != 0) { - WLog_ERR(TAG, "Can't connect to Unix domain socket \"%s\"!", - udspath); + WLog_ERR(TAG, "Can't connect to Unix domain socket \"%s\"!", udspath); close(agent_fd); return -1; } @@ -132,7 +130,6 @@ static int connect_to_sshagent(const char* udspath) return agent_fd; } - /** * Entry point for thread to read from the ssh-agent socket and forward * the data to RDP @@ -148,9 +145,7 @@ static DWORD WINAPI sshagent_read_thread(LPVOID data) while (going) { - int bytes_read = read(callback->agent_fd, - buffer, - sizeof(buffer)); + int bytes_read = read(callback->agent_fd, buffer, sizeof(buffer)); if (bytes_read == 0) { @@ -161,9 +156,7 @@ static DWORD WINAPI sshagent_read_thread(LPVOID data) { if (errno != EINTR) { - WLog_ERR(TAG, - "Error reading from sshagent, errno=%d", - errno); + WLog_ERR(TAG, "Error reading from sshagent, errno=%d", errno); status = ERROR_READ_FAULT; going = 0; } @@ -171,10 +164,7 @@ static DWORD WINAPI sshagent_read_thread(LPVOID data) else { /* Something read: forward to virtual channel */ - status = callback->channel->Write(callback->channel, - bytes_read, - buffer, - NULL); + status = callback->channel->Write(callback->channel, bytes_read, buffer, NULL); if (status != CHANNEL_RC_OK) { @@ -186,11 +176,10 @@ static DWORD WINAPI sshagent_read_thread(LPVOID data) close(callback->agent_fd); if (status != CHANNEL_RC_OK) - setChannelError(callback->rdpcontext, status, - "sshagent_read_thread reported an error"); + setChannelError(callback->rdpcontext, status, "sshagent_read_thread reported an error"); - ExitThread(status); - return status; + ExitThread(status); + return status; } /** @@ -200,7 +189,7 @@ static DWORD WINAPI sshagent_read_thread(LPVOID data) */ static UINT sshagent_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data) { - SSHAGENT_CHANNEL_CALLBACK* callback = (SSHAGENT_CHANNEL_CALLBACK*) pChannelCallback; + SSHAGENT_CHANNEL_CALLBACK* callback = (SSHAGENT_CHANNEL_CALLBACK*)pChannelCallback; BYTE* pBuffer = Stream_Pointer(data); UINT32 cbSize = Stream_GetRemainingLength(data); BYTE* pos = pBuffer; @@ -210,16 +199,13 @@ static UINT sshagent_on_data_received(IWTSVirtualChannelCallback* pChannelCallba while (bytes_to_write > 0) { - int bytes_written = write(callback->agent_fd, pos, - bytes_to_write); + int bytes_written = write(callback->agent_fd, pos, bytes_to_write); if (bytes_written < 0) { if (errno != EINTR) { - WLog_ERR(TAG, - "Error writing to sshagent, errno=%d", - errno); + WLog_ERR(TAG, "Error writing to sshagent, errno=%d", errno); return ERROR_WRITE_FAULT; } } @@ -242,7 +228,7 @@ static UINT sshagent_on_data_received(IWTSVirtualChannelCallback* pChannelCallba */ static UINT sshagent_on_close(IWTSVirtualChannelCallback* pChannelCallback) { - SSHAGENT_CHANNEL_CALLBACK* callback = (SSHAGENT_CHANNEL_CALLBACK*) pChannelCallback; + SSHAGENT_CHANNEL_CALLBACK* callback = (SSHAGENT_CHANNEL_CALLBACK*)pChannelCallback; /* Call shutdown() to wake up the read() in sshagent_read_thread(). */ shutdown(callback->agent_fd, SHUT_RDWR); EnterCriticalSection(&callback->lock); @@ -250,7 +236,7 @@ static UINT sshagent_on_close(IWTSVirtualChannelCallback* pChannelCallback) if (WaitForSingleObject(callback->thread, INFINITE) == WAIT_FAILED) { UINT error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error); return error; } @@ -261,19 +247,19 @@ static UINT sshagent_on_close(IWTSVirtualChannelCallback* pChannelCallback) return CHANNEL_RC_OK; } - /** * Callback for when a new virtual channel is opened * * @return 0 on success, otherwise a Win32 error code */ static UINT sshagent_on_new_channel_connection(IWTSListenerCallback* pListenerCallback, - IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept, - IWTSVirtualChannelCallback** ppCallback) + IWTSVirtualChannel* pChannel, BYTE* Data, + BOOL* pbAccept, + IWTSVirtualChannelCallback** ppCallback) { SSHAGENT_CHANNEL_CALLBACK* callback; - SSHAGENT_LISTENER_CALLBACK* listener_callback = (SSHAGENT_LISTENER_CALLBACK*) pListenerCallback; - callback = (SSHAGENT_CHANNEL_CALLBACK*) calloc(1, sizeof(SSHAGENT_CHANNEL_CALLBACK)); + SSHAGENT_LISTENER_CALLBACK* listener_callback = (SSHAGENT_LISTENER_CALLBACK*)pListenerCallback; + callback = (SSHAGENT_CHANNEL_CALLBACK*)calloc(1, sizeof(SSHAGENT_CHANNEL_CALLBACK)); if (!callback) { @@ -283,8 +269,7 @@ static UINT sshagent_on_new_channel_connection(IWTSListenerCallback* pListenerCa /* Now open a connection to the local ssh-agent. Do this for each * connection to the plugin in case we mess up the agent session. */ - callback->agent_fd - = connect_to_sshagent(listener_callback->agent_uds_path); + callback->agent_fd = connect_to_sshagent(listener_callback->agent_uds_path); if (callback->agent_fd == -1) { @@ -299,13 +284,7 @@ static UINT sshagent_on_new_channel_connection(IWTSListenerCallback* pListenerCa callback->channel_mgr = listener_callback->channel_mgr; callback->channel = pChannel; callback->rdpcontext = listener_callback->rdpcontext; - callback->thread - = CreateThread(NULL, - 0, - sshagent_read_thread, - (void*) callback, - 0, - NULL); + callback->thread = CreateThread(NULL, 0, sshagent_read_thread, (void*)callback, 0, NULL); if (!callback->thread) { @@ -315,7 +294,7 @@ static UINT sshagent_on_new_channel_connection(IWTSListenerCallback* pListenerCa return CHANNEL_RC_INITIALIZATION_ERROR; } - *ppCallback = (IWTSVirtualChannelCallback*) callback; + *ppCallback = (IWTSVirtualChannelCallback*)callback; return CHANNEL_RC_OK; } @@ -326,9 +305,9 @@ static UINT sshagent_on_new_channel_connection(IWTSListenerCallback* pListenerCa */ static UINT sshagent_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr) { - SSHAGENT_PLUGIN* sshagent = (SSHAGENT_PLUGIN*) pPlugin; - sshagent->listener_callback = (SSHAGENT_LISTENER_CALLBACK*) calloc(1, - sizeof(SSHAGENT_LISTENER_CALLBACK)); + SSHAGENT_PLUGIN* sshagent = (SSHAGENT_PLUGIN*)pPlugin; + sshagent->listener_callback = + (SSHAGENT_LISTENER_CALLBACK*)calloc(1, sizeof(SSHAGENT_LISTENER_CALLBACK)); if (!sshagent->listener_callback) { @@ -351,7 +330,7 @@ static UINT sshagent_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelMa } return pChannelMgr->CreateListener(pChannelMgr, "SSHAGENT", 0, - (IWTSListenerCallback*) sshagent->listener_callback, NULL); + (IWTSListenerCallback*)sshagent->listener_callback, NULL); } /** @@ -361,15 +340,15 @@ static UINT sshagent_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelMa */ static UINT sshagent_plugin_terminated(IWTSPlugin* pPlugin) { - SSHAGENT_PLUGIN* sshagent = (SSHAGENT_PLUGIN*) pPlugin; + SSHAGENT_PLUGIN* sshagent = (SSHAGENT_PLUGIN*)pPlugin; free(sshagent); return CHANNEL_RC_OK; } #ifdef BUILTIN_CHANNELS -#define DVCPluginEntry sshagent_DVCPluginEntry +#define DVCPluginEntry sshagent_DVCPluginEntry #else -#define DVCPluginEntry FREERDP_API DVCPluginEntry +#define DVCPluginEntry FREERDP_API DVCPluginEntry #endif /** @@ -381,11 +360,11 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) { UINT status = CHANNEL_RC_OK; SSHAGENT_PLUGIN* sshagent; - sshagent = (SSHAGENT_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "sshagent"); + sshagent = (SSHAGENT_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "sshagent"); if (!sshagent) { - sshagent = (SSHAGENT_PLUGIN*) calloc(1, sizeof(SSHAGENT_PLUGIN)); + sshagent = (SSHAGENT_PLUGIN*)calloc(1, sizeof(SSHAGENT_PLUGIN)); if (!sshagent) { @@ -397,9 +376,10 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) sshagent->iface.Connected = NULL; sshagent->iface.Disconnected = NULL; sshagent->iface.Terminated = sshagent_plugin_terminated; - sshagent->rdpcontext = ((freerdp*)((rdpSettings*) pEntryPoints->GetRdpSettings( - pEntryPoints))->instance)->context; - status = pEntryPoints->RegisterPlugin(pEntryPoints, "sshagent", (IWTSPlugin*) sshagent); + sshagent->rdpcontext = + ((freerdp*)((rdpSettings*)pEntryPoints->GetRdpSettings(pEntryPoints))->instance) + ->context; + status = pEntryPoints->RegisterPlugin(pEntryPoints, "sshagent", (IWTSPlugin*)sshagent); } return status; diff --git a/channels/sshagent/client/sshagent_main.h b/channels/sshagent/client/sshagent_main.h index fc1ac15..550b2b7 100644 --- a/channels/sshagent/client/sshagent_main.h +++ b/channels/sshagent/client/sshagent_main.h @@ -35,8 +35,10 @@ #ifdef WITH_DEBUG_SSHAGENT #define DEBUG_SSHAGENT(...) WLog_DBG(DVC_TAG, __VA_ARGS__) #else -#define DEBUG_SSHAGENT(...) do { } while (0) +#define DEBUG_SSHAGENT(...) \ + do \ + { \ + } while (0) #endif #endif /* SSHAGENT_MAIN_H */ - diff --git a/channels/tsmf/ChannelOptions.cmake b/channels/tsmf/ChannelOptions.cmake index b59578f..b5252ea 100644 --- a/channels/tsmf/ChannelOptions.cmake +++ b/channels/tsmf/ChannelOptions.cmake @@ -1,6 +1,6 @@ set(OPTION_DEFAULT OFF) -set(OPTION_CLIENT_DEFAULT ON) +set(OPTION_CLIENT_DEFAULT OFF) set(OPTION_SERVER_DEFAULT OFF) if(WIN32) @@ -14,7 +14,7 @@ if(ANDROID) endif() define_channel_options(NAME "tsmf" TYPE "dynamic" - DESCRIPTION "Video Redirection Virtual Channel Extension" + DESCRIPTION "[DEPRECATED] Video Redirection Virtual Channel Extension" SPECIFICATIONS "[MS-RDPEV]" DEFAULT ${OPTION_DEFAULT}) diff --git a/channels/tsmf/client/CMakeLists.txt b/channels/tsmf/client/CMakeLists.txt index ee172fc..d7438de 100644 --- a/channels/tsmf/client/CMakeLists.txt +++ b/channels/tsmf/client/CMakeLists.txt @@ -18,6 +18,43 @@ define_channel_client("tsmf") +message(DEPRECATION "TSMF channel is no longer maintained. Use [MS-RDPEVOR] (/video) instead.") + +set(GSTREAMER_0_10_FEATURE_TYPE "OPTIONAL") +set(GSTREAMER_0_10_FEATURE_PURPOSE "multimedia") +set(GSTREAMER_0_10_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback, gstreamer 0.10 version") + +set(GSTREAMER_1_0_FEATURE_TYPE "RECOMMENDED") +set(GSTREAMER_1_0_FEATURE_PURPOSE "multimedia") +set(GSTREAMER_1_0_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback") + +if (WIN32) + set(GSTREAMER_1_0_FEATURE_TYPE "DISABLED") + set(GSTREAMER_0_10_FEATURE_TYPE "OPTIONAL") +endif() +if (APPLE) + set(GSTREAMER_1_0_FEATURE_TYPE "OPTIONAL") + + if (IOS) + set(GSTREAMER_1_0_FEATURE_TYPE "DISABLED") + set(GSTREAMER_0_10_FEATURE_TYPE "DISABLED") + endif() +endif() +if (ANDROID) + set(GSTREAMER_1_0_FEATURE_TYPE "DISABLED") + set(GSTREAMER_0_10_FEATURE_TYPE "DISABLED") +endif() + +find_feature(GStreamer_0_10 ${GSTREAMER_0_10_FEATURE_TYPE} ${GSTREAMER_0_10_FEATURE_PURPOSE} ${GSTREAMER_0_10_FEATURE_DESCRIPTION}) +find_feature(GStreamer_1_0 ${GSTREAMER_1_0_FEATURE_TYPE} ${GSTREAMER_1_0_FEATURE_PURPOSE} ${GSTREAMER_1_0_FEATURE_DESCRIPTION}) + +if (WITH_GSTREAMER_0_10 AND GSTREAMER_0_10_FOUND) + add_definitions(-DWITH_GSTREAMER_0_10) +endif() +if (WITH_GSTREAMER_1_0 AND GSTREAMER_1_0_FOUND) + add_definitions(-DWITH_GSTREAMER_1_0) +endif() + set(${MODULE_PREFIX}_SRCS tsmf_audio.c tsmf_audio.h diff --git a/channels/tsmf/client/alsa/tsmf_alsa.c b/channels/tsmf/client/alsa/tsmf_alsa.c index 3cf821b..6e1f003 100644 --- a/channels/tsmf/client/alsa/tsmf_alsa.c +++ b/channels/tsmf/client/alsa/tsmf_alsa.c @@ -65,7 +65,7 @@ static BOOL tsmf_alsa_open_device(TSMFAlsaAudioDevice* alsa) static BOOL tsmf_alsa_open(ITSMFAudioDevice* audio, const char* device) { - TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*) audio; + TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*)audio; if (!device) { @@ -79,14 +79,14 @@ static BOOL tsmf_alsa_open(ITSMFAudioDevice* audio, const char* device) return tsmf_alsa_open_device(alsa); } -static BOOL tsmf_alsa_set_format(ITSMFAudioDevice* audio, - UINT32 sample_rate, UINT32 channels, UINT32 bits_per_sample) +static BOOL tsmf_alsa_set_format(ITSMFAudioDevice* audio, UINT32 sample_rate, UINT32 channels, + UINT32 bits_per_sample) { int error; snd_pcm_uframes_t frames; snd_pcm_hw_params_t* hw_params; snd_pcm_sw_params_t* sw_params; - TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*) audio; + TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*)audio; if (!alsa->out_handle) return FALSE; @@ -104,17 +104,12 @@ static BOOL tsmf_alsa_set_format(ITSMFAudioDevice* audio, } snd_pcm_hw_params_any(alsa->out_handle, hw_params); - snd_pcm_hw_params_set_access(alsa->out_handle, hw_params, - SND_PCM_ACCESS_RW_INTERLEAVED); - snd_pcm_hw_params_set_format(alsa->out_handle, hw_params, - SND_PCM_FORMAT_S16_LE); - snd_pcm_hw_params_set_rate_near(alsa->out_handle, hw_params, - &alsa->actual_rate, NULL); - snd_pcm_hw_params_set_channels_near(alsa->out_handle, hw_params, - &alsa->actual_channels); + snd_pcm_hw_params_set_access(alsa->out_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); + snd_pcm_hw_params_set_format(alsa->out_handle, hw_params, SND_PCM_FORMAT_S16_LE); + snd_pcm_hw_params_set_rate_near(alsa->out_handle, hw_params, &alsa->actual_rate, NULL); + snd_pcm_hw_params_set_channels_near(alsa->out_handle, hw_params, &alsa->actual_channels); frames = sample_rate; - snd_pcm_hw_params_set_buffer_size_near(alsa->out_handle, hw_params, - &frames); + snd_pcm_hw_params_set_buffer_size_near(alsa->out_handle, hw_params, &frames); snd_pcm_hw_params(alsa->out_handle, hw_params); snd_pcm_hw_params_free(hw_params); error = snd_pcm_sw_params_malloc(&sw_params); @@ -126,22 +121,21 @@ static BOOL tsmf_alsa_set_format(ITSMFAudioDevice* audio, } snd_pcm_sw_params_current(alsa->out_handle, sw_params); - snd_pcm_sw_params_set_start_threshold(alsa->out_handle, sw_params, - frames / 2); + snd_pcm_sw_params_set_start_threshold(alsa->out_handle, sw_params, frames / 2); snd_pcm_sw_params(alsa->out_handle, sw_params); snd_pcm_sw_params_free(sw_params); snd_pcm_prepare(alsa->out_handle); - DEBUG_TSMF("sample_rate %"PRIu32" channels %"PRIu32" bits_per_sample %"PRIu32"", + DEBUG_TSMF("sample_rate %" PRIu32 " channels %" PRIu32 " bits_per_sample %" PRIu32 "", sample_rate, channels, bits_per_sample); DEBUG_TSMF("hardware buffer %lu frames", frames); if ((alsa->actual_rate != alsa->source_rate) || (alsa->actual_channels != alsa->source_channels)) { - DEBUG_TSMF("actual rate %"PRIu32" / channel %"PRIu32" is different " - "from source rate %"PRIu32" / channel %"PRIu32", resampling required.", - alsa->actual_rate, alsa->actual_channels, - alsa->source_rate, alsa->source_channels); + DEBUG_TSMF("actual rate %" PRIu32 " / channel %" PRIu32 " is different " + "from source rate %" PRIu32 " / channel %" PRIu32 ", resampling required.", + alsa->actual_rate, alsa->actual_channels, alsa->source_rate, + alsa->source_channels); } return TRUE; @@ -156,8 +150,8 @@ static BOOL tsmf_alsa_play(ITSMFAudioDevice* audio, const BYTE* src, UINT32 data const BYTE* pindex; int rbytes_per_frame; int sbytes_per_frame; - TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*) audio; - DEBUG_TSMF("data_size %"PRIu32"", data_size); + TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*)audio; + DEBUG_TSMF("data_size %" PRIu32 "", data_size); if (alsa->out_handle) { @@ -202,13 +196,12 @@ static UINT64 tsmf_alsa_get_latency(ITSMFAudioDevice* audio) { UINT64 latency = 0; snd_pcm_sframes_t frames = 0; - TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*) audio; + TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*)audio; if (alsa->out_handle && alsa->actual_rate > 0 && - snd_pcm_delay(alsa->out_handle, &frames) == 0 && - frames > 0) + snd_pcm_delay(alsa->out_handle, &frames) == 0 && frames > 0) { - latency = ((UINT64)frames) * 10000000LL / (UINT64) alsa->actual_rate; + latency = ((UINT64)frames) * 10000000LL / (UINT64)alsa->actual_rate; } return latency; @@ -221,7 +214,7 @@ static BOOL tsmf_alsa_flush(ITSMFAudioDevice* audio) static void tsmf_alsa_free(ITSMFAudioDevice* audio) { - TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*) audio; + TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*)audio; DEBUG_TSMF(""); if (alsa->out_handle) @@ -234,15 +227,16 @@ static void tsmf_alsa_free(ITSMFAudioDevice* audio) } #ifdef BUILTIN_CHANNELS -#define freerdp_tsmf_client_audio_subsystem_entry alsa_freerdp_tsmf_client_audio_subsystem_entry +#define freerdp_tsmf_client_audio_subsystem_entry alsa_freerdp_tsmf_client_audio_subsystem_entry #else -#define freerdp_tsmf_client_audio_subsystem_entry FREERDP_API freerdp_tsmf_client_audio_subsystem_entry +#define freerdp_tsmf_client_audio_subsystem_entry \ + FREERDP_API freerdp_tsmf_client_audio_subsystem_entry #endif ITSMFAudioDevice* freerdp_tsmf_client_audio_subsystem_entry(void) { TSMFAlsaAudioDevice* alsa; - alsa = (TSMFAlsaAudioDevice*) malloc(sizeof(TSMFAlsaAudioDevice)); + alsa = (TSMFAlsaAudioDevice*)malloc(sizeof(TSMFAlsaAudioDevice)); ZeroMemory(alsa, sizeof(TSMFAlsaAudioDevice)); alsa->iface.Open = tsmf_alsa_open; alsa->iface.SetFormat = tsmf_alsa_set_format; @@ -250,5 +244,5 @@ ITSMFAudioDevice* freerdp_tsmf_client_audio_subsystem_entry(void) alsa->iface.GetLatency = tsmf_alsa_get_latency; alsa->iface.Flush = tsmf_alsa_flush; alsa->iface.Free = tsmf_alsa_free; - return (ITSMFAudioDevice*) alsa; + return (ITSMFAudioDevice*)alsa; } diff --git a/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c b/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c index 5522eb7..0444ad0 100644 --- a/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c +++ b/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c @@ -92,7 +92,7 @@ typedef struct _TSMFFFmpegDecoder static BOOL tsmf_ffmpeg_init_context(ITSMFDecoder* decoder) { - TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder; + TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*)decoder; mdecoder->codec_context = avcodec_alloc_context3(NULL); if (!mdecoder->codec_context) @@ -106,7 +106,7 @@ static BOOL tsmf_ffmpeg_init_context(ITSMFDecoder* decoder) static BOOL tsmf_ffmpeg_init_video_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYPE* media_type) { - TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder; + TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*)decoder; mdecoder->codec_context->width = media_type->Width; mdecoder->codec_context->height = media_type->Height; mdecoder->codec_context->bit_rate = media_type->BitRate; @@ -122,7 +122,7 @@ static BOOL tsmf_ffmpeg_init_video_stream(ITSMFDecoder* decoder, const TS_AM_MED static BOOL tsmf_ffmpeg_init_audio_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYPE* media_type) { - TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder; + TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*)decoder; mdecoder->codec_context->sample_rate = media_type->SamplesPerSecond.Numerator; mdecoder->codec_context->bit_rate = media_type->BitRate; mdecoder->codec_context->channels = media_type->Channels; @@ -137,7 +137,7 @@ static BOOL tsmf_ffmpeg_init_audio_stream(ITSMFDecoder* decoder, const TS_AM_MED mdecoder->codec_context->dsp_mask = FF_MM_SSE2 | FF_MM_MMX2; #endif #endif -#else /* LIBAVCODEC_VERSION_MAJOR < 55 */ +#else /* LIBAVCODEC_VERSION_MAJOR < 55 */ #ifdef AV_CPU_FLAG_SSE2 av_set_cpu_flags_mask(AV_CPU_FLAG_SSE2 | AV_CPU_FLAG_MMXEXT); #else @@ -152,7 +152,7 @@ static BOOL tsmf_ffmpeg_init_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYP BYTE* p; UINT32 size; const BYTE* s; - TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder; + TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*)decoder; mdecoder->codec = avcodec_find_decoder(mdecoder->codec_id); if (!mdecoder->codec) @@ -198,12 +198,12 @@ static BOOL tsmf_ffmpeg_init_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYP /* The extradata format that FFmpeg uses is following CodecPrivate in Matroska. See http://haali.su/mkv/codecs.pdf */ p = mdecoder->codec_context->extradata; - *p++ = 1; /* Reserved? */ - *p++ = media_type->ExtraData[8]; /* Profile */ - *p++ = 0; /* Profile */ + *p++ = 1; /* Reserved? */ + *p++ = media_type->ExtraData[8]; /* Profile */ + *p++ = 0; /* Profile */ *p++ = media_type->ExtraData[12]; /* Level */ - *p++ = 0xff; /* Flag? */ - *p++ = 0xe0 | 0x01; /* Reserved | #sps */ + *p++ = 0xff; /* Flag? */ + *p++ = 0xe0 | 0x01; /* Reserved | #sps */ s = media_type->ExtraData + 20; size = ((UINT32)(*s)) * 256 + ((UINT32)(*(s + 1))); memcpy(p, s, size + 2); @@ -215,7 +215,8 @@ static BOOL tsmf_ffmpeg_init_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYP } else { - memcpy(mdecoder->codec_context->extradata, media_type->ExtraData, media_type->ExtraDataSize); + memcpy(mdecoder->codec_context->extradata, media_type->ExtraData, + media_type->ExtraDataSize); memset(mdecoder->codec_context->extradata + media_type->ExtraDataSize, 0, 8); } } @@ -228,7 +229,7 @@ static BOOL tsmf_ffmpeg_init_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYP static BOOL tsmf_ffmpeg_prepare(ITSMFDecoder* decoder) { - TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder; + TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*)decoder; if (avcodec_open2(mdecoder->codec_context, mdecoder->codec, NULL) < 0) { @@ -242,7 +243,7 @@ static BOOL tsmf_ffmpeg_prepare(ITSMFDecoder* decoder) static BOOL tsmf_ffmpeg_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* media_type) { - TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder; + TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*)decoder; switch (media_type->MajorType) { @@ -330,18 +331,19 @@ static BOOL tsmf_ffmpeg_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* medi static BOOL tsmf_ffmpeg_decode_video(ITSMFDecoder* decoder, const BYTE* data, UINT32 data_size, UINT32 extensions) { - TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder; + TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*)decoder; int decoded; int len; AVFrame* frame; BOOL ret = TRUE; -#if LIBAVCODEC_VERSION_MAJOR < 52 || (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR <= 20) +#if LIBAVCODEC_VERSION_MAJOR < 52 || \ + (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR <= 20) len = avcodec_decode_video(mdecoder->codec_context, mdecoder->frame, &decoded, data, data_size); #else { AVPacket pkt; av_init_packet(&pkt); - pkt.data = (BYTE*) data; + pkt.data = (BYTE*)data; pkt.size = data_size; if (extensions & TSMM_SAMPLE_EXT_CLEANPOINT) @@ -353,12 +355,12 @@ static BOOL tsmf_ffmpeg_decode_video(ITSMFDecoder* decoder, const BYTE* data, UI if (len < 0) { - WLog_ERR(TAG, "data_size %"PRIu32", avcodec_decode_video failed (%d)", data_size, len); + WLog_ERR(TAG, "data_size %" PRIu32 ", avcodec_decode_video failed (%d)", data_size, len); ret = FALSE; } else if (!decoded) { - WLog_ERR(TAG, "data_size %"PRIu32", no frame is decoded.", data_size); + WLog_ERR(TAG, "data_size %" PRIu32 ", no frame is decoded.", data_size); ret = FALSE; } else @@ -367,10 +369,11 @@ static BOOL tsmf_ffmpeg_decode_video(ITSMFDecoder* decoder, const BYTE* data, UI "pix_fmt %d width %d height %d", mdecoder->frame->linesize[0], mdecoder->frame->linesize[1], mdecoder->frame->linesize[2], mdecoder->frame->linesize[3], - mdecoder->codec_context->pix_fmt, - mdecoder->codec_context->width, mdecoder->codec_context->height); - mdecoder->decoded_size = avpicture_get_size(mdecoder->codec_context->pix_fmt, - mdecoder->codec_context->width, mdecoder->codec_context->height); + mdecoder->codec_context->pix_fmt, mdecoder->codec_context->width, + mdecoder->codec_context->height); + mdecoder->decoded_size = + avpicture_get_size(mdecoder->codec_context->pix_fmt, mdecoder->codec_context->width, + mdecoder->codec_context->height); mdecoder->decoded_data = calloc(1, mdecoder->decoded_size); if (!mdecoder->decoded_data) @@ -381,12 +384,11 @@ static BOOL tsmf_ffmpeg_decode_video(ITSMFDecoder* decoder, const BYTE* data, UI #else frame = av_frame_alloc(); #endif - avpicture_fill((AVPicture*) frame, mdecoder->decoded_data, - mdecoder->codec_context->pix_fmt, + avpicture_fill((AVPicture*)frame, mdecoder->decoded_data, mdecoder->codec_context->pix_fmt, mdecoder->codec_context->width, mdecoder->codec_context->height); - av_picture_copy((AVPicture*) frame, (AVPicture*) mdecoder->frame, - mdecoder->codec_context->pix_fmt, - mdecoder->codec_context->width, mdecoder->codec_context->height); + av_picture_copy((AVPicture*)frame, (AVPicture*)mdecoder->frame, + mdecoder->codec_context->pix_fmt, mdecoder->codec_context->width, + mdecoder->codec_context->height); av_free(frame); } @@ -396,7 +398,7 @@ static BOOL tsmf_ffmpeg_decode_video(ITSMFDecoder* decoder, const BYTE* data, UI static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder* decoder, const BYTE* data, UINT32 data_size, UINT32 extensions) { - TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder; + TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*)decoder; int len; int frame_size; UINT32 src_size; @@ -426,7 +428,7 @@ static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder* decoder, const BYTE* data, UI return FALSE; /* align the memory for SSE2 needs */ - dst = (BYTE*)(((uintptr_t) mdecoder->decoded_data + 15) & ~ 0x0F); + dst = (BYTE*)(((uintptr_t)mdecoder->decoded_data + 15) & ~0x0F); dst_offset = dst - mdecoder->decoded_data; src = data; src_size = data_size; @@ -444,7 +446,7 @@ static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder* decoder, const BYTE* data, UI mdecoder->decoded_size_max = mdecoder->decoded_size_max * 2 + 16; mdecoder->decoded_data = tmp_data; - dst = (BYTE*)(((uintptr_t)mdecoder->decoded_data + 15) & ~ 0x0F); + dst = (BYTE*)(((uintptr_t)mdecoder->decoded_data + 15) & ~0x0F); if (dst - mdecoder->decoded_data != dst_offset) { @@ -457,9 +459,10 @@ static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder* decoder, const BYTE* data, UI } frame_size = mdecoder->decoded_size_max - mdecoder->decoded_size; -#if LIBAVCODEC_VERSION_MAJOR < 52 || (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR <= 20) - len = avcodec_decode_audio2(mdecoder->codec_context, - (int16_t*) dst, &frame_size, src, src_size); +#if LIBAVCODEC_VERSION_MAJOR < 52 || \ + (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR <= 20) + len = avcodec_decode_audio2(mdecoder->codec_context, (int16_t*)dst, &frame_size, src, + src_size); #else { #if LIBAVCODEC_VERSION_MAJOR < 55 @@ -470,14 +473,15 @@ static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder* decoder, const BYTE* data, UI int got_frame = 0; AVPacket pkt; av_init_packet(&pkt); - pkt.data = (BYTE*) src; + pkt.data = (BYTE*)src; pkt.size = src_size; len = avcodec_decode_audio4(mdecoder->codec_context, decoded_frame, &got_frame, &pkt); if (len >= 0 && got_frame) { frame_size = av_samples_get_buffer_size(NULL, mdecoder->codec_context->channels, - decoded_frame->nb_samples, mdecoder->codec_context->sample_fmt, 1); + decoded_frame->nb_samples, + mdecoder->codec_context->sample_fmt, 1); memcpy(dst, decoded_frame->data[0], frame_size); } else @@ -510,18 +514,18 @@ static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder* decoder, const BYTE* data, UI else if (dst_offset) { /* move the aligned decoded data to original place */ - memmove(mdecoder->decoded_data, mdecoder->decoded_data + dst_offset, mdecoder->decoded_size); + memmove(mdecoder->decoded_data, mdecoder->decoded_data + dst_offset, + mdecoder->decoded_size); } - DEBUG_TSMF("data_size %"PRIu32" decoded_size %"PRIu32"", - data_size, mdecoder->decoded_size); + DEBUG_TSMF("data_size %" PRIu32 " decoded_size %" PRIu32 "", data_size, mdecoder->decoded_size); return TRUE; } static BOOL tsmf_ffmpeg_decode(ITSMFDecoder* decoder, const BYTE* data, UINT32 data_size, UINT32 extensions) { - TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder; + TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*)decoder; if (mdecoder->decoded_data) { @@ -548,7 +552,7 @@ static BOOL tsmf_ffmpeg_decode(ITSMFDecoder* decoder, const BYTE* data, UINT32 d static BYTE* tsmf_ffmpeg_get_decoded_data(ITSMFDecoder* decoder, UINT32* size) { BYTE* buf; - TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder; + TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*)decoder; *size = mdecoder->decoded_size; buf = mdecoder->decoded_data; mdecoder->decoded_data = NULL; @@ -558,7 +562,7 @@ static BYTE* tsmf_ffmpeg_get_decoded_data(ITSMFDecoder* decoder, UINT32* size) static UINT32 tsmf_ffmpeg_get_decoded_format(ITSMFDecoder* decoder) { - TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder; + TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*)decoder; switch (mdecoder->codec_context->pix_fmt) { @@ -566,15 +570,14 @@ static UINT32 tsmf_ffmpeg_get_decoded_format(ITSMFDecoder* decoder) return RDP_PIXFMT_I420; default: - WLog_ERR(TAG, "unsupported pixel format %u", - mdecoder->codec_context->pix_fmt); - return (UINT32) - 1; + WLog_ERR(TAG, "unsupported pixel format %u", mdecoder->codec_context->pix_fmt); + return (UINT32)-1; } } static BOOL tsmf_ffmpeg_get_decoded_dimension(ITSMFDecoder* decoder, UINT32* width, UINT32* height) { - TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder; + TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*)decoder; if (mdecoder->codec_context->width > 0 && mdecoder->codec_context->height > 0) { @@ -590,7 +593,7 @@ static BOOL tsmf_ffmpeg_get_decoded_dimension(ITSMFDecoder* decoder, UINT32* wid static void tsmf_ffmpeg_free(ITSMFDecoder* decoder) { - TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder; + TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*)decoder; if (mdecoder->frame) av_free(mdecoder->frame); @@ -617,17 +620,17 @@ static BOOL CALLBACK InitializeAvCodecs(PINIT_ONCE once, PVOID param, PVOID* con } #ifdef BUILTIN_CHANNELS -#define freerdp_tsmf_client_subsystem_entry ffmpeg_freerdp_tsmf_client_decoder_subsystem_entry +#define freerdp_tsmf_client_subsystem_entry ffmpeg_freerdp_tsmf_client_decoder_subsystem_entry #else -#define freerdp_tsmf_client_subsystem_entry FREERDP_API freerdp_tsmf_client_decoder_subsystem_entry +#define freerdp_tsmf_client_subsystem_entry FREERDP_API freerdp_tsmf_client_decoder_subsystem_entry #endif ITSMFDecoder* freerdp_tsmf_client_subsystem_entry(void) { TSMFFFmpegDecoder* decoder; InitOnceExecuteOnce(&g_Initialized, InitializeAvCodecs, NULL, NULL); - WLog_DBG(TAG, "TSMFDecoderEntry FFMPEG"); - decoder = (TSMFFFmpegDecoder*) calloc(1, sizeof(TSMFFFmpegDecoder)); + WLog_DBG(TAG, "TSMFDecoderEntry FFMPEG"); + decoder = (TSMFFFmpegDecoder*)calloc(1, sizeof(TSMFFFmpegDecoder)); if (!decoder) return NULL; @@ -638,5 +641,5 @@ ITSMFDecoder* freerdp_tsmf_client_subsystem_entry(void) decoder->iface.GetDecodedFormat = tsmf_ffmpeg_get_decoded_format; decoder->iface.GetDecodedDimension = tsmf_ffmpeg_get_decoded_dimension; decoder->iface.Free = tsmf_ffmpeg_free; - return (ITSMFDecoder*) decoder; + return (ITSMFDecoder*)decoder; } diff --git a/channels/tsmf/client/gstreamer/tsmf_X11.c b/channels/tsmf/client/gstreamer/tsmf_X11.c index b57b927..ae383df 100644 --- a/channels/tsmf/client/gstreamer/tsmf_X11.c +++ b/channels/tsmf/client/gstreamer/tsmf_X11.c @@ -16,7 +16,7 @@ * 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 @@ -65,17 +65,17 @@ struct X11Handle { int shmid; - int *xfwin; + int* xfwin; #if defined(WITH_XEXT) BOOL has_shape; #endif - Display *disp; + Display* disp; Window subwin; BOOL subwinMapped; #if GST_VERSION_MAJOR > 0 - GstVideoOverlay *overlay; + GstVideoOverlay* overlay; #else - GstXOverlay *overlay; + GstXOverlay* overlay; #endif int subwinWidth; int subwinHeight; @@ -90,34 +90,35 @@ static const char* get_shm_id() return shm_id; } -static GstBusSyncReply tsmf_platform_bus_sync_handler(GstBus *bus, GstMessage *message, gpointer user_data) +static GstBusSyncReply tsmf_platform_bus_sync_handler(GstBus* bus, GstMessage* message, + gpointer user_data) { struct X11Handle* hdl; TSMFGstreamerDecoder* decoder = user_data; - if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT) + if (GST_MESSAGE_TYPE(message) != GST_MESSAGE_ELEMENT) return GST_BUS_PASS; #if GST_VERSION_MAJOR > 0 - if (!gst_is_video_overlay_prepare_window_handle_message (message)) + if (!gst_is_video_overlay_prepare_window_handle_message(message)) return GST_BUS_PASS; #else - if (!gst_structure_has_name (message->structure, "prepare-xwindow-id")) + if (!gst_structure_has_name(message->structure, "prepare-xwindow-id")) return GST_BUS_PASS; #endif - hdl = (struct X11Handle*) decoder->platform; + hdl = (struct X11Handle*)decoder->platform; if (hdl->subwin) { #if GST_VERSION_MAJOR > 0 - hdl->overlay = GST_VIDEO_OVERLAY (GST_MESSAGE_SRC (message)); + hdl->overlay = GST_VIDEO_OVERLAY(GST_MESSAGE_SRC(message)); gst_video_overlay_set_window_handle(hdl->overlay, hdl->subwin); - gst_video_overlay_handle_events(hdl->overlay, TRUE); + gst_video_overlay_handle_events(hdl->overlay, FALSE); #else - hdl->overlay = GST_X_OVERLAY (GST_MESSAGE_SRC (message)); -#if GST_CHECK_VERSION(0,10,31) + hdl->overlay = GST_X_OVERLAY(GST_MESSAGE_SRC(message)); +#if GST_CHECK_VERSION(0, 10, 31) gst_x_overlay_set_window_handle(hdl->overlay, hdl->subwin); #else gst_x_overlay_set_xwindow_id(hdl->overlay, hdl->subwin); @@ -125,17 +126,20 @@ static GstBusSyncReply tsmf_platform_bus_sync_handler(GstBus *bus, GstMessage *m gst_x_overlay_handle_events(hdl->overlay, TRUE); #endif - if (hdl->subwinWidth != -1 && hdl->subwinHeight != -1 && hdl->subwinX != -1 && hdl->subwinY != -1) + if (hdl->subwinWidth != -1 && hdl->subwinHeight != -1 && hdl->subwinX != -1 && + hdl->subwinY != -1) { #if GST_VERSION_MAJOR > 0 - if (!gst_video_overlay_set_render_rectangle(hdl->overlay, 0, 0, hdl->subwinWidth, hdl->subwinHeight)) + if (!gst_video_overlay_set_render_rectangle(hdl->overlay, 0, 0, hdl->subwinWidth, + hdl->subwinHeight)) { WLog_ERR(TAG, "Could not resize overlay!"); } gst_video_overlay_expose(hdl->overlay); #else - if (!gst_x_overlay_set_render_rectangle(hdl->overlay, 0, 0, hdl->subwinWidth, hdl->subwinHeight)) + if (!gst_x_overlay_set_render_rectangle(hdl->overlay, 0, 0, hdl->subwinWidth, + hdl->subwinHeight)) { WLog_ERR(TAG, "Could not resize overlay!"); } @@ -143,15 +147,18 @@ static GstBusSyncReply tsmf_platform_bus_sync_handler(GstBus *bus, GstMessage *m gst_x_overlay_expose(hdl->overlay); #endif XLockDisplay(hdl->disp); - XMoveResizeWindow(hdl->disp, hdl->subwin, hdl->subwinX, hdl->subwinY, hdl->subwinWidth, hdl->subwinHeight); + XMoveResizeWindow(hdl->disp, hdl->subwin, hdl->subwinX, hdl->subwinY, hdl->subwinWidth, + hdl->subwinHeight); XSync(hdl->disp, FALSE); XUnlockDisplay(hdl->disp); } - } else { - g_warning ("Window was not available before retrieving the overlay!"); + } + else + { + g_warning("Window was not available before retrieving the overlay!"); } - gst_message_unref (message); + gst_message_unref(message); return GST_BUS_DROP; } @@ -187,11 +194,12 @@ int tsmf_platform_create(TSMFGstreamerDecoder* decoder) hdl->shmid = shm_open(get_shm_id(), (O_RDWR | O_CREAT), (PROT_READ | PROT_WRITE)); if (hdl->shmid == -1) { - WLog_ERR(TAG, "failed to get access to shared memory - shmget(%s): %i - %s", get_shm_id(), errno, strerror(errno)); + WLog_ERR(TAG, "failed to get access to shared memory - shmget(%s): %i - %s", get_shm_id(), + errno, strerror(errno)); return -2; } - hdl->xfwin = mmap(0, sizeof(void *), PROT_READ | PROT_WRITE, MAP_SHARED, hdl->shmid, 0); + hdl->xfwin = mmap(0, sizeof(void*), PROT_READ | PROT_WRITE, MAP_SHARED, hdl->shmid, 0); if (hdl->xfwin == MAP_FAILED) { WLog_ERR(TAG, "shmat failed!"); @@ -221,7 +229,6 @@ int tsmf_platform_set_format(TSMFGstreamerDecoder* decoder) if (decoder->media_type == TSMF_MAJOR_TYPE_VIDEO) { - } return 0; @@ -240,9 +247,9 @@ int tsmf_platform_register_handler(TSMFGstreamerDecoder* decoder) bus = gst_pipeline_get_bus(GST_PIPELINE(decoder->pipe)); #if GST_VERSION_MAJOR > 0 - gst_bus_set_sync_handler (bus, (GstBusSyncHandler) tsmf_platform_bus_sync_handler, decoder, NULL); + gst_bus_set_sync_handler(bus, (GstBusSyncHandler)tsmf_platform_bus_sync_handler, decoder, NULL); #else - gst_bus_set_sync_handler (bus, (GstBusSyncHandler) tsmf_platform_bus_sync_handler, decoder); + gst_bus_set_sync_handler(bus, (GstBusSyncHandler)tsmf_platform_bus_sync_handler, decoder); #endif if (!bus) @@ -251,7 +258,7 @@ int tsmf_platform_register_handler(TSMFGstreamerDecoder* decoder) return 1; } - gst_object_unref (bus); + gst_object_unref(bus); return 0; } @@ -295,12 +302,12 @@ int tsmf_window_create(TSMFGstreamerDecoder* decoder) if (!decoder->platform) return -1; - hdl = (struct X11Handle*) decoder->platform; + hdl = (struct X11Handle*)decoder->platform; if (!hdl->subwin) { XLockDisplay(hdl->disp); - hdl->subwin = XCreateSimpleWindow(hdl->disp, *(int *)hdl->xfwin, 0, 0, 1, 1, 0, 0, 0); + hdl->subwin = XCreateSimpleWindow(hdl->disp, *(int*)hdl->xfwin, 0, 0, 1, 1, 0, 0, 0); XUnlockDisplay(hdl->disp); if (!hdl->subwin) @@ -313,18 +320,18 @@ int tsmf_window_create(TSMFGstreamerDecoder* decoder) decoder->ready = TRUE; #if defined(WITH_XEXT) - int event, error; - XLockDisplay(hdl->disp); - hdl->has_shape = XShapeQueryExtension(hdl->disp, &event, &error); - XUnlockDisplay(hdl->disp); + int event, error; + XLockDisplay(hdl->disp); + hdl->has_shape = XShapeQueryExtension(hdl->disp, &event, &error); + XUnlockDisplay(hdl->disp); #endif } return 0; } -int tsmf_window_resize(TSMFGstreamerDecoder* decoder, int x, int y, int width, - int height, int nr_rects, RDP_RECT *rects) +int tsmf_window_resize(TSMFGstreamerDecoder* decoder, int x, int y, int width, int height, + int nr_rects, RDP_RECT* rects) { struct X11Handle* hdl; @@ -339,7 +346,7 @@ int tsmf_window_resize(TSMFGstreamerDecoder* decoder, int x, int y, int width, if (!decoder->platform) return -1; - hdl = (struct X11Handle*) decoder->platform; + hdl = (struct X11Handle*)decoder->platform; DEBUG_TSMF("resize: x=%d, y=%d, w=%d, h=%d", x, y, width, height); if (hdl->overlay) @@ -370,7 +377,8 @@ int tsmf_window_resize(TSMFGstreamerDecoder* decoder, int x, int y, int width, hdl->subwinHeight = height; XLockDisplay(hdl->disp); - XMoveResizeWindow(hdl->disp, hdl->subwin, hdl->subwinX, hdl->subwinY, hdl->subwinWidth, hdl->subwinHeight); + XMoveResizeWindow(hdl->disp, hdl->subwin, hdl->subwinX, hdl->subwinY, hdl->subwinWidth, + hdl->subwinHeight); /* Unmap the window if there are no visibility rects */ if (nr_rects == 0) @@ -382,7 +390,7 @@ int tsmf_window_resize(TSMFGstreamerDecoder* decoder, int x, int y, int width, if (hdl->has_shape) { int i; - XRectangle *xrects = NULL; + XRectangle* xrects = NULL; if (nr_rects == 0) { @@ -396,7 +404,7 @@ int tsmf_window_resize(TSMFGstreamerDecoder* decoder, int x, int y, int width, { xrects = calloc(nr_rects, sizeof(XRectangle)); } - + if (xrects) { for (i = 0; i < nr_rects; i++) @@ -407,7 +415,8 @@ int tsmf_window_resize(TSMFGstreamerDecoder* decoder, int x, int y, int width, xrects[i].height = rects[i].height; } - XShapeCombineRectangles(hdl->disp, hdl->subwin, ShapeBounding, x, y, xrects, nr_rects, ShapeSet, 0); + XShapeCombineRectangles(hdl->disp, hdl->subwin, ShapeBounding, x, y, xrects, + nr_rects, ShapeSet, 0); free(xrects); } } @@ -419,29 +428,13 @@ int tsmf_window_resize(TSMFGstreamerDecoder* decoder, int x, int y, int width, return 0; } -int tsmf_window_pause(TSMFGstreamerDecoder* decoder) -{ - if (!decoder) - return -1; - - return 0; -} - -int tsmf_window_resume(TSMFGstreamerDecoder* decoder) -{ - if (!decoder) - return -1; - - return 0; -} - int tsmf_window_map(TSMFGstreamerDecoder* decoder) { struct X11Handle* hdl; if (!decoder) return -1; - hdl = (struct X11Handle*) decoder->platform; + hdl = (struct X11Handle*)decoder->platform; /* Only need to map the window if it is not currently mapped */ if ((hdl->subwin) && (!hdl->subwinMapped)) @@ -462,22 +455,21 @@ int tsmf_window_unmap(TSMFGstreamerDecoder* decoder) if (!decoder) return -1; - hdl = (struct X11Handle*) decoder->platform; + hdl = (struct X11Handle*)decoder->platform; /* only need to unmap window if it is currently mapped */ if ((hdl->subwin) && (hdl->subwinMapped)) { XLockDisplay(hdl->disp); XUnmapWindow(hdl->disp, hdl->subwin); - hdl->subwinMapped = FALSE; - XSync(hdl->disp, FALSE); + hdl->subwinMapped = FALSE; + XSync(hdl->disp, FALSE); XUnlockDisplay(hdl->disp); } return 0; } - int tsmf_window_destroy(TSMFGstreamerDecoder* decoder) { struct X11Handle* hdl; @@ -493,7 +485,7 @@ int tsmf_window_destroy(TSMFGstreamerDecoder* decoder) if (!decoder->platform) return -1; - hdl = (struct X11Handle*) decoder->platform; + hdl = (struct X11Handle*)decoder->platform; if (hdl->subwin) { @@ -512,4 +504,3 @@ int tsmf_window_destroy(TSMFGstreamerDecoder* decoder) hdl->subwinHeight = -1; return 0; } - diff --git a/channels/tsmf/client/gstreamer/tsmf_gstreamer.c b/channels/tsmf/client/gstreamer/tsmf_gstreamer.c index 0addbe7..61ea6a8 100644 --- a/channels/tsmf/client/gstreamer/tsmf_gstreamer.c +++ b/channels/tsmf/client/gstreamer/tsmf_gstreamer.c @@ -17,7 +17,7 @@ * 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" @@ -54,15 +54,15 @@ #endif /* 1 second = 10,000,000 100ns units*/ -#define SEEK_TOLERANCE 10*1000*1000 +#define SEEK_TOLERANCE 10 * 1000 * 1000 static BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder* mdecoder); static void tsmf_gstreamer_clean_up(TSMFGstreamerDecoder* mdecoder); static int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder* mdecoder, - GstState desired_state); + GstState desired_state); static BOOL tsmf_gstreamer_buffer_level(ITSMFDecoder* decoder); -const char* get_type(TSMFGstreamerDecoder* mdecoder) +static const char* get_type(TSMFGstreamerDecoder* mdecoder) { if (!mdecoder) return NULL; @@ -78,55 +78,59 @@ const char* get_type(TSMFGstreamerDecoder* mdecoder) } } -static void cb_child_added(GstChildProxy *child_proxy, GObject *object, TSMFGstreamerDecoder* mdecoder) +static void cb_child_added(GstChildProxy* child_proxy, GObject* object, + TSMFGstreamerDecoder* mdecoder) { DEBUG_TSMF("NAME: %s", G_OBJECT_TYPE_NAME(object)); - if (!g_strcmp0(G_OBJECT_TYPE_NAME(object), "GstXvImageSink") || !g_strcmp0(G_OBJECT_TYPE_NAME(object), "GstXImageSink") || !g_strcmp0(G_OBJECT_TYPE_NAME(object), "GstFluVAAutoSink")) + if (!g_strcmp0(G_OBJECT_TYPE_NAME(object), "GstXvImageSink") || + !g_strcmp0(G_OBJECT_TYPE_NAME(object), "GstXImageSink") || + !g_strcmp0(G_OBJECT_TYPE_NAME(object), "GstFluVAAutoSink")) { - gst_base_sink_set_max_lateness((GstBaseSink *) object, 10000000); /* nanoseconds */ - g_object_set(G_OBJECT(object), "sync", TRUE, NULL); /* synchronize on the clock */ + gst_base_sink_set_max_lateness((GstBaseSink*)object, 10000000); /* nanoseconds */ + g_object_set(G_OBJECT(object), "sync", TRUE, NULL); /* synchronize on the clock */ g_object_set(G_OBJECT(object), "async", TRUE, NULL); /* no async state changes */ } - else if (!g_strcmp0(G_OBJECT_TYPE_NAME(object), "GstAlsaSink") || !g_strcmp0(G_OBJECT_TYPE_NAME(object), "GstPulseSink")) + else if (!g_strcmp0(G_OBJECT_TYPE_NAME(object), "GstAlsaSink") || + !g_strcmp0(G_OBJECT_TYPE_NAME(object), "GstPulseSink")) { - gst_base_sink_set_max_lateness((GstBaseSink *) object, 10000000); /* nanoseconds */ + gst_base_sink_set_max_lateness((GstBaseSink*)object, 10000000); /* nanoseconds */ g_object_set(G_OBJECT(object), "slave-method", 1, NULL); - g_object_set(G_OBJECT(object), "buffer-time", (gint64) 20000, NULL); /* microseconds */ - g_object_set(G_OBJECT(object), "drift-tolerance", (gint64) 20000, NULL); /* microseconds */ - g_object_set(G_OBJECT(object), "latency-time", (gint64) 10000, NULL); /* microseconds */ - g_object_set(G_OBJECT(object), "sync", TRUE, NULL); /* synchronize on the clock */ + g_object_set(G_OBJECT(object), "buffer-time", (gint64)20000, NULL); /* microseconds */ + g_object_set(G_OBJECT(object), "drift-tolerance", (gint64)20000, NULL); /* microseconds */ + g_object_set(G_OBJECT(object), "latency-time", (gint64)10000, NULL); /* microseconds */ + g_object_set(G_OBJECT(object), "sync", TRUE, NULL); /* synchronize on the clock */ g_object_set(G_OBJECT(object), "async", TRUE, NULL); /* no async state changes */ } } -static void tsmf_gstreamer_enough_data(GstAppSrc *src, gpointer user_data) +static void tsmf_gstreamer_enough_data(GstAppSrc* src, gpointer user_data) { TSMFGstreamerDecoder* mdecoder = user_data; - (void) mdecoder; + (void)mdecoder; DEBUG_TSMF("%s", get_type(mdecoder)); } -static void tsmf_gstreamer_need_data(GstAppSrc *src, guint length, gpointer user_data) +static void tsmf_gstreamer_need_data(GstAppSrc* src, guint length, gpointer user_data) { TSMFGstreamerDecoder* mdecoder = user_data; - (void) mdecoder; + (void)mdecoder; DEBUG_TSMF("%s length=%u", get_type(mdecoder), length); } -static gboolean tsmf_gstreamer_seek_data(GstAppSrc *src, guint64 offset, gpointer user_data) +static gboolean tsmf_gstreamer_seek_data(GstAppSrc* src, guint64 offset, gpointer user_data) { TSMFGstreamerDecoder* mdecoder = user_data; - (void) mdecoder; - DEBUG_TSMF("%s offset=%"PRIu64"", get_type(mdecoder), offset); + (void)mdecoder; + DEBUG_TSMF("%s offset=%" PRIu64 "", get_type(mdecoder), offset); return TRUE; } static BOOL tsmf_gstreamer_change_volume(ITSMFDecoder* decoder, UINT32 newVolume, UINT32 muted) { - TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder; + TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder*)decoder; if (!mdecoder || !mdecoder->pipe) return TRUE; @@ -134,9 +138,9 @@ static BOOL tsmf_gstreamer_change_volume(ITSMFDecoder* decoder, UINT32 newVolume if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) return TRUE; - mdecoder->gstMuted = (BOOL) muted; - DEBUG_TSMF("mute=[%"PRId32"]", mdecoder->gstMuted); - mdecoder->gstVolume = (double) newVolume / (double) 10000; + mdecoder->gstMuted = (BOOL)muted; + DEBUG_TSMF("mute=[%" PRId32 "]", mdecoder->gstMuted); + mdecoder->gstVolume = (double)newVolume / (double)10000; DEBUG_TSMF("gst_new_vol=[%f]", mdecoder->gstVolume); if (!mdecoder->volume) @@ -151,11 +155,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. @@ -173,10 +173,11 @@ int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder* mdecoder, GstState d return 0; if (!mdecoder->pipe) - return 0; /* Just in case this is called during startup or shutdown when we don't expect it */ + return 0; /* Just in case this is called during startup or shutdown when we don't expect it + */ if (desired_state == mdecoder->state) - return 0; /* Redundant request - Nothing to do */ + return 0; /* Redundant request - Nothing to do */ name = gst_element_state_get_name(desired_state); /* For debug */ DEBUG_TSMF("%s to %s", sname, name); @@ -214,7 +215,7 @@ static GstBuffer* tsmf_get_buffer_from_data(const void* raw_data, gsize size) if (!data) { - WLog_ERR(TAG, "Could not allocate %"G_GSIZE_FORMAT" bytes of data.", size); + WLog_ERR(TAG, "Could not allocate %" G_GSIZE_FORMAT " bytes of data.", size); return NULL; } @@ -242,7 +243,7 @@ static GstBuffer* tsmf_get_buffer_from_data(const void* raw_data, gsize size) static BOOL tsmf_gstreamer_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* media_type) { - TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder*) decoder; + TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder*)decoder; if (!mdecoder) return FALSE; @@ -264,175 +265,153 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* m switch (media_type->SubType) { case TSMF_SUB_TYPE_WVC1: - mdecoder->gst_caps = gst_caps_new_simple("video/x-wmv", - "bitrate", G_TYPE_UINT, media_type->BitRate, - "width", G_TYPE_INT, media_type->Width, - "height", G_TYPE_INT, media_type->Height, - "wmvversion", G_TYPE_INT, 3, + mdecoder->gst_caps = gst_caps_new_simple( + "video/x-wmv", "bitrate", G_TYPE_UINT, media_type->BitRate, "width", G_TYPE_INT, + media_type->Width, "height", G_TYPE_INT, media_type->Height, "wmvversion", + G_TYPE_INT, 3, #if GST_VERSION_MAJOR > 0 - "format", G_TYPE_STRING, "WVC1", + "format", G_TYPE_STRING, "WVC1", #else - "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('W', 'V', 'C', '1'), + "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC('W', 'V', 'C', '1'), #endif - "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator, - "pixel-aspect-ratio", GST_TYPE_FRACTION, 1 , 1, - NULL); + "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, + media_type->SamplesPerSecond.Denominator, "pixel-aspect-ratio", GST_TYPE_FRACTION, + 1, 1, NULL); break; case TSMF_SUB_TYPE_MP4S: - mdecoder->gst_caps = gst_caps_new_simple("video/x-divx", - "divxversion", G_TYPE_INT, 5, - "bitrate", G_TYPE_UINT, media_type->BitRate, - "width", G_TYPE_INT, media_type->Width, - "height", G_TYPE_INT, media_type->Height, + mdecoder->gst_caps = gst_caps_new_simple( + "video/x-divx", "divxversion", G_TYPE_INT, 5, "bitrate", G_TYPE_UINT, + media_type->BitRate, "width", G_TYPE_INT, media_type->Width, "height", G_TYPE_INT, + media_type->Height, #if GST_VERSION_MAJOR > 0 - "format", G_TYPE_STRING, "MP42", -#else - "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('M', 'P', '4', '2'), + "format", G_TYPE_STRING, "MP42", +#else + "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC('M', 'P', '4', '2'), #endif - "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator, - NULL); + "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, + media_type->SamplesPerSecond.Denominator, NULL); break; case TSMF_SUB_TYPE_MP42: - mdecoder->gst_caps = gst_caps_new_simple("video/x-msmpeg", - "msmpegversion", G_TYPE_INT, 42, - "bitrate", G_TYPE_UINT, media_type->BitRate, - "width", G_TYPE_INT, media_type->Width, - "height", G_TYPE_INT, media_type->Height, -#if GST_VERSION_MAJOR > 0 - "format", G_TYPE_STRING, "MP42", + mdecoder->gst_caps = gst_caps_new_simple( + "video/x-msmpeg", "msmpegversion", G_TYPE_INT, 42, "bitrate", G_TYPE_UINT, + media_type->BitRate, "width", G_TYPE_INT, media_type->Width, "height", G_TYPE_INT, + media_type->Height, +#if GST_VERSION_MAJOR > 0 + "format", G_TYPE_STRING, "MP42", #else - "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('M', 'P', '4', '2'), + "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC('M', 'P', '4', '2'), #endif - "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator, - NULL); + "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, + media_type->SamplesPerSecond.Denominator, NULL); break; case TSMF_SUB_TYPE_MP43: - mdecoder->gst_caps = gst_caps_new_simple("video/x-msmpeg", - "msmpegversion", G_TYPE_INT, 43, - "bitrate", G_TYPE_UINT, media_type->BitRate, - "width", G_TYPE_INT, media_type->Width, - "height", G_TYPE_INT, media_type->Height, -#if GST_VERSION_MAJOR > 0 - "format", G_TYPE_STRING, "MP43", -#else - "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('M', 'P', '4', '3'), + mdecoder->gst_caps = gst_caps_new_simple( + "video/x-msmpeg", "msmpegversion", G_TYPE_INT, 43, "bitrate", G_TYPE_UINT, + media_type->BitRate, "width", G_TYPE_INT, media_type->Width, "height", G_TYPE_INT, + media_type->Height, +#if GST_VERSION_MAJOR > 0 + "format", G_TYPE_STRING, "MP43", +#else + "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC('M', 'P', '4', '3'), #endif - "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator, - NULL); + "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, + media_type->SamplesPerSecond.Denominator, NULL); break; case TSMF_SUB_TYPE_M4S2: - mdecoder->gst_caps = gst_caps_new_simple ("video/mpeg", - "mpegversion", G_TYPE_INT, 4, - "width", G_TYPE_INT, media_type->Width, - "height", G_TYPE_INT, media_type->Height, -#if GST_VERSION_MAJOR > 0 - "format", G_TYPE_STRING, "M4S2", -#else - "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('M', '4', 'S', '2'), + mdecoder->gst_caps = gst_caps_new_simple( + "video/mpeg", "mpegversion", G_TYPE_INT, 4, "width", G_TYPE_INT, media_type->Width, + "height", G_TYPE_INT, media_type->Height, +#if GST_VERSION_MAJOR > 0 + "format", G_TYPE_STRING, "M4S2", +#else + "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC('M', '4', 'S', '2'), #endif - "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator, - NULL); + "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, + media_type->SamplesPerSecond.Denominator, NULL); break; case TSMF_SUB_TYPE_WMA9: - mdecoder->gst_caps = gst_caps_new_simple("audio/x-wma", - "wmaversion", G_TYPE_INT, 3, - "rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator, - "channels", G_TYPE_INT, media_type->Channels, - "bitrate", G_TYPE_INT, media_type->BitRate, - "depth", G_TYPE_INT, media_type->BitsPerSample, - "width", G_TYPE_INT, media_type->BitsPerSample, - "block_align", G_TYPE_INT, media_type->BlockAlign, - NULL); + mdecoder->gst_caps = gst_caps_new_simple( + "audio/x-wma", "wmaversion", G_TYPE_INT, 3, "rate", G_TYPE_INT, + media_type->SamplesPerSecond.Numerator, "channels", G_TYPE_INT, + media_type->Channels, "bitrate", G_TYPE_INT, media_type->BitRate, "depth", + G_TYPE_INT, media_type->BitsPerSample, "width", G_TYPE_INT, + media_type->BitsPerSample, "block_align", G_TYPE_INT, media_type->BlockAlign, NULL); break; case TSMF_SUB_TYPE_WMA1: - mdecoder->gst_caps = gst_caps_new_simple ("audio/x-wma", - "wmaversion", G_TYPE_INT, 1, - "rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator, - "channels", G_TYPE_INT, media_type->Channels, - "bitrate", G_TYPE_INT, media_type->BitRate, - "depth", G_TYPE_INT, media_type->BitsPerSample, - "width", G_TYPE_INT, media_type->BitsPerSample, - "block_align", G_TYPE_INT, media_type->BlockAlign, - NULL); + mdecoder->gst_caps = gst_caps_new_simple( + "audio/x-wma", "wmaversion", G_TYPE_INT, 1, "rate", G_TYPE_INT, + media_type->SamplesPerSecond.Numerator, "channels", G_TYPE_INT, + media_type->Channels, "bitrate", G_TYPE_INT, media_type->BitRate, "depth", + G_TYPE_INT, media_type->BitsPerSample, "width", G_TYPE_INT, + media_type->BitsPerSample, "block_align", G_TYPE_INT, media_type->BlockAlign, NULL); break; case TSMF_SUB_TYPE_WMA2: - mdecoder->gst_caps = gst_caps_new_simple("audio/x-wma", - "wmaversion", G_TYPE_INT, 2, - "rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator, - "channels", G_TYPE_INT, media_type->Channels, - "bitrate", G_TYPE_INT, media_type->BitRate, - "depth", G_TYPE_INT, media_type->BitsPerSample, - "width", G_TYPE_INT, media_type->BitsPerSample, - "block_align", G_TYPE_INT, media_type->BlockAlign, - NULL); + mdecoder->gst_caps = gst_caps_new_simple( + "audio/x-wma", "wmaversion", G_TYPE_INT, 2, "rate", G_TYPE_INT, + media_type->SamplesPerSecond.Numerator, "channels", G_TYPE_INT, + media_type->Channels, "bitrate", G_TYPE_INT, media_type->BitRate, "depth", + G_TYPE_INT, media_type->BitsPerSample, "width", G_TYPE_INT, + media_type->BitsPerSample, "block_align", G_TYPE_INT, media_type->BlockAlign, NULL); break; case TSMF_SUB_TYPE_MP3: - mdecoder->gst_caps = gst_caps_new_simple("audio/mpeg", - "mpegversion", G_TYPE_INT, 1, - "layer", G_TYPE_INT, 3, - "rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator, - "channels", G_TYPE_INT, media_type->Channels, - NULL); + mdecoder->gst_caps = + gst_caps_new_simple("audio/mpeg", "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, + 3, "rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator, + "channels", G_TYPE_INT, media_type->Channels, NULL); break; case TSMF_SUB_TYPE_WMV1: - mdecoder->gst_caps = gst_caps_new_simple("video/x-wmv", - "bitrate", G_TYPE_UINT, media_type->BitRate, - "width", G_TYPE_INT, media_type->Width, - "height", G_TYPE_INT, media_type->Height, - "wmvversion", G_TYPE_INT, 1, -#if GST_VERSION_MAJOR > 0 - "format", G_TYPE_STRING, "WMV1", -#else - "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('W', 'M', 'V', '1'), + mdecoder->gst_caps = gst_caps_new_simple( + "video/x-wmv", "bitrate", G_TYPE_UINT, media_type->BitRate, "width", G_TYPE_INT, + media_type->Width, "height", G_TYPE_INT, media_type->Height, "wmvversion", + G_TYPE_INT, 1, +#if GST_VERSION_MAJOR > 0 + "format", G_TYPE_STRING, "WMV1", +#else + "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC('W', 'M', 'V', '1'), #endif - "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator, - NULL); + "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, + media_type->SamplesPerSecond.Denominator, NULL); break; case TSMF_SUB_TYPE_WMV2: - mdecoder->gst_caps = gst_caps_new_simple("video/x-wmv", - "width", G_TYPE_INT, media_type->Width, - "height", G_TYPE_INT, media_type->Height, - "wmvversion", G_TYPE_INT, 2, -#if GST_VERSION_MAJOR > 0 - "format", G_TYPE_STRING, "WMV2", + mdecoder->gst_caps = gst_caps_new_simple( + "video/x-wmv", "width", G_TYPE_INT, media_type->Width, "height", G_TYPE_INT, + media_type->Height, "wmvversion", G_TYPE_INT, 2, +#if GST_VERSION_MAJOR > 0 + "format", G_TYPE_STRING, "WMV2", #else - "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('W', 'M', 'V', '2'), + "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC('W', 'M', 'V', '2'), #endif - "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator, - "pixel-aspect-ratio", GST_TYPE_FRACTION, 1 , 1, - NULL); + "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, + media_type->SamplesPerSecond.Denominator, "pixel-aspect-ratio", GST_TYPE_FRACTION, + 1, 1, NULL); break; case TSMF_SUB_TYPE_WMV3: - mdecoder->gst_caps = gst_caps_new_simple("video/x-wmv", - "bitrate", G_TYPE_UINT, media_type->BitRate, - "width", G_TYPE_INT, media_type->Width, - "height", G_TYPE_INT, media_type->Height, - "wmvversion", G_TYPE_INT, 3, -#if GST_VERSION_MAJOR > 0 - "format", G_TYPE_STRING, "WMV3", + mdecoder->gst_caps = gst_caps_new_simple( + "video/x-wmv", "bitrate", G_TYPE_UINT, media_type->BitRate, "width", G_TYPE_INT, + media_type->Width, "height", G_TYPE_INT, media_type->Height, "wmvversion", + G_TYPE_INT, 3, +#if GST_VERSION_MAJOR > 0 + "format", G_TYPE_STRING, "WMV3", #else - "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('W', 'M', 'V', '3'), + "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC('W', 'M', 'V', '3'), #endif - "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator, - "pixel-aspect-ratio", GST_TYPE_FRACTION, 1 , 1, - NULL); + "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, + media_type->SamplesPerSecond.Denominator, "pixel-aspect-ratio", GST_TYPE_FRACTION, + 1, 1, NULL); break; case TSMF_SUB_TYPE_AVC1: case TSMF_SUB_TYPE_H264: - mdecoder->gst_caps = gst_caps_new_simple("video/x-h264", - "width", G_TYPE_INT, media_type->Width, - "height", G_TYPE_INT, media_type->Height, - "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator, - "pixel-aspect-ratio", GST_TYPE_FRACTION, 1 , 1, - "stream-format", G_TYPE_STRING, "byte-stream", - "alignment", G_TYPE_STRING, "nal", - NULL); + mdecoder->gst_caps = gst_caps_new_simple( + "video/x-h264", "width", G_TYPE_INT, media_type->Width, "height", G_TYPE_INT, + media_type->Height, "framerate", GST_TYPE_FRACTION, + media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator, + "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1, "stream-format", G_TYPE_STRING, + "byte-stream", "alignment", G_TYPE_STRING, "nal", NULL); break; case TSMF_SUB_TYPE_AC3: - mdecoder->gst_caps = gst_caps_new_simple("audio/x-ac3", - "rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator, - "channels", G_TYPE_INT, media_type->Channels, - NULL); + mdecoder->gst_caps = gst_caps_new_simple( + "audio/x-ac3", "rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator, + "channels", G_TYPE_INT, media_type->Channels, NULL); break; case TSMF_SUB_TYPE_AAC: @@ -445,59 +424,47 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* m media_type->ExtraDataSize -= 12; } - mdecoder->gst_caps = gst_caps_new_simple("audio/mpeg", - "rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator, - "channels", G_TYPE_INT, media_type->Channels, - "mpegversion", G_TYPE_INT, 4, - "framed", G_TYPE_BOOLEAN, TRUE, - "stream-format", G_TYPE_STRING, "raw", - NULL); + mdecoder->gst_caps = gst_caps_new_simple( + "audio/mpeg", "rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator, + "channels", G_TYPE_INT, media_type->Channels, "mpegversion", G_TYPE_INT, 4, + "framed", G_TYPE_BOOLEAN, TRUE, "stream-format", G_TYPE_STRING, "raw", NULL); break; case TSMF_SUB_TYPE_MP1A: - mdecoder->gst_caps = gst_caps_new_simple("audio/mpeg", - "mpegversion", G_TYPE_INT, 1, - "channels", G_TYPE_INT, media_type->Channels, - NULL); + mdecoder->gst_caps = + gst_caps_new_simple("audio/mpeg", "mpegversion", G_TYPE_INT, 1, "channels", + G_TYPE_INT, media_type->Channels, NULL); break; case TSMF_SUB_TYPE_MP1V: - mdecoder->gst_caps = gst_caps_new_simple("video/mpeg", - "mpegversion", G_TYPE_INT, 1, - "width", G_TYPE_INT, media_type->Width, - "height", G_TYPE_INT, media_type->Height, - "systemstream", G_TYPE_BOOLEAN, FALSE, - NULL); + mdecoder->gst_caps = + gst_caps_new_simple("video/mpeg", "mpegversion", G_TYPE_INT, 1, "width", G_TYPE_INT, + media_type->Width, "height", G_TYPE_INT, media_type->Height, + "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); break; case TSMF_SUB_TYPE_YUY2: #if GST_VERSION_MAJOR > 0 - mdecoder->gst_caps = gst_caps_new_simple("video/x-raw", - "format", G_TYPE_STRING, "YUY2", - "width", G_TYPE_INT, media_type->Width, - "height", G_TYPE_INT, media_type->Height, - NULL); + mdecoder->gst_caps = gst_caps_new_simple( + "video/x-raw", "format", G_TYPE_STRING, "YUY2", "width", G_TYPE_INT, + media_type->Width, "height", G_TYPE_INT, media_type->Height, NULL); #else - mdecoder->gst_caps = gst_caps_new_simple("video/x-raw-yuv", - "format", G_TYPE_STRING, "YUY2", - "width", G_TYPE_INT, media_type->Width, - "height", G_TYPE_INT, media_type->Height, - "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator, - NULL); + mdecoder->gst_caps = gst_caps_new_simple( + "video/x-raw-yuv", "format", G_TYPE_STRING, "YUY2", "width", G_TYPE_INT, + media_type->Width, "height", G_TYPE_INT, media_type->Height, "framerate", + GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, + media_type->SamplesPerSecond.Denominator, NULL); #endif break; case TSMF_SUB_TYPE_MP2V: - mdecoder->gst_caps = gst_caps_new_simple("video/mpeg", - "mpegversion", G_TYPE_INT, 2, - "systemstream", G_TYPE_BOOLEAN, FALSE, - NULL); + mdecoder->gst_caps = gst_caps_new_simple("video/mpeg", "mpegversion", G_TYPE_INT, 2, + "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); break; case TSMF_SUB_TYPE_MP2A: - mdecoder->gst_caps = gst_caps_new_simple("audio/mpeg", - "mpegversion", G_TYPE_INT, 1, - "rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator, - "channels", G_TYPE_INT, media_type->Channels, - NULL); + mdecoder->gst_caps = + gst_caps_new_simple("audio/mpeg", "mpegversion", G_TYPE_INT, 1, "rate", G_TYPE_INT, + media_type->SamplesPerSecond.Numerator, "channels", G_TYPE_INT, + media_type->Channels, NULL); break; case TSMF_SUB_TYPE_FLAC: - mdecoder->gst_caps = gst_caps_new_simple("audio/x-flac", "", NULL); + mdecoder->gst_caps = gst_caps_new_simple("audio/x-flac", "", NULL); break; default: WLog_ERR(TAG, "unknown format:(%d).", media_type->SubType); @@ -506,8 +473,8 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* m if (media_type->ExtraDataSize > 0) { - GstBuffer *buffer; - DEBUG_TSMF("Extra data available (%"PRIu32")", media_type->ExtraDataSize); + GstBuffer* buffer; + DEBUG_TSMF("Extra data available (%" PRIu32 ")", media_type->ExtraDataSize); buffer = tsmf_get_buffer_from_data(media_type->ExtraData, media_type->ExtraDataSize); if (!buffer) @@ -519,7 +486,7 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* m gst_caps_set_simple(mdecoder->gst_caps, "codec_data", GST_TYPE_BUFFER, buffer, NULL); } - DEBUG_TSMF("%p format '%s'", (void*) mdecoder, gst_caps_to_string(mdecoder->gst_caps)); + DEBUG_TSMF("%p format '%s'", (void*)mdecoder, gst_caps_to_string(mdecoder->gst_caps)); tsmf_platform_set_format(mdecoder); /* Create the pipeline... */ @@ -551,11 +518,17 @@ void tsmf_gstreamer_clean_up(TSMFGstreamerDecoder* mdecoder) BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder* mdecoder) { #if GST_VERSION_MAJOR > 0 - const char* video = "appsrc name=videosource ! queue2 name=videoqueue ! decodebin name=videodecoder !"; - const char* audio = "appsrc name=audiosource ! queue2 name=audioqueue ! decodebin name=audiodecoder ! audioconvert ! audiorate ! audioresample ! volume name=audiovolume !"; + const char* video = + "appsrc name=videosource ! queue2 name=videoqueue ! decodebin name=videodecoder !"; + const char* audio = + "appsrc name=audiosource ! queue2 name=audioqueue ! decodebin name=audiodecoder ! " + "audioconvert ! audiorate ! audioresample ! volume name=audiovolume !"; #else - const char* video = "appsrc name=videosource ! queue2 name=videoqueue ! decodebin2 name=videodecoder !"; - const char* audio = "appsrc name=audiosource ! queue2 name=audioqueue ! decodebin2 name=audiodecoder ! audioconvert ! audiorate ! audioresample ! volume name=audiovolume !"; + const char* video = + "appsrc name=videosource ! queue2 name=videoqueue ! decodebin2 name=videodecoder !"; + const char* audio = + "appsrc name=audiosource ! queue2 name=audioqueue ! decodebin2 name=audiodecoder ! " + "audioconvert ! audiorate ! audioresample ! volume name=audiovolume !"; #endif char pipeline[1024]; @@ -566,9 +539,11 @@ BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder* mdecoder) * The only fixed elements necessary are appsrc and the volume element for audio streams. * The rest could easily be provided in gstreamer pipeline notation from command line. */ if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) - sprintf_s(pipeline, sizeof(pipeline), "%s %s name=videosink", video, tsmf_platform_get_video_sink()); + sprintf_s(pipeline, sizeof(pipeline), "%s %s name=videosink", video, + tsmf_platform_get_video_sink()); else - sprintf_s(pipeline, sizeof(pipeline), "%s %s name=audiosink", audio, tsmf_platform_get_audio_sink()); + sprintf_s(pipeline, sizeof(pipeline), "%s %s name=audiosink", audio, + tsmf_platform_get_audio_sink()); DEBUG_TSMF("pipeline=%s", pipeline); mdecoder->pipe = gst_parse_launch(pipeline, NULL); @@ -624,48 +599,54 @@ BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder* mdecoder) return FALSE; } - tsmf_gstreamer_change_volume((ITSMFDecoder*)mdecoder, mdecoder->gstVolume*((double) 10000), mdecoder->gstMuted); + tsmf_gstreamer_change_volume((ITSMFDecoder*)mdecoder, mdecoder->gstVolume * ((double)10000), + mdecoder->gstMuted); } tsmf_platform_register_handler(mdecoder); /* AppSrc settings */ - GstAppSrcCallbacks callbacks = - { - tsmf_gstreamer_need_data, - tsmf_gstreamer_enough_data, - tsmf_gstreamer_seek_data + GstAppSrcCallbacks callbacks = { + tsmf_gstreamer_need_data, tsmf_gstreamer_enough_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); g_object_set(mdecoder->src, "block", FALSE, NULL); g_object_set(mdecoder->src, "blocksize", 1024, NULL); - gst_app_src_set_caps((GstAppSrc *) mdecoder->src, mdecoder->gst_caps); - gst_app_src_set_callbacks((GstAppSrc *)mdecoder->src, &callbacks, mdecoder, NULL); - gst_app_src_set_stream_type((GstAppSrc *) mdecoder->src, GST_APP_STREAM_TYPE_SEEKABLE); - gst_app_src_set_latency((GstAppSrc *) mdecoder->src, 0, -1); - gst_app_src_set_max_bytes((GstAppSrc *) mdecoder->src, (guint64) 0);//unlimited + gst_app_src_set_caps((GstAppSrc*)mdecoder->src, mdecoder->gst_caps); + gst_app_src_set_callbacks((GstAppSrc*)mdecoder->src, &callbacks, mdecoder, NULL); + gst_app_src_set_stream_type((GstAppSrc*)mdecoder->src, GST_APP_STREAM_TYPE_SEEKABLE); + gst_app_src_set_latency((GstAppSrc*)mdecoder->src, 0, -1); + gst_app_src_set_max_bytes((GstAppSrc*)mdecoder->src, (guint64)0); // unlimited g_object_set(G_OBJECT(mdecoder->queue), "use-buffering", FALSE, NULL); g_object_set(G_OBJECT(mdecoder->queue), "use-rate-estimate", FALSE, NULL); g_object_set(G_OBJECT(mdecoder->queue), "max-size-buffers", 0, NULL); g_object_set(G_OBJECT(mdecoder->queue), "max-size-bytes", 0, NULL); - g_object_set(G_OBJECT(mdecoder->queue), "max-size-time", (guint64) 0, NULL); + g_object_set(G_OBJECT(mdecoder->queue), "max-size-time", (guint64)0, NULL); - /* Only set these properties if not an autosink, otherwise we will set properties when real sinks are added */ - if (!g_strcmp0(G_OBJECT_TYPE_NAME(mdecoder->outsink), "GstAutoVideoSink") && !g_strcmp0(G_OBJECT_TYPE_NAME(mdecoder->outsink), "GstAutoAudioSink")) + /* Only set these properties if not an autosink, otherwise we will set properties when real + * sinks are added */ + if (!g_strcmp0(G_OBJECT_TYPE_NAME(mdecoder->outsink), "GstAutoVideoSink") && + !g_strcmp0(G_OBJECT_TYPE_NAME(mdecoder->outsink), "GstAutoAudioSink")) { if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) { - gst_base_sink_set_max_lateness((GstBaseSink *) mdecoder->outsink, 10000000); /* nanoseconds */ + gst_base_sink_set_max_lateness((GstBaseSink*)mdecoder->outsink, + 10000000); /* nanoseconds */ } else { - gst_base_sink_set_max_lateness((GstBaseSink *) mdecoder->outsink, 10000000); /* nanoseconds */ - g_object_set(G_OBJECT(mdecoder->outsink), "buffer-time", (gint64) 20000, NULL); /* microseconds */ - g_object_set(G_OBJECT(mdecoder->outsink), "drift-tolerance", (gint64) 20000, NULL); /* microseconds */ - g_object_set(G_OBJECT(mdecoder->outsink), "latency-time", (gint64) 10000, NULL); /* microseconds */ + gst_base_sink_set_max_lateness((GstBaseSink*)mdecoder->outsink, + 10000000); /* nanoseconds */ + g_object_set(G_OBJECT(mdecoder->outsink), "buffer-time", (gint64)20000, + NULL); /* microseconds */ + g_object_set(G_OBJECT(mdecoder->outsink), "drift-tolerance", (gint64)20000, + NULL); /* microseconds */ + g_object_set(G_OBJECT(mdecoder->outsink), "latency-time", (gint64)10000, + NULL); /* microseconds */ g_object_set(G_OBJECT(mdecoder->outsink), "slave-method", 1, NULL); } - g_object_set(G_OBJECT(mdecoder->outsink), "sync", TRUE, NULL); /* synchronize on the clock */ + g_object_set(G_OBJECT(mdecoder->outsink), "sync", TRUE, + NULL); /* synchronize on the clock */ g_object_set(G_OBJECT(mdecoder->outsink), "async", TRUE, NULL); /* no async state changes */ } @@ -676,16 +657,18 @@ BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder* mdecoder) mdecoder->shutdown = 0; mdecoder->paused = FALSE; - GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(mdecoder->pipe), GST_DEBUG_GRAPH_SHOW_ALL, get_type(mdecoder)); + GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(mdecoder->pipe), GST_DEBUG_GRAPH_SHOW_ALL, + get_type(mdecoder)); return TRUE; } -static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder* decoder, const BYTE *data, UINT32 data_size, UINT32 extensions, - UINT64 start_time, UINT64 end_time, UINT64 duration) +static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder* decoder, const BYTE* data, UINT32 data_size, + UINT32 extensions, UINT64 start_time, UINT64 end_time, + UINT64 duration) { - GstBuffer *gst_buf; - TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder; + GstBuffer* gst_buf; + TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder*)decoder; UINT64 sample_time = tsmf_gstreamer_timestamp_ms_to_gst(start_time); BOOL useTimestamps = TRUE; @@ -701,9 +684,9 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder* decoder, const BYTE *data, UIN * We don't expect to block here often, since the pipeline should * have more than enough buffering. */ - DEBUG_TSMF("%s. Start:(%"PRIu64") End:(%"PRIu64") Duration:(%"PRIu64") Last Start:(%"PRIu64")", - get_type(mdecoder), start_time, end_time, duration, - mdecoder->last_sample_start_time); + DEBUG_TSMF( + "%s. Start:(%" PRIu64 ") End:(%" PRIu64 ") Duration:(%" PRIu64 ") Last Start:(%" PRIu64 ")", + get_type(mdecoder), start_time, end_time, duration, mdecoder->last_sample_start_time); if (mdecoder->shutdown) { @@ -722,7 +705,9 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder* decoder, const BYTE *data, UIN if (!mdecoder->src) { - WLog_ERR(TAG, "failed to construct pipeline correctly. Unable to push buffer to source element."); + WLog_ERR( + TAG, + "failed to construct pipeline correctly. Unable to push buffer to source element."); return FALSE; } @@ -730,7 +715,7 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder* decoder, const BYTE *data, UIN if (gst_buf == NULL) { - WLog_ERR(TAG, "tsmf_get_buffer_from_data(%p, %"PRIu32") failed.", (void*) data, data_size); + WLog_ERR(TAG, "tsmf_get_buffer_from_data(%p, %" PRIu32 ") failed.", (void*)data, data_size); return FALSE; } @@ -755,46 +740,54 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder* decoder, const BYTE *data, UIN { mdecoder->seeking = FALSE; tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PAUSED); - mdecoder->pipeline_start_time_valid = 0; + mdecoder->pipeline_start_time_valid = 0; } if (mdecoder->pipeline_start_time_valid) { - DEBUG_TSMF("%s start time %"PRIu64"", get_type(mdecoder), start_time); + DEBUG_TSMF("%s start time %" PRIu64 "", get_type(mdecoder), start_time); /* Adjusted the condition for a seek to be based on start time only * WMV1 and WMV2 files in particular have bad end time and duration values * there seems to be no real side effects of just using the start time instead */ - UINT64 minTime = mdecoder->last_sample_start_time - (UINT64) SEEK_TOLERANCE; - UINT64 maxTime = mdecoder->last_sample_start_time + (UINT64) SEEK_TOLERANCE; + UINT64 minTime = mdecoder->last_sample_start_time - (UINT64)SEEK_TOLERANCE; + UINT64 maxTime = mdecoder->last_sample_start_time + (UINT64)SEEK_TOLERANCE; - /* Make sure the minTime stops at 0 , should we be at the beginning of the stream */ - if (mdecoder->last_sample_start_time < (UINT64) SEEK_TOLERANCE) - minTime = 0; + /* Make sure the minTime stops at 0 , should we be at the beginning of the stream */ + if (mdecoder->last_sample_start_time < (UINT64)SEEK_TOLERANCE) + minTime = 0; - /* If the start_time is valid and different from the previous start time by more than the seek tolerance, then we have a seek condition */ + /* If the start_time is valid and different from the previous start time by more than the + * seek tolerance, then we have a seek condition */ if (((start_time > maxTime) || (start_time < minTime)) && useTimestamps) { - DEBUG_TSMF("tsmf_gstreamer_decodeEx: start_time=[%"PRIu64"] > last_sample_start_time=[%"PRIu64"] OR ", start_time, mdecoder->last_sample_start_time); - DEBUG_TSMF("tsmf_gstreamer_decodeEx: start_time=[%"PRIu64"] < last_sample_start_time=[%"PRIu64"] with", start_time, mdecoder->last_sample_start_time); - DEBUG_TSMF("tsmf_gstreamer_decodeEX: a tolerance of more than [%lu] from the last sample", SEEK_TOLERANCE); - DEBUG_TSMF("tsmf_gstreamer_decodeEX: minTime=[%"PRIu64"] maxTime=[%"PRIu64"]", minTime, maxTime); + DEBUG_TSMF("tsmf_gstreamer_decodeEx: start_time=[%" PRIu64 + "] > last_sample_start_time=[%" PRIu64 "] OR ", + start_time, mdecoder->last_sample_start_time); + DEBUG_TSMF("tsmf_gstreamer_decodeEx: start_time=[%" PRIu64 + "] < last_sample_start_time=[%" PRIu64 "] with", + start_time, mdecoder->last_sample_start_time); + DEBUG_TSMF( + "tsmf_gstreamer_decodeEX: a tolerance of more than [%lu] from the last sample", + SEEK_TOLERANCE); + DEBUG_TSMF("tsmf_gstreamer_decodeEX: minTime=[%" PRIu64 "] maxTime=[%" PRIu64 "]", + minTime, maxTime); mdecoder->seeking = TRUE; - /* since we cant make the gstreamer pipeline jump to the new start time after a seek - we just maintain - * a offset between realtime and gstreamer time + /* since we cant make the gstreamer pipeline jump to the new start time after a seek - + * we just maintain a offset between realtime and gstreamer time */ mdecoder->seek_offset = start_time; } } else { - DEBUG_TSMF("%s start time %"PRIu64"", get_type(mdecoder), start_time); + DEBUG_TSMF("%s start time %" PRIu64 "", get_type(mdecoder), start_time); /* Always set base/start time to 0. Will use seek offset to translate real buffer times - * back to 0. This allows the video to be started from anywhere and the ability to handle seeks - * without rebuilding the pipeline, etc. since that is costly + * back to 0. This allows the video to be started from anywhere and the ability to handle + * seeks without rebuilding the pipeline, etc. since that is costly */ gst_element_set_base_time(mdecoder->pipe, tsmf_gstreamer_timestamp_ms_to_gst(0)); gst_element_set_start_time(mdecoder->pipe, tsmf_gstreamer_timestamp_ms_to_gst(0)); @@ -805,8 +798,7 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder* decoder, const BYTE *data, UIN mdecoder->seek_offset = start_time; if (!gst_element_seek(mdecoder->pipe, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, - GST_SEEK_TYPE_SET, 0, - GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) + GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) { WLog_ERR(TAG, "seek failed"); } @@ -814,12 +806,14 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder* decoder, const BYTE *data, UIN #if GST_VERSION_MAJOR > 0 if (useTimestamps) - GST_BUFFER_PTS(gst_buf) = sample_time - tsmf_gstreamer_timestamp_ms_to_gst(mdecoder->seek_offset); + GST_BUFFER_PTS(gst_buf) = + sample_time - tsmf_gstreamer_timestamp_ms_to_gst(mdecoder->seek_offset); else GST_BUFFER_PTS(gst_buf) = GST_CLOCK_TIME_NONE; #else if (useTimestamps) - GST_BUFFER_TIMESTAMP(gst_buf) = sample_time - tsmf_gstreamer_timestamp_ms_to_gst(mdecoder->seek_offset); + GST_BUFFER_TIMESTAMP(gst_buf) = + sample_time - tsmf_gstreamer_timestamp_ms_to_gst(mdecoder->seek_offset); else GST_BUFFER_TIMESTAMP(gst_buf) = GST_CLOCK_TIME_NONE; #endif @@ -840,9 +834,11 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder* decoder, const BYTE *data, UIN if (mdecoder->pipe && (GST_STATE(mdecoder->pipe) != GST_STATE_PLAYING)) { - DEBUG_TSMF("%s: state=%s", get_type(mdecoder), gst_element_state_get_name(GST_STATE(mdecoder->pipe))); + DEBUG_TSMF("%s: state=%s", get_type(mdecoder), + gst_element_state_get_name(GST_STATE(mdecoder->pipe))); - DEBUG_TSMF("%s Paused: %"PRIi32" Shutdown: %i Ready: %"PRIi32"", get_type(mdecoder), mdecoder->paused, mdecoder->shutdown, mdecoder->ready); + DEBUG_TSMF("%s Paused: %" PRIi32 " Shutdown: %i Ready: %" PRIi32 "", get_type(mdecoder), + mdecoder->paused, mdecoder->shutdown, mdecoder->ready); if (!mdecoder->paused && !mdecoder->shutdown && mdecoder->ready) tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PLAYING); } @@ -850,9 +846,9 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder* decoder, const BYTE *data, UIN return TRUE; } -static BOOL tsmf_gstreamer_control(ITSMFDecoder* decoder, ITSMFControlMsg control_msg, UINT32 *arg) +static BOOL tsmf_gstreamer_control(ITSMFDecoder* decoder, ITSMFControlMsg control_msg, UINT32* arg) { - TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder; + TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder*)decoder; if (!mdecoder) { @@ -925,7 +921,7 @@ static BOOL tsmf_gstreamer_control(ITSMFDecoder* decoder, ITSMFControlMsg contro static BOOL tsmf_gstreamer_buffer_level(ITSMFDecoder* decoder) { - TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder; + TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder*)decoder; DEBUG_TSMF(""); if (!mdecoder) @@ -942,7 +938,7 @@ static BOOL tsmf_gstreamer_buffer_level(ITSMFDecoder* decoder) static void tsmf_gstreamer_free(ITSMFDecoder* decoder) { - TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder; + TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder*)decoder; DEBUG_TSMF("%s", get_type(mdecoder)); if (mdecoder) @@ -962,7 +958,7 @@ static void tsmf_gstreamer_free(ITSMFDecoder* decoder) static UINT64 tsmf_gstreamer_get_running_time(ITSMFDecoder* decoder) { - TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder; + TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder*)decoder; if (!mdecoder) return 0; @@ -980,38 +976,37 @@ static UINT64 tsmf_gstreamer_get_running_time(ITSMFDecoder* decoder) #else gst_element_query_position(mdecoder->pipe, &fmt, &pos); #endif - return (UINT64) (pos/100 + mdecoder->seek_offset); + return (UINT64)(pos / 100 + mdecoder->seek_offset); } -static BOOL tsmf_gstreamer_update_rendering_area(ITSMFDecoder* decoder, - int newX, int newY, int newWidth, int newHeight, int numRectangles, - RDP_RECT *rectangles) +static BOOL tsmf_gstreamer_update_rendering_area(ITSMFDecoder* decoder, int newX, int newY, + int newWidth, int newHeight, int numRectangles, + RDP_RECT* rectangles) { - TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder; - DEBUG_TSMF("x=%d, y=%d, w=%d, h=%d, rect=%d", newX, newY, newWidth, - newHeight, numRectangles); + TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder*)decoder; + DEBUG_TSMF("x=%d, y=%d, w=%d, h=%d, rect=%d", newX, newY, newWidth, newHeight, numRectangles); if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) { - return tsmf_window_resize(mdecoder, newX, newY, newWidth, newHeight, - numRectangles, rectangles) == 0; + return tsmf_window_resize(mdecoder, newX, newY, newWidth, newHeight, numRectangles, + rectangles) == 0; } return TRUE; } -BOOL tsmf_gstreamer_ack(ITSMFDecoder* decoder, BOOL (*cb)(void *, BOOL), void *stream) +static BOOL tsmf_gstreamer_ack(ITSMFDecoder* decoder, BOOL (*cb)(void*, BOOL), void* stream) { - TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder; + TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder*)decoder; DEBUG_TSMF(""); mdecoder->ack_cb = NULL; mdecoder->stream = stream; return TRUE; } -BOOL tsmf_gstreamer_sync(ITSMFDecoder* decoder, void (*cb)(void *), void *stream) +static BOOL tsmf_gstreamer_sync(ITSMFDecoder* decoder, void (*cb)(void*), void* stream) { - TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder; + TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder*)decoder; DEBUG_TSMF(""); mdecoder->sync_cb = NULL; mdecoder->stream = stream; @@ -1019,16 +1014,16 @@ BOOL tsmf_gstreamer_sync(ITSMFDecoder* decoder, void (*cb)(void *), void *stream } #ifdef BUILTIN_CHANNELS -#define freerdp_tsmf_client_subsystem_entry gstreamer_freerdp_tsmf_client_decoder_subsystem_entry +#define freerdp_tsmf_client_subsystem_entry gstreamer_freerdp_tsmf_client_decoder_subsystem_entry #else -#define freerdp_tsmf_client_subsystem_entry FREERDP_API freerdp_tsmf_client_decoder_subsystem_entry +#define freerdp_tsmf_client_subsystem_entry FREERDP_API freerdp_tsmf_client_decoder_subsystem_entry #endif ITSMFDecoder* freerdp_tsmf_client_subsystem_entry(void) { - TSMFGstreamerDecoder *decoder; + TSMFGstreamerDecoder* decoder; -#if GST_CHECK_VERSION(0,10,31) +#if GST_CHECK_VERSION(0, 10, 31) if (!gst_is_initialized()) { gst_init(NULL, NULL); @@ -1059,7 +1054,7 @@ ITSMFDecoder* freerdp_tsmf_client_subsystem_entry(void) decoder->paused = FALSE; decoder->gstVolume = 0.5; decoder->gstMuted = FALSE; - decoder->state = GST_STATE_VOID_PENDING; /* No real state yet */ + decoder->state = GST_STATE_VOID_PENDING; /* No real state yet */ decoder->last_sample_start_time = 0; decoder->last_sample_end_time = 0; decoder->seek_offset = 0; @@ -1071,5 +1066,5 @@ ITSMFDecoder* freerdp_tsmf_client_subsystem_entry(void) return NULL; } - return (ITSMFDecoder*) decoder; + return (ITSMFDecoder*)decoder; } diff --git a/channels/tsmf/client/gstreamer/tsmf_platform.h b/channels/tsmf/client/gstreamer/tsmf_platform.h index 7fb6be1..b6f0b33 100644 --- a/channels/tsmf/client/gstreamer/tsmf_platform.h +++ b/channels/tsmf/client/gstreamer/tsmf_platform.h @@ -17,7 +17,7 @@ * 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_CHANNEL_TSMF_CLIENT_GST_PLATFORM_H #define FREERDP_CHANNEL_TSMF_CLIENT_GST_PLATFORM_H @@ -34,13 +34,13 @@ typedef struct _TSMFGstreamerDecoder gint64 duration; GstState state; - GstCaps *gst_caps; + GstCaps* gst_caps; - GstElement *pipe; - GstElement *src; - GstElement *queue; - GstElement *outsink; - GstElement *volume; + GstElement* pipe; + GstElement* src; + GstElement* queue; + GstElement* outsink; + GstElement* volume; BOOL ready; BOOL paused; @@ -53,18 +53,16 @@ typedef struct _TSMFGstreamerDecoder BOOL gstMuted; int pipeline_start_time_valid; /* We've set the start time and have not reset the pipeline */ - int shutdown; /* The decoder stream is shutting down */ + int shutdown; /* The decoder stream is shutting down */ - void *platform; + void* platform; - BOOL (*ack_cb)(void *,BOOL); - void (*sync_cb)(void *); - void *stream; + BOOL (*ack_cb)(void*, BOOL); + void (*sync_cb)(void*); + void* stream; } TSMFGstreamerDecoder; -const char* get_type(TSMFGstreamerDecoder* mdecoder); - const char* tsmf_platform_get_video_sink(void); const char* tsmf_platform_get_audio_sink(void); @@ -74,8 +72,8 @@ int tsmf_platform_register_handler(TSMFGstreamerDecoder* decoder); int tsmf_platform_free(TSMFGstreamerDecoder* decoder); int tsmf_window_create(TSMFGstreamerDecoder* decoder); -int tsmf_window_resize(TSMFGstreamerDecoder* decoder, int x, int y, - int width, int height, int nr_rect, RDP_RECT *visible); +int tsmf_window_resize(TSMFGstreamerDecoder* decoder, int x, int y, int width, int height, + int nr_rect, RDP_RECT* visible); int tsmf_window_destroy(TSMFGstreamerDecoder* decoder); int tsmf_window_map(TSMFGstreamerDecoder* decoder); diff --git a/channels/tsmf/client/oss/tsmf_oss.c b/channels/tsmf/client/oss/tsmf_oss.c index 67a7927..774affb 100644 --- a/channels/tsmf/client/oss/tsmf_oss.c +++ b/channels/tsmf/client/oss/tsmf_oss.c @@ -46,7 +46,6 @@ #include "tsmf_audio.h" - typedef struct _TSMFOSSAudioDevice { ITSMFAudioDevice iface; @@ -61,12 +60,10 @@ typedef struct _TSMFOSSAudioDevice UINT32 data_size_last; } TSMFOssAudioDevice; - #define OSS_LOG_ERR(_text, _error) \ - if (_error != 0) \ + if (_error != 0) \ WLog_ERR(TAG, "%s: %i - %s", _text, _error, strerror(_error)); - static BOOL tsmf_oss_open(ITSMFAudioDevice* audio, const char* device) { int tmp; @@ -75,7 +72,7 @@ static BOOL tsmf_oss_open(ITSMFAudioDevice* audio, const char* device) if (oss == NULL || oss->pcm_handle != -1) return FALSE; - if (device == NULL) /* Default device. */ + if (device == NULL) /* Default device. */ { strncpy(oss->dev_name, "/dev/dsp", sizeof(oss->dev_name)); } @@ -161,7 +158,7 @@ static BOOL tsmf_oss_set_format(ITSMFAudioDevice* audio, UINT32 sample_rate, UIN if (ioctl(oss->pcm_handle, SNDCTL_DSP_SETFRAGMENT, &tmp) == -1) OSS_LOG_ERR("SNDCTL_DSP_SETFRAGMENT failed", errno); - DEBUG_TSMF("sample_rate %"PRIu32" channels %"PRIu32" bits_per_sample %"PRIu32"", + DEBUG_TSMF("sample_rate %" PRIu32 " channels %" PRIu32 " bits_per_sample %" PRIu32 "", sample_rate, channels, bits_per_sample); return TRUE; } @@ -171,7 +168,7 @@ static BOOL tsmf_oss_play(ITSMFAudioDevice* audio, const BYTE* data, UINT32 data int status; UINT32 offset; TSMFOssAudioDevice* oss = (TSMFOssAudioDevice*)audio; - DEBUG_TSMF("tsmf_oss_play: data_size %"PRIu32"", data_size); + DEBUG_TSMF("tsmf_oss_play: data_size %" PRIu32 "", data_size); if (oss == NULL || oss->pcm_handle == -1) return FALSE; @@ -206,8 +203,8 @@ static UINT64 tsmf_oss_get_latency(ITSMFAudioDevice* audio) if (oss == NULL) return 0; - //latency = ((oss->data_size_last / (oss->bits_per_sample / 8)) * oss->sample_rate); - //WLog_INFO(TAG, "latency: %zu", latency); + // latency = ((oss->data_size_last / (oss->bits_per_sample / 8)) * oss->sample_rate); + // WLog_INFO(TAG, "latency: %zu", latency); return latency; } @@ -233,9 +230,10 @@ static void tsmf_oss_free(ITSMFAudioDevice* audio) } #ifdef BUILTIN_CHANNELS -#define freerdp_tsmf_client_audio_subsystem_entry oss_freerdp_tsmf_client_audio_subsystem_entry +#define freerdp_tsmf_client_audio_subsystem_entry oss_freerdp_tsmf_client_audio_subsystem_entry #else -#define freerdp_tsmf_client_audio_subsystem_entry FREERDP_API freerdp_tsmf_client_audio_subsystem_entry +#define freerdp_tsmf_client_audio_subsystem_entry \ + FREERDP_API freerdp_tsmf_client_audio_subsystem_entry #endif ITSMFAudioDevice* freerdp_tsmf_client_audio_subsystem_entry(void) diff --git a/channels/tsmf/client/pulse/tsmf_pulse.c b/channels/tsmf/client/pulse/tsmf_pulse.c index e63477c..b2f567e 100644 --- a/channels/tsmf/client/pulse/tsmf_pulse.c +++ b/channels/tsmf/client/pulse/tsmf_pulse.c @@ -45,7 +45,7 @@ typedef struct _TSMFPulseAudioDevice static void tsmf_pulse_context_state_callback(pa_context* context, void* userdata) { - TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) userdata; + TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*)userdata; pa_context_state_t state; state = pa_context_get_state(context); @@ -77,8 +77,7 @@ static BOOL tsmf_pulse_connect(TSMFPulseAudioDevice* pulse) if (pa_context_connect(pulse->context, NULL, 0, NULL)) { - WLog_ERR(TAG, "pa_context_connect failed (%d)", - pa_context_errno(pulse->context)); + WLog_ERR(TAG, "pa_context_connect failed (%d)", pa_context_errno(pulse->context)); return FALSE; } @@ -87,8 +86,7 @@ static BOOL tsmf_pulse_connect(TSMFPulseAudioDevice* pulse) if (pa_threaded_mainloop_start(pulse->mainloop) < 0) { pa_threaded_mainloop_unlock(pulse->mainloop); - WLog_ERR(TAG, "pa_threaded_mainloop_start failed (%d)", - pa_context_errno(pulse->context)); + WLog_ERR(TAG, "pa_threaded_mainloop_start failed (%d)", pa_context_errno(pulse->context)); return FALSE; } @@ -101,8 +99,7 @@ static BOOL tsmf_pulse_connect(TSMFPulseAudioDevice* pulse) if (!PA_CONTEXT_IS_GOOD(state)) { - DEBUG_TSMF("bad context state (%d)", - pa_context_errno(pulse->context)); + DEBUG_TSMF("bad context state (%d)", pa_context_errno(pulse->context)); break; } @@ -125,7 +122,7 @@ static BOOL tsmf_pulse_connect(TSMFPulseAudioDevice* pulse) static BOOL tsmf_pulse_open(ITSMFAudioDevice* audio, const char* device) { - TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio; + TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*)audio; if (device) { @@ -162,7 +159,7 @@ static BOOL tsmf_pulse_open(ITSMFAudioDevice* audio, const char* device) static void tsmf_pulse_stream_success_callback(pa_stream* stream, int success, void* userdata) { - TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) userdata; + TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*)userdata; pa_threaded_mainloop_signal(pulse->mainloop, 0); } @@ -181,7 +178,7 @@ static void tsmf_pulse_wait_for_operation(TSMFPulseAudioDevice* pulse, pa_operat static void tsmf_pulse_stream_state_callback(pa_stream* stream, void* userdata) { - TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) userdata; + TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*)userdata; pa_stream_state_t state; state = pa_stream_get_state(stream); @@ -206,8 +203,8 @@ static void tsmf_pulse_stream_state_callback(pa_stream* stream, void* userdata) static void tsmf_pulse_stream_request_callback(pa_stream* stream, size_t length, void* userdata) { - TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) userdata; - DEBUG_TSMF("%"PRIdz"", length); + TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*)userdata; + DEBUG_TSMF("%" PRIdz "", length); pa_threaded_mainloop_signal(pulse->mainloop, 0); } @@ -219,8 +216,8 @@ static BOOL tsmf_pulse_close_stream(TSMFPulseAudioDevice* pulse) DEBUG_TSMF(""); pa_threaded_mainloop_lock(pulse->mainloop); pa_stream_set_write_callback(pulse->stream, NULL, NULL); - tsmf_pulse_wait_for_operation(pulse, - pa_stream_drain(pulse->stream, tsmf_pulse_stream_success_callback, pulse)); + tsmf_pulse_wait_for_operation( + pulse, pa_stream_drain(pulse->stream, tsmf_pulse_stream_success_callback, pulse)); pa_stream_disconnect(pulse->stream); pa_stream_unref(pulse->stream); pulse->stream = NULL; @@ -238,35 +235,30 @@ static BOOL tsmf_pulse_open_stream(TSMFPulseAudioDevice* pulse) DEBUG_TSMF(""); pa_threaded_mainloop_lock(pulse->mainloop); - pulse->stream = pa_stream_new(pulse->context, "freerdp", - &pulse->sample_spec, NULL); + pulse->stream = pa_stream_new(pulse->context, "freerdp", &pulse->sample_spec, NULL); if (!pulse->stream) { pa_threaded_mainloop_unlock(pulse->mainloop); - WLog_ERR(TAG, "pa_stream_new failed (%d)", - pa_context_errno(pulse->context)); + WLog_ERR(TAG, "pa_stream_new failed (%d)", pa_context_errno(pulse->context)); return FALSE; } - pa_stream_set_state_callback(pulse->stream, - tsmf_pulse_stream_state_callback, pulse); - pa_stream_set_write_callback(pulse->stream, - tsmf_pulse_stream_request_callback, pulse); + pa_stream_set_state_callback(pulse->stream, tsmf_pulse_stream_state_callback, pulse); + pa_stream_set_write_callback(pulse->stream, tsmf_pulse_stream_request_callback, pulse); buffer_attr.maxlength = pa_usec_to_bytes(500000, &pulse->sample_spec); buffer_attr.tlength = pa_usec_to_bytes(250000, &pulse->sample_spec); - buffer_attr.prebuf = (UINT32) - 1; - buffer_attr.minreq = (UINT32) - 1; - buffer_attr.fragsize = (UINT32) - 1; - - if (pa_stream_connect_playback(pulse->stream, - pulse->device[0] ? pulse->device : NULL, &buffer_attr, - PA_STREAM_ADJUST_LATENCY | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE, - NULL, NULL) < 0) + buffer_attr.prebuf = (UINT32)-1; + buffer_attr.minreq = (UINT32)-1; + buffer_attr.fragsize = (UINT32)-1; + + if (pa_stream_connect_playback( + pulse->stream, pulse->device[0] ? pulse->device : NULL, &buffer_attr, + PA_STREAM_ADJUST_LATENCY | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE, + NULL, NULL) < 0) { pa_threaded_mainloop_unlock(pulse->mainloop); - WLog_ERR(TAG, "pa_stream_connect_playback failed (%d)", - pa_context_errno(pulse->context)); + WLog_ERR(TAG, "pa_stream_connect_playback failed (%d)", pa_context_errno(pulse->context)); return FALSE; } @@ -279,8 +271,7 @@ static BOOL tsmf_pulse_open_stream(TSMFPulseAudioDevice* pulse) if (!PA_STREAM_IS_GOOD(state)) { - WLog_ERR(TAG, "bad stream state (%d)", - pa_context_errno(pulse->context)); + WLog_ERR(TAG, "bad stream state (%d)", pa_context_errno(pulse->context)); break; } @@ -301,11 +292,11 @@ static BOOL tsmf_pulse_open_stream(TSMFPulseAudioDevice* pulse) } } -static BOOL tsmf_pulse_set_format(ITSMFAudioDevice* audio, - UINT32 sample_rate, UINT32 channels, UINT32 bits_per_sample) +static BOOL tsmf_pulse_set_format(ITSMFAudioDevice* audio, UINT32 sample_rate, UINT32 channels, + UINT32 bits_per_sample) { - TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio; - DEBUG_TSMF("sample_rate %"PRIu32" channels %"PRIu32" bits_per_sample %"PRIu32"", + TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*)audio; + DEBUG_TSMF("sample_rate %" PRIu32 " channels %" PRIu32 " bits_per_sample %" PRIu32 "", sample_rate, channels, bits_per_sample); pulse->sample_spec.rate = sample_rate; pulse->sample_spec.channels = channels; @@ -315,11 +306,11 @@ static BOOL tsmf_pulse_set_format(ITSMFAudioDevice* audio, static BOOL tsmf_pulse_play(ITSMFAudioDevice* audio, const BYTE* data, UINT32 data_size) { - TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio; + TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*)audio; const BYTE* src; size_t len; int ret; - DEBUG_TSMF("data_size %"PRIu32"", data_size); + DEBUG_TSMF("data_size %" PRIu32 "", data_size); if (pulse->stream) { @@ -334,7 +325,7 @@ static BOOL tsmf_pulse_play(ITSMFAudioDevice* audio, const BYTE* data, UINT32 da pa_threaded_mainloop_wait(pulse->mainloop); } - if (len == (size_t) -1) + if (len == (size_t)-1) break; if (len > data_size) @@ -344,8 +335,7 @@ static BOOL tsmf_pulse_play(ITSMFAudioDevice* audio, const BYTE* data, UINT32 da if (ret < 0) { - DEBUG_TSMF("pa_stream_write failed (%d)", - pa_context_errno(pulse->context)); + DEBUG_TSMF("pa_stream_write failed (%d)", pa_context_errno(pulse->context)); break; } @@ -363,7 +353,7 @@ static UINT64 tsmf_pulse_get_latency(ITSMFAudioDevice* audio) { pa_usec_t usec; UINT64 latency = 0; - TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio; + TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*)audio; if (pulse->stream && pa_stream_get_latency(pulse->stream, &usec, NULL) == 0) { @@ -375,17 +365,17 @@ static UINT64 tsmf_pulse_get_latency(ITSMFAudioDevice* audio) static BOOL tsmf_pulse_flush(ITSMFAudioDevice* audio) { - TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio; + TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*)audio; pa_threaded_mainloop_lock(pulse->mainloop); - tsmf_pulse_wait_for_operation(pulse, - pa_stream_flush(pulse->stream, tsmf_pulse_stream_success_callback, pulse)); + tsmf_pulse_wait_for_operation( + pulse, pa_stream_flush(pulse->stream, tsmf_pulse_stream_success_callback, pulse)); pa_threaded_mainloop_unlock(pulse->mainloop); return TRUE; } static void tsmf_pulse_free(ITSMFAudioDevice* audio) { - TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio; + TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*)audio; DEBUG_TSMF(""); tsmf_pulse_close_stream(pulse); @@ -417,7 +407,7 @@ FREERDP_API ITSMFAudioDevice* freerdp_tsmf_client_audio_subsystem_entry(void) #endif { TSMFPulseAudioDevice* pulse; - pulse = (TSMFPulseAudioDevice*) calloc(1, sizeof(TSMFPulseAudioDevice)); + pulse = (TSMFPulseAudioDevice*)calloc(1, sizeof(TSMFPulseAudioDevice)); if (!pulse) return NULL; @@ -428,6 +418,5 @@ FREERDP_API ITSMFAudioDevice* freerdp_tsmf_client_audio_subsystem_entry(void) pulse->iface.GetLatency = tsmf_pulse_get_latency; pulse->iface.Flush = tsmf_pulse_flush; pulse->iface.Free = tsmf_pulse_free; - return (ITSMFAudioDevice*) pulse; + return (ITSMFAudioDevice*)pulse; } - diff --git a/channels/tsmf/client/tsmf_audio.c b/channels/tsmf/client/tsmf_audio.c index a71b016..9f0bb32 100644 --- a/channels/tsmf/client/tsmf_audio.c +++ b/channels/tsmf/client/tsmf_audio.c @@ -32,7 +32,8 @@ static ITSMFAudioDevice* tsmf_load_audio_device_by_name(const char* name, const ITSMFAudioDevice* audio; TSMF_AUDIO_DEVICE_ENTRY entry; - entry = (TSMF_AUDIO_DEVICE_ENTRY) freerdp_load_channel_addin_entry("tsmf", (LPSTR) name, "audio", 0); + entry = + (TSMF_AUDIO_DEVICE_ENTRY)(void*)freerdp_load_channel_addin_entry("tsmf", name, "audio", 0); if (!entry) return NULL; @@ -84,7 +85,7 @@ ITSMFAudioDevice* tsmf_load_audio_device(const char* name, const char* device) audio = tsmf_load_audio_device_by_name("alsa", device); #endif } - + if (audio == NULL) { WLog_ERR(TAG, "no sound device."); @@ -96,4 +97,3 @@ ITSMFAudioDevice* tsmf_load_audio_device(const char* name, const char* device) return audio; } - diff --git a/channels/tsmf/client/tsmf_audio.h b/channels/tsmf/client/tsmf_audio.h index d589d54..e7ae68c 100644 --- a/channels/tsmf/client/tsmf_audio.h +++ b/channels/tsmf/client/tsmf_audio.h @@ -29,12 +29,12 @@ struct _ITSMFAudioDevice /* Open the audio device. */ BOOL (*Open)(ITSMFAudioDevice* audio, const char* device); /* Set the audio data format. */ - BOOL (*SetFormat)(ITSMFAudioDevice* audio, UINT32 sample_rate, UINT32 channels, - UINT32 bits_per_sample); + BOOL(*SetFormat) + (ITSMFAudioDevice* audio, UINT32 sample_rate, UINT32 channels, UINT32 bits_per_sample); /* Play audio data. */ BOOL (*Play)(ITSMFAudioDevice* audio, const BYTE* data, UINT32 data_size); /* Get the latency of the last written sample, in 100ns */ - UINT64(*GetLatency)(ITSMFAudioDevice* audio); + UINT64 (*GetLatency)(ITSMFAudioDevice* audio); /* Change the playback volume level */ BOOL (*ChangeVolume)(ITSMFAudioDevice* audio, UINT32 newVolume, UINT32 muted); /* Flush queued audio data */ diff --git a/channels/tsmf/client/tsmf_codec.c b/channels/tsmf/client/tsmf_codec.c index 0a4f41d..6672396 100644 --- a/channels/tsmf/client/tsmf_codec.c +++ b/channels/tsmf/client/tsmf_codec.c @@ -43,260 +43,212 @@ typedef struct _TSMFMediaTypeMap int type; } TSMFMediaTypeMap; -static const TSMFMediaTypeMap tsmf_major_type_map[] = -{ +static const TSMFMediaTypeMap tsmf_major_type_map[] = { /* 73646976-0000-0010-8000-00AA00389B71 */ - { - { 0x76, 0x69, 0x64, 0x73, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 }, - "MEDIATYPE_Video", - TSMF_MAJOR_TYPE_VIDEO - }, + { { 0x76, 0x69, 0x64, 0x73, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71 }, + "MEDIATYPE_Video", + TSMF_MAJOR_TYPE_VIDEO }, /* 73647561-0000-0010-8000-00AA00389B71 */ - { - { 0x61, 0x75, 0x64, 0x73, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 }, - "MEDIATYPE_Audio", - TSMF_MAJOR_TYPE_AUDIO - }, + { { 0x61, 0x75, 0x64, 0x73, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71 }, + "MEDIATYPE_Audio", + TSMF_MAJOR_TYPE_AUDIO }, - { - { 0 }, - "Unknown", - TSMF_MAJOR_TYPE_UNKNOWN - } + { { 0 }, "Unknown", TSMF_MAJOR_TYPE_UNKNOWN } }; -static const TSMFMediaTypeMap tsmf_sub_type_map[] = -{ +static const TSMFMediaTypeMap tsmf_sub_type_map[] = { /* 31435657-0000-0010-8000-00AA00389B71 */ - { - { 0x57, 0x56, 0x43, 0x31, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 }, - "MEDIASUBTYPE_WVC1", - TSMF_SUB_TYPE_WVC1 - }, + { { 0x57, 0x56, 0x43, 0x31, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71 }, + "MEDIASUBTYPE_WVC1", + TSMF_SUB_TYPE_WVC1 }, - /* 00000160-0000-0010-8000-00AA00389B71 */ - { - { 0x60, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 }, - "MEDIASUBTYPE_WMAudioV1", /* V7, V8 has the same GUID */ - TSMF_SUB_TYPE_WMA1 - }, + /* 00000160-0000-0010-8000-00AA00389B71 */ + { { 0x60, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71 }, + "MEDIASUBTYPE_WMAudioV1", /* V7, V8 has the same GUID */ + TSMF_SUB_TYPE_WMA1 }, /* 00000161-0000-0010-8000-00AA00389B71 */ - { - { 0x61, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 }, - "MEDIASUBTYPE_WMAudioV2", /* V7, V8 has the same GUID */ - TSMF_SUB_TYPE_WMA2 - }, + { { 0x61, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71 }, + "MEDIASUBTYPE_WMAudioV2", /* V7, V8 has the same GUID */ + TSMF_SUB_TYPE_WMA2 }, /* 00000162-0000-0010-8000-00AA00389B71 */ - { - { 0x62, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 }, - "MEDIASUBTYPE_WMAudioV9", - TSMF_SUB_TYPE_WMA9 - }, + { { 0x62, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71 }, + "MEDIASUBTYPE_WMAudioV9", + TSMF_SUB_TYPE_WMA9 }, /* 00000055-0000-0010-8000-00AA00389B71 */ - { - { 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 }, - "MEDIASUBTYPE_MP3", - TSMF_SUB_TYPE_MP3 - }, + { { 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71 }, + "MEDIASUBTYPE_MP3", + TSMF_SUB_TYPE_MP3 }, /* E06D802B-DB46-11CF-B4D1-00805F6CBBEA */ - { - { 0x2B, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, 0xEA }, - "MEDIASUBTYPE_MPEG2_AUDIO", - TSMF_SUB_TYPE_MP2A - }, + { { 0x2B, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, + 0xEA }, + "MEDIASUBTYPE_MPEG2_AUDIO", + TSMF_SUB_TYPE_MP2A }, /* E06D8026-DB46-11CF-B4D1-00805F6CBBEA */ - { - { 0x26, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, 0xEA }, - "MEDIASUBTYPE_MPEG2_VIDEO", - TSMF_SUB_TYPE_MP2V - }, + { { 0x26, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, + 0xEA }, + "MEDIASUBTYPE_MPEG2_VIDEO", + TSMF_SUB_TYPE_MP2V }, /* 31564D57-0000-0010-8000-00AA00389B71 */ - { - { 0x57, 0x4D, 0x56, 0x31, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 }, - "MEDIASUBTYPE_WMV1", - TSMF_SUB_TYPE_WMV1 - }, + { { 0x57, 0x4D, 0x56, 0x31, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71 }, + "MEDIASUBTYPE_WMV1", + TSMF_SUB_TYPE_WMV1 }, /* 32564D57-0000-0010-8000-00AA00389B71 */ - { - { 0x57, 0x4D, 0x56, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 }, - "MEDIASUBTYPE_WMV2", - TSMF_SUB_TYPE_WMV2 - }, + { { 0x57, 0x4D, 0x56, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71 }, + "MEDIASUBTYPE_WMV2", + TSMF_SUB_TYPE_WMV2 }, /* 33564D57-0000-0010-8000-00AA00389B71 */ - { - { 0x57, 0x4D, 0x56, 0x33, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 }, - "MEDIASUBTYPE_WMV3", - TSMF_SUB_TYPE_WMV3 - }, + { { 0x57, 0x4D, 0x56, 0x33, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71 }, + "MEDIASUBTYPE_WMV3", + TSMF_SUB_TYPE_WMV3 }, /* 00001610-0000-0010-8000-00AA00389B71 */ - { - { 0x10, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 }, - "MEDIASUBTYPE_MPEG_HEAAC", - TSMF_SUB_TYPE_AAC - }, + { { 0x10, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71 }, + "MEDIASUBTYPE_MPEG_HEAAC", + TSMF_SUB_TYPE_AAC }, /* 34363248-0000-0010-8000-00AA00389B71 */ - { - { 0x48, 0x32, 0x36, 0x34, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 }, - "MEDIASUBTYPE_H264", - TSMF_SUB_TYPE_H264 - }, + { { 0x48, 0x32, 0x36, 0x34, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71 }, + "MEDIASUBTYPE_H264", + TSMF_SUB_TYPE_H264 }, /* 31435641-0000-0010-8000-00AA00389B71 */ - { - { 0x41, 0x56, 0x43, 0x31, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 }, - "MEDIASUBTYPE_AVC1", - TSMF_SUB_TYPE_AVC1 - }, + { { 0x41, 0x56, 0x43, 0x31, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71 }, + "MEDIASUBTYPE_AVC1", + TSMF_SUB_TYPE_AVC1 }, /* 3334504D-0000-0010-8000-00AA00389B71 */ - { - { 0x4D, 0x50, 0x34, 0x33, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 }, - "MEDIASUBTYPE_MP43", - TSMF_SUB_TYPE_MP43 - }, + { { 0x4D, 0x50, 0x34, 0x33, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71 }, + "MEDIASUBTYPE_MP43", + TSMF_SUB_TYPE_MP43 }, /* 5634504D-0000-0010-8000-00AA00389B71 */ - { - { 0x4D, 0x50, 0x34, 0x56, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 }, - "MEDIASUBTYPE_MP4S", - TSMF_SUB_TYPE_MP4S - }, + { { 0x4D, 0x50, 0x34, 0x56, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71 }, + "MEDIASUBTYPE_MP4S", + TSMF_SUB_TYPE_MP4S }, /* 3234504D-0000-0010-8000-00AA00389B71 */ - { - { 0x4D, 0x50, 0x34, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 }, - "MEDIASUBTYPE_MP42", - TSMF_SUB_TYPE_MP42 - }, + { { 0x4D, 0x50, 0x34, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71 }, + "MEDIASUBTYPE_MP42", + TSMF_SUB_TYPE_MP42 }, /* 3253344D-0000-0010-8000-00AA00389B71 */ - { - { 0x4D, 0x34, 0x53, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 }, - "MEDIASUBTYPE_MP42", - TSMF_SUB_TYPE_M4S2 - }, + { { 0x4D, 0x34, 0x53, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71 }, + "MEDIASUBTYPE_MP42", + TSMF_SUB_TYPE_M4S2 }, /* E436EB81-524F-11CE-9F53-0020AF0BA770 */ - { - { 0x81, 0xEB, 0x36, 0xE4, 0x4F, 0x52, 0xCE, 0x11, 0x9F, 0x53, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70 }, - "MEDIASUBTYPE_MP1V", - TSMF_SUB_TYPE_MP1V - }, + { { 0x81, 0xEB, 0x36, 0xE4, 0x4F, 0x52, 0xCE, 0x11, 0x9F, 0x53, 0x00, 0x20, 0xAF, 0x0B, 0xA7, + 0x70 }, + "MEDIASUBTYPE_MP1V", + TSMF_SUB_TYPE_MP1V }, /* 00000050-0000-0010-8000-00AA00389B71 */ - { - { 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 }, - "MEDIASUBTYPE_MP1A", - TSMF_SUB_TYPE_MP1A - }, + { { 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71 }, + "MEDIASUBTYPE_MP1A", + TSMF_SUB_TYPE_MP1A }, /* E06D802C-DB46-11CF-B4D1-00805F6CBBEA */ - { - { 0x2C, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, 0xEA }, - "MEDIASUBTYPE_DOLBY_AC3", - TSMF_SUB_TYPE_AC3 - }, + { { 0x2C, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, + 0xEA }, + "MEDIASUBTYPE_DOLBY_AC3", + TSMF_SUB_TYPE_AC3 }, /* 32595559-0000-0010-8000-00AA00389B71 */ - { - { 0x59, 0x55, 0x59, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 }, - "MEDIASUBTYPE_YUY2", - TSMF_SUB_TYPE_YUY2 - }, + { { 0x59, 0x55, 0x59, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71 }, + "MEDIASUBTYPE_YUY2", + TSMF_SUB_TYPE_YUY2 }, /* Opencodec IDS */ - { - {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71}, - "MEDIASUBTYPE_FLAC", - TSMF_SUB_TYPE_FLAC - }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71 }, + "MEDIASUBTYPE_FLAC", + TSMF_SUB_TYPE_FLAC }, - { - {0x61, 0x34, 0x70, 0x6D, 0x7A, 0x76, 0x4D, 0x49, 0xB4, 0x78, 0xF2, 0x9D, 0x25, 0xDC, 0x90, 0x37}, - "MEDIASUBTYPE_OGG", - TSMF_SUB_TYPE_OGG - }, + { { 0x61, 0x34, 0x70, 0x6D, 0x7A, 0x76, 0x4D, 0x49, 0xB4, 0x78, 0xF2, 0x9D, 0x25, 0xDC, 0x90, + 0x37 }, + "MEDIASUBTYPE_OGG", + TSMF_SUB_TYPE_OGG }, - { - {0x4D, 0x34, 0x53, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71}, - "MEDIASUBTYPE_H263", - TSMF_SUB_TYPE_H263 - }, + { { 0x4D, 0x34, 0x53, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71 }, + "MEDIASUBTYPE_H263", + TSMF_SUB_TYPE_H263 }, /* WebMMF codec IDS */ - { - {0x56, 0x50, 0x38, 0x30, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71}, - "MEDIASUBTYPE_VP8", - TSMF_SUB_TYPE_VP8 - }, + { { 0x56, 0x50, 0x38, 0x30, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71 }, + "MEDIASUBTYPE_VP8", + TSMF_SUB_TYPE_VP8 }, - { - {0x0B, 0xD1, 0x2F, 0x8D, 0x41, 0x58, 0x6B, 0x4A, 0x89, 0x05, 0x58, 0x8F, 0xEC, 0x1A, 0xDE, 0xD9}, - "MEDIASUBTYPE_OGG", - TSMF_SUB_TYPE_OGG - }, + { { 0x0B, 0xD1, 0x2F, 0x8D, 0x41, 0x58, 0x6B, 0x4A, 0x89, 0x05, 0x58, 0x8F, 0xEC, 0x1A, 0xDE, + 0xD9 }, + "MEDIASUBTYPE_OGG", + TSMF_SUB_TYPE_OGG }, - { - { 0 }, - "Unknown", - TSMF_SUB_TYPE_UNKNOWN - } + { { 0 }, "Unknown", TSMF_SUB_TYPE_UNKNOWN } }; -static const TSMFMediaTypeMap tsmf_format_type_map[] = -{ +static const TSMFMediaTypeMap tsmf_format_type_map[] = { /* AED4AB2D-7326-43CB-9464-C879CAB9C43D */ - { - { 0x2D, 0xAB, 0xD4, 0xAE, 0x26, 0x73, 0xCB, 0x43, 0x94, 0x64, 0xC8, 0x79, 0xCA, 0xB9, 0xC4, 0x3D }, - "FORMAT_MFVideoFormat", - TSMF_FORMAT_TYPE_MFVIDEOFORMAT - }, + { { 0x2D, 0xAB, 0xD4, 0xAE, 0x26, 0x73, 0xCB, 0x43, 0x94, 0x64, 0xC8, 0x79, 0xCA, 0xB9, 0xC4, + 0x3D }, + "FORMAT_MFVideoFormat", + TSMF_FORMAT_TYPE_MFVIDEOFORMAT }, /* 05589F81-C356-11CE-BF01-00AA0055595A */ - { - { 0x81, 0x9F, 0x58, 0x05, 0x56, 0xC3, 0xCE, 0x11, 0xBF, 0x01, 0x00, 0xAA, 0x00, 0x55, 0x59, 0x5A }, - "FORMAT_WaveFormatEx", - TSMF_FORMAT_TYPE_WAVEFORMATEX - }, + { { 0x81, 0x9F, 0x58, 0x05, 0x56, 0xC3, 0xCE, 0x11, 0xBF, 0x01, 0x00, 0xAA, 0x00, 0x55, 0x59, + 0x5A }, + "FORMAT_WaveFormatEx", + TSMF_FORMAT_TYPE_WAVEFORMATEX }, /* E06D80E3-DB46-11CF-B4D1-00805F6CBBEA */ - { - { 0xE3, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, 0xEA }, - "FORMAT_MPEG2_VIDEO", - TSMF_FORMAT_TYPE_MPEG2VIDEOINFO - }, + { { 0xE3, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, + 0xEA }, + "FORMAT_MPEG2_VIDEO", + TSMF_FORMAT_TYPE_MPEG2VIDEOINFO }, /* F72A76A0-EB0A-11D0-ACE4-0000C0CC16BA */ - { - { 0xA0, 0x76, 0x2A, 0xF7, 0x0A, 0xEB, 0xD0, 0x11, 0xAC, 0xE4, 0x00, 0x00, 0xC0, 0xCC, 0x16, 0xBA }, - "FORMAT_VideoInfo2", - TSMF_FORMAT_TYPE_VIDEOINFO2 - }, + { { 0xA0, 0x76, 0x2A, 0xF7, 0x0A, 0xEB, 0xD0, 0x11, 0xAC, 0xE4, 0x00, 0x00, 0xC0, 0xCC, 0x16, + 0xBA }, + "FORMAT_VideoInfo2", + TSMF_FORMAT_TYPE_VIDEOINFO2 }, /* 05589F82-C356-11CE-BF01-00AA0055595A */ - { - { 0x82, 0x9F, 0x58, 0x05, 0x56, 0xC3, 0xCE, 0x11, 0xBF, 0x01, 0x00, 0xAA, 0x00, 0x55, 0x59, 0x5A }, - "FORMAT_MPEG1_VIDEO", - TSMF_FORMAT_TYPE_MPEG1VIDEOINFO - }, + { { 0x82, 0x9F, 0x58, 0x05, 0x56, 0xC3, 0xCE, 0x11, 0xBF, 0x01, 0x00, 0xAA, 0x00, 0x55, 0x59, + 0x5A }, + "FORMAT_MPEG1_VIDEO", + TSMF_FORMAT_TYPE_MPEG1VIDEOINFO }, - { - { 0 }, - "Unknown", - TSMF_FORMAT_TYPE_UNKNOWN - } + { { 0 }, "Unknown", TSMF_FORMAT_TYPE_UNKNOWN } }; static void tsmf_print_guid(const BYTE* guid) @@ -304,21 +256,20 @@ static void tsmf_print_guid(const BYTE* guid) #ifdef WITH_DEBUG_TSMF char guidString[37]; - snprintf(guidString, sizeof(guidString), "%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"-%02"PRIX8"%02"PRIX8"-%02"PRIX8"%02"PRIX8"-%02"PRIX8"%02"PRIX8"-%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"", - guid[3], guid[2], guid[1], guid[0], - guid[5], guid[4], - guid[7], guid[6], - guid[8], guid[9], - guid[10], guid[11], guid[12], guid[13], guid[14], guid[15] - ); - + snprintf(guidString, sizeof(guidString), + "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "-%02" PRIX8 "%02" PRIX8 "-%02" PRIX8 + "%02" PRIX8 "-%02" PRIX8 "%02" PRIX8 "-%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 + "%02" PRIX8 "%02" PRIX8 "", + guid[3], guid[2], guid[1], guid[0], guid[5], guid[4], guid[7], guid[6], guid[8], + guid[9], guid[10], guid[11], guid[12], guid[13], guid[14], guid[15]); WLog_INFO(TAG, "%s", guidString); #endif } /* http://msdn.microsoft.com/en-us/library/dd318229.aspx */ -static UINT32 tsmf_codec_parse_BITMAPINFOHEADER(TS_AM_MEDIA_TYPE* mediatype, wStream* s, BOOL bypass) +static UINT32 tsmf_codec_parse_BITMAPINFOHEADER(TS_AM_MEDIA_TYPE* mediatype, wStream* s, + BOOL bypass) { UINT32 biSize; UINT32 biWidth; @@ -338,7 +289,7 @@ static UINT32 tsmf_codec_parse_BITMAPINFOHEADER(TS_AM_MEDIA_TYPE* mediatype, wSt mediatype->Height = biHeight; /* Assume there will be no color table for video? */ - if ((biSize < 40) || (Stream_GetRemainingLength(s) < (biSize-40))) + if ((biSize < 40) || (Stream_GetRemainingLength(s) < (biSize - 40))) return 0; if (bypass && biSize > 40) @@ -413,7 +364,7 @@ static UINT32 tsmf_codec_parse_VIDEOINFOHEADER(TS_AM_MEDIA_TYPE* mediatype, wStr static BOOL tsmf_read_format_type(TS_AM_MEDIA_TYPE* mediatype, wStream* s, UINT32 cbFormat) { - int i, j; + UINT32 i, j; switch (mediatype->FormatType) { @@ -422,8 +373,8 @@ static BOOL tsmf_read_format_type(TS_AM_MEDIA_TYPE* mediatype, wStream* s, UINT3 if (Stream_GetRemainingLength(s) < 176) return FALSE; - Stream_Seek(s, 8); /* dwSize and ? */ - Stream_Read_UINT32(s, mediatype->Width); /* videoInfo.dwWidth */ + Stream_Seek(s, 8); /* dwSize and ? */ + Stream_Read_UINT32(s, mediatype->Width); /* videoInfo.dwWidth */ Stream_Read_UINT32(s, mediatype->Height); /* videoInfo.dwHeight */ Stream_Seek(s, 32); /* videoInfo.FramesPerSecond */ @@ -600,7 +551,7 @@ BOOL tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE* mediatype, wStream* s) if (Stream_GetRemainingLength(s) < 4) return FALSE; Stream_Read_UINT32(s, cbFormat); - DEBUG_TSMF("cbFormat %"PRIu32"", cbFormat); + DEBUG_TSMF("cbFormat %" PRIu32 "", cbFormat); #ifdef WITH_DEBUG_TSMF winpr_HexDump(TAG, WLOG_DEBUG, Stream_Pointer(s), cbFormat); #endif @@ -627,7 +578,7 @@ BOOL tsmf_codec_check_media_type(const char* decoder_name, wStream* s) if (firstRun) { - firstRun =FALSE; + firstRun = FALSE; if (tsmf_check_decoder_available(decoder_name)) decoderAvailable = TRUE; } diff --git a/channels/tsmf/client/tsmf_codec.h b/channels/tsmf/client/tsmf_codec.h index a678ea4..ab98899 100644 --- a/channels/tsmf/client/tsmf_codec.h +++ b/channels/tsmf/client/tsmf_codec.h @@ -26,4 +26,3 @@ BOOL tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE* mediatype, wStream* s); BOOL tsmf_codec_check_media_type(const char* decoder_name, wStream* s); #endif /* FREERDP_CHANNEL_TSMF_CLIENT_CODEC_H */ - diff --git a/channels/tsmf/client/tsmf_constants.h b/channels/tsmf/client/tsmf_constants.h index d84370a..43d37f2 100644 --- a/channels/tsmf/client/tsmf_constants.h +++ b/channels/tsmf/client/tsmf_constants.h @@ -26,114 +26,114 @@ /* Interface IDs defined in [MS-RDPEV]. There's no constant names in the MS documentation, so we create them on our own. */ -#define TSMF_INTERFACE_DEFAULT 0x00000000 -#define TSMF_INTERFACE_CLIENT_NOTIFICATIONS 0x00000001 -#define TSMF_INTERFACE_CAPABILITIES 0x00000002 +#define TSMF_INTERFACE_DEFAULT 0x00000000 +#define TSMF_INTERFACE_CLIENT_NOTIFICATIONS 0x00000001 +#define TSMF_INTERFACE_CAPABILITIES 0x00000002 /* Interface ID Mask */ -#define STREAM_ID_STUB 0x80000000 -#define STREAM_ID_PROXY 0x40000000 -#define STREAM_ID_NONE 0x00000000 +#define STREAM_ID_STUB 0x80000000 +#define STREAM_ID_PROXY 0x40000000 +#define STREAM_ID_NONE 0x00000000 /* Functon ID */ /* Common IDs for all interfaces are as follows. */ -#define RIMCALL_RELEASE 0x00000001 -#define RIMCALL_QUERYINTERFACE 0x00000002 +#define RIMCALL_RELEASE 0x00000001 +#define RIMCALL_QUERYINTERFACE 0x00000002 /* Capabilities Negotiator Interface IDs are as follows. */ -#define RIM_EXCHANGE_CAPABILITY_REQUEST 0x00000100 +#define RIM_EXCHANGE_CAPABILITY_REQUEST 0x00000100 /* The Client Notifications Interface ID is as follows. */ -#define PLAYBACK_ACK 0x00000100 -#define CLIENT_EVENT_NOTIFICATION 0x00000101 +#define PLAYBACK_ACK 0x00000100 +#define CLIENT_EVENT_NOTIFICATION 0x00000101 /* Server Data Interface IDs are as follows. */ -#define EXCHANGE_CAPABILITIES_REQ 0x00000100 -#define SET_CHANNEL_PARAMS 0x00000101 -#define ADD_STREAM 0x00000102 -#define ON_SAMPLE 0x00000103 -#define SET_VIDEO_WINDOW 0x00000104 -#define ON_NEW_PRESENTATION 0x00000105 -#define SHUTDOWN_PRESENTATION_REQ 0x00000106 -#define SET_TOPOLOGY_REQ 0x00000107 -#define CHECK_FORMAT_SUPPORT_REQ 0x00000108 -#define ON_PLAYBACK_STARTED 0x00000109 -#define ON_PLAYBACK_PAUSED 0x0000010a -#define ON_PLAYBACK_STOPPED 0x0000010b -#define ON_PLAYBACK_RESTARTED 0x0000010c -#define ON_PLAYBACK_RATE_CHANGED 0x0000010d -#define ON_FLUSH 0x0000010e -#define ON_STREAM_VOLUME 0x0000010f -#define ON_CHANNEL_VOLUME 0x00000110 -#define ON_END_OF_STREAM 0x00000111 -#define SET_ALLOCATOR 0x00000112 -#define NOTIFY_PREROLL 0x00000113 -#define UPDATE_GEOMETRY_INFO 0x00000114 -#define REMOVE_STREAM 0x00000115 -#define SET_SOURCE_VIDEO_RECT 0x00000116 +#define EXCHANGE_CAPABILITIES_REQ 0x00000100 +#define SET_CHANNEL_PARAMS 0x00000101 +#define ADD_STREAM 0x00000102 +#define ON_SAMPLE 0x00000103 +#define SET_VIDEO_WINDOW 0x00000104 +#define ON_NEW_PRESENTATION 0x00000105 +#define SHUTDOWN_PRESENTATION_REQ 0x00000106 +#define SET_TOPOLOGY_REQ 0x00000107 +#define CHECK_FORMAT_SUPPORT_REQ 0x00000108 +#define ON_PLAYBACK_STARTED 0x00000109 +#define ON_PLAYBACK_PAUSED 0x0000010a +#define ON_PLAYBACK_STOPPED 0x0000010b +#define ON_PLAYBACK_RESTARTED 0x0000010c +#define ON_PLAYBACK_RATE_CHANGED 0x0000010d +#define ON_FLUSH 0x0000010e +#define ON_STREAM_VOLUME 0x0000010f +#define ON_CHANNEL_VOLUME 0x00000110 +#define ON_END_OF_STREAM 0x00000111 +#define SET_ALLOCATOR 0x00000112 +#define NOTIFY_PREROLL 0x00000113 +#define UPDATE_GEOMETRY_INFO 0x00000114 +#define REMOVE_STREAM 0x00000115 +#define SET_SOURCE_VIDEO_RECT 0x00000116 /* Supported platform */ -#define MMREDIR_CAPABILITY_PLATFORM_MF 0x00000001 -#define MMREDIR_CAPABILITY_PLATFORM_DSHOW 0x00000002 -#define MMREDIR_CAPABILITY_PLATFORM_OTHER 0x00000004 +#define MMREDIR_CAPABILITY_PLATFORM_MF 0x00000001 +#define MMREDIR_CAPABILITY_PLATFORM_DSHOW 0x00000002 +#define MMREDIR_CAPABILITY_PLATFORM_OTHER 0x00000004 /* TSMM_CLIENT_EVENT Constants */ -#define TSMM_CLIENT_EVENT_ENDOFSTREAM 0x0064 -#define TSMM_CLIENT_EVENT_STOP_COMPLETED 0x00C8 -#define TSMM_CLIENT_EVENT_START_COMPLETED 0x00C9 -#define TSMM_CLIENT_EVENT_MONITORCHANGED 0x012C +#define TSMM_CLIENT_EVENT_ENDOFSTREAM 0x0064 +#define TSMM_CLIENT_EVENT_STOP_COMPLETED 0x00C8 +#define TSMM_CLIENT_EVENT_START_COMPLETED 0x00C9 +#define TSMM_CLIENT_EVENT_MONITORCHANGED 0x012C /* TS_MM_DATA_SAMPLE.SampleExtensions */ -#define TSMM_SAMPLE_EXT_CLEANPOINT 0x00000001 -#define TSMM_SAMPLE_EXT_DISCONTINUITY 0x00000002 -#define TSMM_SAMPLE_EXT_INTERLACED 0x00000004 -#define TSMM_SAMPLE_EXT_BOTTOMFIELDFIRST 0x00000008 -#define TSMM_SAMPLE_EXT_REPEATFIELDFIRST 0x00000010 -#define TSMM_SAMPLE_EXT_SINGLEFIELD 0x00000020 +#define TSMM_SAMPLE_EXT_CLEANPOINT 0x00000001 +#define TSMM_SAMPLE_EXT_DISCONTINUITY 0x00000002 +#define TSMM_SAMPLE_EXT_INTERLACED 0x00000004 +#define TSMM_SAMPLE_EXT_BOTTOMFIELDFIRST 0x00000008 +#define TSMM_SAMPLE_EXT_REPEATFIELDFIRST 0x00000010 +#define TSMM_SAMPLE_EXT_SINGLEFIELD 0x00000020 #define TSMM_SAMPLE_EXT_DERIVEDFROMTOPFIELD 0x00000040 -#define TSMM_SAMPLE_EXT_HAS_NO_TIMESTAMPS 0x00000080 +#define TSMM_SAMPLE_EXT_HAS_NO_TIMESTAMPS 0x00000080 #define TSMM_SAMPLE_EXT_RELATIVE_TIMESTAMPS 0x00000100 #define TSMM_SAMPLE_EXT_ABSOLUTE_TIMESTAMPS 0x00000200 /* MajorType */ -#define TSMF_MAJOR_TYPE_UNKNOWN 0 -#define TSMF_MAJOR_TYPE_VIDEO 1 -#define TSMF_MAJOR_TYPE_AUDIO 2 +#define TSMF_MAJOR_TYPE_UNKNOWN 0 +#define TSMF_MAJOR_TYPE_VIDEO 1 +#define TSMF_MAJOR_TYPE_AUDIO 2 /* SubType */ -#define TSMF_SUB_TYPE_UNKNOWN 0 -#define TSMF_SUB_TYPE_WVC1 1 -#define TSMF_SUB_TYPE_WMA2 2 -#define TSMF_SUB_TYPE_WMA9 3 -#define TSMF_SUB_TYPE_MP3 4 -#define TSMF_SUB_TYPE_MP2A 5 -#define TSMF_SUB_TYPE_MP2V 6 -#define TSMF_SUB_TYPE_WMV3 7 -#define TSMF_SUB_TYPE_AAC 8 -#define TSMF_SUB_TYPE_H264 9 -#define TSMF_SUB_TYPE_AVC1 10 -#define TSMF_SUB_TYPE_AC3 11 -#define TSMF_SUB_TYPE_WMV2 12 -#define TSMF_SUB_TYPE_WMV1 13 -#define TSMF_SUB_TYPE_MP1V 14 -#define TSMF_SUB_TYPE_MP1A 15 -#define TSMF_SUB_TYPE_YUY2 16 -#define TSMF_SUB_TYPE_MP43 17 -#define TSMF_SUB_TYPE_MP4S 18 -#define TSMF_SUB_TYPE_MP42 19 -#define TSMF_SUB_TYPE_OGG 20 -#define TSMF_SUB_TYPE_SPEEX 21 -#define TSMF_SUB_TYPE_THEORA 22 -#define TSMF_SUB_TYPE_FLAC 23 -#define TSMF_SUB_TYPE_VP8 24 -#define TSMF_SUB_TYPE_VP9 25 -#define TSMF_SUB_TYPE_H263 26 -#define TSMF_SUB_TYPE_M4S2 27 -#define TSMF_SUB_TYPE_WMA1 28 +#define TSMF_SUB_TYPE_UNKNOWN 0 +#define TSMF_SUB_TYPE_WVC1 1 +#define TSMF_SUB_TYPE_WMA2 2 +#define TSMF_SUB_TYPE_WMA9 3 +#define TSMF_SUB_TYPE_MP3 4 +#define TSMF_SUB_TYPE_MP2A 5 +#define TSMF_SUB_TYPE_MP2V 6 +#define TSMF_SUB_TYPE_WMV3 7 +#define TSMF_SUB_TYPE_AAC 8 +#define TSMF_SUB_TYPE_H264 9 +#define TSMF_SUB_TYPE_AVC1 10 +#define TSMF_SUB_TYPE_AC3 11 +#define TSMF_SUB_TYPE_WMV2 12 +#define TSMF_SUB_TYPE_WMV1 13 +#define TSMF_SUB_TYPE_MP1V 14 +#define TSMF_SUB_TYPE_MP1A 15 +#define TSMF_SUB_TYPE_YUY2 16 +#define TSMF_SUB_TYPE_MP43 17 +#define TSMF_SUB_TYPE_MP4S 18 +#define TSMF_SUB_TYPE_MP42 19 +#define TSMF_SUB_TYPE_OGG 20 +#define TSMF_SUB_TYPE_SPEEX 21 +#define TSMF_SUB_TYPE_THEORA 22 +#define TSMF_SUB_TYPE_FLAC 23 +#define TSMF_SUB_TYPE_VP8 24 +#define TSMF_SUB_TYPE_VP9 25 +#define TSMF_SUB_TYPE_H263 26 +#define TSMF_SUB_TYPE_M4S2 27 +#define TSMF_SUB_TYPE_WMA1 28 /* FormatType */ -#define TSMF_FORMAT_TYPE_UNKNOWN 0 -#define TSMF_FORMAT_TYPE_MFVIDEOFORMAT 1 -#define TSMF_FORMAT_TYPE_WAVEFORMATEX 2 -#define TSMF_FORMAT_TYPE_MPEG2VIDEOINFO 3 -#define TSMF_FORMAT_TYPE_VIDEOINFO2 4 -#define TSMF_FORMAT_TYPE_MPEG1VIDEOINFO 5 +#define TSMF_FORMAT_TYPE_UNKNOWN 0 +#define TSMF_FORMAT_TYPE_MFVIDEOFORMAT 1 +#define TSMF_FORMAT_TYPE_WAVEFORMATEX 2 +#define TSMF_FORMAT_TYPE_MPEG2VIDEOINFO 3 +#define TSMF_FORMAT_TYPE_VIDEOINFO2 4 +#define TSMF_FORMAT_TYPE_MPEG1VIDEOINFO 5 #endif /* FREERDP_CHANNEL_TSMF_CLIENT_CONSTANTS_H */ diff --git a/channels/tsmf/client/tsmf_decoder.c b/channels/tsmf/client/tsmf_decoder.c index 319dbfc..c59b0f6 100644 --- a/channels/tsmf/client/tsmf_decoder.c +++ b/channels/tsmf/client/tsmf_decoder.c @@ -32,12 +32,12 @@ #include "tsmf_constants.h" #include "tsmf_decoder.h" -static ITSMFDecoder* tsmf_load_decoder_by_name(const char *name) +static ITSMFDecoder* tsmf_load_decoder_by_name(const char* name) { ITSMFDecoder* decoder; TSMF_DECODER_ENTRY entry; - entry = (TSMF_DECODER_ENTRY) freerdp_load_channel_addin_entry("tsmf", (LPSTR) name, "decoder", 0); + entry = (TSMF_DECODER_ENTRY)(void*)freerdp_load_channel_addin_entry("tsmf", name, "decoder", 0); if (!entry) return NULL; @@ -53,7 +53,7 @@ static ITSMFDecoder* tsmf_load_decoder_by_name(const char *name) return decoder; } -static BOOL tsmf_decoder_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE* media_type) +static BOOL tsmf_decoder_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* media_type) { if (decoder->SetFormat(decoder, media_type)) return TRUE; @@ -102,8 +102,8 @@ BOOL tsmf_check_decoder_available(const char* name) decoder = tsmf_load_decoder_by_name(name); } #if defined(WITH_GSTREAMER_1_0) || defined(WITH_GSTREAMER_0_10) - if (!decoder) - decoder = tsmf_load_decoder_by_name("gstreamer"); + if (!decoder) + decoder = tsmf_load_decoder_by_name("gstreamer"); #endif #if defined(WITH_FFMPEG) @@ -120,4 +120,3 @@ BOOL tsmf_check_decoder_available(const char* name) return retValue; } - diff --git a/channels/tsmf/client/tsmf_decoder.h b/channels/tsmf/client/tsmf_decoder.h index a12e8ce..9a16faf 100644 --- a/channels/tsmf/client/tsmf_decoder.h +++ b/channels/tsmf/client/tsmf_decoder.h @@ -36,40 +36,43 @@ typedef struct _ITSMFDecoder ITSMFDecoder; struct _ITSMFDecoder { /* Set the decoder format. Return true if supported. */ - BOOL (*SetFormat)(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *media_type); + BOOL (*SetFormat)(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* media_type); /* Decode a sample. */ - BOOL (*Decode)(ITSMFDecoder *decoder, const BYTE *data, UINT32 data_size, UINT32 extensions); + BOOL (*Decode)(ITSMFDecoder* decoder, const BYTE* data, UINT32 data_size, UINT32 extensions); /* Get the decoded data */ - BYTE *(*GetDecodedData)(ITSMFDecoder *decoder, UINT32 *size); + BYTE* (*GetDecodedData)(ITSMFDecoder* decoder, UINT32* size); /* Get the pixel format of decoded video frame */ - UINT32(*GetDecodedFormat)(ITSMFDecoder *decoder); + UINT32 (*GetDecodedFormat)(ITSMFDecoder* decoder); /* Get the width and height of decoded video frame */ - BOOL (*GetDecodedDimension)(ITSMFDecoder *decoder, UINT32 *width, UINT32 *height); + BOOL (*GetDecodedDimension)(ITSMFDecoder* decoder, UINT32* width, UINT32* height); /* Free the decoder */ - void (*Free)(ITSMFDecoder *decoder); + void (*Free)(ITSMFDecoder* decoder); /* Optional Contol function */ - BOOL (*Control)(ITSMFDecoder *decoder, ITSMFControlMsg control_msg, UINT32 *arg); + BOOL (*Control)(ITSMFDecoder* decoder, ITSMFControlMsg control_msg, UINT32* arg); /* Decode a sample with extended interface. */ - BOOL (*DecodeEx)(ITSMFDecoder *decoder, const BYTE *data, UINT32 data_size, UINT32 extensions, - UINT64 start_time, UINT64 end_time, UINT64 duration); + BOOL(*DecodeEx) + (ITSMFDecoder* decoder, const BYTE* data, UINT32 data_size, UINT32 extensions, + UINT64 start_time, UINT64 end_time, UINT64 duration); /* Get current play time */ - UINT64(*GetRunningTime)(ITSMFDecoder *decoder); + UINT64 (*GetRunningTime)(ITSMFDecoder* decoder); /* Update Gstreamer Rendering Area */ - BOOL (*UpdateRenderingArea)(ITSMFDecoder *decoder, int newX, int newY, int newWidth, int newHeight, int numRectangles, RDP_RECT *rectangles); + BOOL(*UpdateRenderingArea) + (ITSMFDecoder* decoder, int newX, int newY, int newWidth, int newHeight, int numRectangles, + RDP_RECT* rectangles); /* Change Gstreamer Audio Volume */ - BOOL (*ChangeVolume)(ITSMFDecoder *decoder, UINT32 newVolume, UINT32 muted); + BOOL (*ChangeVolume)(ITSMFDecoder* decoder, UINT32 newVolume, UINT32 muted); /* Check buffer level */ - BOOL (*BufferLevel)(ITSMFDecoder *decoder); + BOOL (*BufferLevel)(ITSMFDecoder* decoder); /* Register a callback for frame ack. */ - BOOL (*SetAckFunc)(ITSMFDecoder *decoder, BOOL (*cb)(void *,BOOL), void *stream); + BOOL (*SetAckFunc)(ITSMFDecoder* decoder, BOOL (*cb)(void*, BOOL), void* stream); /* Register a callback for stream seek detection. */ - BOOL (*SetSyncFunc)(ITSMFDecoder *decoder, void (*cb)(void *), void *stream); + BOOL (*SetSyncFunc)(ITSMFDecoder* decoder, void (*cb)(void*), void* stream); }; #define TSMF_DECODER_EXPORT_FUNC_NAME "TSMFDecoderEntry" -typedef ITSMFDecoder *(*TSMF_DECODER_ENTRY)(void); +typedef ITSMFDecoder* (*TSMF_DECODER_ENTRY)(void); -ITSMFDecoder *tsmf_load_decoder(const char *name, TS_AM_MEDIA_TYPE *media_type); +ITSMFDecoder* tsmf_load_decoder(const char* name, TS_AM_MEDIA_TYPE* media_type); BOOL tsmf_check_decoder_available(const char* name); #endif /* FREERDP_CHANNEL_TSMF_CLIENT_DECODER_H */ diff --git a/channels/tsmf/client/tsmf_ifman.c b/channels/tsmf/client/tsmf_ifman.c index 9fcc620..a71a03f 100644 --- a/channels/tsmf/client/tsmf_ifman.c +++ b/channels/tsmf/client/tsmf_ifman.c @@ -52,7 +52,7 @@ UINT tsmf_ifman_rim_exchange_capability_request(TSMF_IFMAN* ifman) return ERROR_INVALID_DATA; Stream_Read_UINT32(ifman->input, CapabilityValue); - DEBUG_TSMF("server CapabilityValue %"PRIu32"", CapabilityValue); + DEBUG_TSMF("server CapabilityValue %" PRIu32 "", CapabilityValue); if (!Stream_EnsureRemainingCapacity(ifman->output, 8)) return ERROR_INVALID_DATA; @@ -108,7 +108,7 @@ UINT tsmf_ifman_exchange_capability_request(TSMF_IFMAN* ifman) return ERROR_INVALID_DATA; Stream_Read_UINT32(ifman->output, v); - DEBUG_TSMF("server protocol version %"PRIu32"", v); + DEBUG_TSMF("server protocol version %" PRIu32 "", v); break; case 2: /* Supported platform */ @@ -116,14 +116,14 @@ UINT tsmf_ifman_exchange_capability_request(TSMF_IFMAN* ifman) return ERROR_INVALID_DATA; Stream_Peek_UINT32(ifman->output, v); - DEBUG_TSMF("server supported platform %"PRIu32"", v); + DEBUG_TSMF("server supported platform %" PRIu32 "", v); /* Claim that we support both MF and DShow platforms. */ - Stream_Write_UINT32(ifman->output, - MMREDIR_CAPABILITY_PLATFORM_MF | MMREDIR_CAPABILITY_PLATFORM_DSHOW); + Stream_Write_UINT32(ifman->output, MMREDIR_CAPABILITY_PLATFORM_MF | + MMREDIR_CAPABILITY_PLATFORM_DSHOW); break; default: - WLog_ERR(TAG, "skipping unknown capability type %"PRIu32"", CapabilityType); + WLog_ERR(TAG, "skipping unknown capability type %" PRIu32 "", CapabilityType); break; } @@ -152,7 +152,7 @@ UINT tsmf_ifman_check_format_support_request(TSMF_IFMAN* ifman) Stream_Read_UINT32(ifman->input, PlatformCookie); Stream_Seek_UINT32(ifman->input); /* NoRolloverFlags (4 bytes) */ Stream_Read_UINT32(ifman->input, numMediaType); - DEBUG_TSMF("PlatformCookie %"PRIu32" numMediaType %"PRIu32"", PlatformCookie, numMediaType); + DEBUG_TSMF("PlatformCookie %" PRIu32 " numMediaType %" PRIu32 "", PlatformCookie, numMediaType); if (!tsmf_codec_check_media_type(ifman->decoder_name, ifman->input)) FormatSupported = 0; @@ -309,7 +309,7 @@ UINT tsmf_ifman_remove_stream(TSMF_IFMAN* ifman) return status; } -float tsmf_stream_read_float(wStream* s) +static float tsmf_stream_read_float(wStream* s) { float fValue; UINT32 iValue; @@ -343,12 +343,12 @@ UINT tsmf_ifman_set_source_video_rect(TSMF_IFMAN* ifman) } else { - Left = tsmf_stream_read_float(ifman->input); /* Left (4 bytes) */ - Top = tsmf_stream_read_float(ifman->input); /* Top (4 bytes) */ - Right = tsmf_stream_read_float(ifman->input); /* Right (4 bytes) */ + Left = tsmf_stream_read_float(ifman->input); /* Left (4 bytes) */ + Top = tsmf_stream_read_float(ifman->input); /* Top (4 bytes) */ + Right = tsmf_stream_read_float(ifman->input); /* Right (4 bytes) */ Bottom = tsmf_stream_read_float(ifman->input); /* Bottom (4 bytes) */ - DEBUG_TSMF("SetSourceVideoRect: Left: %f Top: %f Right: %f Bottom: %f", - Left, Top, Right, Bottom); + DEBUG_TSMF("SetSourceVideoRect: Left: %f Top: %f Right: %f Bottom: %f", Left, Top, Right, + Bottom); } ifman->output_pending = TRUE; @@ -411,9 +411,9 @@ UINT tsmf_ifman_on_stream_volume(TSMF_IFMAN* ifman) Stream_Seek(ifman->input, 16); Stream_Read_UINT32(ifman->input, newVolume); - DEBUG_TSMF("on stream volume: new volume=[%"PRIu32"]", newVolume); + DEBUG_TSMF("on stream volume: new volume=[%" PRIu32 "]", newVolume); Stream_Read_UINT32(ifman->input, muted); - DEBUG_TSMF("on stream volume: muted=[%"PRIu32"]", muted); + DEBUG_TSMF("on stream volume: muted=[%" PRIu32 "]", muted); if (!tsmf_presentation_volume_changed(presentation, newVolume, muted)) return ERROR_INVALID_OPERATION; @@ -443,9 +443,9 @@ UINT tsmf_ifman_on_channel_volume(TSMF_IFMAN* ifman) UINT32 changedChannel; Stream_Seek(ifman->input, 16); Stream_Read_UINT32(ifman->input, channelVolume); - DEBUG_TSMF("on channel volume: channel volume=[%"PRIu32"]", channelVolume); + DEBUG_TSMF("on channel volume: channel volume=[%" PRIu32 "]", channelVolume); Stream_Read_UINT32(ifman->input, changedChannel); - DEBUG_TSMF("on stream volume: changed channel=[%"PRIu32"]", changedChannel); + DEBUG_TSMF("on stream volume: changed channel=[%" PRIu32 "]", changedChannel); } ifman->output_pending = TRUE; @@ -503,12 +503,13 @@ UINT tsmf_ifman_update_geometry_info(TSMF_IFMAN* ifman) Stream_SetPosition(ifman->input, pos + numGeometryInfo); Stream_Read_UINT32(ifman->input, cbVisibleRect); num_rects = cbVisibleRect / 16; - DEBUG_TSMF("numGeometryInfo %"PRIu32" Width %"PRIu32" Height %"PRIu32" Left %"PRIu32" Top %"PRIu32" cbVisibleRect %"PRIu32" num_rects %d", + DEBUG_TSMF("numGeometryInfo %" PRIu32 " Width %" PRIu32 " Height %" PRIu32 " Left %" PRIu32 + " Top %" PRIu32 " cbVisibleRect %" PRIu32 " num_rects %d", numGeometryInfo, Width, Height, Left, Top, cbVisibleRect, num_rects); if (num_rects > 0) { - rects = (RDP_RECT*) calloc(num_rects, sizeof(RDP_RECT)); + rects = (RDP_RECT*)calloc(num_rects, sizeof(RDP_RECT)); for (i = 0; i < num_rects; i++) { @@ -522,12 +523,13 @@ UINT tsmf_ifman_update_geometry_info(TSMF_IFMAN* ifman) Stream_Seek_UINT16(ifman->input); rects[i].width -= rects[i].x; rects[i].height -= rects[i].y; - DEBUG_TSMF("rect %d: %"PRId16" %"PRId16" %"PRId16" %"PRId16"", i, - rects[i].x, rects[i].y, rects[i].width, rects[i].height); + DEBUG_TSMF("rect %d: %" PRId16 " %" PRId16 " %" PRId16 " %" PRId16 "", i, rects[i].x, + rects[i].y, rects[i].width, rects[i].height); } } - if (!tsmf_presentation_set_geometry_info(presentation, Left, Top, Width, Height, num_rects, rects)) + if (!tsmf_presentation_set_geometry_info(presentation, Left, Top, Width, Height, num_rects, + rects)) return ERROR_INVALID_OPERATION; ifman->output_pending = TRUE; @@ -592,10 +594,11 @@ UINT tsmf_ifman_on_sample(TSMF_IFMAN* ifman) if (Stream_GetRemainingLength(ifman->input) < cbData) return ERROR_INVALID_DATA; - DEBUG_TSMF("MessageId %"PRIu32" StreamId %"PRIu32" SampleStartTime %"PRIu64" SampleEndTime %"PRIu64" " - "ThrottleDuration %"PRIu64" SampleExtensions %"PRIu32" cbData %"PRIu32"", - ifman->message_id, StreamId, SampleStartTime, SampleEndTime, - ThrottleDuration, SampleExtensions, cbData); + DEBUG_TSMF("MessageId %" PRIu32 " StreamId %" PRIu32 " SampleStartTime %" PRIu64 + " SampleEndTime %" PRIu64 " " + "ThrottleDuration %" PRIu64 " SampleExtensions %" PRIu32 " cbData %" PRIu32 "", + ifman->message_id, StreamId, SampleStartTime, SampleEndTime, ThrottleDuration, + SampleExtensions, cbData); presentation = tsmf_presentation_find_by_id(ifman->presentation_id); if (!presentation) @@ -612,9 +615,9 @@ UINT tsmf_ifman_on_sample(TSMF_IFMAN* ifman) return ERROR_NOT_FOUND; } - if (!tsmf_stream_push_sample(stream, ifman->channel_callback, - ifman->message_id, SampleStartTime, SampleEndTime, - ThrottleDuration, SampleExtensions, cbData, Stream_Pointer(ifman->input))) + if (!tsmf_stream_push_sample(stream, ifman->channel_callback, ifman->message_id, + SampleStartTime, SampleEndTime, ThrottleDuration, SampleExtensions, + cbData, Stream_Pointer(ifman->input))) { WLog_ERR(TAG, "unable to push sample"); return ERROR_OUTOFMEMORY; @@ -622,7 +625,7 @@ UINT tsmf_ifman_on_sample(TSMF_IFMAN* ifman) if ((error = tsmf_presentation_sync(presentation))) { - WLog_ERR(TAG, "tsmf_presentation_sync failed with error %"PRIu32"", error); + WLog_ERR(TAG, "tsmf_presentation_sync failed with error %" PRIu32 "", error); return error; } @@ -646,7 +649,7 @@ UINT tsmf_ifman_on_flush(TSMF_IFMAN* ifman) Stream_Seek(ifman->input, 16); Stream_Read_UINT32(ifman->input, StreamId); - DEBUG_TSMF("StreamId %"PRIu32"", StreamId); + DEBUG_TSMF("StreamId %" PRIu32 "", StreamId); presentation = tsmf_presentation_find_by_id(ifman->presentation_id); if (!presentation) @@ -698,7 +701,7 @@ UINT tsmf_ifman_on_end_of_stream(TSMF_IFMAN* ifman) tsmf_stream_end(stream, ifman->message_id, ifman->channel_callback); } - DEBUG_TSMF("StreamId %"PRIu32"", StreamId); + DEBUG_TSMF("StreamId %" PRIu32 "", StreamId); ifman->output_pending = TRUE; ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY; return CHANNEL_RC_OK; @@ -727,10 +730,10 @@ UINT tsmf_ifman_on_playback_started(TSMF_IFMAN* ifman) if (!Stream_EnsureRemainingCapacity(ifman->output, 16)) return ERROR_OUTOFMEMORY; - Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */ - Stream_Write_UINT32(ifman->output, 0); /* StreamId */ + Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */ + Stream_Write_UINT32(ifman->output, 0); /* StreamId */ Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_START_COMPLETED); /* EventId */ - Stream_Write_UINT32(ifman->output, 0); /* cbData */ + Stream_Write_UINT32(ifman->output, 0); /* cbData */ ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY; return CHANNEL_RC_OK; } @@ -805,10 +808,10 @@ UINT tsmf_ifman_on_playback_stopped(TSMF_IFMAN* ifman) if (!Stream_EnsureRemainingCapacity(ifman->output, 16)) return ERROR_OUTOFMEMORY; - Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */ - Stream_Write_UINT32(ifman->output, 0); /* StreamId */ + Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */ + Stream_Write_UINT32(ifman->output, 0); /* StreamId */ Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_STOP_COMPLETED); /* EventId */ - Stream_Write_UINT32(ifman->output, 0); /* cbData */ + Stream_Write_UINT32(ifman->output, 0); /* cbData */ ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY; return CHANNEL_RC_OK; } @@ -825,10 +828,10 @@ UINT tsmf_ifman_on_playback_rate_changed(TSMF_IFMAN* ifman) if (!Stream_EnsureRemainingCapacity(ifman->output, 16)) return ERROR_OUTOFMEMORY; - Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */ - Stream_Write_UINT32(ifman->output, 0); /* StreamId */ + Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */ + Stream_Write_UINT32(ifman->output, 0); /* StreamId */ Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_MONITORCHANGED); /* EventId */ - Stream_Write_UINT32(ifman->output, 0); /* cbData */ + Stream_Write_UINT32(ifman->output, 0); /* cbData */ ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY; return CHANNEL_RC_OK; } diff --git a/channels/tsmf/client/tsmf_ifman.h b/channels/tsmf/client/tsmf_ifman.h index b698620..3830f5b 100644 --- a/channels/tsmf/client/tsmf_ifman.h +++ b/channels/tsmf/client/tsmf_ifman.h @@ -67,4 +67,3 @@ UINT tsmf_ifman_on_playback_stopped(TSMF_IFMAN* ifman); UINT tsmf_ifman_on_playback_rate_changed(TSMF_IFMAN* ifman); #endif /* FREERDP_CHANNEL_TSMF_CLIENT_IFMAN_H */ - diff --git a/channels/tsmf/client/tsmf_main.c b/channels/tsmf/client/tsmf_main.c index 9309235..ec281ea 100644 --- a/channels/tsmf/client/tsmf_main.c +++ b/channels/tsmf/client/tsmf_main.c @@ -40,7 +40,7 @@ BOOL tsmf_send_eos_response(IWTSVirtualChannelCallback* pChannelCallback, UINT32 { wStream* s = NULL; int status = -1; - TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*) pChannelCallback; + TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*)pChannelCallback; if (!callback) { @@ -57,12 +57,13 @@ BOOL tsmf_send_eos_response(IWTSVirtualChannelCallback* pChannelCallback, UINT32 Stream_Write_UINT32(s, TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY); Stream_Write_UINT32(s, message_id); - Stream_Write_UINT32(s, CLIENT_EVENT_NOTIFICATION); /* FunctionId */ - Stream_Write_UINT32(s, callback->stream_id); /* StreamId */ + Stream_Write_UINT32(s, CLIENT_EVENT_NOTIFICATION); /* FunctionId */ + Stream_Write_UINT32(s, callback->stream_id); /* StreamId */ Stream_Write_UINT32(s, TSMM_CLIENT_EVENT_ENDOFSTREAM); /* EventId */ - Stream_Write_UINT32(s, 0); /* cbData */ - DEBUG_TSMF("EOS response size %"PRIuz"", Stream_GetPosition(s)); - status = callback->channel->Write(callback->channel, Stream_GetPosition(s), Stream_Buffer(s), NULL); + Stream_Write_UINT32(s, 0); /* cbData */ + DEBUG_TSMF("EOS response size %" PRIuz "", Stream_GetPosition(s)); + status = callback->channel->Write(callback->channel, Stream_GetPosition(s), + Stream_Buffer(s), NULL); if (status) { @@ -75,12 +76,12 @@ BOOL tsmf_send_eos_response(IWTSVirtualChannelCallback* pChannelCallback, UINT32 return (status == 0); } -BOOL tsmf_playback_ack(IWTSVirtualChannelCallback* pChannelCallback, - UINT32 message_id, UINT64 duration, UINT32 data_size) +BOOL tsmf_playback_ack(IWTSVirtualChannelCallback* pChannelCallback, UINT32 message_id, + UINT64 duration, UINT32 data_size) { wStream* s = NULL; int status = -1; - TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*) pChannelCallback; + TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*)pChannelCallback; if (!callback) return FALSE; @@ -92,11 +93,11 @@ BOOL tsmf_playback_ack(IWTSVirtualChannelCallback* pChannelCallback, Stream_Write_UINT32(s, TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY); Stream_Write_UINT32(s, message_id); - Stream_Write_UINT32(s, PLAYBACK_ACK); /* FunctionId */ + Stream_Write_UINT32(s, PLAYBACK_ACK); /* FunctionId */ Stream_Write_UINT32(s, callback->stream_id); /* StreamId */ - Stream_Write_UINT64(s, duration); /* DataDuration */ - Stream_Write_UINT64(s, data_size); /* cbData */ - DEBUG_TSMF("ACK response size %"PRIuz"", Stream_GetPosition(s)); + Stream_Write_UINT64(s, duration); /* DataDuration */ + Stream_Write_UINT64(s, data_size); /* cbData */ + DEBUG_TSMF("ACK response size %" PRIuz "", Stream_GetPosition(s)); if (!callback->channel || !callback->channel->Write) { @@ -106,8 +107,8 @@ BOOL tsmf_playback_ack(IWTSVirtualChannelCallback* pChannelCallback, } else { - status = callback->channel->Write(callback->channel, - Stream_GetPosition(s), Stream_Buffer(s), NULL); + status = callback->channel->Write(callback->channel, Stream_GetPosition(s), + Stream_Buffer(s), NULL); } if (status) @@ -135,13 +136,13 @@ static UINT tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, UINT32 MessageId; UINT32 FunctionId; UINT32 InterfaceId; - TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*) pChannelCallback; + TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*)pChannelCallback; UINT32 cbSize = Stream_GetRemainingLength(data); /* 2.2.1 Shared Message Header (SHARED_MSG_HEADER) */ if (cbSize < 12) { - WLog_ERR(TAG, "invalid size. cbSize=%"PRIu32"", cbSize); + WLog_ERR(TAG, "invalid size. cbSize=%" PRIu32 "", cbSize); return ERROR_INVALID_DATA; } @@ -153,15 +154,16 @@ static UINT tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, Stream_Seek(output, 8); Stream_Read_UINT32(input, InterfaceId); /* InterfaceId (4 bytes) */ - Stream_Read_UINT32(input, MessageId); /* MessageId (4 bytes) */ - Stream_Read_UINT32(input, FunctionId); /* FunctionId (4 bytes) */ - DEBUG_TSMF("cbSize=%"PRIu32" InterfaceId=0x%"PRIX32" MessageId=0x%"PRIX32" FunctionId=0x%"PRIX32"", + Stream_Read_UINT32(input, MessageId); /* MessageId (4 bytes) */ + Stream_Read_UINT32(input, FunctionId); /* FunctionId (4 bytes) */ + DEBUG_TSMF("cbSize=%" PRIu32 " InterfaceId=0x%" PRIX32 " MessageId=0x%" PRIX32 + " FunctionId=0x%" PRIX32 "", cbSize, InterfaceId, MessageId, FunctionId); ZeroMemory(&ifman, sizeof(TSMF_IFMAN)); ifman.channel_callback = pChannelCallback; - ifman.decoder_name = ((TSMF_PLUGIN*) callback->plugin)->decoder_name; - ifman.audio_name = ((TSMF_PLUGIN*) callback->plugin)->audio_name; - ifman.audio_device = ((TSMF_PLUGIN*) callback->plugin)->audio_device; + ifman.decoder_name = ((TSMF_PLUGIN*)callback->plugin)->decoder_name; + ifman.audio_name = ((TSMF_PLUGIN*)callback->plugin)->audio_name; + ifman.audio_device = ((TSMF_PLUGIN*)callback->plugin)->audio_device; CopyMemory(ifman.presentation_id, callback->presentation_id, GUID_SIZE); ifman.stream_id = callback->stream_id; ifman.message_id = MessageId; @@ -171,7 +173,8 @@ static UINT tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, ifman.output_pending = FALSE; ifman.output_interface_id = InterfaceId; - //fprintf(stderr, "InterfaceId: 0x%08"PRIX32" MessageId: 0x%08"PRIX32" FunctionId: 0x%08"PRIX32"\n", InterfaceId, MessageId, FunctionId); + // fprintf(stderr, "InterfaceId: 0x%08"PRIX32" MessageId: 0x%08"PRIX32" FunctionId: + // 0x%08"PRIX32"\n", InterfaceId, MessageId, FunctionId); switch (InterfaceId) { @@ -206,7 +209,7 @@ static UINT tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, CopyMemory(callback->presentation_id, Stream_Pointer(input), GUID_SIZE); Stream_Seek(input, GUID_SIZE); Stream_Read_UINT32(input, callback->stream_id); - DEBUG_TSMF("SET_CHANNEL_PARAMS StreamId=%"PRIu32"", callback->stream_id); + DEBUG_TSMF("SET_CHANNEL_PARAMS StreamId=%" PRIu32 "", callback->stream_id); ifman.output_pending = TRUE; processed = TRUE; break; @@ -227,7 +230,8 @@ static UINT tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, break; case ADD_STREAM: - error = tsmf_ifman_add_stream(&ifman, ((TSMF_PLUGIN*) callback->plugin)->rdpcontext); + error = + tsmf_ifman_add_stream(&ifman, ((TSMF_PLUGIN*)callback->plugin)->rdpcontext); processed = TRUE; break; @@ -340,7 +344,7 @@ static UINT tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, if (error) { - WLog_ERR(TAG, "ifman data received processing error %"PRIu32"", error); + WLog_ERR(TAG, "ifman data received processing error %" PRIu32 "", error); } if (!processed) @@ -364,7 +368,8 @@ static UINT tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, if (!processed) { WLog_ERR(TAG, - "Unknown InterfaceId: 0x%08"PRIX32" MessageId: 0x%08"PRIX32" FunctionId: 0x%08"PRIX32"\n", + "Unknown InterfaceId: 0x%08" PRIX32 " MessageId: 0x%08" PRIX32 + " FunctionId: 0x%08" PRIX32 "\n", InterfaceId, MessageId, FunctionId); /* When a request is not implemented we return empty response indicating error */ } @@ -384,7 +389,7 @@ static UINT tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, if (error) { - WLog_ERR(TAG, "response error %"PRIu32"", error); + WLog_ERR(TAG, "response error %" PRIu32 "", error); } } @@ -402,7 +407,7 @@ static UINT tsmf_on_close(IWTSVirtualChannelCallback* pChannelCallback) { TSMF_STREAM* stream; TSMF_PRESENTATION* presentation; - TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*) pChannelCallback; + TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*)pChannelCallback; DEBUG_TSMF(""); if (callback->stream_id) @@ -428,15 +433,13 @@ static UINT tsmf_on_close(IWTSVirtualChannelCallback* pChannelCallback) * @return 0 on success, otherwise a Win32 error code */ static UINT tsmf_on_new_channel_connection(IWTSListenerCallback* pListenerCallback, - IWTSVirtualChannel* pChannel, - BYTE* Data, - BOOL* pbAccept, - IWTSVirtualChannelCallback** ppCallback) + IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept, + IWTSVirtualChannelCallback** ppCallback) { TSMF_CHANNEL_CALLBACK* callback; - TSMF_LISTENER_CALLBACK* listener_callback = (TSMF_LISTENER_CALLBACK*) pListenerCallback; + TSMF_LISTENER_CALLBACK* listener_callback = (TSMF_LISTENER_CALLBACK*)pListenerCallback; DEBUG_TSMF(""); - callback = (TSMF_CHANNEL_CALLBACK*) calloc(1, sizeof(TSMF_CHANNEL_CALLBACK)); + callback = (TSMF_CHANNEL_CALLBACK*)calloc(1, sizeof(TSMF_CHANNEL_CALLBACK)); if (!callback) return CHANNEL_RC_NO_MEMORY; @@ -447,7 +450,7 @@ static UINT tsmf_on_new_channel_connection(IWTSListenerCallback* pListenerCallba callback->plugin = listener_callback->plugin; callback->channel_mgr = listener_callback->channel_mgr; callback->channel = pChannel; - *ppCallback = (IWTSVirtualChannelCallback*) callback; + *ppCallback = (IWTSVirtualChannelCallback*)callback; return CHANNEL_RC_OK; } @@ -459,9 +462,9 @@ static UINT tsmf_on_new_channel_connection(IWTSListenerCallback* pListenerCallba static UINT tsmf_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr) { UINT status; - TSMF_PLUGIN* tsmf = (TSMF_PLUGIN*) pPlugin; + TSMF_PLUGIN* tsmf = (TSMF_PLUGIN*)pPlugin; DEBUG_TSMF(""); - tsmf->listener_callback = (TSMF_LISTENER_CALLBACK*) calloc(1, sizeof(TSMF_LISTENER_CALLBACK)); + tsmf->listener_callback = (TSMF_LISTENER_CALLBACK*)calloc(1, sizeof(TSMF_LISTENER_CALLBACK)); if (!tsmf->listener_callback) return CHANNEL_RC_NO_MEMORY; @@ -469,8 +472,8 @@ static UINT tsmf_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManage tsmf->listener_callback->iface.OnNewChannelConnection = tsmf_on_new_channel_connection; tsmf->listener_callback->plugin = pPlugin; tsmf->listener_callback->channel_mgr = pChannelMgr; - status = pChannelMgr->CreateListener(pChannelMgr, "TSMF", 0, - (IWTSListenerCallback*) tsmf->listener_callback, &(tsmf->listener)); + status = pChannelMgr->CreateListener( + pChannelMgr, "TSMF", 0, (IWTSListenerCallback*)tsmf->listener_callback, &(tsmf->listener)); tsmf->listener->pInterface = tsmf->iface.pInterface; return status; } @@ -482,21 +485,13 @@ static UINT tsmf_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManage */ static UINT tsmf_plugin_terminated(IWTSPlugin* pPlugin) { - TSMF_PLUGIN* tsmf = (TSMF_PLUGIN*) pPlugin; + TSMF_PLUGIN* tsmf = (TSMF_PLUGIN*)pPlugin; DEBUG_TSMF(""); free(tsmf->listener_callback); free(tsmf); return CHANNEL_RC_OK; } -COMMAND_LINE_ARGUMENT_A tsmf_args[] = -{ - { "sys", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "audio subsystem" }, - { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "audio device name" }, - { "decoder", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "decoder subsystem" }, - { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } -}; - /** * Function description * @@ -507,10 +502,16 @@ static UINT tsmf_process_addin_args(IWTSPlugin* pPlugin, ADDIN_ARGV* args) int status; DWORD flags; COMMAND_LINE_ARGUMENT_A* arg; - TSMF_PLUGIN* tsmf = (TSMF_PLUGIN*) pPlugin; + TSMF_PLUGIN* tsmf = (TSMF_PLUGIN*)pPlugin; + COMMAND_LINE_ARGUMENT_A tsmf_args[] = { { "sys", COMMAND_LINE_VALUE_REQUIRED, "", + NULL, NULL, -1, NULL, "audio subsystem" }, + { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, + NULL, -1, NULL, "audio device name" }, + { "decoder", COMMAND_LINE_VALUE_REQUIRED, "", + NULL, NULL, -1, NULL, "decoder subsystem" }, + { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } }; flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON; - status = CommandLineParseArgumentsA(args->argc, args->argv, - tsmf_args, flags, tsmf, NULL, NULL); + status = CommandLineParseArgumentsA(args->argc, args->argv, tsmf_args, flags, tsmf, NULL, NULL); if (status != 0) return ERROR_INVALID_DATA; @@ -522,8 +523,7 @@ static UINT tsmf_process_addin_args(IWTSPlugin* pPlugin, ADDIN_ARGV* args) if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) continue; - CommandLineSwitchStart(arg) - CommandLineSwitchCase(arg, "sys") + CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "sys") { tsmf->audio_name = _strdup(arg->Value); @@ -548,16 +548,15 @@ static UINT tsmf_process_addin_args(IWTSPlugin* pPlugin, ADDIN_ARGV* args) { } CommandLineSwitchEnd(arg) - } - while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); return CHANNEL_RC_OK; } #ifdef BUILTIN_CHANNELS -#define DVCPluginEntry tsmf_DVCPluginEntry +#define DVCPluginEntry tsmf_DVCPluginEntry #else -#define DVCPluginEntry FREERDP_API DVCPluginEntry +#define DVCPluginEntry FREERDP_API DVCPluginEntry #endif /** @@ -571,11 +570,11 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) TSMF_PLUGIN* tsmf; TsmfClientContext* context; UINT error = CHANNEL_RC_NO_MEMORY; - tsmf = (TSMF_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "tsmf"); + tsmf = (TSMF_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "tsmf"); if (!tsmf) { - tsmf = (TSMF_PLUGIN*) calloc(1, sizeof(TSMF_PLUGIN)); + tsmf = (TSMF_PLUGIN*)calloc(1, sizeof(TSMF_PLUGIN)); if (!tsmf) { @@ -587,9 +586,10 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) tsmf->iface.Connected = NULL; tsmf->iface.Disconnected = NULL; tsmf->iface.Terminated = tsmf_plugin_terminated; - tsmf->rdpcontext = ((freerdp*)((rdpSettings*) pEntryPoints->GetRdpSettings( - pEntryPoints))->instance)->context; - context = (TsmfClientContext*) calloc(1, sizeof(TsmfClientContext)); + tsmf->rdpcontext = + ((freerdp*)((rdpSettings*)pEntryPoints->GetRdpSettings(pEntryPoints))->instance) + ->context; + context = (TsmfClientContext*)calloc(1, sizeof(TsmfClientContext)); if (!context) { @@ -597,8 +597,8 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) goto error_context; } - context->handle = (void*) tsmf; - tsmf->iface.pInterface = (void*) context; + context->handle = (void*)tsmf; + tsmf->iface.pInterface = (void*)context; if (!tsmf_media_init()) { @@ -606,12 +606,13 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) goto error_init; } - status = pEntryPoints->RegisterPlugin(pEntryPoints, "tsmf", (IWTSPlugin*) tsmf); + status = pEntryPoints->RegisterPlugin(pEntryPoints, "tsmf", (IWTSPlugin*)tsmf); } if (status == CHANNEL_RC_OK) { - status = tsmf_process_addin_args((IWTSPlugin*) tsmf, pEntryPoints->GetPluginData(pEntryPoints)); + status = + tsmf_process_addin_args((IWTSPlugin*)tsmf, pEntryPoints->GetPluginData(pEntryPoints)); } return status; diff --git a/channels/tsmf/client/tsmf_main.h b/channels/tsmf/client/tsmf_main.h index 0143d29..366215c 100644 --- a/channels/tsmf/client/tsmf_main.h +++ b/channels/tsmf/client/tsmf_main.h @@ -65,7 +65,7 @@ struct _TSMF_PLUGIN }; BOOL tsmf_send_eos_response(IWTSVirtualChannelCallback* pChannelCallback, UINT32 message_id); -BOOL tsmf_playback_ack(IWTSVirtualChannelCallback* pChannelCallback, - UINT32 message_id, UINT64 duration, UINT32 data_size); +BOOL tsmf_playback_ack(IWTSVirtualChannelCallback* pChannelCallback, UINT32 message_id, + UINT64 duration, UINT32 data_size); #endif /* FREERDP_CHANNEL_TSMF_CLIENT_MAIN_H */ diff --git a/channels/tsmf/client/tsmf_media.c b/channels/tsmf/client/tsmf_media.c index 05ca6c4..b77a3c6 100644 --- a/channels/tsmf/client/tsmf_media.c +++ b/channels/tsmf/client/tsmf_media.c @@ -57,7 +57,7 @@ #define AUDIO_TOLERANCE 10000000LL /* 1 second = 10,000,000 100ns units*/ -#define VIDEO_ADJUST_MAX 10*1000*1000 +#define VIDEO_ADJUST_MAX 10 * 1000 * 1000 #define MAX_ACK_TIME 666667 @@ -194,9 +194,10 @@ static TSMF_SAMPLE* tsmf_stream_pop_sample(TSMF_STREAM* stream, int sync) { if (stream->major_type == TSMF_MAJOR_TYPE_AUDIO) { - /* Check if some other stream has earlier sample that needs to be played first */ - /* Start time is more reliable than end time as some stream types seem to have incorrect - * end times from the server + /* Check if some other stream has earlier sample that needs to be played first + */ + /* Start time is more reliable than end time as some stream types seem to have + * incorrect end times from the server */ if (stream->last_start_time > AUDIO_TOLERANCE) { @@ -205,10 +206,10 @@ static TSMF_SAMPLE* tsmf_stream_pop_sample(TSMF_STREAM* stream, int sync) for (index = 0; index < count; index++) { - s = (TSMF_STREAM*) ArrayList_GetItem(presentation->stream_list, index); + s = (TSMF_STREAM*)ArrayList_GetItem(presentation->stream_list, index); - /* Start time is more reliable than end time as some stream types seem to have incorrect - * end times from the server + /* Start time is more reliable than end time as some stream types seem + * to have incorrect end times from the server */ if (s != stream && !s->eos && s->last_start_time && s->last_start_time < stream->last_start_time - AUDIO_TOLERANCE) @@ -224,8 +225,8 @@ static TSMF_SAMPLE* tsmf_stream_pop_sample(TSMF_STREAM* stream, int sync) } else { - /* Start time is more reliable than end time as some stream types seem to have incorrect - * end times from the server + /* Start time is more reliable than end time as some stream types seem to have + * incorrect end times from the server */ if (stream->last_start_time > presentation->audio_start_time) { @@ -240,16 +241,16 @@ static TSMF_SAMPLE* tsmf_stream_pop_sample(TSMF_STREAM* stream, int sync) if (pending) return NULL; - sample = (TSMF_SAMPLE*) Queue_Dequeue(stream->sample_list); + sample = (TSMF_SAMPLE*)Queue_Dequeue(stream->sample_list); - /* Only update stream last end time if the sample end time is valid and greater than the current stream end time */ - if (sample && (sample->end_time > stream->last_end_time) - && (!sample->invalidTimestamps)) + /* Only update stream last end time if the sample end time is valid and greater than the current + * stream end time */ + if (sample && (sample->end_time > stream->last_end_time) && (!sample->invalidTimestamps)) stream->last_end_time = sample->end_time; - /* Only update stream last start time if the sample start time is valid and greater than the current stream start time */ - if (sample && (sample->start_time > stream->last_start_time) - && (!sample->invalidTimestamps)) + /* Only update stream last start time if the sample start time is valid and greater than the + * current stream start time */ + if (sample && (sample->start_time > stream->last_start_time) && (!sample->invalidTimestamps)) stream->last_start_time = sample->start_time; return sample; @@ -271,8 +272,8 @@ static BOOL tsmf_sample_ack(TSMF_SAMPLE* sample) if (!sample) return FALSE; - return tsmf_playback_ack(sample->channel_callback, sample->sample_id, - sample->duration, sample->data_size); + return tsmf_playback_ack(sample->channel_callback, sample->sample_id, sample->duration, + sample->data_size); } static BOOL tsmf_sample_queue_ack(TSMF_SAMPLE* sample) @@ -300,7 +301,7 @@ static BOOL tsmf_stream_process_ack(void* arg, BOOL force) return TRUE; Queue_Lock(stream->sample_ack_list); - sample = (TSMF_SAMPLE*) Queue_Peek(stream->sample_ack_list); + sample = (TSMF_SAMPLE*)Queue_Peek(stream->sample_ack_list); if (!sample) { @@ -343,14 +344,14 @@ finally: } TSMF_PRESENTATION* tsmf_presentation_new(const BYTE* guid, - IWTSVirtualChannelCallback* pChannelCallback) + IWTSVirtualChannelCallback* pChannelCallback) { TSMF_PRESENTATION* presentation; if (!guid || !pChannelCallback) return NULL; - presentation = (TSMF_PRESENTATION*) calloc(1, sizeof(TSMF_PRESENTATION)); + presentation = (TSMF_PRESENTATION*)calloc(1, sizeof(TSMF_PRESENTATION)); if (!presentation) { @@ -366,8 +367,7 @@ TSMF_PRESENTATION* tsmf_presentation_new(const BYTE* guid, if (!(presentation->stream_list = ArrayList_New(TRUE))) goto error_stream_list; - ArrayList_Object(presentation->stream_list)->fnObjectFree = - _tsmf_stream_free; + ArrayList_Object(presentation->stream_list)->fnObjectFree = _tsmf_stream_free; if (ArrayList_Add(presentation_list, presentation) < 0) goto error_add; @@ -382,13 +382,13 @@ error_stream_list: static char* guid_to_string(const BYTE* guid, char* str, size_t len) { - int i; + size_t i; if (!guid || !str) return NULL; - for (i = 0; i < GUID_SIZE && len > 2 * i; i++) - sprintf_s(str + (2 * i), len - 2 * i, "%02"PRIX8"", guid[i]); + for (i = 0; i < GUID_SIZE && (len > 2 * i); i++) + sprintf_s(str + (2 * i), len - 2 * i, "%02" PRIX8 "", guid[i]); return str; } @@ -405,7 +405,7 @@ TSMF_PRESENTATION* tsmf_presentation_find_by_id(const BYTE* guid) for (index = 0; index < count; index++) { - presentation = (TSMF_PRESENTATION*) ArrayList_GetItem(presentation_list, index); + presentation = (TSMF_PRESENTATION*)ArrayList_GetItem(presentation_list, index); if (memcmp(presentation->presentation_id, guid, GUID_SIZE) == 0) { @@ -417,8 +417,8 @@ TSMF_PRESENTATION* tsmf_presentation_find_by_id(const BYTE* guid) ArrayList_Unlock(presentation_list); if (!found) - WLog_WARN(TAG, "presentation id %s not found", guid_to_string(guid, guid_str, - sizeof(guid_str))); + WLog_WARN(TAG, "presentation id %s not found", + guid_to_string(guid, guid_str, sizeof(guid_str))); return (found) ? presentation : NULL; } @@ -429,10 +429,9 @@ static BOOL tsmf_sample_playback_video(TSMF_SAMPLE* sample) TSMF_VIDEO_FRAME_EVENT event; TSMF_STREAM* stream = sample->stream; TSMF_PRESENTATION* presentation = stream->presentation; - TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*) - sample->channel_callback; - TsmfClientContext* tsmf = (TsmfClientContext*) callback->plugin->pInterface; - DEBUG_TSMF("MessageId %"PRIu32" EndTime %"PRIu64" data_size %"PRIu32" consumed.", + TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*)sample->channel_callback; + TsmfClientContext* tsmf = (TsmfClientContext*)callback->plugin->pInterface; + DEBUG_TSMF("MessageId %" PRIu32 " EndTime %" PRIu64 " data_size %" PRIu32 " consumed.", sample->sample_id, sample->end_time, sample->data_size); if (sample->data) @@ -444,8 +443,7 @@ static BOOL tsmf_sample_playback_video(TSMF_SAMPLE* sample) */ if (stream->next_start_time > t && ((sample->start_time >= presentation->audio_start_time) || - ((sample->start_time < stream->last_start_time) - && (!sample->invalidTimestamps)))) + ((sample->start_time < stream->last_start_time) && (!sample->invalidTimestamps)))) { USleep((stream->next_start_time - t) / 10); } @@ -465,7 +463,7 @@ static BOOL tsmf_sample_playback_video(TSMF_SAMPLE* sample) if (presentation->nr_rects > 0) { event.numVisibleRects = presentation->nr_rects; - event.visibleRects = (RECTANGLE_16*) calloc(event.numVisibleRects, sizeof(RECTANGLE_16)); + event.visibleRects = (RECTANGLE_16*)calloc(event.numVisibleRects, sizeof(RECTANGLE_16)); if (!event.visibleRects) { @@ -473,7 +471,8 @@ static BOOL tsmf_sample_playback_video(TSMF_SAMPLE* sample) return FALSE; } - memcpy(event.visibleRects, presentation->rects, presentation->nr_rects * sizeof(RDP_RECT)); + memcpy(event.visibleRects, presentation->rects, + presentation->nr_rects * sizeof(RDP_RECT)); presentation->nr_rects = 0; } @@ -491,7 +490,7 @@ static BOOL tsmf_sample_playback_video(TSMF_SAMPLE* sample) fwrite("P5\n", 1, 3, fp); sprintf_s(buf, sizeof(buf), "%"PRIu32" %"PRIu32"\n", sample->stream->width, sample->stream->height); - fwrite(buf, 1, strlen(buf), fp); + fwrite(buf, 1, strnlen(buf, sizeof(buf)), fp); fwrite("255\n", 1, 4, fp); fwrite(sample->data, 1, sample->stream->width * sample->stream->height, fp); fflush(fp); @@ -500,7 +499,8 @@ static BOOL tsmf_sample_playback_video(TSMF_SAMPLE* sample) frame_id++; #endif - /* The frame data ownership is passed to the event object, and is freed after the event is processed. */ + /* The frame data ownership is passed to the event object, and is freed after the event is + * processed. */ sample->data = NULL; sample->decoded_size = 0; @@ -521,13 +521,13 @@ static BOOL tsmf_sample_playback_audio(TSMF_SAMPLE* sample) UINT64 latency = 0; TSMF_STREAM* stream = sample->stream; BOOL ret; - DEBUG_TSMF("MessageId %"PRIu32" EndTime %"PRIu64" consumed.", - sample->sample_id, sample->end_time); + DEBUG_TSMF("MessageId %" PRIu32 " EndTime %" PRIu64 " consumed.", sample->sample_id, + sample->end_time); if (stream->audio && sample->data) { - ret = sample->stream->audio->Play(sample->stream->audio, sample->data, - sample->decoded_size); + ret = + sample->stream->audio->Play(sample->stream->audio, sample->data, sample->decoded_size); free(sample->data); sample->data = NULL; sample->decoded_size = 0; @@ -567,9 +567,10 @@ static BOOL tsmf_sample_playback(TSMF_SAMPLE* sample) { if (stream->decoder->DecodeEx) { - /* Try to "sync" video buffers to audio buffers by looking at the running time for each stream - * The difference between the two running times causes an offset between audio and video actual - * render times. So, we try to adjust timestamps on the video buffer to match those on the audio buffer. + /* Try to "sync" video buffers to audio buffers by looking at the running time for each + * stream The difference between the two running times causes an offset between audio + * and video actual render times. So, we try to adjust timestamps on the video buffer to + * match those on the audio buffer. */ if (stream->major_type == TSMF_MAJOR_TYPE_VIDEO) { @@ -582,14 +583,14 @@ static BOOL tsmf_sample_playback(TSMF_SAMPLE* sample) for (index = 0; index < count; index++) { UINT64 time_diff; - temp_stream = (TSMF_STREAM*) ArrayList_GetItem(presentation->stream_list, - index); + temp_stream = (TSMF_STREAM*)ArrayList_GetItem(presentation->stream_list, index); if (temp_stream->major_type == TSMF_MAJOR_TYPE_AUDIO) { - UINT64 video_time = (UINT64) stream->decoder->GetRunningTime(stream->decoder); - UINT64 audio_time = (UINT64) temp_stream->decoder->GetRunningTime( - temp_stream->decoder); + UINT64 video_time = + (UINT64)stream->decoder->GetRunningTime(stream->decoder); + UINT64 audio_time = + (UINT64)temp_stream->decoder->GetRunningTime(temp_stream->decoder); UINT64 max_adjust = VIDEO_ADJUST_MAX; if (video_time < audio_time) @@ -610,9 +611,9 @@ static BOOL tsmf_sample_playback(TSMF_SAMPLE* sample) ArrayList_Unlock(presentation->stream_list); } - ret = stream->decoder->DecodeEx(stream->decoder, sample->data, - sample->data_size, sample->extensions, - sample->start_time, sample->end_time, sample->duration); + ret = stream->decoder->DecodeEx(stream->decoder, sample->data, sample->data_size, + sample->extensions, sample->start_time, + sample->end_time, sample->duration); } else { @@ -643,7 +644,7 @@ static BOOL tsmf_sample_playback(TSMF_SAMPLE* sample) { pixfmt = stream->decoder->GetDecodedFormat(stream->decoder); - if (pixfmt == ((UINT32) - 1)) + if (pixfmt == ((UINT32)-1)) { WLog_ERR(TAG, "unable to decode video format"); @@ -664,7 +665,7 @@ static BOOL tsmf_sample_playback(TSMF_SAMPLE* sample) if (ret && (width != stream->width || height != stream->height)) { - DEBUG_TSMF("video dimension changed to %"PRIu32" x %"PRIu32"", width, height); + DEBUG_TSMF("video dimension changed to %" PRIu32 " x %" PRIu32 "", width, height); stream->width = width; stream->height = height; } @@ -673,19 +674,16 @@ static BOOL tsmf_sample_playback(TSMF_SAMPLE* sample) if (stream->decoder->GetDecodedData) { - sample->data = stream->decoder->GetDecodedData(stream->decoder, - &sample->decoded_size); + sample->data = stream->decoder->GetDecodedData(stream->decoder, &sample->decoded_size); switch (sample->stream->major_type) { case TSMF_MAJOR_TYPE_VIDEO: - ret = tsmf_sample_playback_video(sample) && - tsmf_sample_queue_ack(sample); + ret = tsmf_sample_playback_video(sample) && tsmf_sample_queue_ack(sample); break; case TSMF_MAJOR_TYPE_AUDIO: - ret = tsmf_sample_playback_audio(sample) && - tsmf_sample_queue_ack(sample); + ret = tsmf_sample_playback_audio(sample) && tsmf_sample_queue_ack(sample); break; } } @@ -702,28 +700,20 @@ 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) { case TSMF_MAJOR_TYPE_VIDEO: - { - break; - } + { + break; + } case TSMF_MAJOR_TYPE_AUDIO: - { - break; - } + { + break; + } } sample->ack_time = ack_anticipation_time; @@ -741,9 +731,9 @@ static BOOL tsmf_sample_playback(TSMF_SAMPLE* sample) static DWORD WINAPI tsmf_stream_ack_func(LPVOID arg) { HANDLE hdl[2]; - TSMF_STREAM* stream = (TSMF_STREAM*) arg; + TSMF_STREAM* stream = (TSMF_STREAM*)arg; UINT error = CHANNEL_RC_OK; - DEBUG_TSMF("in %"PRIu32"", stream->stream_id); + DEBUG_TSMF("in %" PRIu32 "", stream->stream_id); hdl[0] = stream->stopEvent; hdl[1] = Queue_Event(stream->sample_ack_list); @@ -754,7 +744,7 @@ static DWORD WINAPI tsmf_stream_ack_func(LPVOID arg) if (ev == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", error); break; } @@ -764,8 +754,7 @@ static DWORD WINAPI tsmf_stream_ack_func(LPVOID arg) if (stream->eos) { - while ((stream->currentBufferLevel > 0) - && !(tsmf_stream_process_ack(stream, TRUE))) + while ((stream->currentBufferLevel > 0) && !(tsmf_stream_process_ack(stream, TRUE))) { DEBUG_TSMF("END OF STREAM PROCESSING!"); @@ -814,10 +803,9 @@ static DWORD WINAPI tsmf_stream_ack_func(LPVOID arg) } if (error && stream->rdpcontext) - setChannelError(stream->rdpcontext, error, - "tsmf_stream_ack_func reported an error"); + setChannelError(stream->rdpcontext, error, "tsmf_stream_ack_func reported an error"); - DEBUG_TSMF("out %"PRIu32"", stream->stream_id); + DEBUG_TSMF("out %" PRIu32 "", stream->stream_id); ExitThread(error); return error; } @@ -826,24 +814,26 @@ static DWORD WINAPI tsmf_stream_playback_func(LPVOID arg) { HANDLE hdl[2]; TSMF_SAMPLE* sample = NULL; - TSMF_STREAM* stream = (TSMF_STREAM*) arg; + TSMF_STREAM* stream = (TSMF_STREAM*)arg; TSMF_PRESENTATION* presentation = stream->presentation; UINT error = CHANNEL_RC_OK; DWORD status; - DEBUG_TSMF("in %"PRIu32"", stream->stream_id); + DEBUG_TSMF("in %" PRIu32 "", stream->stream_id); - if (stream->major_type == TSMF_MAJOR_TYPE_AUDIO && - stream->sample_rate && stream->channels && stream->bits_per_sample) + if (stream->major_type == TSMF_MAJOR_TYPE_AUDIO && stream->sample_rate && stream->channels && + stream->bits_per_sample) { if (stream->decoder) { if (stream->decoder->GetDecodedData) { stream->audio = tsmf_load_audio_device( - presentation->audio_name - && presentation->audio_name[0] ? presentation->audio_name : NULL, - presentation->audio_device - && presentation->audio_device[0] ? presentation->audio_device : NULL); + presentation->audio_name && presentation->audio_name[0] + ? presentation->audio_name + : NULL, + presentation->audio_device && presentation->audio_device[0] + ? presentation->audio_device + : NULL); if (stream->audio) { @@ -864,7 +854,7 @@ static DWORD WINAPI tsmf_stream_playback_func(LPVOID arg) if (status == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", error); break; } @@ -873,7 +863,7 @@ static DWORD WINAPI tsmf_stream_playback_func(LPVOID arg) if (status == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error); break; } @@ -904,18 +894,16 @@ static DWORD WINAPI tsmf_stream_playback_func(LPVOID arg) } if (error && stream->rdpcontext) - setChannelError(stream->rdpcontext, error, - "tsmf_stream_playback_func reported an error"); + setChannelError(stream->rdpcontext, error, "tsmf_stream_playback_func reported an error"); - DEBUG_TSMF("out %"PRIu32"", stream->stream_id); + DEBUG_TSMF("out %" PRIu32 "", stream->stream_id); ExitThread(error); return error; } static BOOL tsmf_stream_start(TSMF_STREAM* stream) { - if (!stream || !stream->presentation || !stream->decoder - || !stream->decoder->Control) + if (!stream || !stream->presentation || !stream->decoder || !stream->decoder->Control) return TRUE; stream->eos = 0; @@ -963,8 +951,7 @@ static BOOL tsmf_stream_restart(TSMF_STREAM* stream) return stream->decoder->Control(stream->decoder, Control_Restart, NULL); } -static BOOL tsmf_stream_change_volume(TSMF_STREAM* stream, UINT32 newVolume, - UINT32 muted) +static BOOL tsmf_stream_change_volume(TSMF_STREAM* stream, UINT32 newVolume, UINT32 muted) { if (!stream || !stream->decoder) return TRUE; @@ -981,8 +968,8 @@ static BOOL tsmf_stream_change_volume(TSMF_STREAM* stream, UINT32 newVolume, return TRUE; } -BOOL tsmf_presentation_volume_changed(TSMF_PRESENTATION* presentation, - UINT32 newVolume, UINT32 muted) +BOOL tsmf_presentation_volume_changed(TSMF_PRESENTATION* presentation, UINT32 newVolume, + UINT32 muted) { UINT32 index; UINT32 count; @@ -995,7 +982,7 @@ BOOL tsmf_presentation_volume_changed(TSMF_PRESENTATION* presentation, for (index = 0; index < count; index++) { - stream = (TSMF_STREAM*) ArrayList_GetItem(presentation->stream_list, index); + stream = (TSMF_STREAM*)ArrayList_GetItem(presentation->stream_list, index); ret &= tsmf_stream_change_volume(stream, newVolume, muted); } @@ -1014,7 +1001,7 @@ BOOL tsmf_presentation_paused(TSMF_PRESENTATION* presentation) for (index = 0; index < count; index++) { - stream = (TSMF_STREAM*) ArrayList_GetItem(presentation->stream_list, index); + stream = (TSMF_STREAM*)ArrayList_GetItem(presentation->stream_list, index); ret &= tsmf_stream_pause(stream); } @@ -1033,7 +1020,7 @@ BOOL tsmf_presentation_restarted(TSMF_PRESENTATION* presentation) for (index = 0; index < count; index++) { - stream = (TSMF_STREAM*) ArrayList_GetItem(presentation->stream_list, index); + stream = (TSMF_STREAM*)ArrayList_GetItem(presentation->stream_list, index); ret &= tsmf_stream_restart(stream); } @@ -1052,7 +1039,7 @@ BOOL tsmf_presentation_start(TSMF_PRESENTATION* presentation) for (index = 0; index < count; index++) { - stream = (TSMF_STREAM*) ArrayList_GetItem(presentation->stream_list, index); + stream = (TSMF_STREAM*)ArrayList_GetItem(presentation->stream_list, index); ret &= tsmf_stream_start(stream); } @@ -1075,13 +1062,12 @@ UINT tsmf_presentation_sync(TSMF_PRESENTATION* presentation) for (index = 0; index < count; index++) { - TSMF_STREAM* stream = (TSMF_STREAM*) ArrayList_GetItem( - presentation->stream_list, index); + TSMF_STREAM* stream = (TSMF_STREAM*)ArrayList_GetItem(presentation->stream_list, index); if (WaitForSingleObject(stream->ready, 500) == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error); return error; } } @@ -1101,7 +1087,7 @@ BOOL tsmf_presentation_stop(TSMF_PRESENTATION* presentation) for (index = 0; index < count; index++) { - stream = (TSMF_STREAM*) ArrayList_GetItem(presentation->stream_list, index); + stream = (TSMF_STREAM*)ArrayList_GetItem(presentation->stream_list, index); ret &= tsmf_stream_stop(stream); } @@ -1111,8 +1097,9 @@ BOOL tsmf_presentation_stop(TSMF_PRESENTATION* presentation) return ret; } -BOOL tsmf_presentation_set_geometry_info(TSMF_PRESENTATION* presentation, - UINT32 x, UINT32 y, UINT32 width, UINT32 height, int num_rects, RDP_RECT* rects) +BOOL tsmf_presentation_set_geometry_info(TSMF_PRESENTATION* presentation, UINT32 x, UINT32 y, + UINT32 width, UINT32 height, int num_rects, + RDP_RECT* rects) { UINT32 index; UINT32 count; @@ -1125,9 +1112,10 @@ BOOL tsmf_presentation_set_geometry_info(TSMF_PRESENTATION* presentation, if (!width || !height) return TRUE; - /* Streams can be added/removed from the presentation and the server will resend geometry info when a new stream is - * added to the presentation. Also, num_rects is used to indicate whether or not the window is visible. - * So, always process a valid message with unchanged position/size and/or no visibility rects. + /* Streams can be added/removed from the presentation and the server will resend geometry info + * when a new stream is added to the presentation. Also, num_rects is used to indicate whether + * or not the window is visible. So, always process a valid message with unchanged position/size + * and/or no visibility rects. */ presentation->x = x; presentation->y = y; @@ -1140,13 +1128,14 @@ BOOL tsmf_presentation_set_geometry_info(TSMF_PRESENTATION* presentation, presentation->nr_rects = num_rects; presentation->rects = tmp_rects; - CopyMemory(presentation->rects, rects, sizeof(RDP_RECT) * num_rects); + if (presentation->rects) + CopyMemory(presentation->rects, rects, sizeof(RDP_RECT) * num_rects); ArrayList_Lock(presentation->stream_list); count = ArrayList_Count(presentation->stream_list); for (index = 0; index < count; index++) { - stream = (TSMF_STREAM*) ArrayList_GetItem(presentation->stream_list, index); + stream = (TSMF_STREAM*)ArrayList_GetItem(presentation->stream_list, index); if (!stream->decoder) continue; @@ -1154,7 +1143,7 @@ BOOL tsmf_presentation_set_geometry_info(TSMF_PRESENTATION* presentation, if (stream->decoder->UpdateRenderingArea) { ret = stream->decoder->UpdateRenderingArea(stream->decoder, x, y, width, height, - num_rects, rects); + num_rects, rects); } } @@ -1162,8 +1151,8 @@ BOOL tsmf_presentation_set_geometry_info(TSMF_PRESENTATION* presentation, return ret; } -void tsmf_presentation_set_audio_device(TSMF_PRESENTATION* presentation, - const char* name, const char* device) +void tsmf_presentation_set_audio_device(TSMF_PRESENTATION* presentation, const char* name, + const char* device) { presentation->audio_name = name; presentation->audio_device = device; @@ -1173,7 +1162,7 @@ BOOL tsmf_stream_flush(TSMF_STREAM* stream) { BOOL ret = TRUE; - //TSMF_SAMPLE* sample; + // TSMF_SAMPLE* sample; /* TODO: free lists */ if (stream->audio) ret = stream->audio->Flush(stream->audio); @@ -1222,11 +1211,11 @@ TSMF_STREAM* tsmf_stream_new(TSMF_PRESENTATION* presentation, UINT32 stream_id, if (stream) { - WLog_ERR(TAG, "duplicated stream id %"PRIu32"!", stream_id); + WLog_ERR(TAG, "duplicated stream id %" PRIu32 "!", stream_id); return NULL; } - stream = (TSMF_STREAM*) calloc(1, sizeof(TSMF_STREAM)); + stream = (TSMF_STREAM*)calloc(1, sizeof(TSMF_STREAM)); if (!stream) { @@ -1265,14 +1254,14 @@ TSMF_STREAM* tsmf_stream_new(TSMF_PRESENTATION* presentation, UINT32 stream_id, goto error_sample_ack_list; stream->sample_ack_list->object.fnObjectFree = tsmf_sample_free; - stream->play_thread = CreateThread(NULL, 0, tsmf_stream_playback_func, - stream, CREATE_SUSPENDED, NULL); + stream->play_thread = + CreateThread(NULL, 0, tsmf_stream_playback_func, stream, CREATE_SUSPENDED, NULL); if (!stream->play_thread) goto error_play_thread; - stream->ack_thread = CreateThread(NULL, 0, tsmf_stream_ack_func, stream, - CREATE_SUSPENDED, NULL); + stream->ack_thread = + CreateThread(NULL, 0, tsmf_stream_ack_func, stream, CREATE_SUSPENDED, NULL); if (!stream->ack_thread) goto error_ack_thread; @@ -1286,13 +1275,13 @@ error_add: SetEvent(stream->stopEvent); if (WaitForSingleObject(stream->ack_thread, INFINITE) == WAIT_FAILED) - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", GetLastError()); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", GetLastError()); error_ack_thread: SetEvent(stream->stopEvent); if (WaitForSingleObject(stream->play_thread, INFINITE) == WAIT_FAILED) - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", GetLastError()); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", GetLastError()); error_play_thread: Queue_Free(stream->sample_ack_list); @@ -1313,8 +1302,7 @@ void tsmf_stream_start_threads(TSMF_STREAM* stream) ResumeThread(stream->ack_thread); } -TSMF_STREAM* tsmf_stream_find_by_id(TSMF_PRESENTATION* presentation, - UINT32 stream_id) +TSMF_STREAM* tsmf_stream_find_by_id(TSMF_PRESENTATION* presentation, UINT32 stream_id) { UINT32 index; UINT32 count; @@ -1325,7 +1313,7 @@ TSMF_STREAM* tsmf_stream_find_by_id(TSMF_PRESENTATION* presentation, for (index = 0; index < count; index++) { - stream = (TSMF_STREAM*) ArrayList_GetItem(presentation->stream_list, index); + stream = (TSMF_STREAM*)ArrayList_GetItem(presentation->stream_list, index); if (stream->stream_id == stream_id) { @@ -1363,20 +1351,21 @@ BOOL tsmf_stream_set_format(TSMF_STREAM* stream, const char* name, wStream* s) if (mediatype.MajorType == TSMF_MAJOR_TYPE_VIDEO) { - DEBUG_TSMF("video width %"PRIu32" height %"PRIu32" bit_rate %"PRIu32" frame_rate %f codec_data %"PRIu32"", + DEBUG_TSMF("video width %" PRIu32 " height %" PRIu32 " bit_rate %" PRIu32 + " frame_rate %f codec_data %" PRIu32 "", mediatype.Width, mediatype.Height, mediatype.BitRate, - (double) mediatype.SamplesPerSecond.Numerator / (double) - mediatype.SamplesPerSecond.Denominator, + (double)mediatype.SamplesPerSecond.Numerator / + (double)mediatype.SamplesPerSecond.Denominator, mediatype.ExtraDataSize); stream->minBufferLevel = VIDEO_MIN_BUFFER_LEVEL; stream->maxBufferLevel = VIDEO_MAX_BUFFER_LEVEL; } else if (mediatype.MajorType == TSMF_MAJOR_TYPE_AUDIO) { - DEBUG_TSMF("audio channel %"PRIu32" sample_rate %"PRIu32" bits_per_sample %"PRIu32" codec_data %"PRIu32"", + DEBUG_TSMF("audio channel %" PRIu32 " sample_rate %" PRIu32 " bits_per_sample %" PRIu32 + " codec_data %" PRIu32 "", mediatype.Channels, mediatype.SamplesPerSecond.Numerator, - mediatype.BitsPerSample, - mediatype.ExtraDataSize); + mediatype.BitsPerSample, mediatype.ExtraDataSize); stream->sample_rate = mediatype.SamplesPerSecond.Numerator; stream->channels = mediatype.Channels; stream->bits_per_sample = mediatype.BitsPerSample; @@ -1399,12 +1388,10 @@ BOOL tsmf_stream_set_format(TSMF_STREAM* stream, const char* name, wStream* s) return FALSE; if (stream->decoder->SetAckFunc) - ret &= stream->decoder->SetAckFunc(stream->decoder, tsmf_stream_process_ack, - stream); + ret &= stream->decoder->SetAckFunc(stream->decoder, tsmf_stream_process_ack, stream); if (stream->decoder->SetSyncFunc) - ret &= stream->decoder->SetSyncFunc(stream->decoder, tsmf_stream_resync, - stream); + ret &= stream->decoder->SetSyncFunc(stream->decoder, tsmf_stream_resync, stream); return ret; } @@ -1434,7 +1421,7 @@ void _tsmf_stream_free(void* obj) { if (WaitForSingleObject(stream->play_thread, INFINITE) == WAIT_FAILED) { - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", GetLastError()); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", GetLastError()); return; } @@ -1446,7 +1433,7 @@ void _tsmf_stream_free(void* obj) { if (WaitForSingleObject(stream->ack_thread, INFINITE) == WAIT_FAILED) { - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", GetLastError()); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", GetLastError()); return; } @@ -1475,11 +1462,9 @@ void tsmf_stream_free(TSMF_STREAM* stream) ArrayList_Remove(presentation->stream_list, stream); } -BOOL tsmf_stream_push_sample(TSMF_STREAM* stream, - IWTSVirtualChannelCallback* pChannelCallback, +BOOL tsmf_stream_push_sample(TSMF_STREAM* stream, IWTSVirtualChannelCallback* pChannelCallback, UINT32 sample_id, UINT64 start_time, UINT64 end_time, UINT64 duration, - UINT32 extensions, - UINT32 data_size, BYTE* data) + UINT32 extensions, UINT32 data_size, BYTE* data) { TSMF_SAMPLE* sample; SetEvent(stream->ready); @@ -1487,7 +1472,7 @@ BOOL tsmf_stream_push_sample(TSMF_STREAM* stream, if (TERMINATING) return TRUE; - sample = (TSMF_SAMPLE*) calloc(1, sizeof(TSMF_SAMPLE)); + sample = (TSMF_SAMPLE*)calloc(1, sizeof(TSMF_SAMPLE)); if (!sample) { diff --git a/channels/tsmf/client/tsmf_media.h b/channels/tsmf/client/tsmf_media.h index 3ab21dd..ade06da 100644 --- a/channels/tsmf/client/tsmf_media.h +++ b/channels/tsmf/client/tsmf_media.h @@ -37,7 +37,7 @@ typedef struct _TSMF_STREAM TSMF_STREAM; typedef struct _TSMF_SAMPLE TSMF_SAMPLE; TSMF_PRESENTATION* tsmf_presentation_new(const BYTE* guid, - IWTSVirtualChannelCallback* pChannelCallback); + IWTSVirtualChannelCallback* pChannelCallback); TSMF_PRESENTATION* tsmf_presentation_find_by_id(const BYTE* guid); BOOL tsmf_presentation_start(TSMF_PRESENTATION* presentation); BOOL tsmf_presentation_stop(TSMF_PRESENTATION* presentation); @@ -46,11 +46,11 @@ BOOL tsmf_presentation_paused(TSMF_PRESENTATION* presentation); BOOL tsmf_presentation_restarted(TSMF_PRESENTATION* presentation); BOOL tsmf_presentation_volume_changed(TSMF_PRESENTATION* presentation, UINT32 newVolume, UINT32 muted); -BOOL tsmf_presentation_set_geometry_info(TSMF_PRESENTATION* presentation, - UINT32 x, UINT32 y, UINT32 width, UINT32 height, - int num_rects, RDP_RECT* rects); -void tsmf_presentation_set_audio_device(TSMF_PRESENTATION* presentation, - const char* name, const char* device); +BOOL tsmf_presentation_set_geometry_info(TSMF_PRESENTATION* presentation, UINT32 x, UINT32 y, + UINT32 width, UINT32 height, int num_rects, + RDP_RECT* rects); +void tsmf_presentation_set_audio_device(TSMF_PRESENTATION* presentation, const char* name, + const char* device); void tsmf_presentation_free(TSMF_PRESENTATION* presentation); TSMF_STREAM* tsmf_stream_new(TSMF_PRESENTATION* presentation, UINT32 stream_id, @@ -63,11 +63,10 @@ void tsmf_stream_free(TSMF_STREAM* stream); BOOL tsmf_stream_flush(TSMF_STREAM* stream); BOOL tsmf_stream_push_sample(TSMF_STREAM* stream, IWTSVirtualChannelCallback* pChannelCallback, - UINT32 sample_id, UINT64 start_time, UINT64 end_time, UINT64 duration, UINT32 extensions, - UINT32 data_size, BYTE* data); + UINT32 sample_id, UINT64 start_time, UINT64 end_time, UINT64 duration, + UINT32 extensions, UINT32 data_size, BYTE* data); BOOL tsmf_media_init(void); void tsmf_stream_start_threads(TSMF_STREAM* stream); #endif /* FREERDP_CHANNEL_TSMF_CLIENT_MEDIA_H */ - diff --git a/channels/tsmf/client/tsmf_types.h b/channels/tsmf/client/tsmf_types.h index a6833f0..7e3823d 100644 --- a/channels/tsmf/client/tsmf_types.h +++ b/channels/tsmf/client/tsmf_types.h @@ -33,7 +33,10 @@ #ifdef WITH_DEBUG_TSMF #define DEBUG_TSMF(...) WLog_DBG(TAG, __VA_ARGS__) #else -#define DEBUG_TSMF(...) do { } while (0) +#define DEBUG_TSMF(...) \ + do \ + { \ + } while (0) #endif typedef struct _TS_AM_MEDIA_TYPE @@ -58,4 +61,3 @@ typedef struct _TS_AM_MEDIA_TYPE } TS_AM_MEDIA_TYPE; #endif /* FREERDP_CHANNEL_TSMF_CLIENT_TYPES_H */ - diff --git a/channels/urbdrc/CMakeLists.txt b/channels/urbdrc/CMakeLists.txt index c7e546f..bc570e0 100644 --- a/channels/urbdrc/CMakeLists.txt +++ b/channels/urbdrc/CMakeLists.txt @@ -17,38 +17,14 @@ define_channel("urbdrc") -if(NOT WIN32) - find_package(DevD) - find_package(UDev) - find_package(UUID) - find_package(DbusGlib) - find_package(libusb-1.0) -endif() +include_directories(common) +add_subdirectory(common) -if(DEVD_FOUND OR UDEV_FOUND) - include_directories(${UDEV_INCLUDE_DIR}) - if(UUID_FOUND AND DBUS_GLIB_FOUND AND LIBUSB_1_FOUND) - include_directories(${UUID_INCLUDE_DIRS}) - include_directories(${LIBUSB_1_INCLUDE_DIRS}) - include_directories(${DBUS_GLIB_INCLUDE_DIRS}) +if(WITH_CLIENT_CHANNELS) + option(WITH_DEBUG_URBDRC "Dump data send/received in URBDRC channel" OFF) - set(URBDRC_DEPENDENCIES_FOUND TRUE) - message(STATUS "Found all URBDRC dependencies") - else() - if(NOT UUID_FOUND) - message(STATUS "URBDRC dependencie not found: UUID") - endif() - if(NOT DBUS_GLIB_FOUND) - message(STATUS "URBDRC dependencie not found: DBUS_GLIB") - endif() - if(NOT LIBUSB_1_FOUND) - message(STATUS "URBDRC dependencie not found: LIBUSB_1") - endif() - endif() -endif() + find_package(libusb-1.0 REQUIRED) + include_directories(${LIBUSB_1_INCLUDE_DIRS}) -if(WITH_CLIENT_CHANNELS) - if(URBDRC_DEPENDENCIES_FOUND) - add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME}) - endif() + add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME}) endif() diff --git a/channels/urbdrc/ChannelOptions.cmake b/channels/urbdrc/ChannelOptions.cmake index ff00af9..770ba5e 100644 --- a/channels/urbdrc/ChannelOptions.cmake +++ b/channels/urbdrc/ChannelOptions.cmake @@ -1,7 +1,13 @@ -set(OPTION_DEFAULT OFF) -set(OPTION_CLIENT_DEFAULT OFF) -set(OPTION_SERVER_DEFAULT OFF) +if (IOS OR ANDROID) + set(OPTION_DEFAULT OFF) + set(OPTION_CLIENT_DEFAULT OFF) + set(OPTION_SERVER_DEFAULT OFF) +else() + set(OPTION_DEFAULT ON) + set(OPTION_CLIENT_DEFAULT ON) + set(OPTION_SERVER_DEFAULT OFF) +endif() define_channel_options(NAME "urbdrc" TYPE "dynamic" DESCRIPTION "USB Devices Virtual Channel Extension" diff --git a/channels/urbdrc/client/CMakeLists.txt b/channels/urbdrc/client/CMakeLists.txt index 24c7ee9..2d69618 100644 --- a/channels/urbdrc/client/CMakeLists.txt +++ b/channels/urbdrc/client/CMakeLists.txt @@ -18,25 +18,16 @@ define_channel_client("urbdrc") -set(${MODULE_PREFIX}_SRCS - searchman.c - searchman.h - isoch_queue.c - isoch_queue.h +set(${MODULE_PREFIX}_SRCS data_transfer.c data_transfer.h urbdrc_main.c urbdrc_main.h - urbdrc_types.h) - -include_directories(..) + $ + ) add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry") - - -#set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} libusb-devman) - set(${MODULE_PREFIX}_LIBS) if (UDEV_FOUND AND UDEV_LIBRARIES) set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${UDEV_LIBRARIES}) diff --git a/channels/urbdrc/client/data_transfer.c b/channels/urbdrc/client/data_transfer.c index 47ab753..ecacc69 100644 --- a/channels/urbdrc/client/data_transfer.c +++ b/channels/urbdrc/client/data_transfer.c @@ -21,415 +21,369 @@ #include #include #include -#include -#include -#include -#include +#include + +#include #include "urbdrc_types.h" #include "data_transfer.h" -static void usb_process_get_port_status(IUDEVICE* pdev, BYTE* OutputBuffer) +static void usb_process_get_port_status(IUDEVICE* pdev, wStream* out) { int bcdUSB = pdev->query_device_descriptor(pdev, BCD_USB); switch (bcdUSB) { case USB_v1_0: - data_write_UINT32(OutputBuffer, 0x303); + Stream_Write_UINT32(out, 0x303); break; case USB_v1_1: - data_write_UINT32(OutputBuffer, 0x103); + Stream_Write_UINT32(out, 0x103); break; case USB_v2_0: - data_write_UINT32(OutputBuffer, 0x503); + Stream_Write_UINT32(out, 0x503); break; default: - data_write_UINT32(OutputBuffer, 0x503); + Stream_Write_UINT32(out, 0x503); break; } } -#if ISOCH_FIFO - -static int func_check_isochronous_fds(IUDEVICE* pdev) +static UINT urb_write_completion(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, BOOL noAck, + wStream* out, UINT32 InterfaceId, UINT32 MessageId, + UINT32 RequestId, UINT32 usbd_status, UINT32 OutputBufferSize) { - int ret = 0; - BYTE* data_temp; - UINT32 size_temp, process_times = 2; - ISOCH_CALLBACK_QUEUE* isoch_queue = NULL; - ISOCH_CALLBACK_DATA* isoch = NULL; - URBDRC_CHANNEL_CALLBACK* callback; + if (!out) + return ERROR_INVALID_PARAMETER; - isoch_queue = (ISOCH_CALLBACK_QUEUE*) pdev->get_isoch_queue(pdev); - - while (process_times) + if (Stream_Capacity(out) < OutputBufferSize + 36) { - process_times--; - - if (isoch_queue == NULL || !pdev) - return -1; - - pthread_mutex_lock(&isoch_queue->isoch_loading); - - if (isoch_queue->head == NULL) - { - pthread_mutex_unlock(&isoch_queue->isoch_loading); - continue; - } - else - { - isoch = isoch_queue->head; - } - - if (!isoch || !isoch->out_data) - { - pthread_mutex_unlock(&isoch_queue->isoch_loading); - continue; - } - else - { - callback = (URBDRC_CHANNEL_CALLBACK*) isoch->callback; - size_temp = isoch->out_size; - data_temp = isoch->out_data; - - ret = isoch_queue->unregister_data(isoch_queue, isoch); + Stream_Free(out, TRUE); + return ERROR_INVALID_PARAMETER; + } - if (!ret) - WLog_DBG(TAG, "isoch_queue_unregister_data: Not found isoch data!!"); + Stream_SetPosition(out, 0); + Stream_Write_UINT32(out, InterfaceId); /** interface */ + Stream_Write_UINT32(out, MessageId); /** message id */ - pthread_mutex_unlock(&isoch_queue->isoch_loading); + if (OutputBufferSize != 0) + Stream_Write_UINT32(out, URB_COMPLETION); + else + Stream_Write_UINT32(out, URB_COMPLETION_NO_DATA); - if (pdev && !pdev->isSigToEnd(pdev)) - { - callback->channel->Write(callback->channel, size_temp, data_temp, NULL); - zfree(data_temp); - } - } - } + Stream_Write_UINT32(out, RequestId); /** RequestId */ + Stream_Write_UINT32(out, 8); /** CbTsUrbResult */ + /** TsUrbResult TS_URB_RESULT_HEADER */ + Stream_Write_UINT16(out, 8); /** Size */ + Stream_Write_UINT16(out, 0); /* Padding */ + Stream_Write_UINT32(out, usbd_status); /** UsbdStatus */ + Stream_Write_UINT32(out, 0); /** HResult */ + Stream_Write_UINT32(out, OutputBufferSize); /** OutputBufferSize */ + Stream_Seek(out, OutputBufferSize); + + if (!noAck) + return stream_write_and_free(callback->plugin, callback->channel, out); + else + Stream_Free(out, TRUE); - return 0; + return ERROR_SUCCESS; } -#endif +static wStream* urb_create_iocompletion(UINT32 InterfaceField, UINT32 MessageId, UINT32 RequestId, + UINT32 OutputBufferSize) +{ + const UINT32 InterfaceId = (STREAM_ID_PROXY << 30) | (InterfaceField & 0x3FFFFFFF); + wStream* out = Stream_New(NULL, OutputBufferSize + 28); + + if (!out) + return NULL; + + Stream_Write_UINT32(out, InterfaceId); /** interface */ + Stream_Write_UINT32(out, MessageId); /** message id */ + Stream_Write_UINT32(out, IOCONTROL_COMPLETION); /** function id */ + Stream_Write_UINT32(out, RequestId); /** RequestId */ + Stream_Write_UINT32(out, USBD_STATUS_SUCCESS); /** HResult */ + Stream_Write_UINT32(out, OutputBufferSize); /** Information */ + Stream_Write_UINT32(out, OutputBufferSize); /** OutputBufferSize */ + return out; +} -static int urbdrc_process_register_request_callback(URBDRC_CHANNEL_CALLBACK* callback, - BYTE* data, UINT32 data_sizem, IUDEVMAN* udevman, UINT32 UsbDevice) +static UINT urbdrc_process_register_request_callback(IUDEVICE* pdev, + URBDRC_CHANNEL_CALLBACK* callback, wStream* s, + IUDEVMAN* udevman) { - IUDEVICE* pdev; UINT32 NumRequestCompletion = 0; UINT32 RequestCompletion = 0; + URBDRC_PLUGIN* urbdrc; - WLog_DBG(TAG, "urbdrc_process_register_request_callback"); + if (!callback || !s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); + urbdrc = (URBDRC_PLUGIN*)callback->plugin; - if (pdev == NULL) - return 0; + if (!urbdrc) + return ERROR_INVALID_PARAMETER; - if (data_sizem >= 8) + WLog_Print(urbdrc->log, WLOG_DEBUG, "urbdrc_process_register_request_callback"); + + if (Stream_GetRemainingLength(s) >= 8) { - data_read_UINT32(data + 0, NumRequestCompletion); /** must be 1 */ + Stream_Read_UINT32(s, NumRequestCompletion); /** must be 1 */ /** RequestCompletion: - * unique Request Completion interface for the client to use */ - data_read_UINT32(data + 4, RequestCompletion); + * unique Request Completion interface for the client to use */ + Stream_Read_UINT32(s, RequestCompletion); pdev->set_ReqCompletion(pdev, RequestCompletion); } - else /** Unregister the device */ + else if (Stream_GetRemainingLength(s) >= 4) /** Unregister the device */ { - data_read_UINT32(data + 0, RequestCompletion); + Stream_Read_UINT32(s, RequestCompletion); - if (1)//(pdev->get_ReqCompletion(pdev) == RequestCompletion) - { - /** The wrong driver may also receive this message, So we - * need some time(default 3s) to check the driver or delete - * it */ - sleep(3); - callback->channel->Write(callback->channel, 0, NULL, NULL); - pdev->SigToEnd(pdev); - } + if (pdev->get_ReqCompletion(pdev) == RequestCompletion) + pdev->setChannelClosed(pdev); } + else + return ERROR_INVALID_DATA; - return 0; + return ERROR_SUCCESS; } -static int urbdrc_process_cancel_request(BYTE* data, UINT32 data_sizem, IUDEVMAN* udevman, UINT32 UsbDevice) +static UINT urbdrc_process_cancel_request(IUDEVICE* pdev, wStream* s, IUDEVMAN* udevman) { - IUDEVICE* pdev; UINT32 CancelId; - int error = 0; + URBDRC_PLUGIN* urbdrc; - data_read_UINT32(data + 0, CancelId); /** RequestId */ + if (!s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; - WLog_DBG(TAG, "urbdrc_process_cancel_request: id 0x%"PRIx32"", CancelId); + urbdrc = (URBDRC_PLUGIN*)udevman->plugin; - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); + if (Stream_GetRemainingLength(s) < 4) + return ERROR_INVALID_DATA; - if (pdev == NULL) - return 0; + Stream_Read_UINT32(s, CancelId); + WLog_Print(urbdrc->log, WLOG_DEBUG, "CANCEL_REQUEST: CancelId=%08" PRIx32 "", CancelId); - error = pdev->cancel_transfer_request(pdev, CancelId); + if (pdev->cancel_transfer_request(pdev, CancelId) < 0) + return ERROR_INTERNAL_ERROR; - return error; + return ERROR_SUCCESS; } -static int urbdrc_process_retract_device_request(BYTE* data, UINT32 data_sizem, IUDEVMAN* udevman, UINT32 UsbDevice) +static UINT urbdrc_process_retract_device_request(IUDEVICE* pdev, wStream* s, IUDEVMAN* udevman) { UINT32 Reason; - WLog_DBG(TAG, "urbdrc_process_retract_device_request"); + URBDRC_PLUGIN* urbdrc; + + if (!s || !udevman) + return ERROR_INVALID_PARAMETER; + + urbdrc = (URBDRC_PLUGIN*)udevman->plugin; + + if (!urbdrc) + return ERROR_INVALID_PARAMETER; - data_read_UINT32(data + 0, Reason); /** Reason */ + if (Stream_GetRemainingLength(s) < 4) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, Reason); /** Reason */ switch (Reason) { case UsbRetractReason_BlockedByPolicy: - WLog_DBG(TAG, "UsbRetractReason_BlockedByPolicy: now it is not support"); - return -1; - break; + WLog_Print(urbdrc->log, WLOG_DEBUG, + "UsbRetractReason_BlockedByPolicy: now it is not support"); + return ERROR_ACCESS_DENIED; default: - WLog_DBG(TAG, "urbdrc_process_retract_device_request: Unknown Reason %"PRIu32"", Reason); - return -1; - break; + WLog_Print(urbdrc->log, WLOG_DEBUG, + "urbdrc_process_retract_device_request: Unknown Reason %" PRIu32 "", Reason); + return ERROR_ACCESS_DENIED; } - return 0; + return ERROR_SUCCESS; } -static int urbdrc_process_io_control(URBDRC_CHANNEL_CALLBACK* callback, BYTE* data, - UINT32 data_sizem, UINT32 MessageId, IUDEVMAN * udevman, UINT32 UsbDevice) +static UINT urbdrc_process_io_control(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, wStream* s, + UINT32 MessageId, IUDEVMAN* udevman) { - IUDEVICE* pdev; - UINT32 out_size; UINT32 InterfaceId; UINT32 IoControlCode; UINT32 InputBufferSize; UINT32 OutputBufferSize; UINT32 RequestId; UINT32 usbd_status = USBD_STATUS_SUCCESS; - BYTE* OutputBuffer; - BYTE* out_data; - int i, offset, success = 0; + wStream* out; + int success = 0; + URBDRC_PLUGIN* urbdrc; - WLog_DBG(TAG, "urbdrc_process__io_control"); + if (!callback || !s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; - data_read_UINT32(data + 0, IoControlCode); - data_read_UINT32(data + 4, InputBufferSize); - data_read_UINT32(data + 8 + InputBufferSize, OutputBufferSize); - data_read_UINT32(data + 12 + InputBufferSize, RequestId); + urbdrc = (URBDRC_PLUGIN*)callback->plugin; - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); - if (pdev == NULL) - return 0; + if (!urbdrc) + return ERROR_INVALID_PARAMETER; + + if (Stream_GetRemainingLength(s) < 8) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, IoControlCode); + Stream_Read_UINT32(s, InputBufferSize); - InterfaceId = ((STREAM_ID_PROXY<<30) | pdev->get_ReqCompletion(pdev)); + if (!Stream_SafeSeek(s, InputBufferSize)) + return ERROR_INVALID_DATA; + if (Stream_GetRemainingLength(s) < 8ULL) + return ERROR_INVALID_DATA; - /** process */ - OutputBuffer = (BYTE *)calloc(1, OutputBufferSize); - if (!OutputBuffer) + Stream_Read_UINT32(s, OutputBufferSize); + Stream_Read_UINT32(s, RequestId); + InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); + out = urb_create_iocompletion(InterfaceId, MessageId, RequestId, OutputBufferSize); + + if (!out) return ERROR_OUTOFMEMORY; switch (IoControlCode) { - case IOCTL_INTERNAL_USB_SUBMIT_URB: /** 0x00220003 */ - WLog_DBG(TAG, "ioctl: IOCTL_INTERNAL_USB_SUBMIT_URB"); - WLog_ERR(TAG, " Function IOCTL_INTERNAL_USB_SUBMIT_URB: Unchecked"); + case IOCTL_INTERNAL_USB_SUBMIT_URB: /** 0x00220003 */ + WLog_Print(urbdrc->log, WLOG_DEBUG, "ioctl: IOCTL_INTERNAL_USB_SUBMIT_URB"); + WLog_Print(urbdrc->log, WLOG_ERROR, + " Function IOCTL_INTERNAL_USB_SUBMIT_URB: Unchecked"); break; - case IOCTL_INTERNAL_USB_RESET_PORT: /** 0x00220007 */ - WLog_DBG(TAG, "ioctl: IOCTL_INTERNAL_USB_RESET_PORT"); + case IOCTL_INTERNAL_USB_RESET_PORT: /** 0x00220007 */ + WLog_Print(urbdrc->log, WLOG_DEBUG, "ioctl: IOCTL_INTERNAL_USB_RESET_PORT"); break; case IOCTL_INTERNAL_USB_GET_PORT_STATUS: /** 0x00220013 */ - WLog_DBG(TAG, "ioctl: IOCTL_INTERNAL_USB_GET_PORT_STATUS"); - - success = pdev->query_device_port_status(pdev, &usbd_status, &OutputBufferSize, OutputBuffer); + WLog_Print(urbdrc->log, WLOG_DEBUG, "ioctl: IOCTL_INTERNAL_USB_GET_PORT_STATUS"); + success = pdev->query_device_port_status(pdev, &usbd_status, &OutputBufferSize, + Stream_Pointer(out)); if (success) { + Stream_Seek(out, OutputBufferSize); + if (pdev->isExist(pdev) == 0) - { - data_write_UINT32(OutputBuffer, 0); - } + Stream_Write_UINT32(out, 0); else - { - usb_process_get_port_status(pdev, OutputBuffer); - OutputBufferSize = 4; - } - - WLog_DBG(TAG, "PORT STATUS(fake!):0x%02"PRIx8"%02"PRIx8"%02"PRIx8"%02"PRIx8"", - OutputBuffer[3], OutputBuffer[2], OutputBuffer[1], OutputBuffer[0]); + usb_process_get_port_status(pdev, out); } break; - case IOCTL_INTERNAL_USB_CYCLE_PORT: /** 0x0022001F */ - WLog_DBG(TAG, "ioctl: IOCTL_INTERNAL_USB_CYCLE_PORT"); - WLog_ERR(TAG, " Function IOCTL_INTERNAL_USB_CYCLE_PORT: Unchecked"); + case IOCTL_INTERNAL_USB_CYCLE_PORT: /** 0x0022001F */ + WLog_Print(urbdrc->log, WLOG_DEBUG, "ioctl: IOCTL_INTERNAL_USB_CYCLE_PORT"); + WLog_Print(urbdrc->log, WLOG_ERROR, + " Function IOCTL_INTERNAL_USB_CYCLE_PORT: Unchecked"); break; case IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION: /** 0x00220027 */ - WLog_DBG(TAG, "ioctl: IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION"); - WLog_ERR(TAG, " Function IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION: Unchecked"); + WLog_Print(urbdrc->log, WLOG_DEBUG, + "ioctl: IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION"); + WLog_Print(urbdrc->log, WLOG_ERROR, + " Function IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION: Unchecked"); break; default: - WLog_DBG(TAG, "urbdrc_process_io_control: unknown IoControlCode 0x%"PRIX32"", IoControlCode); - zfree(OutputBuffer); + WLog_Print(urbdrc->log, WLOG_DEBUG, + "urbdrc_process_io_control: unknown IoControlCode 0x%" PRIX32 "", + IoControlCode); + Stream_Free(out, TRUE); return ERROR_INVALID_OPERATION; - break; - } - - offset = 28; - out_size = offset + OutputBufferSize; - out_data = (BYTE *) calloc(1, out_size); - if (!out_data) - { - zfree(OutputBuffer); - return ERROR_OUTOFMEMORY; - } - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ - data_write_UINT32(out_data + 8, IOCONTROL_COMPLETION); /** function id */ - data_write_UINT32(out_data + 12, RequestId); /** RequestId */ - data_write_UINT32(out_data + 16, USBD_STATUS_SUCCESS); /** HResult */ - data_write_UINT32(out_data + 20, OutputBufferSize); /** Information */ - data_write_UINT32(out_data + 24, OutputBufferSize); /** OutputBufferSize */ - - for (i = 0; i < OutputBufferSize; i++) - { - data_write_BYTE(out_data + offset, OutputBuffer[i]); /** OutputBuffer */ - offset += 1; } - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); - - zfree(out_data); - zfree(OutputBuffer); - - return CHANNEL_RC_OK; + return stream_write_and_free(callback->plugin, callback->channel, out); } -static int urbdrc_process_internal_io_control(URBDRC_CHANNEL_CALLBACK* callback, BYTE* data, - UINT32 data_sizem, UINT32 MessageId, IUDEVMAN* udevman, UINT32 UsbDevice) +static UINT urbdrc_process_internal_io_control(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, + wStream* s, UINT32 MessageId, IUDEVMAN* udevman) { - IUDEVICE* pdev; - BYTE* out_data; - UINT32 out_size, IoControlCode, InterfaceId, InputBufferSize; + wStream* out; + UINT32 IoControlCode, InterfaceId, InputBufferSize; UINT32 OutputBufferSize, RequestId, frames; - data_read_UINT32(data + 0, IoControlCode); - - WLog_DBG(TAG, "urbdrc_process_internal_io_control:0x%"PRIx32"", IoControlCode); + if (!pdev || !callback || !s || !udevman) + return ERROR_INVALID_PARAMETER; - data_read_UINT32(data + 4, InputBufferSize); - data_read_UINT32(data + 8, OutputBufferSize); - data_read_UINT32(data + 12, RequestId); + if (Stream_GetRemainingLength(s) < 8) + return ERROR_INVALID_DATA; - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); + Stream_Read_UINT32(s, IoControlCode); + Stream_Read_UINT32(s, InputBufferSize); - if (pdev == NULL) - return 0; + if (!Stream_SafeSeek(s, InputBufferSize)) + return ERROR_INVALID_DATA; + if (Stream_GetRemainingLength(s) < 8ULL) + return ERROR_INVALID_DATA; + Stream_Read_UINT32(s, OutputBufferSize); + Stream_Read_UINT32(s, RequestId); + InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); + // TODO: Implement control code. + /** Fixme: Currently this is a FALSE bustime... */ + frames = GetTickCount(); + out = urb_create_iocompletion(InterfaceId, MessageId, RequestId, 4); - InterfaceId = ((STREAM_ID_PROXY<<30) | pdev->get_ReqCompletion(pdev)); + if (!out) + return ERROR_OUTOFMEMORY; - /** Fixme: Currently this is a FALSE bustime... */ - urbdrc_get_mstime(frames); - - out_size = 32; - out_data = (BYTE *) malloc(out_size); - memset(out_data, 0, out_size); - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ - data_write_UINT32(out_data + 8, IOCONTROL_COMPLETION); /** function id */ - data_write_UINT32(out_data + 12, RequestId); /** RequestId */ - data_write_UINT32(out_data + 16, 0); /** HResult */ - data_write_UINT32(out_data + 20, 4); /** Information */ - data_write_UINT32(out_data + 24, 4); /** OutputBufferSize */ - data_write_UINT32(out_data + 28, frames); /** OutputBuffer */ - - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); - - zfree(out_data); - - return 0; + Stream_Write_UINT32(out, frames); /** OutputBuffer */ + return stream_write_and_free(callback->plugin, callback->channel, out); } -static int urbdrc_process_query_device_text(URBDRC_CHANNEL_CALLBACK* callback, BYTE* data, - UINT32 data_sizem, UINT32 MessageId, IUDEVMAN* udevman, UINT32 UsbDevice) +static UINT urbdrc_process_query_device_text(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, + wStream* s, UINT32 MessageId, IUDEVMAN* udevman) { - IUDEVICE* pdev; UINT32 out_size; - UINT32 InterfaceId; UINT32 TextType; UINT32 LocaleId; - UINT32 bufferSize = 1024; - BYTE* out_data; - BYTE DeviceDescription[bufferSize]; - int out_offset; - - WLog_DBG(TAG, "urbdrc_process_query_device_text"); - - data_read_UINT32(data + 0, TextType); - data_read_UINT32(data + 4, LocaleId); - - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); - - if (pdev == NULL) - return 0; - - pdev->control_query_device_text(pdev, TextType, LocaleId, &bufferSize, DeviceDescription); - - InterfaceId = ((STREAM_ID_STUB << 30) | UsbDevice); - - out_offset = 16; - out_size = out_offset + bufferSize; + UINT32 InterfaceId; + UINT8 bufferSize = 0xFF; + UINT32 hr; + wStream* out; + BYTE DeviceDescription[0x100] = { 0 }; + + if (!pdev || !callback || !s || !udevman) + return ERROR_INVALID_PARAMETER; + if (Stream_GetRemainingLength(s) < 8) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, TextType); + Stream_Read_UINT32(s, LocaleId); + if (LocaleId > UINT16_MAX) + return ERROR_INVALID_DATA; + + hr = pdev->control_query_device_text(pdev, TextType, (UINT16)LocaleId, &bufferSize, + DeviceDescription); + InterfaceId = ((STREAM_ID_STUB << 30) | pdev->get_UsbDevice(pdev)); + out_size = 16 + bufferSize; if (bufferSize != 0) out_size += 2; - out_data = (BYTE*) malloc(out_size); - memset(out_data, 0, out_size); + out = Stream_New(NULL, out_size); - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ - - if (bufferSize != 0) - { - data_write_UINT32(out_data + 8, (bufferSize/2)+1); /** cchDeviceDescription */ - out_offset = 12; - memcpy(out_data + out_offset, DeviceDescription, bufferSize); - out_offset += bufferSize; - data_write_UINT16(out_data + out_offset, 0x0000); - out_offset += 2; - } - else - { - data_write_UINT32(out_data + 8, 0); /** cchDeviceDescription */ - out_offset = 12; - } - - data_write_UINT32(out_data + out_offset, 0); /** HResult */ - - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); - - zfree(out_data); + if (!out) + return ERROR_OUTOFMEMORY; - return 0; + Stream_Write_UINT32(out, InterfaceId); /** interface */ + Stream_Write_UINT32(out, MessageId); /** message id */ + Stream_Write_UINT32(out, bufferSize / 2); /** cchDeviceDescription in WCHAR */ + Stream_Write(out, DeviceDescription, bufferSize); /* '\0' terminated unicode */ + Stream_Write_UINT32(out, hr); /** HResult */ + return stream_write_and_free(callback->plugin, callback->channel, out); } -static void func_select_all_interface_for_msconfig(IUDEVICE* pdev, MSUSB_CONFIG_DESCRIPTOR* MsConfig) +static void func_select_all_interface_for_msconfig(IUDEVICE* pdev, + MSUSB_CONFIG_DESCRIPTOR* MsConfig) { - int inum; + UINT32 inum; MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces = MsConfig->MsInterfaces; - BYTE InterfaceNumber, AlternateSetting; + BYTE InterfaceNumber, AlternateSetting; UINT32 NumInterfaces = MsConfig->NumInterfaces; for (inum = 0; inum < NumInterfaces; inum++) @@ -440,763 +394,613 @@ static void func_select_all_interface_for_msconfig(IUDEVICE* pdev, MSUSB_CONFIG_ } } -static int urb_select_configuration(URBDRC_CHANNEL_CALLBACK* callback, BYTE* data, - UINT32 data_sizem, UINT32 MessageId, IUDEVMAN* udevman, UINT32 UsbDevice, int transferDir) +static UINT urb_select_configuration(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, wStream* s, + UINT32 RequestField, UINT32 MessageId, IUDEVMAN* udevman, + int transferDir) { - MSUSB_CONFIG_DESCRIPTOR * MsConfig = NULL; - IUDEVICE* pdev = NULL; - UINT32 out_size, InterfaceId, RequestId, NumInterfaces, usbd_status = 0; + MSUSB_CONFIG_DESCRIPTOR* MsConfig = NULL; + size_t out_size; + UINT32 InterfaceId, NumInterfaces, usbd_status = 0; BYTE ConfigurationDescriptorIsValid; - BYTE* out_data; - int MsOutSize = 0, offset = 0; + wStream* out; + int MsOutSize = 0; + URBDRC_PLUGIN* urbdrc; + const BOOL noAck = (RequestField & 0x80000000U) != 0; + const UINT32 RequestId = RequestField & 0x7FFFFFFF; + + if (!callback || !s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; + + urbdrc = (URBDRC_PLUGIN*)callback->plugin; + + if (!urbdrc) + return ERROR_INVALID_PARAMETER; if (transferDir == 0) { - WLog_ERR(TAG, "urb_select_configuration: not support transfer out"); - return -1; + WLog_Print(urbdrc->log, WLOG_ERROR, "urb_select_configuration: unsupported transfer out"); + return ERROR_INVALID_PARAMETER; } - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); - - if (pdev == NULL) - return 0; + if (Stream_GetRemainingLength(s) < 8) + return ERROR_INVALID_DATA; - InterfaceId = ((STREAM_ID_PROXY<<30) | pdev->get_ReqCompletion(pdev)); - data_read_UINT32(data + 0, RequestId); - data_read_BYTE(data + 4, ConfigurationDescriptorIsValid); - data_read_UINT32(data + 8, NumInterfaces); - offset = 12; + InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); + Stream_Read_UINT8(s, ConfigurationDescriptorIsValid); + Stream_Seek(s, 3); /* Padding */ + Stream_Read_UINT32(s, NumInterfaces); /** if ConfigurationDescriptorIsValid is zero, then just do nothing.*/ if (ConfigurationDescriptorIsValid) { /* parser data for struct config */ - MsConfig = msusb_msconfig_read(data + offset, data_sizem - offset, NumInterfaces); + MsConfig = msusb_msconfig_read(s, NumInterfaces); + + if (!MsConfig) + return ERROR_INVALID_DATA; + /* select config */ pdev->select_configuration(pdev, MsConfig->bConfigurationValue); /* select all interface */ func_select_all_interface_for_msconfig(pdev, MsConfig); /* complete configuration setup */ - MsConfig = pdev->complete_msconfig_setup(pdev, MsConfig); + if (!pdev->complete_msconfig_setup(pdev, MsConfig)) + { + msusb_msconfig_free(MsConfig); + MsConfig = NULL; + } } if (MsConfig) MsOutSize = MsConfig->MsOutSize; + if (MsOutSize > SIZE_MAX - 36) + return ERROR_INVALID_DATA; + if (MsOutSize > 0) out_size = 36 + MsOutSize; else out_size = 44; - out_data = (BYTE *) malloc(out_size); - memset(out_data, 0, out_size); - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ - data_write_UINT32(out_data + 8, URB_COMPLETION_NO_DATA); /** function id */ - data_write_UINT32(out_data + 12, RequestId); /** RequestId */ + + out = Stream_New(NULL, out_size); + + if (!out) + return ERROR_OUTOFMEMORY; + + Stream_Write_UINT32(out, InterfaceId); /** interface */ + Stream_Write_UINT32(out, MessageId); /** message id */ + Stream_Write_UINT32(out, URB_COMPLETION_NO_DATA); /** function id */ + Stream_Write_UINT32(out, RequestId); /** RequestId */ + if (MsOutSize > 0) { /** CbTsUrbResult */ - data_write_UINT32(out_data + 16, 8 + MsOutSize); + Stream_Write_UINT32(out, 8 + MsOutSize); /** TS_URB_RESULT_HEADER Size*/ - data_write_UINT16(out_data + 20, 8 + MsOutSize); + Stream_Write_UINT16(out, 8 + MsOutSize); } else { - data_write_UINT32(out_data + 16, 16); - data_write_UINT16(out_data + 20, 16); + Stream_Write_UINT32(out, 16); + Stream_Write_UINT16(out, 16); } /** Padding, MUST be ignored upon receipt */ - data_write_UINT16(out_data + 22, URB_FUNCTION_SELECT_CONFIGURATION); - data_write_UINT32(out_data + 24, usbd_status); /** UsbdStatus */ - offset = 28; + Stream_Write_UINT16(out, TS_URB_SELECT_CONFIGURATION); + Stream_Write_UINT32(out, usbd_status); /** UsbdStatus */ + /** TS_URB_SELECT_CONFIGURATION_RESULT */ if (MsOutSize > 0) - { - msusb_msconfig_write(MsConfig, out_data, &offset); - } + msusb_msconfig_write(MsConfig, out); else { - data_write_UINT32(out_data + offset, 0); /** ConfigurationHandle */ - data_write_UINT32(out_data + offset + 4, NumInterfaces); /** NumInterfaces */ - offset += 8; + Stream_Write_UINT32(out, 0); /** ConfigurationHandle */ + Stream_Write_UINT32(out, NumInterfaces); /** NumInterfaces */ } - data_write_UINT32(out_data + offset, 0); /** HResult */ - data_write_UINT32(out_data + offset + 4, 0); /** OutputBufferSize */ - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); - zfree(out_data); - return 0; + Stream_Write_UINT32(out, 0); /** HResult */ + Stream_Write_UINT32(out, 0); /** OutputBufferSize */ + + if (!noAck) + return stream_write_and_free(callback->plugin, callback->channel, out); + else + Stream_Free(out, TRUE); + + return ERROR_SUCCESS; } -static int urb_select_interface(URBDRC_CHANNEL_CALLBACK* callback, BYTE* data, UINT32 data_sizem, - UINT32 MessageId, IUDEVMAN* udevman, UINT32 UsbDevice, int transferDir) +static UINT urb_select_interface(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, wStream* s, + UINT32 RequestField, UINT32 MessageId, IUDEVMAN* udevman, + int transferDir) { MSUSB_CONFIG_DESCRIPTOR* MsConfig; MSUSB_INTERFACE_DESCRIPTOR* MsInterface; - IUDEVICE* pdev; - UINT32 out_size, InterfaceId, RequestId, ConfigurationHandle; + UINT32 out_size, InterfaceId, ConfigurationHandle; UINT32 OutputBufferSize; BYTE InterfaceNumber; - BYTE* out_data; - int out_offset, interface_size; + wStream* out; + UINT32 interface_size; + URBDRC_PLUGIN* urbdrc; + const BOOL noAck = (RequestField & 0x80000000U) != 0; + const UINT32 RequestId = RequestField & 0x7FFFFFFF; + + if (!callback || !s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; + + urbdrc = (URBDRC_PLUGIN*)callback->plugin; + + if (!urbdrc) + return ERROR_INVALID_PARAMETER; if (transferDir == 0) { - WLog_ERR(TAG, "urb_select_interface: not support transfer out"); - return -1; + WLog_Print(urbdrc->log, WLOG_ERROR, "urb_select_interface: not support transfer out"); + return ERROR_INVALID_PARAMETER; } - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); - - if (pdev == NULL) - return 0; + if (Stream_GetRemainingLength(s) < 4) + return ERROR_INVALID_DATA; InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); + Stream_Read_UINT32(s, ConfigurationHandle); + MsInterface = msusb_msinterface_read(s); - data_read_UINT32(data + 0, RequestId); - data_read_UINT32(data + 4, ConfigurationHandle); - out_offset = 8; - - MsInterface = msusb_msinterface_read(data + out_offset, data_sizem - out_offset, &out_offset); - - data_read_UINT32(data + out_offset, OutputBufferSize); + if ((Stream_GetRemainingLength(s) < 4) || !MsInterface) + return ERROR_INVALID_DATA; + Stream_Read_UINT32(s, OutputBufferSize); pdev->select_interface(pdev, MsInterface->InterfaceNumber, MsInterface->AlternateSetting); - /* replace device's MsInterface */ MsConfig = pdev->get_MsConfig(pdev); InterfaceNumber = MsInterface->InterfaceNumber; - msusb_msinterface_replace(MsConfig, InterfaceNumber, MsInterface); - + if (!msusb_msinterface_replace(MsConfig, InterfaceNumber, MsInterface)) + { + msusb_msconfig_free(MsConfig); + return ERROR_BAD_CONFIGURATION; + } /* complete configuration setup */ - MsConfig = pdev->complete_msconfig_setup(pdev, MsConfig); + if (!pdev->complete_msconfig_setup(pdev, MsConfig)) + { + msusb_msconfig_free(MsConfig); + return ERROR_BAD_CONFIGURATION; + } MsInterface = MsConfig->MsInterfaces[InterfaceNumber]; interface_size = 16 + (MsInterface->NumberOfPipes * 20); + out_size = 36 + interface_size; + out = Stream_New(NULL, out_size); - out_size = 36 + interface_size ; - out_data = (BYTE*) malloc(out_size); - memset(out_data, 0, out_size); + if (!out) + return ERROR_OUTOFMEMORY; - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ - data_write_UINT32(out_data + 8, URB_COMPLETION_NO_DATA); /** function id */ - data_write_UINT32(out_data + 12, RequestId); /** RequestId */ - data_write_UINT32(out_data + 16, 8 + interface_size); /** CbTsUrbResult */ + Stream_Write_UINT32(out, InterfaceId); /** interface */ + Stream_Write_UINT32(out, MessageId); /** message id */ + Stream_Write_UINT32(out, URB_COMPLETION_NO_DATA); /** function id */ + Stream_Write_UINT32(out, RequestId); /** RequestId */ + Stream_Write_UINT32(out, 8 + interface_size); /** CbTsUrbResult */ /** TS_URB_RESULT_HEADER */ - data_write_UINT16(out_data + 20, 8 + interface_size); /** Size */ + Stream_Write_UINT16(out, 8 + interface_size); /** Size */ /** Padding, MUST be ignored upon receipt */ - data_write_UINT16(out_data + 22, URB_FUNCTION_SELECT_INTERFACE); - data_write_UINT32(out_data + 24, USBD_STATUS_SUCCESS); /** UsbdStatus */ - out_offset = 28; - + Stream_Write_UINT16(out, TS_URB_SELECT_INTERFACE); + Stream_Write_UINT32(out, USBD_STATUS_SUCCESS); /** UsbdStatus */ /** TS_URB_SELECT_INTERFACE_RESULT */ - msusb_msinterface_write(MsInterface, out_data + out_offset, &out_offset); - - data_write_UINT32(out_data + out_offset, 0); /** HResult */ - data_write_UINT32(out_data + out_offset + 4, OutputBufferSize); /** OutputBufferSize */ + msusb_msinterface_write(MsInterface, out); + Stream_Write_UINT32(out, 0); /** HResult */ + Stream_Write_UINT32(out, 0); /** OutputBufferSize */ - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); - - zfree(out_data); + if (!noAck) + return stream_write_and_free(callback->plugin, callback->channel, out); + else + Stream_Free(out, TRUE); - return 0; + return ERROR_SUCCESS; } -static int urb_control_transfer(URBDRC_CHANNEL_CALLBACK* callback, BYTE* data, - UINT32 data_sizem, UINT32 MessageId, IUDEVMAN* udevman, UINT32 UsbDevice, int transferDir, int External) +static UINT urb_control_transfer(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, wStream* s, + UINT32 RequestField, UINT32 MessageId, IUDEVMAN* udevman, + int transferDir, int External) { - IUDEVICE* pdev; - UINT32 out_size, RequestId, InterfaceId, EndpointAddress, PipeHandle; + UINT32 out_size, InterfaceId, EndpointAddress, PipeHandle; UINT32 TransferFlags, OutputBufferSize, usbd_status, Timeout; BYTE bmRequestType, Request; UINT16 Value, Index, length; BYTE* buffer; - BYTE* out_data; - int offset, ret; + wStream* out; + URBDRC_PLUGIN* urbdrc; + const BOOL noAck = (RequestField & 0x80000000U) != 0; + const UINT32 RequestId = RequestField & 0x7FFFFFFF; - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); + if (!callback || !s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; - if (pdev == NULL) - return 0; + urbdrc = (URBDRC_PLUGIN*)callback->plugin; - InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); - data_read_UINT32(data + 0, RequestId); - data_read_UINT32(data + 4, PipeHandle); - data_read_UINT32(data + 8, TransferFlags); /** TransferFlags */ + if (!urbdrc) + return ERROR_INVALID_PARAMETER; + + if (Stream_GetRemainingLength(s) < 8) + return ERROR_INVALID_DATA; + InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); + Stream_Read_UINT32(s, PipeHandle); + Stream_Read_UINT32(s, TransferFlags); /** TransferFlags */ EndpointAddress = (PipeHandle & 0x000000ff); - offset = 12; Timeout = 2000; switch (External) { case URB_CONTROL_TRANSFER_EXTERNAL: - data_read_UINT32(data + offset, Timeout); /** TransferFlags */ - offset += 4; + if (Stream_GetRemainingLength(s) < 4) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, Timeout); /** TransferFlags */ break; + case URB_CONTROL_TRANSFER_NONEXTERNAL: break; } /** SetupPacket 8 bytes */ - data_read_BYTE(data + offset, bmRequestType); - data_read_BYTE(data + offset + 1, Request); - data_read_UINT16(data + offset + 2, Value); - data_read_UINT16(data + offset + 4, Index); - data_read_UINT16(data + offset + 6, length); - data_read_UINT32(data + offset + 8, OutputBufferSize); - offset += 12; + if (Stream_GetRemainingLength(s) < 12) + return ERROR_INVALID_DATA; + + Stream_Read_UINT8(s, bmRequestType); + Stream_Read_UINT8(s, Request); + Stream_Read_UINT16(s, Value); + Stream_Read_UINT16(s, Index); + Stream_Read_UINT16(s, length); + Stream_Read_UINT32(s, OutputBufferSize); if (length != OutputBufferSize) { - WLog_ERR(TAG, "urb_control_transfer ERROR: buf != length"); - return -1; + WLog_Print(urbdrc->log, WLOG_ERROR, "urb_control_transfer ERROR: buf != length"); + return ERROR_INVALID_DATA; } out_size = 36 + OutputBufferSize; - out_data = (BYTE *) malloc(out_size); - memset(out_data, 0, out_size); + out = Stream_New(NULL, out_size); - buffer = out_data + 36; + if (!out) + return ERROR_OUTOFMEMORY; + Stream_Seek(out, 36); /** Get Buffer Data */ + buffer = Stream_Pointer(out); + if (transferDir == USBD_TRANSFER_DIRECTION_OUT) - memcpy(buffer, data + offset, OutputBufferSize); - - /** process URB_FUNCTION_CONTROL_TRANSFER */ - ret = pdev->control_transfer( - pdev, RequestId, EndpointAddress, TransferFlags, - bmRequestType, - Request, - Value, - Index, - &usbd_status, - &OutputBufferSize, - buffer, - Timeout); - - if (ret < 0){ - WLog_DBG(TAG, "control_transfer: error num %d!!", ret); - OutputBufferSize = 0; - } + Stream_Copy(s, out, OutputBufferSize); - /** send data */ - offset = 36; - if (transferDir == USBD_TRANSFER_DIRECTION_IN) - out_size = offset + OutputBufferSize; - else - out_size = offset; + /** process TS_URB_CONTROL_TRANSFER */ + if (!pdev->control_transfer(pdev, RequestId, EndpointAddress, TransferFlags, bmRequestType, + Request, Value, Index, &usbd_status, &OutputBufferSize, buffer, + Timeout)) + { + WLog_Print(urbdrc->log, WLOG_ERROR, "control_transfer failed"); + Stream_Free(out, TRUE); + return ERROR_INTERNAL_ERROR; + } - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ + return urb_write_completion(pdev, callback, noAck, out, InterfaceId, MessageId, RequestId, + usbd_status, OutputBufferSize); +} - if(transferDir == USBD_TRANSFER_DIRECTION_IN && OutputBufferSize != 0) - data_write_UINT32(out_data + 8, URB_COMPLETION); /** function id */ +static void urb_bulk_transfer_cb(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, wStream* out, + UINT32 InterfaceId, BOOL noAck, UINT32 MessageId, UINT32 RequestId, + UINT32 NumberOfPackets, UINT32 status, UINT32 StartFrame, + UINT32 ErrorCount, UINT32 OutputBufferSize) +{ + if (!pdev->isChannelClosed(pdev)) + urb_write_completion(pdev, callback, noAck, out, InterfaceId, MessageId, RequestId, status, + OutputBufferSize); else - data_write_UINT32(out_data + 8, URB_COMPLETION_NO_DATA); - data_write_UINT32(out_data + 12, RequestId); /** RequestId */ - data_write_UINT32(out_data + 16, 0x00000008); /** CbTsUrbResult */ - /** TsUrbResult TS_URB_RESULT_HEADER */ - data_write_UINT16(out_data + 20, 0x0008); /** Size */ - - /** Padding, MUST be ignored upon receipt */ - data_write_UINT16(out_data + 22, URB_FUNCTION_CONTROL_TRANSFER); - data_write_UINT32(out_data + 24, usbd_status); /** UsbdStatus */ - - data_write_UINT32(out_data + 28, 0); /** HResult */ - data_write_UINT32(out_data + 32, OutputBufferSize); /** OutputBufferSize */ - - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); - - zfree(out_data); - - return 0; + Stream_Free(out, TRUE); } -static int urb_bulk_or_interrupt_transfer(URBDRC_CHANNEL_CALLBACK* callback, BYTE* data, - UINT32 data_sizem, UINT32 MessageId, IUDEVMAN* udevman, UINT32 UsbDevice, int transferDir) +static UINT urb_bulk_or_interrupt_transfer(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, + wStream* s, UINT32 RequestField, UINT32 MessageId, + IUDEVMAN* udevman, int transferDir) { - int offset; - BYTE* Buffer; - IUDEVICE* pdev; - BYTE* out_data; - UINT32 out_size, RequestId, InterfaceId, EndpointAddress, PipeHandle; - UINT32 TransferFlags, OutputBufferSize, usbd_status = 0; - - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); + UINT32 EndpointAddress, PipeHandle; + UINT32 TransferFlags, OutputBufferSize; + const BOOL noAck = (RequestField & 0x80000000U) != 0; + const UINT32 RequestId = RequestField & 0x7FFFFFFF; - if (pdev == NULL) - return 0; + if (!pdev || !callback || !s || !udevman) + return ERROR_INVALID_PARAMETER; - InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); + if (Stream_GetRemainingLength(s) < 12) + return ERROR_INVALID_DATA; - data_read_UINT32(data + 0, RequestId); - data_read_UINT32(data + 4, PipeHandle); - data_read_UINT32(data + 8, TransferFlags); /** TransferFlags */ - data_read_UINT32(data + 12, OutputBufferSize); - offset = 16; + Stream_Read_UINT32(s, PipeHandle); + Stream_Read_UINT32(s, TransferFlags); /** TransferFlags */ + Stream_Read_UINT32(s, OutputBufferSize); EndpointAddress = (PipeHandle & 0x000000ff); - - if (transferDir == USBD_TRANSFER_DIRECTION_OUT) - out_size = 36; - else - out_size = 36 + OutputBufferSize; - - Buffer = NULL; - out_data = (BYTE*) malloc(out_size); - memset(out_data, 0, out_size); - - switch (transferDir) - { - case USBD_TRANSFER_DIRECTION_OUT: - Buffer = data + offset; - break; - - case USBD_TRANSFER_DIRECTION_IN: - Buffer = out_data + 36; - break; - } - - /** process URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER */ - pdev->bulk_or_interrupt_transfer( - pdev, RequestId, EndpointAddress, - TransferFlags, - &usbd_status, - &OutputBufferSize, - Buffer, - 10000); - - offset = 36; - if (transferDir == USBD_TRANSFER_DIRECTION_IN) - out_size = offset + OutputBufferSize; - else - out_size = offset; - /** send data */ - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ - if(transferDir == USBD_TRANSFER_DIRECTION_IN && OutputBufferSize != 0) - data_write_UINT32(out_data + 8, URB_COMPLETION); /** function id */ - else - data_write_UINT32(out_data + 8, URB_COMPLETION_NO_DATA); - data_write_UINT32(out_data + 12, RequestId); /** RequestId */ - data_write_UINT32(out_data + 16, 0x00000008); /** CbTsUrbResult */ - /** TsUrbResult TS_URB_RESULT_HEADER */ - data_write_UINT16(out_data + 20, 0x0008); /** Size */ - - /** Padding, MUST be ignored upon receipt */ - data_write_UINT16(out_data + 22, URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER); - data_write_UINT32(out_data + 24, usbd_status); /** UsbdStatus */ - - data_write_UINT32(out_data + 28, 0); /** HResult */ - data_write_UINT32(out_data + 32, OutputBufferSize); /** OutputBufferSize */ - - if (pdev && !pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); - - zfree(out_data); - - return 0; + /** process TS_URB_BULK_OR_INTERRUPT_TRANSFER */ + return pdev->bulk_or_interrupt_transfer(pdev, callback, MessageId, RequestId, EndpointAddress, + TransferFlags, noAck, OutputBufferSize, + urb_bulk_transfer_cb, 10000); } - -static int urb_isoch_transfer(URBDRC_CHANNEL_CALLBACK * callback, BYTE * data, - UINT32 data_sizem, - UINT32 MessageId, - IUDEVMAN * udevman, - UINT32 UsbDevice, - int transferDir) +static void urb_isoch_transfer_cb(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, wStream* out, + UINT32 InterfaceId, BOOL noAck, UINT32 MessageId, + UINT32 RequestId, UINT32 NumberOfPackets, UINT32 status, + UINT32 StartFrame, UINT32 ErrorCount, UINT32 OutputBufferSize) { - IUDEVICE * pdev; - UINT32 RequestId, InterfaceId, EndpointAddress; - UINT32 PipeHandle, TransferFlags, StartFrame, NumberOfPackets; - UINT32 ErrorCount, OutputBufferSize, usbd_status = 0; - UINT32 RequestField, noAck = 0; - UINT32 out_size = 0; - BYTE * iso_buffer = NULL; - BYTE * iso_packets = NULL; - BYTE * out_data = NULL; - int offset, nullBuffer = 0, iso_status; - - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); - if (pdev == NULL) - return 0; - if (pdev->isSigToEnd(pdev)) - return 0; - - InterfaceId = ((STREAM_ID_PROXY<<30) | pdev->get_ReqCompletion(pdev)); - data_read_UINT32(data + 0, RequestField); - RequestId = RequestField & 0x7fffffff; - noAck = (RequestField & 0x80000000)>>31; - data_read_UINT32(data + 4, PipeHandle); - EndpointAddress = (PipeHandle & 0x000000ff); - data_read_UINT32(data + 8, TransferFlags); /** TransferFlags */ - data_read_UINT32(data + 12, StartFrame); /** StartFrame */ - data_read_UINT32(data + 16, NumberOfPackets); /** NumberOfPackets */ - data_read_UINT32(data + 20, ErrorCount); /** ErrorCount */ - offset = 24 + (NumberOfPackets * 12); - data_read_UINT32(data + offset, OutputBufferSize); - offset += 4; - - /** send data memory alloc */ - if (transferDir == USBD_TRANSFER_DIRECTION_OUT) { - if (!noAck) { - out_size = 48 + (NumberOfPackets * 12); - out_data = (BYTE *) malloc(out_size); - iso_packets = out_data + 40; - } - } - else { - out_size = 48 + OutputBufferSize + (NumberOfPackets * 12); - out_data = (BYTE *) malloc(out_size); - iso_packets = out_data + 40; - } - - if (out_size) - memset(out_data, 0, out_size); - - switch (transferDir) + if (!noAck) { - case USBD_TRANSFER_DIRECTION_OUT: - /** Get Buffer Data */ - //memcpy(iso_buffer, data + offset, OutputBufferSize); - iso_buffer = data + offset; - break; - case USBD_TRANSFER_DIRECTION_IN: - iso_buffer = out_data + 48 + (NumberOfPackets * 12); - break; - } - - WLog_DBG(TAG, "urb_isoch_transfer: EndpointAddress: 0x%"PRIx32", " - "TransferFlags: 0x%"PRIx32", " - "StartFrame: 0x%"PRIx32", " - "NumberOfPackets: 0x%"PRIx32", " - "OutputBufferSize: 0x%"PRIx32" " - "RequestId: 0x%"PRIx32"", - EndpointAddress, TransferFlags, StartFrame, - NumberOfPackets, OutputBufferSize, RequestId); - -#if ISOCH_FIFO - ISOCH_CALLBACK_QUEUE * isoch_queue = NULL; - ISOCH_CALLBACK_DATA * isoch = NULL; - if(!noAck) - { - isoch_queue = (ISOCH_CALLBACK_QUEUE *)pdev->get_isoch_queue(pdev); - isoch = isoch_queue->register_data(isoch_queue, callback, pdev); - } -#endif - - iso_status = pdev->isoch_transfer( - pdev, RequestId, EndpointAddress, - TransferFlags, - noAck, - &ErrorCount, - &usbd_status, - &StartFrame, - NumberOfPackets, - iso_packets, - &OutputBufferSize, - iso_buffer, - 2000); - - if(noAck) - { - zfree(out_data); - return 0; - } + UINT32 packetSize = (status == 0) ? NumberOfPackets * 12 : 0; + Stream_SetPosition(out, 0); + /* fill the send data */ + Stream_Write_UINT32(out, InterfaceId); /** interface */ + Stream_Write_UINT32(out, MessageId); /** message id */ + + if (OutputBufferSize == 0) + Stream_Write_UINT32(out, URB_COMPLETION_NO_DATA); /** function id */ + else + Stream_Write_UINT32(out, URB_COMPLETION); /** function id */ - if (iso_status < 0) - nullBuffer = 1; + Stream_Write_UINT32(out, RequestId); /** RequestId */ + Stream_Write_UINT32(out, 20 + packetSize); /** CbTsUrbResult */ + /** TsUrbResult TS_URB_RESULT_HEADER */ + Stream_Write_UINT16(out, 20 + packetSize); /** Size */ + Stream_Write_UINT16(out, 0); /* Padding */ + Stream_Write_UINT32(out, status); /** UsbdStatus */ + Stream_Write_UINT32(out, StartFrame); /** StartFrame */ + if (status == 0) + { + /** NumberOfPackets */ + Stream_Write_UINT32(out, NumberOfPackets); + Stream_Write_UINT32(out, ErrorCount); /** ErrorCount */ + Stream_Seek(out, packetSize); + } + else + { + Stream_Write_UINT32(out, 0); /** NumberOfPackets */ + Stream_Write_UINT32(out, ErrorCount); /** ErrorCount */ + } - out_size = 48; - if (nullBuffer) - OutputBufferSize = 0; - else - out_size += OutputBufferSize + (NumberOfPackets * 12); - /* fill the send data */ - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ - if(OutputBufferSize != 0 && !nullBuffer) - data_write_UINT32(out_data + 8, URB_COMPLETION); /** function id */ - else - data_write_UINT32(out_data + 8, URB_COMPLETION_NO_DATA); - data_write_UINT32(out_data + 12, RequestId); /** RequestId */ - data_write_UINT32(out_data + 16, 20 + (NumberOfPackets * 12)); /** CbTsUrbResult */ - /** TsUrbResult TS_URB_RESULT_HEADER */ - data_write_UINT16(out_data + 20, 20 + (NumberOfPackets * 12)); /** Size */ - /** Padding, MUST be ignored upon receipt */ - data_write_UINT16(out_data + 22, URB_FUNCTION_ISOCH_TRANSFER); - data_write_UINT32(out_data + 24, usbd_status); /** UsbdStatus */ + Stream_Write_UINT32(out, 0); /** HResult */ + Stream_Write_UINT32(out, OutputBufferSize); /** OutputBufferSize */ + Stream_Seek(out, OutputBufferSize); - data_write_UINT32(out_data + 28, StartFrame); /** StartFrame */ - if (!nullBuffer) - { - /** NumberOfPackets */ - data_write_UINT32(out_data + 32, NumberOfPackets); - data_write_UINT32(out_data + 36, ErrorCount); /** ErrorCount */ - offset = 40 + (NumberOfPackets * 12); - } - else - { - data_write_UINT32(out_data + 32, 0); /** NumberOfPackets */ - data_write_UINT32(out_data + 36, NumberOfPackets); /** ErrorCount */ - offset = 40; + if (!pdev->isChannelClosed(pdev)) + callback->channel->Write(callback->channel, Stream_GetPosition(out), Stream_Buffer(out), + NULL); } +} - data_write_UINT32(out_data + offset, 0); /** HResult */ - data_write_UINT32(out_data + offset + 4, OutputBufferSize); /** OutputBufferSize */ +static UINT urb_isoch_transfer(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, wStream* s, + UINT32 RequestField, UINT32 MessageId, IUDEVMAN* udevman, + int transferDir) +{ + UINT32 EndpointAddress; + UINT32 PipeHandle, TransferFlags, StartFrame, NumberOfPackets; + UINT32 ErrorCount, OutputBufferSize; + BYTE* packetDescriptorData; + const BOOL noAck = (RequestField & 0x80000000U) != 0; + const UINT32 RequestId = RequestField & 0x7FFFFFFF; -#if ISOCH_FIFO - if(!noAck){ - pthread_mutex_lock(&isoch_queue->isoch_loading); - isoch->out_data = out_data; - isoch->out_size = out_size; - pthread_mutex_unlock(&isoch_queue->isoch_loading); - } -#else - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); - zfree(out_data); -#endif + if (!pdev || !callback || !udevman) + return ERROR_INVALID_PARAMETER; - if (nullBuffer) - return -1; + if (Stream_GetRemainingLength(s) < 20) + return ERROR_INVALID_DATA; - return 0; + Stream_Read_UINT32(s, PipeHandle); + EndpointAddress = (PipeHandle & 0x000000ff); + Stream_Read_UINT32(s, TransferFlags); /** TransferFlags */ + Stream_Read_UINT32(s, StartFrame); /** StartFrame */ + Stream_Read_UINT32(s, NumberOfPackets); /** NumberOfPackets */ + Stream_Read_UINT32(s, ErrorCount); /** ErrorCount */ + + if (Stream_GetRemainingLength(s) < NumberOfPackets * 12 + 4) + return ERROR_INVALID_DATA; + + packetDescriptorData = Stream_Pointer(s); + Stream_Seek(s, NumberOfPackets * 12); + Stream_Read_UINT32(s, OutputBufferSize); + return pdev->isoch_transfer( + pdev, callback, MessageId, RequestId, EndpointAddress, TransferFlags, StartFrame, + ErrorCount, noAck, packetDescriptorData, NumberOfPackets, OutputBufferSize, + (transferDir == USBD_TRANSFER_DIRECTION_OUT) ? Stream_Pointer(s) : NULL, + urb_isoch_transfer_cb, 2000); } -static int urb_control_descriptor_request(URBDRC_CHANNEL_CALLBACK* callback, - BYTE * data, - UINT32 data_sizem, - UINT32 MessageId, - IUDEVMAN * udevman, - UINT32 UsbDevice, - BYTE func_recipient, - int transferDir) +static UINT urb_control_descriptor_request(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, + wStream* s, UINT32 RequestField, UINT32 MessageId, + IUDEVMAN* udevman, BYTE func_recipient, int transferDir) { - IUDEVICE* pdev; - UINT32 out_size, InterfaceId, RequestId, OutputBufferSize, usbd_status; + size_t out_size; + UINT32 InterfaceId, OutputBufferSize, usbd_status; BYTE bmRequestType, desc_index, desc_type; UINT16 langId; - BYTE* buffer; - BYTE* out_data; - int ret, offset; + wStream* out; + URBDRC_PLUGIN* urbdrc; + const BOOL noAck = (RequestField & 0x80000000U) != 0; + const UINT32 RequestId = RequestField & 0x7FFFFFFF; - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); + if (!callback || !s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; - if (pdev == NULL) - return 0; + urbdrc = (URBDRC_PLUGIN*)callback->plugin; - InterfaceId = ((STREAM_ID_PROXY<<30) | pdev->get_ReqCompletion(pdev)); - data_read_UINT32(data + 0, RequestId); - data_read_BYTE(data + 4, desc_index); - data_read_BYTE(data + 5, desc_type); - data_read_UINT16(data + 6, langId); - data_read_UINT32(data + 8, OutputBufferSize); + if (!urbdrc) + return ERROR_INVALID_PARAMETER; - out_size = 36 + OutputBufferSize; - out_data = (BYTE *) malloc(out_size); - memset(out_data, 0, out_size); + if (Stream_GetRemainingLength(s) < 8) + return ERROR_INVALID_DATA; - buffer = out_data + 36; + InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); + Stream_Read_UINT8(s, desc_index); + Stream_Read_UINT8(s, desc_type); + Stream_Read_UINT16(s, langId); + Stream_Read_UINT32(s, OutputBufferSize); + if (OutputBufferSize > UINT32_MAX - 36) + return ERROR_INVALID_DATA; + if (transferDir == USBD_TRANSFER_DIRECTION_OUT) + { + if (Stream_GetRemainingLength(s) < OutputBufferSize) + return ERROR_INVALID_DATA; + } + out_size = 36ULL + OutputBufferSize; + out = Stream_New(NULL, out_size); + + if (!out) + return ERROR_OUTOFMEMORY; + + Stream_Seek(out, 36); bmRequestType = func_recipient; + switch (transferDir) { case USBD_TRANSFER_DIRECTION_IN: bmRequestType |= 0x80; break; + case USBD_TRANSFER_DIRECTION_OUT: bmRequestType |= 0x00; - offset = 12; - memcpy(buffer, data + offset, OutputBufferSize); + Stream_Copy(s, out, OutputBufferSize); + Stream_Rewind(out, OutputBufferSize); break; + default: - WLog_DBG(TAG, "get error transferDir"); + WLog_Print(urbdrc->log, WLOG_DEBUG, "get error transferDir"); OutputBufferSize = 0; usbd_status = USBD_STATUS_STALL_PID; break; } /** process get usb device descriptor */ - - ret = pdev->control_transfer( - pdev, RequestId, 0, 0, bmRequestType, - 0x06, /* REQUEST_GET_DESCRIPTOR */ - (desc_type << 8) | desc_index, - langId, - &usbd_status, - &OutputBufferSize, - buffer, - 1000); - - - if (ret < 0) { - WLog_DBG(TAG, "get_descriptor: error num %d", ret); - OutputBufferSize = 0; + if (!pdev->control_transfer(pdev, RequestId, 0, 0, bmRequestType, + 0x06, /* REQUEST_GET_DESCRIPTOR */ + (desc_type << 8) | desc_index, langId, &usbd_status, + &OutputBufferSize, Stream_Pointer(out), 1000)) + { + WLog_Print(urbdrc->log, WLOG_ERROR, "get_descriptor failed"); + Stream_Free(out, TRUE); + return ERROR_INTERNAL_ERROR; } - offset = 36; - out_size = offset + OutputBufferSize; - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ - data_write_UINT32(out_data + 8, URB_COMPLETION); /** function id */ - data_write_UINT32(out_data + 12, RequestId); /** RequestId */ - data_write_UINT32(out_data + 16, 0x00000008); /** CbTsUrbResult */ - /** TsUrbResult TS_URB_RESULT_HEADER */ - data_write_UINT16(out_data + 20, 0x0008); /** Size */ - /** Padding, MUST be ignored upon receipt */ - data_write_UINT16(out_data + 22, URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE); - data_write_UINT32(out_data + 24, usbd_status); /** UsbdStatus */ - data_write_UINT32(out_data + 28, 0); /** HResult */ - data_write_UINT32(out_data + 32, OutputBufferSize); /** OutputBufferSize */ - - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); - - zfree(out_data); - return 0; + return urb_write_completion(pdev, callback, noAck, out, InterfaceId, MessageId, RequestId, + usbd_status, OutputBufferSize); } -static int urb_control_get_status_request(URBDRC_CHANNEL_CALLBACK * callback, BYTE * data, - UINT32 data_sizem, - UINT32 MessageId, - IUDEVMAN * udevman, - UINT32 UsbDevice, - BYTE func_recipient, - int transferDir) +static UINT urb_control_get_status_request(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, + wStream* s, UINT32 RequestField, UINT32 MessageId, + IUDEVMAN* udevman, BYTE func_recipient, int transferDir) { - IUDEVICE* pdev; - UINT32 out_size, RequestId, InterfaceId, OutputBufferSize, usbd_status; + size_t out_size; + UINT32 InterfaceId, OutputBufferSize, usbd_status; UINT16 Index; BYTE bmRequestType; - BYTE* buffer; - BYTE* out_data; - int offset, ret; + wStream* out; + URBDRC_PLUGIN* urbdrc; + const BOOL noAck = (RequestField & 0x80000000U) != 0; + const UINT32 RequestId = RequestField & 0x7FFFFFFF; - if (transferDir == 0){ - WLog_DBG(TAG, "urb_control_get_status_request: not support transfer out"); - return -1; - } + if (!callback || !s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); - if (pdev == NULL) - return 0; - InterfaceId = ((STREAM_ID_PROXY<<30) | pdev->get_ReqCompletion(pdev)); + urbdrc = (URBDRC_PLUGIN*)callback->plugin; - data_read_UINT32(data + 0, RequestId); - data_read_UINT16(data + 4, Index); /** Index */ - data_read_UINT32(data + 8, OutputBufferSize); + if (!urbdrc) + return ERROR_INVALID_PARAMETER; - out_size = 36 + OutputBufferSize; - out_data = (BYTE *) malloc(out_size); - memset(out_data, 0, out_size); + if (transferDir == 0) + { + WLog_Print(urbdrc->log, WLOG_DEBUG, + "urb_control_get_status_request: transfer out not supported"); + return ERROR_INVALID_PARAMETER; + } - buffer = out_data + 36; + if (Stream_GetRemainingLength(s) < 8) + return ERROR_INVALID_DATA; + + InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); + Stream_Read_UINT16(s, Index); /** Index */ + Stream_Seek(s, 2); + Stream_Read_UINT32(s, OutputBufferSize); + if (OutputBufferSize > UINT32_MAX - 36) + return ERROR_INVALID_DATA; + out_size = 36ULL + OutputBufferSize; + out = Stream_New(NULL, out_size); + + if (!out) + return ERROR_OUTOFMEMORY; + Stream_Seek(out, 36); bmRequestType = func_recipient | 0x80; - ret = pdev->control_transfer( - pdev, RequestId, 0, 0, bmRequestType, - 0x00, /* REQUEST_GET_STATUS */ - 0, - Index, - &usbd_status, - &OutputBufferSize, - buffer, - 1000); - - if (ret < 0){ - WLog_DBG(TAG, "control_transfer: error num %d!!", ret); - OutputBufferSize = 0; - usbd_status = USBD_STATUS_STALL_PID; - } - else{ - usbd_status = USBD_STATUS_SUCCESS; + if (!pdev->control_transfer(pdev, RequestId, 0, 0, bmRequestType, 0x00, /* REQUEST_GET_STATUS */ + 0, Index, &usbd_status, &OutputBufferSize, Stream_Pointer(out), + 1000)) + { + WLog_Print(urbdrc->log, WLOG_ERROR, "control_transfer failed"); + Stream_Free(out, TRUE); + return ERROR_INTERNAL_ERROR; } - /** send data */ - offset = 36; - if (transferDir == USBD_TRANSFER_DIRECTION_IN) - out_size = offset + OutputBufferSize; - else - out_size = offset; - - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ + return urb_write_completion(pdev, callback, noAck, out, InterfaceId, MessageId, RequestId, + usbd_status, OutputBufferSize); +} - if(transferDir == USBD_TRANSFER_DIRECTION_IN && OutputBufferSize != 0) - data_write_UINT32(out_data + 8, URB_COMPLETION); /** function id */ - else - data_write_UINT32(out_data + 8, URB_COMPLETION_NO_DATA); +static UINT urb_control_vendor_or_class_request(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, + wStream* s, UINT32 RequestField, UINT32 MessageId, + IUDEVMAN* udevman, BYTE func_type, + BYTE func_recipient, int transferDir) +{ + UINT32 out_size, InterfaceId, TransferFlags, usbd_status; + UINT32 OutputBufferSize; + BYTE ReqTypeReservedBits, Request, bmRequestType; + UINT16 Value, Index, Padding; + wStream* out; + URBDRC_PLUGIN* urbdrc; + const BOOL noAck = (RequestField & 0x80000000U) != 0; + const UINT32 RequestId = RequestField & 0x7FFFFFFF; - data_write_UINT32(out_data + 12, RequestId); /** RequestId, include NoAck*/ - data_write_UINT32(out_data + 16, 0x00000008); /** CbTsUrbResult */ - /** TsUrbResult TS_URB_RESULT_HEADER */ - data_write_UINT16(out_data + 20, 0x0008); /** Size */ - /** Padding, MUST be ignored upon receipt */ - data_write_UINT16(out_data + 22, URB_FUNCTION_VENDOR_DEVICE); - data_write_UINT32(out_data + 24, usbd_status); /** UsbdStatus */ + if (!callback || !s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; - data_write_UINT32(out_data + 28, 0); /** HResult */ - data_write_UINT32(out_data + 32, OutputBufferSize); /** OutputBufferSize */ + urbdrc = (URBDRC_PLUGIN*)callback->plugin; - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); + if (!urbdrc) + return ERROR_INVALID_PARAMETER; - zfree(out_data); + if (Stream_GetRemainingLength(s) < 16) + return ERROR_INVALID_DATA; - return 0; -} + InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); + Stream_Read_UINT32(s, TransferFlags); /** TransferFlags */ + Stream_Read_UINT8(s, ReqTypeReservedBits); /** ReqTypeReservedBids */ + Stream_Read_UINT8(s, Request); /** Request */ + Stream_Read_UINT16(s, Value); /** value */ + Stream_Read_UINT16(s, Index); /** index */ + Stream_Read_UINT16(s, Padding); /** Padding */ + Stream_Read_UINT32(s, OutputBufferSize); + if (OutputBufferSize > UINT32_MAX - 36) + return ERROR_INVALID_DATA; -static int urb_control_vendor_or_class_request(URBDRC_CHANNEL_CALLBACK * callback, - BYTE * data, - UINT32 data_sizem, - UINT32 MessageId, - IUDEVMAN * udevman, - UINT32 UsbDevice, - BYTE func_type, - BYTE func_recipient, - int transferDir) -{ - IUDEVICE* pdev; - UINT32 out_size, RequestId, InterfaceId, TransferFlags, usbd_status; - UINT32 OutputBufferSize; - BYTE ReqTypeReservedBits, Request, bmRequestType; - UINT16 Value, Index, Padding; - BYTE* buffer; - BYTE* out_data; - int offset, ret; - /** control by vendor command */ + if (transferDir == USBD_TRANSFER_DIRECTION_OUT) + { + if (Stream_GetRemainingLength(s) < OutputBufferSize) + return ERROR_INVALID_DATA; + } - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); - if (pdev == NULL) - return 0; - InterfaceId = ((STREAM_ID_PROXY<<30) | pdev->get_ReqCompletion(pdev)); - - data_read_UINT32(data + 0, RequestId); - data_read_UINT32(data + 4, TransferFlags); /** TransferFlags */ - data_read_BYTE(data + 8, ReqTypeReservedBits); /** ReqTypeReservedBids */ - data_read_BYTE(data + 9, Request); /** Request */ - data_read_UINT16(data + 10, Value); /** value */ - data_read_UINT16(data + 12, Index); /** index */ - data_read_UINT16(data + 14, Padding); /** Padding */ - data_read_UINT32(data + 16, OutputBufferSize); - offset = 20; + out_size = 36ULL + OutputBufferSize; + out = Stream_New(NULL, out_size); - out_size = 36 + OutputBufferSize; - out_data = (BYTE *) malloc(out_size); - memset(out_data, 0, out_size); + if (!out) + return ERROR_OUTOFMEMORY; - buffer = out_data + 36; + Stream_Seek(out, 36); /** Get Buffer */ if (transferDir == USBD_TRANSFER_DIRECTION_OUT) - memcpy(buffer, data + offset, OutputBufferSize); + { + Stream_Copy(s, out, OutputBufferSize); + Stream_Rewind(out, OutputBufferSize); + } /** vendor or class command */ bmRequestType = func_type | func_recipient; @@ -1204,513 +1008,425 @@ static int urb_control_vendor_or_class_request(URBDRC_CHANNEL_CALLBACK * callbac if (TransferFlags & USBD_TRANSFER_DIRECTION) bmRequestType |= 0x80; - WLog_DBG(TAG, "urb_control_vendor_or_class_request: " - "RequestId 0x%"PRIx32" TransferFlags: 0x%"PRIx32" ReqTypeReservedBits: 0x%"PRIx8" " - "Request:0x%"PRIx8" Value: 0x%"PRIx16" Index: 0x%"PRIx16" OutputBufferSize: 0x%"PRIx32" bmRequestType: 0x%"PRIx8"!!", - RequestId, TransferFlags, ReqTypeReservedBits, Request, Value, - Index, OutputBufferSize, bmRequestType); - - ret = pdev->control_transfer( - pdev, RequestId, 0, 0, bmRequestType, - Request, - Value, - Index, - &usbd_status, - &OutputBufferSize, - buffer, - 2000); - - if (ret < 0){ - WLog_DBG(TAG, "control_transfer: error num %d!!", ret); - OutputBufferSize = 0; - usbd_status = USBD_STATUS_STALL_PID; - } - else{ - usbd_status = USBD_STATUS_SUCCESS; - } - - offset = 36; - if (transferDir == USBD_TRANSFER_DIRECTION_IN) - out_size = offset + OutputBufferSize; - else - out_size = offset; - /** send data */ - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ - - if(transferDir == USBD_TRANSFER_DIRECTION_IN && OutputBufferSize != 0) - data_write_UINT32(out_data + 8, URB_COMPLETION); /** function id */ - else - data_write_UINT32(out_data + 8, URB_COMPLETION_NO_DATA); - - data_write_UINT32(out_data + 12, RequestId); /** RequestId, include NoAck*/ - data_write_UINT32(out_data + 16, 0x00000008); /** CbTsUrbResult */ - /** TsUrbResult TS_URB_RESULT_HEADER */ - data_write_UINT16(out_data + 20, 0x0008); /** Size */ - data_write_UINT16(out_data + 22, URB_FUNCTION_VENDOR_DEVICE); /** Padding, MUST be ignored upon receipt */ - data_write_UINT32(out_data + 24, usbd_status); /** UsbdStatus */ - - data_write_UINT32(out_data + 28, 0); /** HResult */ - data_write_UINT32(out_data + 32, OutputBufferSize); /** OutputBufferSize */ + WLog_Print(urbdrc->log, WLOG_DEBUG, + "RequestId 0x%" PRIx32 " TransferFlags: 0x%" PRIx32 " ReqTypeReservedBits: 0x%" PRIx8 + " " + "Request:0x%" PRIx8 " Value: 0x%" PRIx16 " Index: 0x%" PRIx16 + " OutputBufferSize: 0x%" PRIx32 " bmRequestType: 0x%" PRIx8, + RequestId, TransferFlags, ReqTypeReservedBits, Request, Value, Index, + OutputBufferSize, bmRequestType); - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); + if (!pdev->control_transfer(pdev, RequestId, 0, 0, bmRequestType, Request, Value, Index, + &usbd_status, &OutputBufferSize, Stream_Pointer(out), 2000)) + { + WLog_Print(urbdrc->log, WLOG_ERROR, "control_transfer failed"); + Stream_Free(out, TRUE); + return ERROR_INTERNAL_ERROR; + } - zfree(out_data); - return 0; + return urb_write_completion(pdev, callback, noAck, out, InterfaceId, MessageId, RequestId, + usbd_status, OutputBufferSize); } - - -static int urb_os_feature_descriptor_request(URBDRC_CHANNEL_CALLBACK * callback, - BYTE * data, - UINT32 data_sizem, - UINT32 MessageId, - IUDEVMAN * udevman, - UINT32 UsbDevice, - int transferDir) +static UINT urb_os_feature_descriptor_request(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, + wStream* s, UINT32 RequestField, UINT32 MessageId, + IUDEVMAN* udevman, int transferDir) { - IUDEVICE* pdev; - UINT32 out_size, RequestId, InterfaceId, OutputBufferSize, usbd_status; + size_t out_size; + UINT32 InterfaceId, OutputBufferSize, usbd_status; BYTE Recipient, InterfaceNumber, Ms_PageIndex; UINT16 Ms_featureDescIndex; - BYTE* out_data; - BYTE* buffer; - int offset, ret; + wStream* out; + int ret; + URBDRC_PLUGIN* urbdrc; + const BOOL noAck = (RequestField & 0x80000000U) != 0; + const UINT32 RequestId = RequestField & 0x7FFFFFFF; + + if (!callback || !s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; + + urbdrc = (URBDRC_PLUGIN*)callback->plugin; + + if (!urbdrc) + return ERROR_INVALID_PARAMETER; + + if (Stream_GetRemainingLength(s) < 12) + return ERROR_INVALID_DATA; + + /* 2.2.9.15 TS_URB_OS_FEATURE_DESCRIPTOR_REQUEST */ + Stream_Read_UINT8(s, Recipient); /** Recipient */ + Recipient = (Recipient & 0x1f); /* Mask out Padding1 */ + Stream_Read_UINT8(s, InterfaceNumber); /** InterfaceNumber */ + Stream_Read_UINT8(s, Ms_PageIndex); /** Ms_PageIndex */ + Stream_Read_UINT16(s, Ms_featureDescIndex); /** Ms_featureDescIndex */ + Stream_Seek(s, 3); /* Padding 2 */ + Stream_Read_UINT32(s, OutputBufferSize); + if (OutputBufferSize > UINT32_MAX - 36) + return ERROR_INVALID_DATA; - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); + switch (transferDir) + { + case USBD_TRANSFER_DIRECTION_OUT: + if (Stream_GetRemainingLength(s) < OutputBufferSize) + return ERROR_INVALID_DATA; - if (pdev == NULL) - return 0; + break; - InterfaceId = ((STREAM_ID_PROXY<<30) | pdev->get_ReqCompletion(pdev)); + default: + break; + } - data_read_UINT32(data + 0, RequestId); - data_read_BYTE(data + 4, Recipient); /** Recipient */ - Recipient = (Recipient & 0x1f); /* XXX: origin: Recipient && 0x1f !? */ - data_read_BYTE(data + 5, InterfaceNumber); /** InterfaceNumber */ - data_read_BYTE(data + 6, Ms_PageIndex); /** Ms_PageIndex */ - data_read_UINT16(data + 7, Ms_featureDescIndex); /** Ms_featureDescIndex */ - data_read_UINT32(data + 12, OutputBufferSize); - offset = 16; + InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); + out_size = 36ULL + OutputBufferSize; + out = Stream_New(NULL, out_size); - out_size = 36 + OutputBufferSize; - out_data = (BYTE *) malloc(out_size); - memset(out_data, 0, out_size); + if (!out) + return ERROR_OUTOFMEMORY; - buffer = out_data + 36; + Stream_Seek(out, 36); switch (transferDir) { case USBD_TRANSFER_DIRECTION_OUT: - WLog_ERR(TAG, "Function urb_os_feature_descriptor_request: OUT Unchecked"); - memcpy(buffer, data + offset, OutputBufferSize); + Stream_Copy(s, out, OutputBufferSize); + Stream_Rewind(out, OutputBufferSize); break; + case USBD_TRANSFER_DIRECTION_IN: break; } - WLog_DBG(TAG, "Ms descriptor arg: Recipient:0x%"PRIx8", " - "InterfaceNumber:0x%"PRIx8", Ms_PageIndex:0x%"PRIx8", " - "Ms_featureDescIndex:0x%"PRIx16", OutputBufferSize:0x%"PRIx32"", - Recipient, InterfaceNumber, Ms_PageIndex, - Ms_featureDescIndex, OutputBufferSize); - + WLog_Print(urbdrc->log, WLOG_DEBUG, + "Ms descriptor arg: Recipient:0x%" PRIx8 ", " + "InterfaceNumber:0x%" PRIx8 ", Ms_PageIndex:0x%" PRIx8 ", " + "Ms_featureDescIndex:0x%" PRIx16 ", OutputBufferSize:0x%" PRIx32 "", + Recipient, InterfaceNumber, Ms_PageIndex, Ms_featureDescIndex, OutputBufferSize); /** get ms string */ - ret = pdev->os_feature_descriptor_request( - pdev, RequestId, Recipient, - InterfaceNumber, - Ms_PageIndex, - Ms_featureDescIndex, - &usbd_status, - &OutputBufferSize, - buffer, - 1000); + ret = pdev->os_feature_descriptor_request(pdev, RequestId, Recipient, InterfaceNumber, + Ms_PageIndex, Ms_featureDescIndex, &usbd_status, + &OutputBufferSize, Stream_Pointer(out), 1000); if (ret < 0) - WLog_DBG(TAG, "os_feature_descriptor_request: error num %d", ret); - - offset = 36; - out_size = offset + OutputBufferSize; - /** send data */ - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ - if(OutputBufferSize!=0) - data_write_UINT32(out_data + 8, URB_COMPLETION); /** function id */ - else - data_write_UINT32(out_data + 8, URB_COMPLETION_NO_DATA); - data_write_UINT32(out_data + 12, RequestId); /** RequestId */ - data_write_UINT32(out_data + 16, 0x00000008); /** CbTsUrbResult */ - /** TsUrbResult TS_URB_RESULT_HEADER */ - data_write_UINT16(out_data + 20, 0x0008); /** Size */ - - /** Padding, MUST be ignored upon receipt */ - data_write_UINT16(out_data + 22, URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR); - data_write_UINT32(out_data + 24, usbd_status); /** UsbdStatus */ - - data_write_UINT32(out_data + 28, 0); /** HResult */ - data_write_UINT32(out_data + 32, OutputBufferSize); /** OutputBufferSize */ - - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); + WLog_Print(urbdrc->log, WLOG_DEBUG, "os_feature_descriptor_request: error num %d", ret); - zfree(out_data); - - return 0; + return urb_write_completion(pdev, callback, noAck, out, InterfaceId, MessageId, RequestId, + usbd_status, OutputBufferSize); } -static int urb_pipe_request(URBDRC_CHANNEL_CALLBACK * callback, BYTE * data, - UINT32 data_sizem, - UINT32 MessageId, - IUDEVMAN * udevman, - UINT32 UsbDevice, - int transferDir, - int action) +static UINT urb_pipe_request(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, wStream* s, + UINT32 RequestField, UINT32 MessageId, IUDEVMAN* udevman, + int transferDir, int action) { - IUDEVICE* pdev; - UINT32 out_size, RequestId, InterfaceId, PipeHandle, EndpointAddress; + UINT32 out_size, InterfaceId, PipeHandle, EndpointAddress; UINT32 OutputBufferSize, usbd_status = 0; - BYTE* out_data; - int out_offset, ret; + wStream* out; + UINT32 ret = USBD_STATUS_REQUEST_FAILED; + int rc; + URBDRC_PLUGIN* urbdrc; + const BOOL noAck = (RequestField & 0x80000000U) != 0; + const UINT32 RequestId = RequestField & 0x7FFFFFFF; - if (transferDir == 0){ - WLog_DBG(TAG, "urb_pipe_request: not support transfer out"); - return -1; - } + if (!callback || !s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); + urbdrc = (URBDRC_PLUGIN*)callback->plugin; - if (pdev == NULL) - return 0; + if (!urbdrc) + return ERROR_INVALID_PARAMETER; - InterfaceId = ((STREAM_ID_PROXY<<30) | pdev->get_ReqCompletion(pdev)); + if (Stream_GetRemainingLength(s) < 8) + return ERROR_INVALID_DATA; - data_read_UINT32(data + 0, RequestId); - data_read_UINT32(data + 4, PipeHandle); /** PipeHandle */ - data_read_UINT32(data + 8, OutputBufferSize); - EndpointAddress = (PipeHandle & 0x000000ff); + if (transferDir == 0) + { + WLog_Print(urbdrc->log, WLOG_DEBUG, "urb_pipe_request: not support transfer out"); + return ERROR_INVALID_PARAMETER; + } + InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); + Stream_Read_UINT32(s, PipeHandle); /** PipeHandle */ + Stream_Read_UINT32(s, OutputBufferSize); + EndpointAddress = (PipeHandle & 0x000000ff); - switch (action){ + switch (action) + { case PIPE_CANCEL: - WLog_DBG(TAG, "urb_pipe_request: PIPE_CANCEL 0x%"PRIx32"", EndpointAddress); - - ret = pdev->control_pipe_request( - pdev, RequestId, EndpointAddress, - &usbd_status, - PIPE_CANCEL); - - if (ret < 0) { - WLog_DBG(TAG, "PIPE SET HALT: error num %d", ret); - } + rc = pdev->control_pipe_request(pdev, RequestId, EndpointAddress, &usbd_status, + PIPE_CANCEL); + if (rc < 0) + WLog_Print(urbdrc->log, WLOG_DEBUG, "PIPE SET HALT: error %d", ret); + else + ret = USBD_STATUS_SUCCESS; break; - case PIPE_RESET: - WLog_DBG(TAG, "urb_pipe_request: PIPE_RESET ep 0x%"PRIx32"", EndpointAddress); - ret = pdev->control_pipe_request( - pdev, RequestId, EndpointAddress, - &usbd_status, - PIPE_RESET); + case PIPE_RESET: + WLog_Print(urbdrc->log, WLOG_DEBUG, "urb_pipe_request: PIPE_RESET ep 0x%" PRIx32 "", + EndpointAddress); + rc = pdev->control_pipe_request(pdev, RequestId, EndpointAddress, &usbd_status, + PIPE_RESET); - if (ret < 0) - WLog_DBG(TAG, "PIPE RESET: error num %d!!", ret); + if (rc < 0) + WLog_Print(urbdrc->log, WLOG_DEBUG, "PIPE RESET: error %d", ret); + else + ret = USBD_STATUS_SUCCESS; break; + default: - WLog_DBG(TAG, "urb_pipe_request action: %d is not support!", action); + WLog_Print(urbdrc->log, WLOG_DEBUG, "urb_pipe_request action: %d not supported", + action); + ret = USBD_STATUS_INVALID_URB_FUNCTION; break; } - /** send data */ - out_offset = 36; - out_size = out_offset + OutputBufferSize; - out_data = (BYTE *) malloc(out_size); - memset(out_data, 0, out_size); - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ - - data_write_UINT32(out_data + 8, URB_COMPLETION_NO_DATA); - data_write_UINT32(out_data + 12, RequestId); /** RequestId */ - data_write_UINT32(out_data + 16, 0x00000008); /** CbTsUrbResult */ - /** TsUrbResult TS_URB_RESULT_HEADER */ - data_write_UINT16(out_data + 20, 0x0008); /** Size */ - - /** Padding, MUST be ignored upon receipt */ - data_write_UINT16(out_data + 22, URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL); - data_write_UINT32(out_data + 24, usbd_status); /** UsbdStatus */ + out_size = 36; + out = Stream_New(NULL, out_size); - data_write_UINT32(out_data + 28, 0); /** HResult */ - data_write_UINT32(out_data + 32, 0); /** OutputBufferSize */ - - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); - zfree(out_data); + if (!out) + return ERROR_OUTOFMEMORY; - return 0; + return urb_write_completion(pdev, callback, noAck, out, InterfaceId, MessageId, RequestId, ret, + 0); } -static int urb_get_current_frame_number(URBDRC_CHANNEL_CALLBACK* callback, - BYTE * data, - UINT32 data_sizem, - UINT32 MessageId, - IUDEVMAN * udevman, - UINT32 UsbDevice, - int transferDir) +static UINT urb_get_current_frame_number(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, + wStream* s, UINT32 RequestField, UINT32 MessageId, + IUDEVMAN* udevman, int transferDir) { - IUDEVICE* pdev; - UINT32 out_size, RequestId, InterfaceId, OutputBufferSize; + UINT32 out_size, InterfaceId, OutputBufferSize; UINT32 dummy_frames; - BYTE* out_data; + wStream* out; + URBDRC_PLUGIN* urbdrc; + const BOOL noAck = (RequestField & 0x80000000U) != 0; + const UINT32 RequestId = RequestField & 0x7FFFFFFF; - if (transferDir == 0){ - WLog_DBG(TAG, "urb_get_current_frame_number: not support transfer out"); - //exit(1); - return -1; - } + if (!callback || !s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); - if (pdev == NULL) - return 0; - InterfaceId = ((STREAM_ID_PROXY<<30) | pdev->get_ReqCompletion(pdev)); + urbdrc = (URBDRC_PLUGIN*)callback->plugin; + + if (!urbdrc) + return ERROR_INVALID_PARAMETER; - data_read_UINT32(data + 0, RequestId); - data_read_UINT32(data + 4, OutputBufferSize); + if (Stream_GetRemainingLength(s) < 4) + return ERROR_INVALID_DATA; - /** Fixme: Need to fill actual frame number!!*/ - urbdrc_get_mstime(dummy_frames); + if (transferDir == 0) + { + WLog_Print(urbdrc->log, WLOG_DEBUG, + "urb_get_current_frame_number: not support transfer out"); + return ERROR_INVALID_PARAMETER; + } + InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); + Stream_Read_UINT32(s, OutputBufferSize); + /** Fixme: Need to fill actual frame number!!*/ + dummy_frames = GetTickCount(); out_size = 40; - out_data = (BYTE *) malloc(out_size); - memset(out_data, 0, out_size); - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ - - data_write_UINT32(out_data + 8, URB_COMPLETION_NO_DATA); - data_write_UINT32(out_data + 12, RequestId); /** RequestId */ - data_write_UINT32(out_data + 16, 12); /** CbTsUrbResult */ - /** TsUrbResult TS_URB_RESULT_HEADER */ - data_write_UINT16(out_data + 20, 12); /** Size */ + out = Stream_New(NULL, out_size); - /** Padding, MUST be ignored upon receipt */ - data_write_UINT16(out_data + 22, URB_FUNCTION_GET_CURRENT_FRAME_NUMBER); - data_write_UINT32(out_data + 24, USBD_STATUS_SUCCESS); /** UsbdStatus */ - data_write_UINT32(out_data + 28, dummy_frames); /** FrameNumber */ + if (!out) + return ERROR_OUTOFMEMORY; - data_write_UINT32(out_data + 32, 0); /** HResult */ - data_write_UINT32(out_data + 36, 0); /** OutputBufferSize */ + Stream_Write_UINT32(out, InterfaceId); /** interface */ + Stream_Write_UINT32(out, MessageId); /** message id */ + Stream_Write_UINT32(out, URB_COMPLETION_NO_DATA); + Stream_Write_UINT32(out, RequestId); /** RequestId */ + Stream_Write_UINT32(out, 12); /** CbTsUrbResult */ + /** TsUrbResult TS_URB_RESULT_HEADER */ + Stream_Write_UINT16(out, 12); /** Size */ + /** Padding, MUST be ignored upon receipt */ + Stream_Write_UINT16(out, TS_URB_GET_CURRENT_FRAME_NUMBER); + Stream_Write_UINT32(out, USBD_STATUS_SUCCESS); /** UsbdStatus */ + Stream_Write_UINT32(out, dummy_frames); /** FrameNumber */ + Stream_Write_UINT32(out, 0); /** HResult */ + Stream_Write_UINT32(out, 0); /** OutputBufferSize */ + + if (!noAck) + return stream_write_and_free(callback->plugin, callback->channel, out); + else + Stream_Free(out, TRUE); - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); - zfree(out_data); - return 0; + return ERROR_SUCCESS; } - /* Unused function for current server */ -static int urb_control_get_configuration_request(URBDRC_CHANNEL_CALLBACK* callback, - BYTE * data, - UINT32 data_sizem, - UINT32 MessageId, - IUDEVMAN * udevman, - UINT32 UsbDevice, - int transferDir) +static UINT urb_control_get_configuration_request(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, + wStream* s, UINT32 RequestField, UINT32 MessageId, + IUDEVMAN* udevman, int transferDir) { - IUDEVICE* pdev; - UINT32 out_size, RequestId, InterfaceId, OutputBufferSize, usbd_status; - BYTE* buffer; - BYTE* out_data; - int ret, offset; - - if (transferDir == 0) - { - WLog_DBG(TAG, "urb_control_get_configuration_request:" - " not support transfer out"); - return -1; - } - - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); + size_t out_size; + UINT32 InterfaceId, OutputBufferSize, usbd_status; + wStream* out; + URBDRC_PLUGIN* urbdrc; + const BOOL noAck = (RequestField & 0x80000000U) != 0; + const UINT32 RequestId = RequestField & 0x7FFFFFFF; - if (pdev == NULL) - return 0; + if (!callback || !s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; - InterfaceId = ((STREAM_ID_PROXY<<30) | pdev->get_ReqCompletion(pdev)); + urbdrc = (URBDRC_PLUGIN*)callback->plugin; - data_read_UINT32(data + 0, RequestId); - data_read_UINT32(data + 4, OutputBufferSize); + if (!urbdrc) + return ERROR_INVALID_PARAMETER; - out_size = 36 + OutputBufferSize; - out_data = (BYTE *) malloc(out_size); - memset(out_data, 0, out_size); - - buffer = out_data + 36; - - ret = pdev->control_transfer( - pdev, RequestId, 0, 0, 0x80 | 0x00, - 0x08, /* REQUEST_GET_CONFIGURATION */ - 0, - 0, - &usbd_status, - &OutputBufferSize, - buffer, - 1000); - - if (ret < 0){ - WLog_DBG(TAG, "control_transfer: error num %d", ret); - OutputBufferSize = 0; + if (transferDir == 0) + { + WLog_Print(urbdrc->log, WLOG_DEBUG, + "urb_control_get_configuration_request:" + " not support transfer out"); + return ERROR_INVALID_PARAMETER; } + if (Stream_GetRemainingLength(s) < 4) + return ERROR_INVALID_DATA; - offset = 36; - out_size = offset + OutputBufferSize; - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ + Stream_Read_UINT32(s, OutputBufferSize); + if (OutputBufferSize > UINT32_MAX - 36) + return ERROR_INVALID_DATA; + out_size = 36ULL + OutputBufferSize; + out = Stream_New(NULL, out_size); - if (OutputBufferSize != 0) - data_write_UINT32(out_data + 8, URB_COMPLETION); - else - data_write_UINT32(out_data + 8, URB_COMPLETION_NO_DATA); - data_write_UINT32(out_data + 12, RequestId); /** RequestId */ - data_write_UINT32(out_data + 16, 8); /** CbTsUrbResult */ - /** TsUrbResult TS_URB_RESULT_HEADER */ - data_write_UINT16(out_data + 20, 8); /** Size */ + if (!out) + return ERROR_OUTOFMEMORY; - /** Padding, MUST be ignored upon receipt */ - data_write_UINT16(out_data + 22, URB_FUNCTION_GET_CONFIGURATION); - data_write_UINT32(out_data + 24, usbd_status); /** UsbdStatus */ + Stream_Seek(out, 36); + InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); - data_write_UINT32(out_data + 28, 0); /** HResult */ - data_write_UINT32(out_data + 32, OutputBufferSize); /** OutputBufferSize */ + if (!pdev->control_transfer(pdev, RequestId, 0, 0, 0x80 | 0x00, + 0x08, /* REQUEST_GET_CONFIGURATION */ + 0, 0, &usbd_status, &OutputBufferSize, Stream_Pointer(out), 1000)) + { + WLog_Print(urbdrc->log, WLOG_DEBUG, "control_transfer failed"); + Stream_Free(out, TRUE); + return ERROR_INTERNAL_ERROR; + } - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); - zfree(out_data); - return 0; + return urb_write_completion(pdev, callback, noAck, out, InterfaceId, MessageId, RequestId, + usbd_status, OutputBufferSize); } /* Unused function for current server */ -static int urb_control_get_interface_request(URBDRC_CHANNEL_CALLBACK* callback, - BYTE * data, - UINT32 data_sizem, - UINT32 MessageId, - IUDEVMAN * udevman, - UINT32 UsbDevice, - int transferDir) +static UINT urb_control_get_interface_request(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, + wStream* s, UINT32 RequestField, UINT32 MessageId, + IUDEVMAN* udevman, int transferDir) { - IUDEVICE* pdev; - UINT32 out_size, RequestId, InterfaceId, OutputBufferSize, usbd_status; + size_t out_size; + UINT32 InterfaceId, OutputBufferSize, usbd_status; UINT16 interface; - BYTE* buffer; - BYTE* out_data; - int ret, offset; + wStream* out; + URBDRC_PLUGIN* urbdrc; + const BOOL noAck = (RequestField & 0x80000000U) != 0; + const UINT32 RequestId = RequestField & 0x7FFFFFFF; - if (transferDir == 0){ - WLog_DBG(TAG, "urb_control_get_interface_request: not support transfer out"); - return -1; - } + if (!callback || !s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); - if (pdev == NULL) - return 0; - InterfaceId = ((STREAM_ID_PROXY<<30) | pdev->get_ReqCompletion(pdev)); + urbdrc = (URBDRC_PLUGIN*)callback->plugin; - data_read_UINT32(data + 0, RequestId); - data_read_UINT16(data + 4, interface); - data_read_UINT32(data + 8, OutputBufferSize); + if (!urbdrc) + return ERROR_INVALID_PARAMETER; - out_size = 36 + OutputBufferSize; - out_data = (BYTE *) malloc(out_size); - memset(out_data, 0, out_size); - - buffer = out_data + 36; - - ret = pdev->control_transfer(pdev, RequestId, 0, 0, 0x80 | 0x01, - 0x0A, /* REQUEST_GET_INTERFACE */ - 0, - interface, - &usbd_status, - &OutputBufferSize, - buffer, - 1000); - - if (ret < 0){ - WLog_DBG(TAG, "control_transfer: error num %d", ret); - OutputBufferSize = 0; - } + if (Stream_GetRemainingLength(s) < 8) + return ERROR_INVALID_DATA; - offset = 36; - out_size = offset + OutputBufferSize; - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ + if (transferDir == 0) + { + WLog_Print(urbdrc->log, WLOG_DEBUG, + "urb_control_get_interface_request: not support transfer out"); + return ERROR_INVALID_PARAMETER; + } - if (OutputBufferSize != 0) - data_write_UINT32(out_data + 8, URB_COMPLETION); - else - data_write_UINT32(out_data + 8, URB_COMPLETION_NO_DATA); - data_write_UINT32(out_data + 12, RequestId); /** RequestId */ - data_write_UINT32(out_data + 16, 8); /** CbTsUrbResult */ - /** TsUrbResult TS_URB_RESULT_HEADER */ - data_write_UINT16(out_data + 20, 8); /** Size */ + InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); + Stream_Read_UINT16(s, interface); + Stream_Seek(s, 2); + Stream_Read_UINT32(s, OutputBufferSize); + if (OutputBufferSize > UINT32_MAX - 36) + return ERROR_INVALID_DATA; + out_size = 36ULL + OutputBufferSize; + out = Stream_New(NULL, out_size); + + if (!out) + return ERROR_OUTOFMEMORY; - /** Padding, MUST be ignored upon receipt */ - data_write_UINT16(out_data + 22, URB_FUNCTION_GET_INTERFACE); - data_write_UINT32(out_data + 24, usbd_status); /** UsbdStatus */ + Stream_Seek(out, 36); - data_write_UINT32(out_data + 28, 0); /** HResult */ - data_write_UINT32(out_data + 32, OutputBufferSize); /** OutputBufferSize */ + if (!pdev->control_transfer( + pdev, RequestId, 0, 0, 0x80 | 0x01, 0x0A, /* REQUEST_GET_INTERFACE */ + 0, interface, &usbd_status, &OutputBufferSize, Stream_Pointer(out), 1000)) + { + WLog_Print(urbdrc->log, WLOG_DEBUG, "control_transfer failed"); + Stream_Free(out, TRUE); + return ERROR_INTERNAL_ERROR; + } - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); - zfree(out_data); - return 0; + return urb_write_completion(pdev, callback, noAck, out, InterfaceId, MessageId, RequestId, + usbd_status, OutputBufferSize); } -static int urb_control_feature_request(URBDRC_CHANNEL_CALLBACK * callback, BYTE * data, - UINT32 data_sizem, - UINT32 MessageId, - IUDEVMAN * udevman, - UINT32 UsbDevice, - BYTE func_recipient, - BYTE command, - int transferDir) +static UINT urb_control_feature_request(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, + wStream* s, UINT32 RequestField, UINT32 MessageId, + IUDEVMAN* udevman, BYTE func_recipient, BYTE command, + int transferDir) { - IUDEVICE* pdev; - UINT32 out_size, RequestId, InterfaceId, OutputBufferSize, usbd_status; + UINT32 InterfaceId, OutputBufferSize, usbd_status; UINT16 FeatureSelector, Index; BYTE bmRequestType, bmRequest; - BYTE* buffer; - BYTE* out_data; - int ret, offset; + wStream* out; + URBDRC_PLUGIN* urbdrc; + const BOOL noAck = (RequestField & 0x80000000U) != 0; + const UINT32 RequestId = RequestField & 0x7FFFFFFF; - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); + if (!callback || !s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; - if (pdev == NULL) - return 0; + urbdrc = (URBDRC_PLUGIN*)callback->plugin; - InterfaceId = ((STREAM_ID_PROXY<<30) | pdev->get_ReqCompletion(pdev)); + if (!urbdrc) + return ERROR_INVALID_PARAMETER; - data_read_UINT32(data + 0, RequestId); - data_read_UINT16(data + 4, FeatureSelector); - data_read_UINT16(data + 6, Index); - data_read_UINT32(data + 8, OutputBufferSize); - offset = 12; + if (Stream_GetRemainingLength(s) < 8) + return ERROR_INVALID_DATA; - out_size = 36 + OutputBufferSize; - out_data = (BYTE *) malloc(out_size); - memset(out_data, 0, out_size); + InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); + Stream_Read_UINT16(s, FeatureSelector); + Stream_Read_UINT16(s, Index); + Stream_Read_UINT32(s, OutputBufferSize); + if (OutputBufferSize > UINT32_MAX - 36) + return ERROR_INVALID_DATA; + switch (transferDir) + { + case USBD_TRANSFER_DIRECTION_OUT: + if (Stream_GetRemainingLength(s) < OutputBufferSize) + return ERROR_INVALID_DATA; + + break; - buffer = out_data + 36; + default: + break; + } + + out = Stream_New(NULL, 36ULL + OutputBufferSize); + + if (!out) + return ERROR_OUTOFMEMORY; + Stream_Seek(out, 36); bmRequestType = func_recipient; + switch (transferDir) { case USBD_TRANSFER_DIRECTION_OUT: - WLog_ERR(TAG, "Function urb_control_feature_request: OUT Unchecked"); - memcpy(buffer, data + offset, OutputBufferSize); + WLog_Print(urbdrc->log, WLOG_ERROR, + "Function urb_control_feature_request: OUT Unchecked"); + Stream_Copy(s, out, OutputBufferSize); + Stream_Rewind(out, OutputBufferSize); bmRequestType |= 0x00; break; + case USBD_TRANSFER_DIRECTION_IN: bmRequestType |= 0x80; break; @@ -1721,731 +1437,408 @@ static int urb_control_feature_request(URBDRC_CHANNEL_CALLBACK * callback, BYTE case URB_SET_FEATURE: bmRequest = 0x03; /* REQUEST_SET_FEATURE */ break; + case URB_CLEAR_FEATURE: bmRequest = 0x01; /* REQUEST_CLEAR_FEATURE */ break; + default: - WLog_ERR(TAG, "urb_control_feature_request: Error Command 0x%02"PRIx8"", command); - zfree(out_data); - return -1; + WLog_Print(urbdrc->log, WLOG_ERROR, + "urb_control_feature_request: Error Command 0x%02" PRIx8 "", command); + Stream_Free(out, TRUE); + return ERROR_INTERNAL_ERROR; } - ret = pdev->control_transfer( - pdev, RequestId, 0, 0, bmRequestType, bmRequest, - FeatureSelector, - Index, - &usbd_status, - &OutputBufferSize, - buffer, - 1000); - - if (ret < 0){ - WLog_DBG(TAG, "feature control transfer: error num %d", ret); - OutputBufferSize = 0; + if (!pdev->control_transfer(pdev, RequestId, 0, 0, bmRequestType, bmRequest, FeatureSelector, + Index, &usbd_status, &OutputBufferSize, Stream_Pointer(out), 1000)) + { + WLog_Print(urbdrc->log, WLOG_DEBUG, "feature control transfer failed"); + Stream_Free(out, TRUE); + return ERROR_INTERNAL_ERROR; } - offset = 36; - out_size = offset + OutputBufferSize; - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ + return urb_write_completion(pdev, callback, noAck, out, InterfaceId, MessageId, RequestId, + usbd_status, OutputBufferSize); +} - if (OutputBufferSize != 0) - data_write_UINT32(out_data + 8, URB_COMPLETION); - else - data_write_UINT32(out_data + 8, URB_COMPLETION_NO_DATA); - data_write_UINT32(out_data + 12, RequestId); /** RequestId */ - data_write_UINT32(out_data + 16, 8); /** CbTsUrbResult */ - /** TsUrbResult TS_URB_RESULT_HEADER */ - data_write_UINT16(out_data + 20, 8); /** Size */ +static UINT urbdrc_process_transfer_request(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, + wStream* s, UINT32 MessageId, IUDEVMAN* udevman, + int transferDir) +{ + UINT32 CbTsUrb; + UINT16 Size; + UINT16 URB_Function; + UINT32 RequestId; + UINT error = ERROR_INTERNAL_ERROR; + URBDRC_PLUGIN* urbdrc; - /** Padding, MUST be ignored upon receipt */ - data_write_UINT16(out_data + 22, URB_FUNCTION_GET_INTERFACE); - data_write_UINT32(out_data + 24, usbd_status); /** UsbdStatus */ + if (!callback || !s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; - data_write_UINT32(out_data + 28, 0); /** HResult */ - data_write_UINT32(out_data + 32, OutputBufferSize); /** OutputBufferSize */ + urbdrc = (URBDRC_PLUGIN*)callback->plugin; + if (!urbdrc) + return ERROR_INVALID_PARAMETER; - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); - zfree(out_data); - return 0; -} + if (Stream_GetRemainingLength(s) < 12) + return ERROR_INVALID_DATA; -static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, BYTE * data, - UINT32 data_sizem, - UINT32 MessageId, - IUDEVMAN * udevman, - UINT32 UsbDevice, - int transferDir) -{ - IUDEVICE * pdev; - UINT32 CbTsUrb; - UINT16 Size; - UINT16 URB_Function; - UINT32 OutputBufferSize; - int error = 0; - - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); - if (pdev == NULL) - return 0; - data_read_UINT32(data + 0, CbTsUrb); /** CbTsUrb */ - data_read_UINT16(data + 4, Size); /** size */ - data_read_UINT16(data + 6, URB_Function); - data_read_UINT32(data + 4 + CbTsUrb, OutputBufferSize); + Stream_Read_UINT32(s, CbTsUrb); /** CbTsUrb */ + Stream_Read_UINT16(s, Size); /** size */ + Stream_Read_UINT16(s, URB_Function); + Stream_Read_UINT32(s, RequestId); + WLog_Print(urbdrc->log, WLOG_DEBUG, "URB %s[" PRIu16 "]", urb_function_string(URB_Function), + URB_Function); switch (URB_Function) { - case URB_FUNCTION_SELECT_CONFIGURATION: /** 0x0000 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SELECT_CONFIGURATION"); - error = urb_select_configuration( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - transferDir); - break; - case URB_FUNCTION_SELECT_INTERFACE: /** 0x0001 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SELECT_INTERFACE"); - error = urb_select_interface( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - transferDir); - break; - case URB_FUNCTION_ABORT_PIPE: /** 0x0002 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_ABORT_PIPE"); - error = urb_pipe_request( - callback, data + 8, data_sizem - 8, - MessageId, - udevman, - UsbDevice, - transferDir, - PIPE_CANCEL); - break; - case URB_FUNCTION_TAKE_FRAME_LENGTH_CONTROL: /** 0x0003 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_TAKE_FRAME_LENGTH_CONTROL"); - error = -1; /** This URB function is obsolete in Windows 2000 - * and later operating systems - * and is not supported by Microsoft. */ - break; - case URB_FUNCTION_RELEASE_FRAME_LENGTH_CONTROL: /** 0x0004 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_RELEASE_FRAME_LENGTH_CONTROL"); - error = -1; /** This URB function is obsolete in Windows 2000 - * and later operating systems - * and is not supported by Microsoft. */ - break; - case URB_FUNCTION_GET_FRAME_LENGTH: /** 0x0005 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_FRAME_LENGTH"); - error = -1; /** This URB function is obsolete in Windows 2000 - * and later operating systems - * and is not supported by Microsoft. */ - break; - case URB_FUNCTION_SET_FRAME_LENGTH: /** 0x0006 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SET_FRAME_LENGTH"); - error = -1; /** This URB function is obsolete in Windows 2000 - * and later operating systems - * and is not supported by Microsoft. */ - break; - case URB_FUNCTION_GET_CURRENT_FRAME_NUMBER: /** 0x0007 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_CURRENT_FRAME_NUMBER"); - error = urb_get_current_frame_number( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - transferDir); - break; - case URB_FUNCTION_CONTROL_TRANSFER: /** 0x0008 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_CONTROL_TRANSFER"); - error = urb_control_transfer( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - transferDir, - URB_CONTROL_TRANSFER_NONEXTERNAL); - break; - case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER: /** 0x0009 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER"); - error = urb_bulk_or_interrupt_transfer( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - transferDir); - break; - case URB_FUNCTION_ISOCH_TRANSFER: /** 0x000A */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_ISOCH_TRANSFER"); - error = urb_isoch_transfer( - callback, data + 8, data_sizem - 8, - MessageId, - udevman, - UsbDevice, - transferDir); - break; - case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE: /** 0x000B */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE"); - error = urb_control_descriptor_request( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - 0x00, - transferDir); - break; - case URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE: /** 0x000C */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE"); - error = urb_control_descriptor_request( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - 0x00, - transferDir); - break; - case URB_FUNCTION_SET_FEATURE_TO_DEVICE: /** 0x000D */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SET_FEATURE_TO_DEVICE"); - error = urb_control_feature_request(callback, - data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - 0x00, - URB_SET_FEATURE, - transferDir); - break; - case URB_FUNCTION_SET_FEATURE_TO_INTERFACE: /** 0x000E */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SET_FEATURE_TO_INTERFACE"); - error = urb_control_feature_request( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - 0x01, - URB_SET_FEATURE, - transferDir); - break; - case URB_FUNCTION_SET_FEATURE_TO_ENDPOINT: /** 0x000F */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SET_FEATURE_TO_ENDPOINT"); - error = urb_control_feature_request( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - 0x02, - URB_SET_FEATURE, - transferDir); - break; - case URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE: /** 0x0010 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE"); - error = urb_control_feature_request( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - 0x00, - URB_CLEAR_FEATURE, - transferDir); - break; - case URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE: /** 0x0011 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE"); - error = urb_control_feature_request( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - 0x01, - URB_CLEAR_FEATURE, - transferDir); - break; - case URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT: /** 0x0012 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT"); - error = urb_control_feature_request( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - 0x02, - URB_CLEAR_FEATURE, - transferDir); - break; - case URB_FUNCTION_GET_STATUS_FROM_DEVICE: /** 0x0013 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_STATUS_FROM_DEVICE"); - error = urb_control_get_status_request( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - 0x00, - transferDir); - break; - case URB_FUNCTION_GET_STATUS_FROM_INTERFACE: /** 0x0014 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_STATUS_FROM_INTERFACE"); - error = urb_control_get_status_request( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - 0x01, - transferDir); - break; - case URB_FUNCTION_GET_STATUS_FROM_ENDPOINT: /** 0x0015 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_STATUS_FROM_ENDPOINT"); - error = urb_control_get_status_request( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - 0x02, - transferDir); - break; - case URB_FUNCTION_RESERVED_0X0016: /** 0x0016 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_RESERVED_0X0016"); - error = -1; - break; - case URB_FUNCTION_VENDOR_DEVICE: /** 0x0017 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_VENDOR_DEVICE"); - error = urb_control_vendor_or_class_request( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - (0x02 << 5), /* vendor type */ - 0x00, - transferDir); - break; - case URB_FUNCTION_VENDOR_INTERFACE: /** 0x0018 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_VENDOR_INTERFACE"); - error = urb_control_vendor_or_class_request( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - (0x02 << 5), /* vendor type */ - 0x01, - transferDir); - break; - case URB_FUNCTION_VENDOR_ENDPOINT: /** 0x0019 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_VENDOR_ENDPOINT"); - error = urb_control_vendor_or_class_request( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - (0x02 << 5), /* vendor type */ - 0x02, - transferDir); - break; - case URB_FUNCTION_CLASS_DEVICE: /** 0x001A */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_CLASS_DEVICE"); - error = urb_control_vendor_or_class_request( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - (0x01 << 5), /* class type */ - 0x00, - transferDir); - break; - case URB_FUNCTION_CLASS_INTERFACE: /** 0x001B */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_CLASS_INTERFACE"); - error = urb_control_vendor_or_class_request( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - (0x01 << 5), /* class type */ - 0x01, - transferDir); - break; - case URB_FUNCTION_CLASS_ENDPOINT: /** 0x001C */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_CLASS_ENDPOINT"); - error = urb_control_vendor_or_class_request( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - (0x01 << 5), /* class type */ - 0x02, - transferDir); - break; - case URB_FUNCTION_RESERVE_0X001D: /** 0x001D */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_RESERVE_0X001D"); - error = -1; - break; - case URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL: /** 0x001E */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL"); - error = urb_pipe_request( - callback, data + 8, data_sizem - 8, - MessageId, - udevman, - UsbDevice, - transferDir, - PIPE_RESET); - break; - case URB_FUNCTION_CLASS_OTHER: /** 0x001F */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_CLASS_OTHER"); - error = urb_control_vendor_or_class_request( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - (0x01 << 5), /* class type */ - 0x03, - transferDir); - break; - case URB_FUNCTION_VENDOR_OTHER: /** 0x0020 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_VENDOR_OTHER"); - error = urb_control_vendor_or_class_request( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - (0x02 << 5), /* vendor type */ - 0x03, - transferDir); - break; - case URB_FUNCTION_GET_STATUS_FROM_OTHER: /** 0x0021 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_STATUS_FROM_OTHER"); - error = urb_control_get_status_request( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - 0x03, - transferDir); - break; - case URB_FUNCTION_CLEAR_FEATURE_TO_OTHER: /** 0x0022 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_CLEAR_FEATURE_TO_OTHER"); - error = urb_control_feature_request( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - 0x03, - URB_CLEAR_FEATURE, - transferDir); - break; - case URB_FUNCTION_SET_FEATURE_TO_OTHER: /** 0x0023 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SET_FEATURE_TO_OTHER"); - error = urb_control_feature_request( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - 0x03, - URB_SET_FEATURE, - transferDir); - break; - case URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT: /** 0x0024 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT"); - error = urb_control_descriptor_request( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - 0x02, - transferDir); - break; - case URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT: /** 0x0025 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT"); - error = urb_control_descriptor_request( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - 0x02, - transferDir); - break; - case URB_FUNCTION_GET_CONFIGURATION: /** 0x0026 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_CONFIGURATION"); - error = urb_control_get_configuration_request( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - transferDir); - break; - case URB_FUNCTION_GET_INTERFACE: /** 0x0027 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_INTERFACE"); - error = urb_control_get_interface_request( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - transferDir); - break; - case URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE: /** 0x0028 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE"); - error = urb_control_descriptor_request( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - 0x01, - transferDir); - break; - case URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE: /** 0x0029 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE"); - error = urb_control_descriptor_request( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - 0x01, - transferDir); - break; - case URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR: /** 0x002A */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR"); - error = urb_os_feature_descriptor_request( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - transferDir); - break; - case URB_FUNCTION_RESERVE_0X002B: /** 0x002B */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_RESERVE_0X002B"); - error = -1; - break; - case URB_FUNCTION_RESERVE_0X002C: /** 0x002C */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_RESERVE_0X002C"); - error = -1; - break; - case URB_FUNCTION_RESERVE_0X002D: /** 0x002D */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_RESERVE_0X002D"); - error = -1; - break; - case URB_FUNCTION_RESERVE_0X002E: /** 0x002E */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_RESERVE_0X002E"); - error = -1; - break; - case URB_FUNCTION_RESERVE_0X002F: /** 0x002F */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_RESERVE_0X002F"); - error = -1; + case TS_URB_SELECT_CONFIGURATION: /** 0x0000 */ + error = urb_select_configuration(pdev, callback, s, RequestId, MessageId, udevman, + transferDir); + break; + + case TS_URB_SELECT_INTERFACE: /** 0x0001 */ + error = + urb_select_interface(pdev, callback, s, RequestId, MessageId, udevman, transferDir); + break; + + case TS_URB_PIPE_REQUEST: /** 0x0002 */ + error = urb_pipe_request(pdev, callback, s, RequestId, MessageId, udevman, transferDir, + PIPE_CANCEL); + break; + + case TS_URB_TAKE_FRAME_LENGTH_CONTROL: /** 0x0003 */ + /** This URB function is obsolete in Windows 2000 + * and later operating systems + * and is not supported by Microsoft. */ + break; + + case TS_URB_RELEASE_FRAME_LENGTH_CONTROL: /** 0x0004 */ + /** This URB function is obsolete in Windows 2000 + * and later operating systems + * and is not supported by Microsoft. */ + break; + + case TS_URB_GET_FRAME_LENGTH: /** 0x0005 */ + /** This URB function is obsolete in Windows 2000 + * and later operating systems + * and is not supported by Microsoft. */ + break; + + case TS_URB_SET_FRAME_LENGTH: /** 0x0006 */ + /** This URB function is obsolete in Windows 2000 + * and later operating systems + * and is not supported by Microsoft. */ + break; + + case TS_URB_GET_CURRENT_FRAME_NUMBER: /** 0x0007 */ + error = urb_get_current_frame_number(pdev, callback, s, RequestId, MessageId, udevman, + transferDir); + break; + + case TS_URB_CONTROL_TRANSFER: /** 0x0008 */ + error = urb_control_transfer(pdev, callback, s, RequestId, MessageId, udevman, + transferDir, URB_CONTROL_TRANSFER_NONEXTERNAL); + break; + + case TS_URB_BULK_OR_INTERRUPT_TRANSFER: /** 0x0009 */ + error = urb_bulk_or_interrupt_transfer(pdev, callback, s, RequestId, MessageId, udevman, + transferDir); + break; + + case TS_URB_ISOCH_TRANSFER: /** 0x000A */ + error = + urb_isoch_transfer(pdev, callback, s, RequestId, MessageId, udevman, transferDir); + break; + + case TS_URB_GET_DESCRIPTOR_FROM_DEVICE: /** 0x000B */ + error = urb_control_descriptor_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x00, transferDir); + break; + + case TS_URB_SET_DESCRIPTOR_TO_DEVICE: /** 0x000C */ + error = urb_control_descriptor_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x00, transferDir); + break; + + case TS_URB_SET_FEATURE_TO_DEVICE: /** 0x000D */ + error = urb_control_feature_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x00, URB_SET_FEATURE, transferDir); + break; + + case TS_URB_SET_FEATURE_TO_INTERFACE: /** 0x000E */ + error = urb_control_feature_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x01, URB_SET_FEATURE, transferDir); + break; + + case TS_URB_SET_FEATURE_TO_ENDPOINT: /** 0x000F */ + error = urb_control_feature_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x02, URB_SET_FEATURE, transferDir); + break; + + case TS_URB_CLEAR_FEATURE_TO_DEVICE: /** 0x0010 */ + error = urb_control_feature_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x00, URB_CLEAR_FEATURE, transferDir); + break; + + case TS_URB_CLEAR_FEATURE_TO_INTERFACE: /** 0x0011 */ + error = urb_control_feature_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x01, URB_CLEAR_FEATURE, transferDir); + break; + + case TS_URB_CLEAR_FEATURE_TO_ENDPOINT: /** 0x0012 */ + error = urb_control_feature_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x02, URB_CLEAR_FEATURE, transferDir); + break; + + case TS_URB_GET_STATUS_FROM_DEVICE: /** 0x0013 */ + error = urb_control_get_status_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x00, transferDir); + break; + + case TS_URB_GET_STATUS_FROM_INTERFACE: /** 0x0014 */ + error = urb_control_get_status_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x01, transferDir); + break; + + case TS_URB_GET_STATUS_FROM_ENDPOINT: /** 0x0015 */ + error = urb_control_get_status_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x02, transferDir); + break; + + case TS_URB_RESERVED_0X0016: /** 0x0016 */ + break; + + case TS_URB_VENDOR_DEVICE: /** 0x0017 */ + error = urb_control_vendor_or_class_request(pdev, callback, s, RequestId, MessageId, + udevman, (0x02 << 5), /* vendor type */ + 0x00, transferDir); + break; + + case TS_URB_VENDOR_INTERFACE: /** 0x0018 */ + error = urb_control_vendor_or_class_request(pdev, callback, s, RequestId, MessageId, + udevman, (0x02 << 5), /* vendor type */ + 0x01, transferDir); break; + + case TS_URB_VENDOR_ENDPOINT: /** 0x0019 */ + error = urb_control_vendor_or_class_request(pdev, callback, s, RequestId, MessageId, + udevman, (0x02 << 5), /* vendor type */ + 0x02, transferDir); + break; + + case TS_URB_CLASS_DEVICE: /** 0x001A */ + error = urb_control_vendor_or_class_request(pdev, callback, s, RequestId, MessageId, + udevman, (0x01 << 5), /* class type */ + 0x00, transferDir); + break; + + case TS_URB_CLASS_INTERFACE: /** 0x001B */ + error = urb_control_vendor_or_class_request(pdev, callback, s, RequestId, MessageId, + udevman, (0x01 << 5), /* class type */ + 0x01, transferDir); + break; + + case TS_URB_CLASS_ENDPOINT: /** 0x001C */ + error = urb_control_vendor_or_class_request(pdev, callback, s, RequestId, MessageId, + udevman, (0x01 << 5), /* class type */ + 0x02, transferDir); + break; + + case TS_URB_RESERVE_0X001D: /** 0x001D */ + break; + + case TS_URB_SYNC_RESET_PIPE_AND_CLEAR_STALL: /** 0x001E */ + error = urb_pipe_request(pdev, callback, s, RequestId, MessageId, udevman, transferDir, + PIPE_RESET); + break; + + case TS_URB_CLASS_OTHER: /** 0x001F */ + error = urb_control_vendor_or_class_request(pdev, callback, s, RequestId, MessageId, + udevman, (0x01 << 5), /* class type */ + 0x03, transferDir); + break; + + case TS_URB_VENDOR_OTHER: /** 0x0020 */ + error = urb_control_vendor_or_class_request(pdev, callback, s, RequestId, MessageId, + udevman, (0x02 << 5), /* vendor type */ + 0x03, transferDir); + break; + + case TS_URB_GET_STATUS_FROM_OTHER: /** 0x0021 */ + error = urb_control_get_status_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x03, transferDir); + break; + + case TS_URB_CLEAR_FEATURE_TO_OTHER: /** 0x0022 */ + error = urb_control_feature_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x03, URB_CLEAR_FEATURE, transferDir); + break; + + case TS_URB_SET_FEATURE_TO_OTHER: /** 0x0023 */ + error = urb_control_feature_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x03, URB_SET_FEATURE, transferDir); + break; + + case TS_URB_GET_DESCRIPTOR_FROM_ENDPOINT: /** 0x0024 */ + error = urb_control_descriptor_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x02, transferDir); + break; + + case TS_URB_SET_DESCRIPTOR_TO_ENDPOINT: /** 0x0025 */ + error = urb_control_descriptor_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x02, transferDir); + break; + + case TS_URB_CONTROL_GET_CONFIGURATION_REQUEST: /** 0x0026 */ + error = urb_control_get_configuration_request(pdev, callback, s, RequestId, MessageId, + udevman, transferDir); + break; + + case TS_URB_CONTROL_GET_INTERFACE_REQUEST: /** 0x0027 */ + error = urb_control_get_interface_request(pdev, callback, s, RequestId, MessageId, + udevman, transferDir); + break; + + case TS_URB_GET_DESCRIPTOR_FROM_INTERFACE: /** 0x0028 */ + error = urb_control_descriptor_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x01, transferDir); + break; + + case TS_URB_SET_DESCRIPTOR_TO_INTERFACE: /** 0x0029 */ + error = urb_control_descriptor_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x01, transferDir); + break; + + case TS_URB_GET_OS_FEATURE_DESCRIPTOR_REQUEST: /** 0x002A */ + error = urb_os_feature_descriptor_request(pdev, callback, s, RequestId, MessageId, + udevman, transferDir); + break; + + case TS_URB_RESERVE_0X002B: /** 0x002B */ + case TS_URB_RESERVE_0X002C: /** 0x002C */ + case TS_URB_RESERVE_0X002D: /** 0x002D */ + case TS_URB_RESERVE_0X002E: /** 0x002E */ + case TS_URB_RESERVE_0X002F: /** 0x002F */ + break; + /** USB 2.0 calls start at 0x0030 */ - case URB_FUNCTION_SYNC_RESET_PIPE: /** 0x0030 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SYNC_RESET_PIPE"); - error = urb_pipe_request( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - transferDir, - PIPE_RESET); - error = -9; /** function not support */ - break; - case URB_FUNCTION_SYNC_CLEAR_STALL: /** 0x0031 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SYNC_CLEAR_STALL"); - error = urb_pipe_request( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - transferDir, - PIPE_RESET); - error = -9; - break; - case URB_FUNCTION_CONTROL_TRANSFER_EX: /** 0x0032 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_CONTROL_TRANSFER_EX"); - error = urb_control_transfer( - callback, data + 8, - data_sizem - 8, - MessageId, - udevman, - UsbDevice, - transferDir, - URB_CONTROL_TRANSFER_EXTERNAL); + case TS_URB_SYNC_RESET_PIPE: /** 0x0030 */ + error = urb_pipe_request(pdev, callback, s, RequestId, MessageId, udevman, transferDir, + PIPE_RESET); + break; + + case TS_URB_SYNC_CLEAR_STALL: /** 0x0031 */ + urb_pipe_request(pdev, callback, s, RequestId, MessageId, udevman, transferDir, + PIPE_RESET); break; + + case TS_URB_CONTROL_TRANSFER_EX: /** 0x0032 */ + error = urb_control_transfer(pdev, callback, s, RequestId, MessageId, udevman, + transferDir, URB_CONTROL_TRANSFER_EXTERNAL); + break; + default: - WLog_DBG(TAG, "URB_Func: %"PRIx16" is not found!", URB_Function); + WLog_Print(urbdrc->log, WLOG_DEBUG, "URB_Func: %" PRIx16 " is not found!", + URB_Function); break; } return error; } -void* urbdrc_process_udev_data_transfer(void* arg) +UINT urbdrc_process_udev_data_transfer(URBDRC_CHANNEL_CALLBACK* callback, URBDRC_PLUGIN* urbdrc, + IUDEVMAN* udevman, wStream* data) { - TRANSFER_DATA* transfer_data = (TRANSFER_DATA*) arg; - URBDRC_CHANNEL_CALLBACK * callback = transfer_data->callback; - BYTE * pBuffer = transfer_data->pBuffer; - UINT32 cbSize = transfer_data->cbSize; - UINT32 UsbDevice = transfer_data->UsbDevice; - IUDEVMAN * udevman = transfer_data->udevman; - UINT32 MessageId; - UINT32 FunctionId; - IUDEVICE* pdev; - int error = 0; - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); - if (pdev == NULL || pdev->isSigToEnd(pdev)) + UINT32 InterfaceId; + UINT32 MessageId; + UINT32 FunctionId; + IUDEVICE* pdev; + UINT error = ERROR_INTERNAL_ERROR; + size_t len; + + if (!urbdrc || !data || !callback || !udevman) + goto fail; + + len = Stream_GetRemainingLength(data); + + if (len < 8) + goto fail; + + Stream_Rewind_UINT32(data); + + Stream_Read_UINT32(data, InterfaceId); + Stream_Read_UINT32(data, MessageId); + Stream_Read_UINT32(data, FunctionId); + + pdev = udevman->get_udevice_by_UsbDevice(udevman, InterfaceId); + + /* Device does not exist, ignore this request. */ + if (pdev == NULL) { - if (transfer_data->pBuffer) - zfree(transfer_data->pBuffer); - zfree(transfer_data); - return 0; + error = ERROR_SUCCESS; + goto fail; } - pdev->push_action(pdev); + /* Device has been removed, ignore this request. */ + if (pdev->isChannelClosed(pdev)) + { + error = ERROR_SUCCESS; + goto fail; + } /* USB kernel driver detach!! */ pdev->detach_kernel_driver(pdev); - data_read_UINT32(pBuffer + 0, MessageId); - data_read_UINT32(pBuffer + 4, FunctionId); switch (FunctionId) { case CANCEL_REQUEST: - WLog_DBG(TAG, "urbdrc_process_udev_data_transfer:" - " >>CANCEL_REQUEST<<0x%"PRIX32"", FunctionId); - error = urbdrc_process_cancel_request( - pBuffer + 8, - cbSize - 8, - udevman, - UsbDevice); + error = urbdrc_process_cancel_request(pdev, data, udevman); break; + case REGISTER_REQUEST_CALLBACK: - WLog_DBG(TAG, "urbdrc_process_udev_data_transfer:" - " >>REGISTER_REQUEST_CALLBACK<<0x%"PRIX32"", FunctionId); - error = urbdrc_process_register_request_callback( - callback, - pBuffer + 8, - cbSize - 8, - udevman, - UsbDevice); + error = urbdrc_process_register_request_callback(pdev, callback, data, udevman); break; + case IO_CONTROL: - WLog_DBG(TAG, "urbdrc_process_udev_data_transfer:" - " >>IO_CONTROL<<0x%"PRIX32"", FunctionId); - error = urbdrc_process_io_control( - callback, - pBuffer + 8, - cbSize - 8, - MessageId, - udevman, UsbDevice); + error = urbdrc_process_io_control(pdev, callback, data, MessageId, udevman); break; + case INTERNAL_IO_CONTROL: - WLog_DBG(TAG, "urbdrc_process_udev_data_transfer:" - " >>INTERNAL_IO_CONTROL<<0x%"PRIX32"", FunctionId); - error = urbdrc_process_internal_io_control( - callback, - pBuffer + 8, - cbSize - 8, - MessageId, - udevman, UsbDevice); + error = urbdrc_process_internal_io_control(pdev, callback, data, MessageId, udevman); break; + case QUERY_DEVICE_TEXT: - WLog_DBG(TAG, "urbdrc_process_udev_data_transfer:" - " >>QUERY_DEVICE_TEXT<<0x%"PRIX32"", FunctionId); - error = urbdrc_process_query_device_text( - callback, - pBuffer + 8, - cbSize - 8, - MessageId, - udevman, - UsbDevice); + error = urbdrc_process_query_device_text(pdev, callback, data, MessageId, udevman); break; + case TRANSFER_IN_REQUEST: - WLog_DBG(TAG, "urbdrc_process_udev_data_transfer:" - " >>TRANSFER_IN_REQUEST<<0x%"PRIX32"", FunctionId); - error = urbdrc_process_transfer_request( - callback, - pBuffer + 8, - cbSize - 8, - MessageId, - udevman, - UsbDevice, - USBD_TRANSFER_DIRECTION_IN); + error = urbdrc_process_transfer_request(pdev, callback, data, MessageId, udevman, + USBD_TRANSFER_DIRECTION_IN); break; + case TRANSFER_OUT_REQUEST: - WLog_DBG(TAG, "urbdrc_process_udev_data_transfer:" - " >>TRANSFER_OUT_REQUEST<<0x%"PRIX32"", FunctionId); - error = urbdrc_process_transfer_request( - callback, - pBuffer + 8, - cbSize - 8, - MessageId, - udevman, - UsbDevice, - USBD_TRANSFER_DIRECTION_OUT); + error = urbdrc_process_transfer_request(pdev, callback, data, MessageId, udevman, + USBD_TRANSFER_DIRECTION_OUT); break; + case RETRACT_DEVICE: - WLog_DBG(TAG, "urbdrc_process_udev_data_transfer:" - " >>RETRACT_DEVICE<<0x%"PRIX32"", FunctionId); - error = urbdrc_process_retract_device_request( - pBuffer + 8, - cbSize - 8, - udevman, - UsbDevice); + error = urbdrc_process_retract_device_request(pdev, data, udevman); break; + default: - WLog_DBG(TAG, "urbdrc_process_udev_data_transfer:" - " unknown FunctionId 0x%"PRIX32"", FunctionId); - error = -1; + WLog_Print(urbdrc->log, WLOG_WARN, + "urbdrc_process_udev_data_transfer:" + " unknown FunctionId 0x%" PRIX32 "", + FunctionId); break; } - if (transfer_data) - { - if (transfer_data->pBuffer) - zfree(transfer_data->pBuffer); - zfree(transfer_data); - } - - if (pdev) +fail: + if (error) { -#if ISOCH_FIFO - /* check isochronous fds */ - func_check_isochronous_fds(pdev); -#endif - /* close this channel, if device is not found. */ - pdev->complete_action(pdev); - } - else - { - udevman->push_urb(udevman); - return 0; + WLog_WARN(TAG, "USB request failed with %08" PRIx32, error); } - udevman->push_urb(udevman); - return 0; + return error; } diff --git a/channels/urbdrc/client/data_transfer.h b/channels/urbdrc/client/data_transfer.h index bc3d708..d63f82e 100644 --- a/channels/urbdrc/client/data_transfer.h +++ b/channels/urbdrc/client/data_transfer.h @@ -21,15 +21,16 @@ #ifndef FREERDP_CHANNEL_URBDRC_CLIENT_DATA_TRANSFER_H #define FREERDP_CHANNEL_URBDRC_CLIENT_DATA_TRANSFER_H +#include + #include "urbdrc_main.h" #define DEVICE_CTX(dev) ((dev)->ctx) #define HANDLE_CTX(handle) (DEVICE_CTX((handle)->dev)) #define TRANSFER_CTX(transfer) (HANDLE_CTX((transfer)->dev_handle)) -#define ITRANSFER_CTX(transfer) \ - (TRANSFER_CTX(__USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer))) +#define ITRANSFER_CTX(transfer) (TRANSFER_CTX(__USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer))) -void *urbdrc_process_udev_data_transfer(void* arg); +UINT urbdrc_process_udev_data_transfer(URBDRC_CHANNEL_CALLBACK* callback, URBDRC_PLUGIN* urbdrc, + IUDEVMAN* udevman, wStream* data); #endif /* FREERDP_CHANNEL_URBDRC_CLIENT_DATA_TRANSFER_H */ - diff --git a/channels/urbdrc/client/libusb/CMakeLists.txt b/channels/urbdrc/client/libusb/CMakeLists.txt index abb4356..c5e9b70 100644 --- a/channels/urbdrc/client/libusb/CMakeLists.txt +++ b/channels/urbdrc/client/libusb/CMakeLists.txt @@ -21,9 +21,7 @@ define_channel_client_subsystem("urbdrc" "libusb" "") set(${MODULE_PREFIX}_SRCS libusb_udevman.c libusb_udevice.c - libusb_udevice.h - request_queue.c - request_queue.h) + libusb_udevice.h) include_directories(..) @@ -38,7 +36,7 @@ set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${LIBUSB_1_LIBRARIES}) -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr urbdrc-client) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/channels/urbdrc/client/libusb/libusb_udevice.c b/channels/urbdrc/client/libusb/libusb_udevice.c index 6be973d..214cb7a 100644 --- a/channels/urbdrc/client/libusb/libusb_udevice.c +++ b/channels/urbdrc/client/libusb/libusb_udevice.c @@ -21,222 +21,249 @@ #include #include #include -#include -#if defined(__linux__) -#include -#endif + +#include +#include #include -#include #include "libusb_udevice.h" - -#define BASIC_STATE_FUNC_DEFINED(_arg, _type) \ - static _type udev_get_##_arg (IUDEVICE* idev) \ - { \ - UDEVICE* pdev = (UDEVICE*) idev; \ - return pdev->_arg; \ - } \ - static void udev_set_##_arg (IUDEVICE* idev, _type _t) \ - { \ - UDEVICE* pdev = (UDEVICE*) idev; \ - pdev->_arg = _t; \ - } - -#define BASIC_POINT_FUNC_DEFINED(_arg, _type) \ - static _type udev_get_p_##_arg (IUDEVICE* idev) \ - { \ - UDEVICE* pdev = (UDEVICE*) idev; \ - return pdev->_arg; \ - } \ - static void udev_set_p_##_arg (IUDEVICE* idev, _type _t) \ - { \ - UDEVICE* pdev = (UDEVICE*) idev; \ - pdev->_arg = _t; \ +#include "../common/urbdrc_types.h" + +#define BASIC_STATE_FUNC_DEFINED(_arg, _type) \ + static _type udev_get_##_arg(IUDEVICE* idev) \ + { \ + UDEVICE* pdev = (UDEVICE*)idev; \ + return pdev->_arg; \ + } \ + static void udev_set_##_arg(IUDEVICE* idev, _type _t) \ + { \ + UDEVICE* pdev = (UDEVICE*)idev; \ + pdev->_arg = _t; \ + } + +#define BASIC_POINT_FUNC_DEFINED(_arg, _type) \ + static _type udev_get_p_##_arg(IUDEVICE* idev) \ + { \ + UDEVICE* pdev = (UDEVICE*)idev; \ + return pdev->_arg; \ + } \ + static void udev_set_p_##_arg(IUDEVICE* idev, _type _t) \ + { \ + UDEVICE* pdev = (UDEVICE*)idev; \ + pdev->_arg = _t; \ } #define BASIC_STATE_FUNC_REGISTER(_arg, _dev) \ _dev->iface.get_##_arg = udev_get_##_arg; \ _dev->iface.set_##_arg = udev_set_##_arg +#if LIBUSB_API_VERSION >= 0x01000103 +#define HAVE_STREAM_ID_API 1 +#endif -typedef struct _ISO_USER_DATA ISO_USER_DATA; +typedef struct _ASYNC_TRANSFER_USER_DATA ASYNC_TRANSFER_USER_DATA; -struct _ISO_USER_DATA +struct _ASYNC_TRANSFER_USER_DATA { - BYTE* IsoPacket; - BYTE* output_data; - int iso_status; - int completed; - UINT32 error_count; - int noack; - UINT32 start_frame; + wStream* data; + BOOL noack; + UINT32 MessageId; + UINT32 StartFrame; + UINT32 ErrorCount; + IUDEVICE* idev; + UINT32 OutputBufferSize; + URBDRC_CHANNEL_CALLBACK* callback; + t_isoch_transfer_cb cb; + wHashTable* queue; +#if !defined(HAVE_STREAM_ID_API) + UINT32 streamID; +#endif }; -static int get_next_timeout(libusb_context* ctx, struct timeval* tv, struct timeval* out) +static BOOL log_libusb_result(wLog* log, DWORD lvl, const char* fmt, int error, ...) { - int r; - struct timeval timeout; - r = libusb_get_next_timeout(ctx, &timeout); - - if (r) + if (error < 0) { - /* timeout already expired? */ - if (!timerisset(&timeout)) - return 1; + char buffer[8192] = { 0 }; + va_list ap; + va_start(ap, error); + vsnprintf(buffer, sizeof(buffer), fmt, ap); + va_end(ap); - /* choose the smallest of next URB timeout or user specified timeout */ - if (timercmp(&timeout, tv, <)) - *out = timeout; - else - *out = *tv; - } - else - { - *out = *tv; + WLog_Print(log, lvl, "%s: error %s[%d]", buffer, libusb_error_name(error), error); + return TRUE; } - - return 0; + return FALSE; } -/* - * a simple wrapper to implement libusb_handle_events_timeout_completed - * function in libusb library git tree (1.0.9 later) */ -static int handle_events_completed(libusb_context* ctx, int* completed) +const char* usb_interface_class_to_string(uint8_t class) { - struct timeval tv; - tv.tv_sec = 60; - tv.tv_usec = 0; -#ifdef HAVE_NEW_LIBUSB - return libusb_handle_events_timeout_completed(ctx, &tv, completed); -#else - int r; - struct timeval poll_timeout; - r = get_next_timeout(ctx, &tv, &poll_timeout); -retry: - - if (libusb_try_lock_events(ctx) == 0) - { - if (completed == NULL || !*completed) - { - /* we obtained the event lock: do our own event handling */ - WLog_DBG(TAG, "doing our own event handling"); - r = libusb_handle_events_locked(ctx, &tv); - } - - libusb_unlock_events(ctx); - return r; + switch (class) + { + case LIBUSB_CLASS_PER_INTERFACE: + return "LIBUSB_CLASS_PER_INTERFACE"; + case LIBUSB_CLASS_AUDIO: + return "LIBUSB_CLASS_AUDIO"; + case LIBUSB_CLASS_COMM: + return "LIBUSB_CLASS_COMM"; + case LIBUSB_CLASS_HID: + return "LIBUSB_CLASS_HID"; + case LIBUSB_CLASS_PHYSICAL: + return "LIBUSB_CLASS_PHYSICAL"; + case LIBUSB_CLASS_PRINTER: + return "LIBUSB_CLASS_PRINTER"; + case LIBUSB_CLASS_IMAGE: + return "LIBUSB_CLASS_IMAGE"; + case LIBUSB_CLASS_MASS_STORAGE: + return "LIBUSB_CLASS_MASS_STORAGE"; + case LIBUSB_CLASS_HUB: + return "LIBUSB_CLASS_HUB"; + case LIBUSB_CLASS_DATA: + return "LIBUSB_CLASS_DATA"; + case LIBUSB_CLASS_SMART_CARD: + return "LIBUSB_CLASS_SMART_CARD"; + case LIBUSB_CLASS_CONTENT_SECURITY: + return "LIBUSB_CLASS_CONTENT_SECURITY"; + case LIBUSB_CLASS_VIDEO: + return "LIBUSB_CLASS_VIDEO"; + case LIBUSB_CLASS_PERSONAL_HEALTHCARE: + return "LIBUSB_CLASS_PERSONAL_HEALTHCARE"; + case LIBUSB_CLASS_DIAGNOSTIC_DEVICE: + return "LIBUSB_CLASS_DIAGNOSTIC_DEVICE"; + case LIBUSB_CLASS_WIRELESS: + return "LIBUSB_CLASS_WIRELESS"; + case LIBUSB_CLASS_APPLICATION: + return "LIBUSB_CLASS_APPLICATION"; + case LIBUSB_CLASS_VENDOR_SPEC: + return "LIBUSB_CLASS_VENDOR_SPEC"; + default: + return "UNKNOWN_DEVICE_CLASS"; } +} - /* another thread is doing event handling. wait for thread events that - * notify event completion. */ - libusb_lock_event_waiters(ctx); +static ASYNC_TRANSFER_USER_DATA* async_transfer_user_data_new(IUDEVICE* idev, UINT32 MessageId, + size_t offset, size_t BufferSize, + size_t packetSize, BOOL NoAck, + t_isoch_transfer_cb cb, + URBDRC_CHANNEL_CALLBACK* callback) +{ + ASYNC_TRANSFER_USER_DATA* user_data = calloc(1, sizeof(ASYNC_TRANSFER_USER_DATA)); + UDEVICE* pdev = (UDEVICE*)idev; + + if (!user_data) + return NULL; - if (completed && *completed) - goto already_done; + user_data->data = Stream_New(NULL, offset + BufferSize + packetSize); - if (!libusb_event_handler_active(ctx)) + if (!user_data->data) { - /* we hit a race: whoever was event handling earlier finished in the - * time it took us to reach this point. try the cycle again. */ - libusb_unlock_event_waiters(ctx); - WLog_DBG(TAG, "event handler was active but went away, retrying"); - goto retry; + free(user_data); + return NULL; } + Stream_Seek(user_data->data, offset); /* Skip header offset */ - WLog_DBG(TAG, "another thread is doing event handling"); - r = libusb_wait_for_event(ctx, &poll_timeout); -already_done: - libusb_unlock_event_waiters(ctx); + user_data->noack = NoAck; + user_data->cb = cb; + user_data->callback = callback; + user_data->idev = idev; + user_data->MessageId = MessageId; + user_data->OutputBufferSize = BufferSize; + user_data->queue = pdev->request_queue; - if (r < 0) - { - return r; - } - else if (r == 1) - { - return libusb_handle_events_timeout(ctx, &tv); - } - else + return user_data; +} + +static void async_transfer_user_data_free(ASYNC_TRANSFER_USER_DATA* user_data) +{ + + if (user_data) { - return 0; + Stream_Free(user_data->data, TRUE); + free(user_data); } - -#endif /* HAVE_NEW_LIBUSE */ } static void func_iso_callback(struct libusb_transfer* transfer) { - ISO_USER_DATA* iso_user_data = (ISO_USER_DATA*) transfer->user_data; - BYTE* data = iso_user_data->IsoPacket; - int* completed = &iso_user_data->completed; - UINT32 offset = 0; - UINT32 index = 0; - UINT32 i, act_len; - BYTE* b; - *completed = 1; - - /* Fixme: currently fill the dummy frame number, tt needs to be - * filled a real frame number */ - // urbdrc_get_mstime(iso_user_data->start_frame); - if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && (!iso_user_data->noack)) + ASYNC_TRANSFER_USER_DATA* user_data = (ASYNC_TRANSFER_USER_DATA*)transfer->user_data; +#if defined(HAVE_STREAM_ID_API) + const UINT32 streamID = libusb_transfer_get_stream_id(transfer); +#else + const UINT32 streamID = user_data->streamID; +#endif + + switch (transfer->status) { - for (i = 0; i < transfer->num_iso_packets; i++) + + case LIBUSB_TRANSFER_COMPLETED: { - act_len = transfer->iso_packet_desc[i].actual_length; - data_write_UINT32(data + offset, index); - data_write_UINT32(data + offset + 4, act_len); - data_write_UINT32(data + offset + 8, - transfer->iso_packet_desc[i].status); - offset += 12; - - if (transfer->iso_packet_desc[i].status == USBD_STATUS_SUCCESS) + int i; + UINT32 index = 0; + BYTE* dataStart = Stream_Pointer(user_data->data); + Stream_SetPosition(user_data->data, + 40); /* TS_URB_ISOCH_TRANSFER_RESULT IsoPacket offset */ + + for (i = 0; i < transfer->num_iso_packets; i++) { - b = libusb_get_iso_packet_buffer_simple(transfer, i); + const UINT32 act_len = transfer->iso_packet_desc[i].actual_length; + Stream_Write_UINT32(user_data->data, index); + Stream_Write_UINT32(user_data->data, act_len); + Stream_Write_UINT32(user_data->data, transfer->iso_packet_desc[i].status); - if (act_len > 0) + if (transfer->iso_packet_desc[i].status != USBD_STATUS_SUCCESS) + user_data->ErrorCount++; + else { - if (iso_user_data->output_data + index != b) - memcpy(iso_user_data->output_data + index, b, act_len); + const unsigned char* packetBuffer = + libusb_get_iso_packet_buffer_simple(transfer, i); + BYTE* data = dataStart + index; + + if (data != packetBuffer) + memmove(data, packetBuffer, act_len); index += act_len; } - else - { - //WLog_ERR(TAG, "actual length %"PRIu32"", act_len); - //exit(EXIT_FAILURE); - } } - else + } + /* fallthrough */ + + case LIBUSB_TRANSFER_CANCELLED: + case LIBUSB_TRANSFER_TIMED_OUT: + case LIBUSB_TRANSFER_ERROR: + { + const UINT32 InterfaceId = + ((STREAM_ID_PROXY << 30) | user_data->idev->get_ReqCompletion(user_data->idev)); + + if (HashTable_Contains(user_data->queue, (void*)(size_t)streamID)) { - iso_user_data->error_count++; - //print_transfer_status(transfer->iso_packet_desc[i].status); + if (!user_data->noack) + { + const UINT32 RequestID = streamID & INTERFACE_ID_MASK; + user_data->cb(user_data->idev, user_data->callback, user_data->data, + InterfaceId, user_data->noack, user_data->MessageId, RequestID, + transfer->num_iso_packets, transfer->status, + user_data->StartFrame, user_data->ErrorCount, + user_data->OutputBufferSize); + user_data->data = NULL; + } + HashTable_Remove(user_data->queue, (void*)(size_t)streamID); } } - - transfer->actual_length = index; - iso_user_data->iso_status = 1; - } - else if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && (iso_user_data->noack)) - { - /* This situation occurs when we do not need to - * return any packet */ - iso_user_data->iso_status = 1; - } - else - { - //print_status(transfer->status); - iso_user_data->iso_status = -1; + break; + default: + break; } } static const LIBUSB_ENDPOINT_DESCEIPTOR* func_get_ep_desc(LIBUSB_CONFIG_DESCRIPTOR* LibusbConfig, - MSUSB_CONFIG_DESCRIPTOR* MsConfig, UINT32 EndpointAddress) + MSUSB_CONFIG_DESCRIPTOR* MsConfig, + UINT32 EndpointAddress) { BYTE alt; - int inum, pnum; + UINT32 inum, pnum; MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces; - const LIBUSB_INTERFACE* interface; + const LIBUSB_INTERFACE* interface; const LIBUSB_ENDPOINT_DESCEIPTOR* endpoint; MsInterfaces = MsConfig->MsInterfaces; interface = LibusbConfig->interface; @@ -260,13 +287,43 @@ static const LIBUSB_ENDPOINT_DESCEIPTOR* func_get_ep_desc(LIBUSB_CONFIG_DESCRIPT static void func_bulk_transfer_cb(struct libusb_transfer* transfer) { - int* completed = transfer->user_data; - *completed = 1; - /* caller interprets results and frees transfer */ + ASYNC_TRANSFER_USER_DATA* user_data; + uint32_t streamID; + + user_data = (ASYNC_TRANSFER_USER_DATA*)transfer->user_data; + if (!user_data) + { + WLog_ERR(TAG, "[%s]: Invalid transfer->user_data!"); + return; + } + +#if defined(HAVE_STREAM_ID_API) + streamID = libusb_transfer_get_stream_id(transfer); +#else + streamID = user_data->streamID; +#endif + + if (HashTable_Contains(user_data->queue, (void*)(size_t)streamID)) + { + const UINT32 InterfaceId = + ((STREAM_ID_PROXY << 30) | user_data->idev->get_ReqCompletion(user_data->idev)); + const UINT32 RequestID = streamID & INTERFACE_ID_MASK; + + user_data->cb(user_data->idev, user_data->callback, user_data->data, InterfaceId, + user_data->noack, user_data->MessageId, RequestID, transfer->num_iso_packets, + transfer->status, user_data->StartFrame, user_data->ErrorCount, + transfer->actual_length); + user_data->data = NULL; + HashTable_Remove(user_data->queue, (void*)(size_t)streamID); + } } -static int func_set_usbd_status(UDEVICE* pdev, UINT32* status, int err_result) +static BOOL func_set_usbd_status(URBDRC_PLUGIN* urbdrc, UDEVICE* pdev, UINT32* status, + int err_result) { + if (!urbdrc || !status) + return FALSE; + switch (err_result) { case LIBUSB_SUCCESS: @@ -275,7 +332,6 @@ static int func_set_usbd_status(UDEVICE* pdev, UINT32* status, int err_result) case LIBUSB_ERROR_IO: *status = USBD_STATUS_STALL_PID; - WLog_ERR(TAG, "LIBUSB_ERROR_IO!!"); break; case LIBUSB_ERROR_INVALID_PARAM: @@ -292,10 +348,7 @@ static int func_set_usbd_status(UDEVICE* pdev, UINT32* status, int err_result) if (pdev) { if (!(pdev->status & URBDRC_DEVICE_NOT_FOUND)) - { pdev->status |= URBDRC_DEVICE_NOT_FOUND; - WLog_WARN(TAG, "LIBUSB_ERROR_NO_DEVICE!!"); - } } break; @@ -341,41 +394,28 @@ static int func_set_usbd_status(UDEVICE* pdev, UINT32* status, int err_result) break; } - return 0; -} - -static void func_iso_data_init(ISO_USER_DATA* iso_user_data, UINT32 numPacket, UINT32 buffsize, - UINT32 noAck, BYTE* isoPacket, BYTE* buffer) -{ - /* init struct iso_user_data */ - iso_user_data->IsoPacket = isoPacket; - iso_user_data->output_data = buffer; - iso_user_data->error_count = 0; - iso_user_data->completed = 0; - iso_user_data->noack = noAck; - urbdrc_get_mstime(iso_user_data->start_frame); + return TRUE; } -static int func_config_release_all_interface(LIBUSB_DEVICE_HANDLE* libusb_handle, - UINT32 NumInterfaces) +static int func_config_release_all_interface(URBDRC_PLUGIN* urbdrc, + LIBUSB_DEVICE_HANDLE* libusb_handle, + UINT32 NumInterfaces) { - int i, ret; + UINT32 i; for (i = 0; i < NumInterfaces; i++) { - ret = libusb_release_interface(libusb_handle, i); + int ret = libusb_release_interface(libusb_handle, i); - if (ret < 0) - { - WLog_ERR(TAG, "config_release_all_interface: error num %d", ret); + if (log_libusb_result(urbdrc->log, WLOG_WARN, "libusb_release_interface", ret)) return -1; - } } return 0; } -static int func_claim_all_interface(LIBUSB_DEVICE_HANDLE* libusb_handle, int NumInterfaces) +static int func_claim_all_interface(URBDRC_PLUGIN* urbdrc, LIBUSB_DEVICE_HANDLE* libusb_handle, + int NumInterfaces) { int i, ret; @@ -383,108 +423,48 @@ static int func_claim_all_interface(LIBUSB_DEVICE_HANDLE* libusb_handle, int Num { ret = libusb_claim_interface(libusb_handle, i); - if (ret < 0) - { - WLog_ERR(TAG, "claim_all_interface: error num %d", ret); + if (log_libusb_result(urbdrc->log, WLOG_ERROR, "libusb_claim_interface", ret)) return -1; - } } return 0; } -/* -static void* print_transfer_status(enum libusb_transfer_status status) -{ - switch (status) - { - case LIBUSB_TRANSFER_COMPLETED: - //WLog_ERR(TAG, "Transfer Status: LIBUSB_TRANSFER_COMPLETED"); - break; - case LIBUSB_TRANSFER_ERROR: - WLog_ERR(TAG, "Transfer Status: LIBUSB_TRANSFER_ERROR"); - break; - case LIBUSB_TRANSFER_TIMED_OUT: - WLog_ERR(TAG, "Transfer Status: LIBUSB_TRANSFER_TIMED_OUT"); - break; - case LIBUSB_TRANSFER_CANCELLED: - WLog_ERR(TAG, "Transfer Status: LIBUSB_TRANSFER_CANCELLED"); - break; - case LIBUSB_TRANSFER_STALL: - WLog_ERR(TAG, "Transfer Status: LIBUSB_TRANSFER_STALL"); - break; - case LIBUSB_TRANSFER_NO_DEVICE: - WLog_ERR(TAG, "Transfer Status: LIBUSB_TRANSFER_NO_DEVICE"); - break; - case LIBUSB_TRANSFER_OVERFLOW: - WLog_ERR(TAG, "Transfer Status: LIBUSB_TRANSFER_OVERFLOW"); - break; - default: - WLog_ERR(TAG, "Transfer Status: Get unknow error num %d (0x%x)", - status, status); - } - return 0; -} - -static void print_status(enum libusb_transfer_status status) -{ - switch (status) - { - case LIBUSB_TRANSFER_COMPLETED: - WLog_ERR(TAG, "Transfer status: LIBUSB_TRANSFER_COMPLETED"); - break; - case LIBUSB_TRANSFER_ERROR: - WLog_ERR(TAG, "Transfer status: LIBUSB_TRANSFER_ERROR"); - break; - case LIBUSB_TRANSFER_TIMED_OUT: - WLog_ERR(TAG, "Transfer status: LIBUSB_TRANSFER_TIMED_OUT"); - break; - case LIBUSB_TRANSFER_CANCELLED: - WLog_ERR(TAG, "Transfer status: LIBUSB_TRANSFER_CANCELLED"); - break; - case LIBUSB_TRANSFER_STALL: - WLog_ERR(TAG, "Transfer status: LIBUSB_TRANSFER_STALL"); - break; - case LIBUSB_TRANSFER_NO_DEVICE: - WLog_ERR(TAG, "Transfer status: LIBUSB_TRANSFER_NO_DEVICE"); - break; - case LIBUSB_TRANSFER_OVERFLOW: - WLog_ERR(TAG, "Transfer status: LIBUSB_TRANSFER_OVERFLOW"); - break; - default: - WLog_ERR(TAG, "Transfer status: unknow status %d(0x%x)", status, status); - break; - } -} -*/ - -static LIBUSB_DEVICE* udev_get_libusb_dev(int bus_number, int dev_number) +static LIBUSB_DEVICE* udev_get_libusb_dev(libusb_context* context, uint8_t bus_number, + uint8_t dev_number) { ssize_t i, total_device; LIBUSB_DEVICE** libusb_list; - total_device = libusb_get_device_list(NULL, &libusb_list); + LIBUSB_DEVICE* device = NULL; + total_device = libusb_get_device_list(context, &libusb_list); for (i = 0; i < total_device; i++) { - if ((bus_number == libusb_get_bus_number(libusb_list[i])) && - (dev_number == libusb_get_device_address(libusb_list[i]))) - return libusb_list[i]; + uint8_t cbus = libusb_get_bus_number(libusb_list[i]); + uint8_t caddr = libusb_get_device_address(libusb_list[i]); + + if ((bus_number == cbus) && (dev_number == caddr)) + { + device = libusb_list[i]; + break; + } } libusb_free_device_list(libusb_list, 1); - return NULL; + return device; } -static LIBUSB_DEVICE_DESCRIPTOR* udev_new_descript(LIBUSB_DEVICE* libusb_dev) +static LIBUSB_DEVICE_DESCRIPTOR* udev_new_descript(URBDRC_PLUGIN* urbdrc, LIBUSB_DEVICE* libusb_dev) { int ret; - LIBUSB_DEVICE_DESCRIPTOR* descriptor; - descriptor = (LIBUSB_DEVICE_DESCRIPTOR*) malloc(sizeof(LIBUSB_DEVICE_DESCRIPTOR)); + LIBUSB_DEVICE_DESCRIPTOR* descriptor = + (LIBUSB_DEVICE_DESCRIPTOR*)calloc(1, sizeof(LIBUSB_DEVICE_DESCRIPTOR)); + if (!descriptor) + return NULL; ret = libusb_get_device_descriptor(libusb_dev, descriptor); - if (ret < 0) + if (log_libusb_result(urbdrc->log, WLOG_ERROR, "libusb_get_device_descriptor", ret)) { - WLog_ERR(TAG, "libusb_get_device_descriptor: ERROR!!"); free(descriptor); return NULL; } @@ -492,338 +472,134 @@ static LIBUSB_DEVICE_DESCRIPTOR* udev_new_descript(LIBUSB_DEVICE* libusb_dev) return descriptor; } -/* Get HUB handle */ -#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) -static int udev_get_hub_handle(UDEVICE* pdev, UINT16 bus_number, UINT16 dev_number) + +static int libusb_udev_select_interface(IUDEVICE* idev, BYTE InterfaceNumber, BYTE AlternateSetting) { - int error; - ssize_t i, total_device, ports_cnt; - uint8_t port_numbers[16]; - LIBUSB_DEVICE** libusb_list; - total_device = libusb_get_device_list(NULL, &libusb_list); - /* Look for device. */ - error = -1; + int error = 0, diff = 0; + UDEVICE* pdev = (UDEVICE*)idev; + URBDRC_PLUGIN* urbdrc; + MSUSB_CONFIG_DESCRIPTOR* MsConfig; + MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces; - for (i = 0; i < total_device; i ++) - { - if ((bus_number != libusb_get_bus_number(libusb_list[i])) || - (dev_number != libusb_get_device_address(libusb_list[i]))) - continue; + if (!pdev || !pdev->urbdrc) + return -1; - error = libusb_open(libusb_list[i], &pdev->hub_handle); + urbdrc = pdev->urbdrc; + MsConfig = pdev->MsConfig; - if (error < 0) + if (MsConfig) + { + MsInterfaces = MsConfig->MsInterfaces; + if (MsInterfaces) { - WLog_ERR(TAG, "libusb_open error: %i - %s", error, libusb_strerror(error)); - break; - } - - /* get port number */ - error = libusb_get_port_numbers(libusb_list[i], port_numbers, sizeof(port_numbers)); - libusb_close(pdev->hub_handle); + WLog_Print(urbdrc->log, WLOG_INFO, + "select Interface(%" PRIu8 ") curr AlternateSetting(%" PRIu8 + ") new AlternateSetting(" PRIu8 ")", + InterfaceNumber, MsInterfaces[InterfaceNumber]->AlternateSetting, + AlternateSetting); - if (error < 1) - { - /* Prevent open hub, treat as error. */ - WLog_ERR(TAG, "libusb_get_port_numbers error: %i - %s", error, libusb_strerror(error)); - break; + if (MsInterfaces[InterfaceNumber]->AlternateSetting != AlternateSetting) + { + diff = 1; + } } - pdev->port_number = port_numbers[(error - 1)]; - error = 0; - WLog_DBG(TAG, " Port: %d", pdev->port_number); - /* gen device path */ - sprintf_s(pdev->path, ARRAYSIZE(pdev->path), "ugen%"PRIu16".%"PRIu16"", bus_number, dev_number); - WLog_DBG(TAG, " DevPath: %s", pdev->path); - break; - } - - /* Look for device hub. */ - if (error == 0) - { - error = -1; - - for (i = 0; i < total_device; i ++) + if (diff) { - if ((bus_number != libusb_get_bus_number(libusb_list[i])) || - (1 != libusb_get_device_address(libusb_list[i]))) /* Root hub allways first on bus. */ - continue; + error = libusb_set_interface_alt_setting(pdev->libusb_handle, InterfaceNumber, + AlternateSetting); - WLog_DBG(TAG, " Open hub: %"PRIu16"", bus_number); - error = libusb_open(libusb_list[i], &pdev->hub_handle); - - if (error < 0) - WLog_ERR(TAG, "libusb_open error: %i - %s", error, libusb_strerror(error)); - - break; + log_libusb_result(urbdrc->log, WLOG_ERROR, "libusb_set_interface_alt_setting", error); } } - libusb_free_device_list(libusb_list, 1); - - if (error < 0) - return -1; - - WLog_DBG(TAG, "libusb_open success!"); - return 0; + return error; } -#endif -#if defined(__linux__) -static int udev_get_hub_handle(UDEVICE* pdev, UINT16 bus_number, UINT16 dev_number) -{ - struct udev* udev; - struct udev_enumerate* enumerate; - struct udev_list_entry* devices; - struct udev_list_entry* dev_list_entry; - struct udev_device* dev; - LIBUSB_DEVICE* libusb_dev; - int hub_found = 0; - unsigned long hub_bus = 0; - unsigned long hub_dev = 0; - int error = 0; - udev = udev_new(); - - if (!udev) - { - WLog_ERR(TAG, "Can't create udev"); - return -1; - } - enumerate = udev_enumerate_new(udev); - udev_enumerate_add_match_subsystem(enumerate, "usb"); - udev_enumerate_add_match_property(enumerate, "DEVTYPE", "usb_device"); - udev_enumerate_scan_devices(enumerate); - devices = udev_enumerate_get_list_entry(enumerate); - udev_list_entry_foreach(dev_list_entry, devices) - { - const char* path; - errno = 0; - path = udev_list_entry_get_name(dev_list_entry); - dev = udev_device_new_from_syspath(udev, path); +static MSUSB_CONFIG_DESCRIPTOR* +libusb_udev_complete_msconfig_setup(IUDEVICE* idev, MSUSB_CONFIG_DESCRIPTOR* MsConfig) +{ + UDEVICE* pdev = (UDEVICE*)idev; + MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces; + MSUSB_INTERFACE_DESCRIPTOR* MsInterface; + MSUSB_PIPE_DESCRIPTOR** MsPipes; + MSUSB_PIPE_DESCRIPTOR* MsPipe; + MSUSB_PIPE_DESCRIPTOR** t_MsPipes; + MSUSB_PIPE_DESCRIPTOR* t_MsPipe; + LIBUSB_CONFIG_DESCRIPTOR* LibusbConfig; + const LIBUSB_INTERFACE* LibusbInterface; + const LIBUSB_INTERFACE_DESCRIPTOR* LibusbAltsetting; + const LIBUSB_ENDPOINT_DESCEIPTOR* LibusbEndpoint; + BYTE LibusbNumEndpoint; + URBDRC_PLUGIN* urbdrc; + UINT32 inum = 0, pnum = 0, MsOutSize = 0; - if (!dev) - continue; + if (!pdev || !pdev->LibusbConfig || !pdev->urbdrc || !MsConfig) + return NULL; - unsigned long tmp_b, tmp_d; - tmp_b = strtoul(udev_device_get_property_value(dev, "BUSNUM"), NULL, 0); + urbdrc = pdev->urbdrc; + LibusbConfig = pdev->LibusbConfig; - if (errno != 0) - continue; + if (LibusbConfig->bNumInterfaces != MsConfig->NumInterfaces) + { + WLog_Print(urbdrc->log, WLOG_ERROR, + "Select Configuration: Libusb NumberInterfaces(%" PRIu8 ") is different " + "with MsConfig NumberInterfaces(%" PRIu32 ")", + LibusbConfig->bNumInterfaces, MsConfig->NumInterfaces); + } - tmp_d = strtoul(udev_device_get_property_value(dev, "DEVNUM"), NULL, 0); + /* replace MsPipes for libusb */ + MsInterfaces = MsConfig->MsInterfaces; - if (errno != 0) - continue; + for (inum = 0; inum < MsConfig->NumInterfaces; inum++) + { + MsInterface = MsInterfaces[inum]; + /* get libusb's number of endpoints */ + LibusbInterface = &LibusbConfig->interface[MsInterface->InterfaceNumber]; + LibusbAltsetting = &LibusbInterface->altsetting[MsInterface->AlternateSetting]; + LibusbNumEndpoint = LibusbAltsetting->bNumEndpoints; + t_MsPipes = + (MSUSB_PIPE_DESCRIPTOR**)calloc(LibusbNumEndpoint, sizeof(MSUSB_PIPE_DESCRIPTOR*)); - if (bus_number == tmp_b && dev_number == tmp_d) + for (pnum = 0; pnum < LibusbNumEndpoint; pnum++) { - /* get port number */ - char* p1, *p2; - const char* sysfs_path = - udev_device_get_property_value(dev, "DEVPATH"); - p1 = (char*) sysfs_path; - - do - { - p2 = p1 + 1; - p1 = strchr(p2, '.'); - } - while (p1 != NULL); + t_MsPipe = (MSUSB_PIPE_DESCRIPTOR*)calloc(1, sizeof(MSUSB_PIPE_DESCRIPTOR)); - if ((p2 - sysfs_path) < (strlen(sysfs_path) - 2)) - { - p1 = (char*) sysfs_path; - - do - { - p2 = p1 + 1; - p1 = strchr(p2, '-'); - } - while (p1 != NULL); - } - - errno = 0; - { - unsigned long val = strtoul(p2, NULL, 0); - - if ((errno != 0) || (val == 0) || (val > UINT16_MAX)) - continue; - - pdev->port_number = val; - } - WLog_DBG(TAG, " Port: %d", pdev->port_number); - /* get device path */ - p1 = (char*) sysfs_path; - - do + if (pnum < MsInterface->NumberOfPipes && MsInterface->MsPipes) { - p2 = p1 + 1; - p1 = strchr(p2, '/'); + MsPipe = MsInterface->MsPipes[pnum]; + t_MsPipe->MaximumPacketSize = MsPipe->MaximumPacketSize; + t_MsPipe->MaximumTransferSize = MsPipe->MaximumTransferSize; + t_MsPipe->PipeFlags = MsPipe->PipeFlags; } - while (p1 != NULL); - - sprintf_s(pdev->path, ARRAYSIZE(pdev->path), "%s", p2); - WLog_DBG(TAG, " DevPath: %s", pdev->path); - /* query parent hub info */ - dev = udev_device_get_parent(dev); - - if (dev != NULL) + else { - hub_found = 1; - hub_bus = strtoul(udev_device_get_property_value(dev, "BUSNUM"), NULL, 0); - hub_dev = strtoul(udev_device_get_property_value(dev, "DEVNUM"), NULL, 0); - WLog_DBG(TAG, " Hub BUS/DEV: %d %d", hub_bus, hub_dev); + t_MsPipe->MaximumPacketSize = 0; + t_MsPipe->MaximumTransferSize = 0xffffffff; + t_MsPipe->PipeFlags = 0; } - udev_device_unref(dev); - break; + t_MsPipe->PipeHandle = 0; + t_MsPipe->bEndpointAddress = 0; + t_MsPipe->bInterval = 0; + t_MsPipe->PipeType = 0; + t_MsPipe->InitCompleted = 0; + t_MsPipes[pnum] = t_MsPipe; } - udev_device_unref(dev); - } - udev_enumerate_unref(enumerate); - udev_unref(udev); - - if (!hub_found) - { - WLog_WARN(TAG, "hub was not found!"); - return -1; - } - - /* Get libusb hub handle */ - libusb_dev = udev_get_libusb_dev(hub_bus, hub_dev); - - if (libusb_dev == NULL) - { - WLog_DBG(TAG, "get hub libusb_dev fail!"); - return -1; - } - - error = libusb_open(libusb_dev, &pdev->hub_handle); - - if (error < 0) - { - WLog_DBG(TAG, "libusb_open error!"); - return -1; - } - - WLog_DBG(TAG, "libusb_open success!"); - /* Success! */ - return 0; -} -#endif - -static int libusb_udev_select_interface(IUDEVICE* idev, BYTE InterfaceNumber, BYTE AlternateSetting) -{ - int error = 0, diff = 1; - UDEVICE* pdev = (UDEVICE*) idev; - MSUSB_CONFIG_DESCRIPTOR* MsConfig; - MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces; - MsConfig = pdev->MsConfig; - - if (MsConfig) - { - MsInterfaces = MsConfig->MsInterfaces; - - if ((MsInterfaces) && (MsInterfaces[InterfaceNumber]->AlternateSetting == AlternateSetting)) - { - diff = 0; - } - } - - if (diff) - { - error = libusb_set_interface_alt_setting(pdev->libusb_handle, - InterfaceNumber, AlternateSetting); - - if (error < 0) - { - WLog_ERR(TAG, "Set interface altsetting get error num %d", - error); - } - } - - return error; -} - -static MSUSB_CONFIG_DESCRIPTOR* libusb_udev_complete_msconfig_setup(IUDEVICE* idev, - MSUSB_CONFIG_DESCRIPTOR* MsConfig) -{ - UDEVICE* pdev = (UDEVICE*) idev; - MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces; - MSUSB_INTERFACE_DESCRIPTOR* MsInterface; - MSUSB_PIPE_DESCRIPTOR** MsPipes; - MSUSB_PIPE_DESCRIPTOR* MsPipe; - MSUSB_PIPE_DESCRIPTOR** t_MsPipes; - MSUSB_PIPE_DESCRIPTOR* t_MsPipe; - LIBUSB_CONFIG_DESCRIPTOR* LibusbConfig; - const LIBUSB_INTERFACE* LibusbInterface; - const LIBUSB_INTERFACE_DESCRIPTOR* LibusbAltsetting; - const LIBUSB_ENDPOINT_DESCEIPTOR* LibusbEndpoint; - BYTE LibusbNumEndpoint; - int inum = 0, pnum = 0, MsOutSize = 0; - LibusbConfig = pdev->LibusbConfig; - - if (LibusbConfig->bNumInterfaces != MsConfig->NumInterfaces) - { - WLog_ERR(TAG, "Select Configuration: Libusb NumberInterfaces(%"PRIu8") is different " - "with MsConfig NumberInterfaces(%"PRIu32")", - LibusbConfig->bNumInterfaces, MsConfig->NumInterfaces); - } - - /* replace MsPipes for libusb */ - MsInterfaces = MsConfig->MsInterfaces; - - for (inum = 0; inum < MsConfig->NumInterfaces; inum++) - { - MsInterface = MsInterfaces[inum]; - /* get libusb's number of endpoints */ - LibusbInterface = &LibusbConfig->interface[MsInterface->InterfaceNumber]; - LibusbAltsetting = &LibusbInterface->altsetting[MsInterface->AlternateSetting]; - LibusbNumEndpoint = LibusbAltsetting->bNumEndpoints; - t_MsPipes = (MSUSB_PIPE_DESCRIPTOR**) calloc(LibusbNumEndpoint, sizeof(MSUSB_PIPE_DESCRIPTOR*)); - - for (pnum = 0; pnum < LibusbNumEndpoint; pnum++) - { - t_MsPipe = (MSUSB_PIPE_DESCRIPTOR*) malloc(sizeof(MSUSB_PIPE_DESCRIPTOR)); - memset(t_MsPipe, 0, sizeof(MSUSB_PIPE_DESCRIPTOR)); - - if (pnum < MsInterface->NumberOfPipes && MsInterface->MsPipes) - { - MsPipe = MsInterface->MsPipes[pnum]; - t_MsPipe->MaximumPacketSize = MsPipe->MaximumPacketSize; - t_MsPipe->MaximumTransferSize = MsPipe->MaximumTransferSize; - t_MsPipe->PipeFlags = MsPipe->PipeFlags; - } - else - { - t_MsPipe->MaximumPacketSize = 0; - t_MsPipe->MaximumTransferSize = 0xffffffff; - t_MsPipe->PipeFlags = 0; - } - - t_MsPipe->PipeHandle = 0; - t_MsPipe->bEndpointAddress = 0; - t_MsPipe->bInterval = 0; - t_MsPipe->PipeType = 0; - t_MsPipe->InitCompleted = 0; - t_MsPipes[pnum] = t_MsPipe; - } - - msusb_mspipes_replace(MsInterface, t_MsPipes, LibusbNumEndpoint); + msusb_mspipes_replace(MsInterface, t_MsPipes, LibusbNumEndpoint); } /* setup configuration */ MsOutSize = 8; /* ConfigurationHandle: 4 bytes - * --------------------------------------------------------------- - * ||<<< 1 byte >>>|<<< 1 byte >>>|<<<<<<<<<< 2 byte >>>>>>>>>>>|| - * || bus_number | dev_number | bConfigurationValue || - * --------------------------------------------------------------- + * --------------------------------------------------------------- + * ||<<< 1 byte >>>|<<< 1 byte >>>|<<<<<<<<<< 2 byte >>>>>>>>>>>|| + * || bus_number | dev_number | bConfigurationValue || + * --------------------------------------------------------------- * ***********************/ - MsConfig->ConfigurationHandle = MsConfig->bConfigurationValue | - (pdev->bus_number << 24) | - (pdev->dev_number << 16); + MsConfig->ConfigurationHandle = + MsConfig->bConfigurationValue | (pdev->bus_number << 24) | (pdev->dev_number << 16); MsInterfaces = MsConfig->MsInterfaces; for (inum = 0; inum < MsConfig->NumInterfaces; inum++) @@ -839,10 +615,9 @@ static MSUSB_CONFIG_DESCRIPTOR* libusb_udev_complete_msconfig_setup(IUDEVICE* id * || bus_number | dev_number | altsetting | interfaceNum || * --------------------------------------------------------------- * ***********************/ - MsInterface->InterfaceHandle = LibusbAltsetting->bInterfaceNumber - | (LibusbAltsetting->bAlternateSetting << 8) - | (pdev->dev_number << 16) - | (pdev->bus_number << 24); + MsInterface->InterfaceHandle = LibusbAltsetting->bInterfaceNumber | + (LibusbAltsetting->bAlternateSetting << 8) | + (pdev->dev_number << 16) | (pdev->bus_number << 24); MsInterface->Length = 16 + (MsInterface->NumberOfPipes * 20); MsInterface->bInterfaceClass = LibusbAltsetting->bInterfaceClass; MsInterface->bInterfaceSubClass = LibusbAltsetting->bInterfaceSubClass; @@ -863,9 +638,8 @@ static MSUSB_CONFIG_DESCRIPTOR* libusb_udev_complete_msconfig_setup(IUDEVICE* id * || bus_number | dev_number | bEndpointAddress || * --------------------------------------------------------------- * ***********************/ - MsPipe->PipeHandle = LibusbEndpoint->bEndpointAddress - | (pdev->dev_number << 16) - | (pdev->bus_number << 24); + MsPipe->PipeHandle = LibusbEndpoint->bEndpointAddress | (pdev->dev_number << 16) | + (pdev->bus_number << 24); /* count endpoint max packet size */ int max = LibusbEndpoint->wMaxPacketSize & 0x07ff; BYTE attr = LibusbEndpoint->bmAttributes; @@ -887,7 +661,7 @@ static MSUSB_CONFIG_DESCRIPTOR* libusb_udev_complete_msconfig_setup(IUDEVICE* id MsConfig->InitCompleted = 1; /* replace device's MsConfig */ - if (!(MsConfig == pdev->MsConfig)) + if (MsConfig != pdev->MsConfig) { msusb_msconfig_free(pdev->MsConfig); pdev->MsConfig = MsConfig; @@ -898,16 +672,27 @@ static MSUSB_CONFIG_DESCRIPTOR* libusb_udev_complete_msconfig_setup(IUDEVICE* id static int libusb_udev_select_configuration(IUDEVICE* idev, UINT32 bConfigurationValue) { - UDEVICE* pdev = (UDEVICE*) idev; - MSUSB_CONFIG_DESCRIPTOR* MsConfig = pdev->MsConfig; - LIBUSB_DEVICE_HANDLE* libusb_handle = pdev->libusb_handle; - LIBUSB_DEVICE* libusb_dev = pdev->libusb_dev; - LIBUSB_CONFIG_DESCRIPTOR** LibusbConfig = &pdev->LibusbConfig; + UDEVICE* pdev = (UDEVICE*)idev; + MSUSB_CONFIG_DESCRIPTOR* MsConfig; + LIBUSB_DEVICE_HANDLE* libusb_handle; + LIBUSB_DEVICE* libusb_dev; + URBDRC_PLUGIN* urbdrc; + LIBUSB_CONFIG_DESCRIPTOR** LibusbConfig; int ret = 0; + if (!pdev || !pdev->MsConfig || !pdev->LibusbConfig || !pdev->urbdrc) + return -1; + + urbdrc = pdev->urbdrc; + MsConfig = pdev->MsConfig; + libusb_handle = pdev->libusb_handle; + libusb_dev = pdev->libusb_dev; + LibusbConfig = &pdev->LibusbConfig; + if (MsConfig->InitCompleted) { - func_config_release_all_interface(libusb_handle, (*LibusbConfig)->bNumInterfaces); + func_config_release_all_interface(pdev->urbdrc, libusb_handle, + (*LibusbConfig)->bNumInterfaces); } /* The configuration value -1 is mean to put the device in unconfigured state. */ @@ -916,33 +701,31 @@ static int libusb_udev_select_configuration(IUDEVICE* idev, UINT32 bConfiguratio else ret = libusb_set_configuration(libusb_handle, bConfigurationValue); - if (ret < 0) + if (log_libusb_result(urbdrc->log, WLOG_ERROR, "libusb_set_configuration", ret)) { - WLog_ERR(TAG, "libusb_set_configuration: ERROR number %d!!", ret); - func_claim_all_interface(libusb_handle, (*LibusbConfig)->bNumInterfaces); + func_claim_all_interface(urbdrc, libusb_handle, (*LibusbConfig)->bNumInterfaces); return -1; } else { ret = libusb_get_active_config_descriptor(libusb_dev, LibusbConfig); - if (ret < 0) + if (log_libusb_result(urbdrc->log, WLOG_ERROR, "libusb_set_configuration", ret)) { - WLog_ERR(TAG, "libusb_get_config_descriptor_by_value: ERROR number %d!!", ret); - func_claim_all_interface(libusb_handle, (*LibusbConfig)->bNumInterfaces); + func_claim_all_interface(urbdrc, libusb_handle, (*LibusbConfig)->bNumInterfaces); return -1; } } - func_claim_all_interface(libusb_handle, (*LibusbConfig)->bNumInterfaces); + func_claim_all_interface(urbdrc, libusb_handle, (*LibusbConfig)->bNumInterfaces); return 0; } static int libusb_udev_control_pipe_request(IUDEVICE* idev, UINT32 RequestId, - UINT32 EndpointAddress, UINT32* UsbdStatus, int command) + UINT32 EndpointAddress, UINT32* UsbdStatus, int command) { int error = 0; - UDEVICE* pdev = (UDEVICE*) idev; + UDEVICE* pdev = (UDEVICE*)idev; /* pdev->request_queue->register_request(pdev->request_queue, RequestId, NULL, 0); @@ -952,22 +735,17 @@ static int libusb_udev_control_pipe_request(IUDEVICE* idev, UINT32 RequestId, case PIPE_CANCEL: /** cancel bulk or int transfer */ idev->cancel_all_transfer_request(idev); - //dummy_wait_s_obj(1); + // dummy_wait_s_obj(1); /** set feature to ep (set halt)*/ - error = libusb_control_transfer(pdev->libusb_handle, - LIBUSB_ENDPOINT_OUT | LIBUSB_RECIPIENT_ENDPOINT, - LIBUSB_REQUEST_SET_FEATURE, - ENDPOINT_HALT, - EndpointAddress, - NULL, - 0, - 1000); + error = libusb_control_transfer( + pdev->libusb_handle, LIBUSB_ENDPOINT_OUT | LIBUSB_RECIPIENT_ENDPOINT, + LIBUSB_REQUEST_SET_FEATURE, ENDPOINT_HALT, EndpointAddress, NULL, 0, 1000); break; case PIPE_RESET: idev->cancel_all_transfer_request(idev); error = libusb_clear_halt(pdev->libusb_handle, EndpointAddress); - //func_set_usbd_status(pdev, UsbdStatus, error); + // func_set_usbd_status(pdev, UsbdStatus, error); break; default: @@ -976,128 +754,135 @@ static int libusb_udev_control_pipe_request(IUDEVICE* idev, UINT32 RequestId, } *UsbdStatus = 0; - /* - if(pdev->request_queue->unregister_request(pdev->request_queue, RequestId)) - WLog_ERR(TAG, "request_queue_unregister_request: not fount request 0x%x", RequestId); - */ return error; } -static int libusb_udev_control_query_device_text(IUDEVICE* idev, UINT32 TextType, - UINT32 LocaleId, - UINT32* BufferSize, - BYTE* Buffer) +static UINT32 libusb_udev_control_query_device_text(IUDEVICE* idev, UINT32 TextType, + UINT16 LocaleId, UINT8* BufferSize, + BYTE* Buffer) { - UDEVICE* pdev = (UDEVICE*) idev; - LIBUSB_DEVICE_DESCRIPTOR* devDescriptor = pdev->devDescriptor; - char* strDesc = "Generic Usb String"; - char deviceLocation[25]; + UDEVICE* pdev = (UDEVICE*)idev; + LIBUSB_DEVICE_DESCRIPTOR* devDescriptor; + const char strDesc[] = "Generic Usb String"; + char deviceLocation[25] = { 0 }; BYTE bus_number; BYTE device_address; - int ret = 0, i = 0; + int ret = 0; + size_t i, len; + URBDRC_PLUGIN* urbdrc; + WCHAR* text = (WCHAR*)Buffer; + BYTE slen, locale; + const UINT8 inSize = *BufferSize; + + *BufferSize = 0; + if (!pdev || !pdev->devDescriptor || !pdev->urbdrc) + return ERROR_INVALID_DATA; + + urbdrc = pdev->urbdrc; + devDescriptor = pdev->devDescriptor; switch (TextType) { case DeviceTextDescription: - ret = libusb_get_string_descriptor(pdev->libusb_handle, - devDescriptor->iProduct, - LocaleId, - Buffer, - *BufferSize); - - for (i = 0; i < ret; i++) + { + BYTE data[0x100] = { 0 }; + ret = libusb_get_string_descriptor(pdev->libusb_handle, devDescriptor->iProduct, + LocaleId, data, 0xFF); + /* The returned data in the buffer is: + * 1 byte length of following data + * 1 byte descriptor type, must be 0x03 for strings + * n WCHAR unicode string (of length / 2 characters) including '\0' + */ + slen = data[0]; + locale = data[1]; + + if ((ret <= 0) || (ret <= 4) || (slen <= 4) || (locale != LIBUSB_DT_STRING) || + (ret > UINT8_MAX)) { - Buffer[i] = Buffer[i + 2]; - } - - ret -= 2; - - if (ret <= 0 || ret < 4) - { - WLog_DBG(TAG, "libusb_get_string_descriptor: " - "ERROR num %d, iProduct: %"PRIu8"!", ret, devDescriptor->iProduct); - memcpy(Buffer, strDesc, strlen(strDesc)); - Buffer[strlen(strDesc)] = '\0'; - *BufferSize = (strlen((char*)Buffer)) * 2; - - for (i = strlen((char*)Buffer); i > 0; i--) - { - Buffer[i * 2] = Buffer[i]; - Buffer[(i * 2) - 1] = 0; - } + char* msg = "SHORT_DESCRIPTOR"; + if (ret < 0) + msg = libusb_error_name(ret); + WLog_Print(urbdrc->log, WLOG_DEBUG, + "libusb_get_string_descriptor: " + "%s [%d], iProduct: %" PRIu8 "!", + msg, ret, devDescriptor->iProduct); + + len = MIN(sizeof(strDesc), inSize); + for (i = 0; i < len; i++) + text[i] = (WCHAR)strDesc[i]; + + *BufferSize = (BYTE)(len * 2); } else { - *BufferSize = ret; + /* ret and slen should be equals, but you never know creativity + * of device manufacturers... + * So also check the string length returned as server side does + * not honor strings with multi '\0' characters well. + */ + const size_t rchar = _wcsnlen((WCHAR*)&data[2], sizeof(data) / 2); + len = MIN((BYTE)ret, slen); + len = MIN(len, inSize); + len = MIN(len, rchar * 2 + sizeof(WCHAR)); + memcpy(Buffer, &data[2], len); + + /* Just as above, the returned WCHAR string should be '\0' + * terminated, but never trust hardware to conform to specs... */ + Buffer[len - 2] = '\0'; + Buffer[len - 1] = '\0'; + *BufferSize = (BYTE)len; } - - break; + } + break; case DeviceTextLocationInformation: bus_number = libusb_get_bus_number(pdev->libusb_dev); device_address = libusb_get_device_address(pdev->libusb_dev); - sprintf_s(deviceLocation, ARRAYSIZE(deviceLocation), "Port_#%04"PRIu8".Hub_#%04"PRIu8"", - device_address, bus_number); - - for (i = 0; i < strlen(deviceLocation); i++) - { - Buffer[i * 2] = (BYTE)deviceLocation[i]; - Buffer[(i * 2) + 1] = 0; - } - - *BufferSize = (i * 2); + sprintf_s(deviceLocation, sizeof(deviceLocation), + "Port_#%04" PRIu8 ".Hub_#%04" PRIu8 "", device_address, bus_number); + + len = strnlen(deviceLocation, MIN(sizeof(deviceLocation), inSize - 1)); + for (i = 0; i < len; i++) + text[i] = (WCHAR)deviceLocation[i]; + text[len++] = '\0'; + *BufferSize = (UINT8)(len * sizeof(WCHAR)); break; default: - WLog_DBG(TAG, "Query Text: unknown TextType %"PRIu32"", TextType); - break; + WLog_Print(urbdrc->log, WLOG_DEBUG, "Query Text: unknown TextType %" PRIu32 "", + TextType); + return ERROR_INVALID_DATA; } - return 0; + return S_OK; } - static int libusb_udev_os_feature_descriptor_request(IUDEVICE* idev, UINT32 RequestId, - BYTE Recipient, - BYTE InterfaceNumber, - BYTE Ms_PageIndex, - UINT16 Ms_featureDescIndex, - UINT32* UsbdStatus, - UINT32* BufferSize, - BYTE* Buffer, - int Timeout) + BYTE Recipient, BYTE InterfaceNumber, + BYTE Ms_PageIndex, UINT16 Ms_featureDescIndex, + UINT32* UsbdStatus, UINT32* BufferSize, + BYTE* Buffer, int Timeout) { - UDEVICE* pdev = (UDEVICE*) idev; - BYTE ms_string_desc[0x13]; + UDEVICE* pdev = (UDEVICE*)idev; + BYTE ms_string_desc[0x13] = { 0 }; int error = 0; /* pdev->request_queue->register_request(pdev->request_queue, RequestId, NULL, 0); */ - memset(ms_string_desc, 0, 0x13); - error = libusb_control_transfer(pdev->libusb_handle, - LIBUSB_ENDPOINT_IN | Recipient, - LIBUSB_REQUEST_GET_DESCRIPTOR, - 0x03ee, - 0, - ms_string_desc, - 0x12, + error = libusb_control_transfer(pdev->libusb_handle, LIBUSB_ENDPOINT_IN | Recipient, + LIBUSB_REQUEST_GET_DESCRIPTOR, 0x03ee, 0, ms_string_desc, 0x12, Timeout); - //WLog_ERR(TAG, "Get ms string: result number %d", error); + log_libusb_result(pdev->urbdrc->log, WLOG_DEBUG, "libusb_control_transfer", error); + if (error > 0) { - BYTE bMS_Vendorcode; - data_read_BYTE(ms_string_desc + 16, bMS_Vendorcode); - //WLog_ERR(TAG, "bMS_Vendorcode:0x%x", bMS_Vendorcode); + const BYTE bMS_Vendorcode = ms_string_desc[16]; /** get os descriptor */ error = libusb_control_transfer(pdev->libusb_handle, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | Recipient, - bMS_Vendorcode, - (InterfaceNumber << 8) | Ms_PageIndex, - Ms_featureDescIndex, - Buffer, - *BufferSize, - Timeout); + bMS_Vendorcode, (InterfaceNumber << 8) | Ms_PageIndex, + Ms_featureDescIndex, Buffer, *BufferSize, Timeout); *BufferSize = error; } @@ -1106,16 +891,12 @@ static int libusb_udev_os_feature_descriptor_request(IUDEVICE* idev, UINT32 Requ else *UsbdStatus = USBD_STATUS_SUCCESS; - /* - if(pdev->request_queue->unregister_request(pdev->request_queue, RequestId)) - WLog_ERR(TAG, "request_queue_unregister_request: not fount request 0x%x", RequestId); - */ - return error; + return ERROR_SUCCESS; } static int libusb_udev_query_device_descriptor(IUDEVICE* idev, int offset) { - UDEVICE* pdev = (UDEVICE*) idev; + UDEVICE* pdev = (UDEVICE*)idev; switch (offset) { @@ -1168,192 +949,163 @@ static int libusb_udev_query_device_descriptor(IUDEVICE* idev, int offset) return 0; } -static void libusb_udev_detach_kernel_driver(IUDEVICE* idev) +static BOOL libusb_udev_detach_kernel_driver(IUDEVICE* idev) { int i, err = 0; - UDEVICE* pdev = (UDEVICE*) idev; + UDEVICE* pdev = (UDEVICE*)idev; + URBDRC_PLUGIN* urbdrc; + + if (!pdev || !pdev->LibusbConfig || !pdev->libusb_handle || !pdev->urbdrc) + return FALSE; + + urbdrc = pdev->urbdrc; if ((pdev->status & URBDRC_DEVICE_DETACH_KERNEL) == 0) { for (i = 0; i < pdev->LibusbConfig->bNumInterfaces; i++) { err = libusb_kernel_driver_active(pdev->libusb_handle, i); - WLog_DBG(TAG, "libusb_kernel_driver_active = %d", err); + log_libusb_result(urbdrc->log, WLOG_DEBUG, "libusb_kernel_driver_active", err); if (err) { err = libusb_detach_kernel_driver(pdev->libusb_handle, i); - WLog_DBG(TAG, "libusb_detach_kernel_driver = %d", err); + log_libusb_result(urbdrc->log, WLOG_DEBUG, "libusb_detach_kernel_driver", err); } } pdev->status |= URBDRC_DEVICE_DETACH_KERNEL; } + + return TRUE; } -static void libusb_udev_attach_kernel_driver(IUDEVICE* idev) +static BOOL libusb_udev_attach_kernel_driver(IUDEVICE* idev) { int i, err = 0; - UDEVICE* pdev = (UDEVICE*) idev; + UDEVICE* pdev = (UDEVICE*)idev; + + if (!pdev || !pdev->LibusbConfig || !pdev->libusb_handle || !pdev->urbdrc) + return FALSE; for (i = 0; i < pdev->LibusbConfig->bNumInterfaces && err != LIBUSB_ERROR_NO_DEVICE; i++) { err = libusb_release_interface(pdev->libusb_handle, i); - if (err < 0) - { - WLog_DBG(TAG, "libusb_release_interface: error num %d = %d", i, err); - } + log_libusb_result(pdev->urbdrc->log, WLOG_DEBUG, "libusb_release_interface", err); if (err != LIBUSB_ERROR_NO_DEVICE) { err = libusb_attach_kernel_driver(pdev->libusb_handle, i); - WLog_DBG(TAG, "libusb_attach_kernel_driver if%d = %d", i, err); + log_libusb_result(pdev->urbdrc->log, WLOG_DEBUG, "libusb_attach_kernel_driver if=%d", + err, i); } } + + return TRUE; } static int libusb_udev_is_composite_device(IUDEVICE* idev) { - UDEVICE* pdev = (UDEVICE*) idev; + UDEVICE* pdev = (UDEVICE*)idev; return pdev->isCompositeDevice; } -static int libusb_udev_is_signal_end(IUDEVICE* idev) -{ - UDEVICE* pdev = (UDEVICE*) idev; - return (pdev->status & URBDRC_DEVICE_SIGNAL_END) ? 1 : 0; -} - static int libusb_udev_is_exist(IUDEVICE* idev) { - UDEVICE* pdev = (UDEVICE*) idev; + UDEVICE* pdev = (UDEVICE*)idev; return (pdev->status & URBDRC_DEVICE_NOT_FOUND) ? 0 : 1; } static int libusb_udev_is_channel_closed(IUDEVICE* idev) { - UDEVICE* pdev = (UDEVICE*) idev; - return (pdev->status & URBDRC_DEVICE_CHANNEL_CLOSED) ? 1 : 0; -} - -static int libusb_udev_is_already_send(IUDEVICE* idev) -{ - UDEVICE* pdev = (UDEVICE*) idev; - return (pdev->status & URBDRC_DEVICE_ALREADY_SEND) ? 1 : 0; -} + UDEVICE* pdev = (UDEVICE*)idev; + IUDEVMAN* udevman; + if (!pdev || !pdev->urbdrc) + return 1; -static void libusb_udev_signal_end(IUDEVICE* idev) -{ - UDEVICE* pdev = (UDEVICE*) idev; - pdev->status |= URBDRC_DEVICE_SIGNAL_END; -} + udevman = pdev->urbdrc->udevman; + if (udevman) + { + if (udevman->status & URBDRC_DEVICE_CHANNEL_CLOSED) + return 1; + } -static void libusb_udev_channel_closed(IUDEVICE* idev) -{ - UDEVICE* pdev = (UDEVICE*) idev; - pdev->status |= URBDRC_DEVICE_CHANNEL_CLOSED; -} + if (pdev->status & URBDRC_DEVICE_CHANNEL_CLOSED) + return 1; -static void libusb_udev_set_already_send(IUDEVICE* idev) -{ - UDEVICE* pdev = (UDEVICE*) idev; - pdev->status |= URBDRC_DEVICE_ALREADY_SEND; + return 0; } -static char* libusb_udev_get_path(IUDEVICE* idev) +static int libusb_udev_is_already_send(IUDEVICE* idev) { - UDEVICE* pdev = (UDEVICE*) idev; - return pdev->path; + UDEVICE* pdev = (UDEVICE*)idev; + return (pdev->status & URBDRC_DEVICE_ALREADY_SEND) ? 1 : 0; } -static int libusb_udev_wait_action_completion(IUDEVICE* idev) +static void libusb_udev_channel_closed(IUDEVICE* idev) { - int error, sval; - UDEVICE* pdev = (UDEVICE*) idev; - - while (1) + UDEVICE* pdev = (UDEVICE*)idev; + if (pdev) { - usleep(500000); - error = sem_getvalue(&pdev->sem_id, &sval); + URBDRC_PLUGIN* urbdrc = pdev->urbdrc; + const uint8_t busNr = idev->get_bus_number(idev); + const uint8_t devNr = idev->get_dev_number(idev); + IWTSVirtualChannel* channel = NULL; - if (sval == 0) - break; - } - - return error; -} + if (pdev->channelManager) + channel = IFCALLRESULT(NULL, pdev->channelManager->FindChannelById, + pdev->channelManager, pdev->channelID); -static void libusb_udev_push_action(IUDEVICE* idev) -{ - UDEVICE* pdev = (UDEVICE*) idev; - sem_post(&pdev->sem_id); -} + pdev->status |= URBDRC_DEVICE_CHANNEL_CLOSED; -static void libusb_udev_complete_action(IUDEVICE* idev) -{ - UDEVICE* pdev = (UDEVICE*) idev; - sem_trywait(&pdev->sem_id); -} - -static int libusb_udev_wait_for_detach(IUDEVICE* idev) -{ - int error = 0; - int times = 0; - UDEVICE* pdev = (UDEVICE*) idev; - - while (times < 25) - { - if (pdev->status & URBDRC_DEVICE_SIGNAL_END) + if (channel) { - error = -1; - break; + /* Notify the server the device is no longer available. */ + channel->Write(channel, 0, NULL, NULL); } - - usleep(200000); - times++; + urbdrc->udevman->unregister_udevice(urbdrc->udevman, busNr, devNr); } - - return error; } -static void libusb_udev_lock_fifo_isoch(IUDEVICE* idev) +static void libusb_udev_set_already_send(IUDEVICE* idev) { - UDEVICE* pdev = (UDEVICE*) idev; - pthread_mutex_lock(&pdev->mutex_isoch); + UDEVICE* pdev = (UDEVICE*)idev; + pdev->status |= URBDRC_DEVICE_ALREADY_SEND; } -static void libusb_udev_unlock_fifo_isoch(IUDEVICE* idev) +static char* libusb_udev_get_path(IUDEVICE* idev) { - UDEVICE* pdev = (UDEVICE*) idev; - pthread_mutex_unlock(&pdev->mutex_isoch); + UDEVICE* pdev = (UDEVICE*)idev; + return pdev->path; } static int libusb_udev_query_device_port_status(IUDEVICE* idev, UINT32* UsbdStatus, - UINT32* BufferSize, BYTE* Buffer) + UINT32* BufferSize, BYTE* Buffer) { - UDEVICE* pdev = (UDEVICE*) idev; + UDEVICE* pdev = (UDEVICE*)idev; int success = 0, ret; - WLog_DBG(TAG, "..."); + URBDRC_PLUGIN* urbdrc; + + if (!pdev || !pdev->urbdrc) + return -1; + + urbdrc = pdev->urbdrc; if (pdev->hub_handle != NULL) { - ret = idev->control_transfer(idev, 0xffff, 0, 0, - LIBUSB_ENDPOINT_IN - | LIBUSB_REQUEST_TYPE_CLASS - | LIBUSB_RECIPIENT_OTHER, - LIBUSB_REQUEST_GET_STATUS, - 0, pdev->port_number, UsbdStatus, BufferSize, Buffer, 1000); - - if (ret < 0) - { - WLog_DBG(TAG, "libusb_control_transfer: error num %d", ret); + ret = idev->control_transfer( + idev, 0xffff, 0, 0, + LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_OTHER, + LIBUSB_REQUEST_GET_STATUS, 0, pdev->port_number, UsbdStatus, BufferSize, Buffer, 1000); + + if (log_libusb_result(urbdrc->log, WLOG_DEBUG, "libusb_control_transfer", ret)) *BufferSize = 0; - } else { - WLog_DBG(TAG, "PORT STATUS:0x%02"PRIx8"%02"PRIx8"%02"PRIx8"%02"PRIx8"", - Buffer[3], Buffer[2], Buffer[1], Buffer[0]); + WLog_Print(urbdrc->log, WLOG_DEBUG, + "PORT STATUS:0x%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "", Buffer[3], + Buffer[2], Buffer[1], Buffer[0]); success = 1; } } @@ -1361,434 +1113,324 @@ static int libusb_udev_query_device_port_status(IUDEVICE* idev, UINT32* UsbdStat return success; } -static int libusb_udev_request_queue_is_none(IUDEVICE* idev) -{ - UDEVICE* pdev = (UDEVICE*) idev; - - if (pdev->request_queue->request_num == 0) - return 1; - - return 0; -} - -static int libusb_udev_isoch_transfer(IUDEVICE* idev, UINT32 RequestId, UINT32 EndpointAddress, - UINT32 TransferFlags, int NoAck, UINT32* ErrorCount, - UINT32* UrbdStatus, UINT32* StartFrame, UINT32 NumberOfPackets, - BYTE* IsoPacket, UINT32* BufferSize, BYTE* Buffer, int Timeout) +static int libusb_udev_isoch_transfer(IUDEVICE* idev, URBDRC_CHANNEL_CALLBACK* callback, + UINT32 MessageId, UINT32 RequestId, UINT32 EndpointAddress, + UINT32 TransferFlags, UINT32 StartFrame, UINT32 ErrorCount, + BOOL NoAck, const BYTE* packetDescriptorData, + UINT32 NumberOfPackets, UINT32 BufferSize, const BYTE* Buffer, + t_isoch_transfer_cb cb, UINT32 Timeout) { UINT32 iso_packet_size; - UDEVICE* pdev = (UDEVICE*) idev; - ISO_USER_DATA iso_user_data; + UDEVICE* pdev = (UDEVICE*)idev; + ASYNC_TRANSFER_USER_DATA* user_data; struct libusb_transfer* iso_transfer = NULL; - int status = 0, ret = 0, submit = 0; - iso_packet_size = *BufferSize / NumberOfPackets; - iso_transfer = libusb_alloc_transfer(NumberOfPackets); + URBDRC_PLUGIN* urbdrc; + size_t outSize = (NumberOfPackets * 12); + uint32_t streamID = 0x40000000 | RequestId; - if (iso_transfer == NULL) - { - WLog_ERR(TAG, "Error: libusb_alloc_transfer."); - status = -1; - } + if (!pdev || !pdev->urbdrc) + return -1; - /** process URB_FUNCTION_IOSCH_TRANSFER */ - func_iso_data_init(&iso_user_data, NumberOfPackets, *BufferSize, NoAck, IsoPacket, Buffer); - /** fill setting */ - libusb_fill_iso_transfer(iso_transfer, - pdev->libusb_handle, EndpointAddress, Buffer, *BufferSize, - NumberOfPackets, func_iso_callback, &iso_user_data, 2000); - libusb_set_iso_packet_lengths(iso_transfer, iso_packet_size); + urbdrc = pdev->urbdrc; + user_data = async_transfer_user_data_new(idev, MessageId, 48, BufferSize, outSize + 1024, NoAck, + cb, callback); - if (pdev->status & (URBDRC_DEVICE_SIGNAL_END | URBDRC_DEVICE_NOT_FOUND)) - status = -1; + if (!user_data) + return -1; - iso_user_data.iso_status = 0; + user_data->ErrorCount = ErrorCount; + user_data->StartFrame = StartFrame; - if (!(status < 0)) + if (Buffer) /* We read data, prepare a bufffer */ { - submit = libusb_submit_transfer(iso_transfer); - - if (submit < 0) - { - WLog_DBG(TAG, "Error: Failed to submit transfer (ret = %d).", submit); - status = -1; - func_set_usbd_status(pdev, UrbdStatus, ret); - } + user_data->OutputBufferSize = 0; + memmove(Stream_Pointer(user_data->data), Buffer, BufferSize); } + else + Stream_Seek(user_data->data, (NumberOfPackets * 12)); -#if ISOCH_FIFO + iso_packet_size = BufferSize / NumberOfPackets; + iso_transfer = libusb_alloc_transfer(NumberOfPackets); - if (!NoAck) + if (iso_transfer == NULL) { - idev->unlock_fifo_isoch(idev); + WLog_Print(urbdrc->log, WLOG_ERROR, "Error: libusb_alloc_transfer."); + async_transfer_user_data_free(user_data); + return -1; } + iso_transfer->flags = LIBUSB_TRANSFER_FREE_TRANSFER; + /** process URB_FUNCTION_IOSCH_TRANSFER */ + libusb_fill_iso_transfer(iso_transfer, pdev->libusb_handle, EndpointAddress, + Stream_Pointer(user_data->data), BufferSize, NumberOfPackets, + func_iso_callback, user_data, Timeout); +#if defined(HAVE_STREAM_ID_API) + libusb_transfer_set_stream_id(iso_transfer, streamID); +#else + user_data->streamID = streamID; #endif + libusb_set_iso_packet_lengths(iso_transfer, iso_packet_size); - while (pdev && iso_user_data.iso_status == 0 && status >= 0 && submit >= 0) - { - if (pdev->status & URBDRC_DEVICE_NOT_FOUND) - { - status = -1; - break; - } - - ret = handle_events_completed(NULL, &iso_user_data.completed); - - if (ret < 0) - { - WLog_DBG(TAG, "Error: libusb_handle_events (ret = %d).", ret); - status = -1; - break; - } - -#if WAIT_COMPLETE_SLEEP - - if (iso_user_data.iso_status == 0) - { - usleep(WAIT_COMPLETE_SLEEP); - } - -#endif - } - - if (iso_user_data.iso_status < 0) - status = -1; - - *ErrorCount = iso_user_data.error_count; - *StartFrame = iso_user_data.start_frame; - *BufferSize = iso_transfer->actual_length; - libusb_free_transfer(iso_transfer); - return status; + HashTable_Add(pdev->request_queue, (void*)(size_t)streamID, iso_transfer); + return libusb_submit_transfer(iso_transfer); } -static int libusb_udev_control_transfer(IUDEVICE* idev, UINT32 RequestId, UINT32 EndpointAddress, - UINT32 TransferFlags, BYTE bmRequestType, BYTE Request, UINT16 Value, UINT16 Index, - UINT32* UrbdStatus, UINT32* BufferSize, BYTE* Buffer, UINT32 Timeout) +static BOOL libusb_udev_control_transfer(IUDEVICE* idev, UINT32 RequestId, UINT32 EndpointAddress, + UINT32 TransferFlags, BYTE bmRequestType, BYTE Request, + UINT16 Value, UINT16 Index, UINT32* UrbdStatus, + UINT32* BufferSize, BYTE* Buffer, UINT32 Timeout) { int status = 0; - UDEVICE* pdev = (UDEVICE*) idev; - status = libusb_control_transfer(pdev->libusb_handle, - bmRequestType, Request, Value, Index, Buffer, *BufferSize, Timeout); + UDEVICE* pdev = (UDEVICE*)idev; - if (!(status < 0)) - *BufferSize = status; + if (!pdev || !pdev->urbdrc) + return FALSE; - func_set_usbd_status(pdev, UrbdStatus, status); - return status; + status = libusb_control_transfer(pdev->libusb_handle, bmRequestType, Request, Value, Index, + Buffer, *BufferSize, Timeout); + + if (status >= 0) + *BufferSize = (UINT32)status; + else + log_libusb_result(pdev->urbdrc->log, WLOG_ERROR, "libusb_control_transfer", status); + + if (!func_set_usbd_status(pdev->urbdrc, pdev, UrbdStatus, status)) + return FALSE; + + return TRUE; } -static int libusb_udev_bulk_or_interrupt_transfer(IUDEVICE* idev, UINT32 RequestId, - UINT32 EndpointAddress, UINT32 TransferFlags, UINT32* UsbdStatus, UINT32* BufferSize, BYTE* Buffer, - UINT32 Timeout) +static int libusb_udev_bulk_or_interrupt_transfer(IUDEVICE* idev, URBDRC_CHANNEL_CALLBACK* callback, + UINT32 MessageId, UINT32 RequestId, + UINT32 EndpointAddress, UINT32 TransferFlags, + BOOL NoAck, UINT32 BufferSize, + t_isoch_transfer_cb cb, UINT32 Timeout) { UINT32 transfer_type; - UDEVICE* pdev = (UDEVICE*) idev; + UDEVICE* pdev = (UDEVICE*)idev; const LIBUSB_ENDPOINT_DESCEIPTOR* ep_desc; struct libusb_transfer* transfer = NULL; - TRANSFER_REQUEST* request = NULL; - int completed = 0, status = 0, submit = 0; - int transferDir = EndpointAddress & 0x80; + URBDRC_PLUGIN* urbdrc; + ASYNC_TRANSFER_USER_DATA* user_data; + uint32_t streamID = 0x80000000 | RequestId; + + if (!pdev || !pdev->LibusbConfig || !pdev->urbdrc) + return -1; + + urbdrc = pdev->urbdrc; + user_data = + async_transfer_user_data_new(idev, MessageId, 36, BufferSize, 0, NoAck, cb, callback); + + if (!user_data) + return -1; + /* alloc memory for urb transfer */ transfer = libusb_alloc_transfer(0); + if (!transfer) + { + async_transfer_user_data_free(user_data); + return -1; + } + transfer->flags = LIBUSB_TRANSFER_FREE_TRANSFER; + ep_desc = func_get_ep_desc(pdev->LibusbConfig, pdev->MsConfig, EndpointAddress); if (!ep_desc) { - WLog_ERR(TAG, "func_get_ep_desc: endpoint 0x%"PRIx32" is not found!!", EndpointAddress); + WLog_Print(urbdrc->log, WLOG_ERROR, "func_get_ep_desc: endpoint 0x%" PRIx32 " not found", + EndpointAddress); + libusb_free_transfer(transfer); + async_transfer_user_data_free(user_data); return -1; } transfer_type = (ep_desc->bmAttributes) & 0x3; - WLog_DBG(TAG, "urb_bulk_or_interrupt_transfer: ep:0x%"PRIx32" " - "transfer_type %"PRIu32" flag:%"PRIu32" OutputBufferSize:0x%"PRIx32"", - EndpointAddress, transfer_type, TransferFlags, *BufferSize); + WLog_Print(urbdrc->log, WLOG_DEBUG, + "urb_bulk_or_interrupt_transfer: ep:0x%" PRIx32 " " + "transfer_type %" PRIu32 " flag:%" PRIu32 " OutputBufferSize:0x%" PRIx32 "", + EndpointAddress, transfer_type, TransferFlags, BufferSize); switch (transfer_type) { case BULK_TRANSFER: /** Bulk Transfer */ - //Timeout = 10000; + libusb_fill_bulk_transfer(transfer, pdev->libusb_handle, EndpointAddress, + Stream_Pointer(user_data->data), BufferSize, + func_bulk_transfer_cb, user_data, Timeout); break; case INTERRUPT_TRANSFER: - /** Interrupt Transfer */ - /** Sometime, we may have receive a oversized transfer request, - * it make submit urb return error, so we set the length of - * request to wMaxPacketSize */ - if (*BufferSize != (ep_desc->wMaxPacketSize)) - { - WLog_DBG(TAG, "Interrupt Transfer(%s): " - "BufferSize is different than maxPacketsize(0x%x)", - ((transferDir) ? "IN" : "OUT"), ep_desc->wMaxPacketSize); - - if ((*BufferSize) > (ep_desc->wMaxPacketSize) && - transferDir == USBD_TRANSFER_DIRECTION_IN) - (*BufferSize) = ep_desc->wMaxPacketSize; - } - - Timeout = 0; + libusb_fill_interrupt_transfer(transfer, pdev->libusb_handle, EndpointAddress, + Stream_Pointer(user_data->data), BufferSize, + func_bulk_transfer_cb, user_data, Timeout); break; default: - WLog_DBG(TAG, "urb_bulk_or_interrupt_transfer:" - " other transfer type 0x%"PRIX32"", transfer_type); + WLog_Print(urbdrc->log, WLOG_DEBUG, + "urb_bulk_or_interrupt_transfer:" + " other transfer type 0x%" PRIX32 "", + transfer_type); + async_transfer_user_data_free(user_data); + libusb_free_transfer(transfer); return -1; - break; } - libusb_fill_bulk_transfer(transfer, pdev->libusb_handle, EndpointAddress, - Buffer, *BufferSize, func_bulk_transfer_cb, &completed, Timeout); - transfer->type = (unsigned char) transfer_type; - /** Bug fixed in libusb-1.0-8 later: issue of memory crash */ - submit = libusb_submit_transfer(transfer); - - if (submit < 0) - { - WLog_DBG(TAG, "libusb_bulk_transfer: error num %d", status); - func_set_usbd_status(pdev, UsbdStatus, status); - *BufferSize = 0; - } - else - { - request = pdev->request_queue->register_request( - pdev->request_queue, RequestId, transfer, EndpointAddress); - request->submit = 1; - } - - if ((pdev && *UsbdStatus == 0) && (submit >= 0) && - (pdev->iface.isSigToEnd((IUDEVICE*) pdev) == 0)) - { - while (!completed) - { - status = handle_events_completed(NULL, &completed); - - if (status < 0) - { - if (status == LIBUSB_ERROR_INTERRUPTED) - continue; - - libusb_cancel_transfer(transfer); - - while (!completed) - { - if (handle_events_completed(NULL, &completed) < 0) - break; - -#if WAIT_COMPLETE_SLEEP - - if (!completed) - usleep(WAIT_COMPLETE_SLEEP); - -#endif - } - - break; - } - -#if WAIT_COMPLETE_SLEEP - - if (!completed) - usleep(WAIT_COMPLETE_SLEEP); - +#if defined(HAVE_STREAM_ID_API) + libusb_transfer_set_stream_id(transfer, streamID); +#else + user_data->streamID = streamID; #endif - } - - switch (transfer->status) - { - case LIBUSB_TRANSFER_COMPLETED: - func_set_usbd_status(pdev, UsbdStatus, 0); - break; - - case LIBUSB_TRANSFER_TIMED_OUT: - func_set_usbd_status(pdev, UsbdStatus, LIBUSB_ERROR_TIMEOUT); - break; - - case LIBUSB_TRANSFER_STALL: - func_set_usbd_status(pdev, UsbdStatus, LIBUSB_ERROR_PIPE); - break; - - case LIBUSB_TRANSFER_OVERFLOW: - func_set_usbd_status(pdev, UsbdStatus, LIBUSB_ERROR_OVERFLOW); - break; - - case LIBUSB_TRANSFER_NO_DEVICE: - func_set_usbd_status(pdev, UsbdStatus, LIBUSB_ERROR_NO_DEVICE); - break; + HashTable_Add(pdev->request_queue, (void*)(size_t)streamID, transfer); + return libusb_submit_transfer(transfer); +} - default: - func_set_usbd_status(pdev, UsbdStatus, LIBUSB_ERROR_OTHER); - break; - } +static int func_cancel_xact_request(URBDRC_PLUGIN* urbdrc, wHashTable* queue, uint32_t streamID, + struct libusb_transfer* transfer) +{ + int status; - *BufferSize = transfer->actual_length; - } + if (!urbdrc || !queue || !transfer) + return -1; - WLog_DBG(TAG, "bulk or interrupt Transfer data size : 0x%"PRIx32"", *BufferSize); + status = libusb_cancel_transfer(transfer); - if (request) + if (log_libusb_result(urbdrc->log, WLOG_WARN, "libusb_cancel_transfer", status)) { - if (pdev->request_queue->unregister_request(pdev->request_queue, RequestId)) - WLog_ERR(TAG, "request_queue_unregister_request: not fount request 0x%"PRIx32"", RequestId); + if (status == LIBUSB_ERROR_NOT_FOUND) + return -1; } + else + return 1; - libusb_free_transfer(transfer); return 0; } - static void libusb_udev_cancel_all_transfer_request(IUDEVICE* idev) { - int status; - UDEVICE* pdev = (UDEVICE*) idev; - REQUEST_QUEUE* request_queue = pdev->request_queue; - TRANSFER_REQUEST* request = NULL; - pthread_mutex_lock(&request_queue->request_loading); - request_queue->rewind(request_queue); + UDEVICE* pdev = (UDEVICE*)idev; + ULONG_PTR* keys; + int count, x; - while (request_queue->has_next(request_queue)) - { - request = request_queue->get_next(request_queue); + if (!pdev || !pdev->request_queue || !pdev->urbdrc) + return; - if ((!request) || (!request->transfer) || - (request->endpoint != request->transfer->endpoint) || - (request->transfer->endpoint == 0) || (request->submit != 1)) - { - continue; - } - - status = libusb_cancel_transfer(request->transfer); + count = HashTable_GetKeys(pdev->request_queue, &keys); - if (status < 0) - { - WLog_DBG(TAG, "libusb_cancel_transfer: error num %d!!", status); - } - else - { - request->submit = -1; - } + for (x = 0; x < count; x++) + { + struct libusb_transfer* transfer = + HashTable_GetItemValue(pdev->request_queue, (void*)keys[x]); + func_cancel_xact_request(pdev->urbdrc, pdev->request_queue, (uint32_t)keys[x], transfer); } - pthread_mutex_unlock(&request_queue->request_loading); + free(keys); } -static int func_cancel_xact_request(TRANSFER_REQUEST* request) +static int libusb_udev_cancel_transfer_request(IUDEVICE* idev, UINT32 RequestId) { - int status; + UDEVICE* pdev = (UDEVICE*)idev; + struct libusb_transfer* transfer; + URBDRC_PLUGIN* urbdrc; + BOOL id1; + uint32_t cancelID; + uint32_t cancelID1 = 0x40000000 | RequestId; + uint32_t cancelID2 = 0x80000000 | RequestId; + + if (!idev || !pdev->urbdrc || !pdev->request_queue) + return -1; + + id1 = HashTable_Contains(pdev->request_queue, (void*)(size_t)cancelID1); - if (!request) + if (!id1) return -1; - if ((!request->transfer) || (request->endpoint != request->transfer->endpoint) || - (request->transfer->endpoint == 0) || (request->submit != 1)) - { - return 0; - } + urbdrc = (URBDRC_PLUGIN*)pdev->urbdrc; + cancelID = (id1) ? cancelID1 : cancelID2; - status = libusb_cancel_transfer(request->transfer); + transfer = HashTable_GetItemValue(pdev->request_queue, (void*)(size_t)cancelID); + return func_cancel_xact_request(urbdrc, pdev->request_queue, cancelID, transfer); +} - if (status < 0) - { - WLog_DBG(TAG, "libusb_cancel_transfer: error num %d!!", status); +BASIC_STATE_FUNC_DEFINED(channelManager, IWTSVirtualChannelManager*) +BASIC_STATE_FUNC_DEFINED(channelID, UINT32) +BASIC_STATE_FUNC_DEFINED(ReqCompletion, UINT32) +BASIC_STATE_FUNC_DEFINED(bus_number, BYTE) +BASIC_STATE_FUNC_DEFINED(dev_number, BYTE) +BASIC_STATE_FUNC_DEFINED(port_number, int) +BASIC_STATE_FUNC_DEFINED(MsConfig, MSUSB_CONFIG_DESCRIPTOR*) - if (status == LIBUSB_ERROR_NOT_FOUND) - return -1; - } - else - { - WLog_DBG(TAG, "libusb_cancel_transfer: Success num:0x%x!!", request->RequestId); - request->submit = -1; - return 1; - } +BASIC_POINT_FUNC_DEFINED(udev, void*) +BASIC_POINT_FUNC_DEFINED(prev, void*) +BASIC_POINT_FUNC_DEFINED(next, void*) - return 0; +static UINT32 udev_get_UsbDevice(IUDEVICE* idev) +{ + UDEVICE* pdev = (UDEVICE*)idev; + + if (!pdev) + return 0; + + return pdev->UsbDevice; } -static int libusb_udev_cancel_transfer_request(IUDEVICE* idev, UINT32 RequestId) +static void udev_set_UsbDevice(IUDEVICE* idev, UINT32 val) { - UDEVICE* pdev = (UDEVICE*) idev; - REQUEST_QUEUE* request_queue = pdev->request_queue; - TRANSFER_REQUEST* request = NULL; - int status = 0, retry_times = 0; -cancel_retry: - pthread_mutex_lock(&request_queue->request_loading); - request_queue->rewind(request_queue); - - while (request_queue->has_next(request_queue)) - { - request = request_queue->get_next(request_queue); + UDEVICE* pdev = (UDEVICE*)idev; - if (!request) - continue; + if (!pdev) + return; - WLog_DBG(TAG, "CancelId:0x%"PRIx32" RequestId:0x%x endpoint 0x%x!!", - RequestId, request->RequestId, request->endpoint); + pdev->UsbDevice = val; +} - if (request->RequestId == (RequestId && retry_times <= 10)) - { - status = func_cancel_xact_request(request); - break; - } - else if ((request->transfer) && (retry_times > 10)) - { - status = -1; - break; - } - } +static void udev_free(IUDEVICE* idev) +{ + int rc; + UDEVICE* udev = (UDEVICE*)idev; + URBDRC_PLUGIN* urbdrc; - pthread_mutex_unlock(&request_queue->request_loading); + if (!idev || !udev->urbdrc) + return; - if ((status == 0) && (retry_times < 10)) - { - retry_times++; - usleep(100000); - WLog_DBG(TAG, "urbdrc_process_cancel_request: go retry!!"); - goto cancel_retry; - } - else if ((status < 0) || (retry_times >= 10)) + urbdrc = udev->urbdrc; + + if (udev->libusb_handle) { - /** END */ - WLog_DBG(TAG, "urbdrc_process_cancel_request: error go exit!!"); - return -1; + rc = libusb_reset_device(udev->libusb_handle); + + log_libusb_result(urbdrc->log, WLOG_ERROR, "libusb_reset_device", rc); } - WLog_DBG(TAG, "urbdrc_process_cancel_request: success!!"); - return 0; + /* release all interface and attach kernel driver */ + udev->iface.attach_kernel_driver(idev); + HashTable_Free(udev->request_queue); + /* free the config descriptor that send from windows */ + msusb_msconfig_free(udev->MsConfig); + libusb_close(udev->libusb_handle); + libusb_close(udev->hub_handle); + free(udev->devDescriptor); + free(idev); } -BASIC_STATE_FUNC_DEFINED(channel_id, UINT32) -BASIC_STATE_FUNC_DEFINED(UsbDevice, UINT32) -BASIC_STATE_FUNC_DEFINED(ReqCompletion, UINT32) -BASIC_STATE_FUNC_DEFINED(bus_number, UINT16) -BASIC_STATE_FUNC_DEFINED(dev_number, UINT16) -BASIC_STATE_FUNC_DEFINED(port_number, int) -BASIC_STATE_FUNC_DEFINED(isoch_queue, void*) -BASIC_STATE_FUNC_DEFINED(MsConfig, MSUSB_CONFIG_DESCRIPTOR*) - -BASIC_POINT_FUNC_DEFINED(udev, void*) -BASIC_POINT_FUNC_DEFINED(prev, void*) -BASIC_POINT_FUNC_DEFINED(next, void*) - static void udev_load_interface(UDEVICE* pdev) { /* load interface */ /* Basic */ - BASIC_STATE_FUNC_REGISTER(channel_id, pdev); + BASIC_STATE_FUNC_REGISTER(channelManager, pdev); + BASIC_STATE_FUNC_REGISTER(channelID, pdev); BASIC_STATE_FUNC_REGISTER(UsbDevice, pdev); BASIC_STATE_FUNC_REGISTER(ReqCompletion, pdev); BASIC_STATE_FUNC_REGISTER(bus_number, pdev); BASIC_STATE_FUNC_REGISTER(dev_number, pdev); BASIC_STATE_FUNC_REGISTER(port_number, pdev); - BASIC_STATE_FUNC_REGISTER(isoch_queue, pdev); BASIC_STATE_FUNC_REGISTER(MsConfig, pdev); BASIC_STATE_FUNC_REGISTER(p_udev, pdev); BASIC_STATE_FUNC_REGISTER(p_prev, pdev); BASIC_STATE_FUNC_REGISTER(p_next, pdev); pdev->iface.isCompositeDevice = libusb_udev_is_composite_device; - pdev->iface.isSigToEnd = libusb_udev_is_signal_end; pdev->iface.isExist = libusb_udev_is_exist; pdev->iface.isAlreadySend = libusb_udev_is_already_send; pdev->iface.isChannelClosed = libusb_udev_is_channel_closed; - pdev->iface.SigToEnd = libusb_udev_signal_end; pdev->iface.setAlreadySend = libusb_udev_set_already_send; pdev->iface.setChannelClosed = libusb_udev_channel_closed; pdev->iface.getPath = libusb_udev_get_path; @@ -1807,198 +1449,262 @@ static void udev_load_interface(UDEVICE* pdev) pdev->iface.query_device_descriptor = libusb_udev_query_device_descriptor; pdev->iface.detach_kernel_driver = libusb_udev_detach_kernel_driver; pdev->iface.attach_kernel_driver = libusb_udev_attach_kernel_driver; - pdev->iface.wait_action_completion = libusb_udev_wait_action_completion; - pdev->iface.push_action = libusb_udev_push_action; - pdev->iface.complete_action = libusb_udev_complete_action; - pdev->iface.lock_fifo_isoch = libusb_udev_lock_fifo_isoch; - pdev->iface.unlock_fifo_isoch = libusb_udev_unlock_fifo_isoch; pdev->iface.query_device_port_status = libusb_udev_query_device_port_status; - pdev->iface.request_queue_is_none = libusb_udev_request_queue_is_none; - pdev->iface.wait_for_detach = libusb_udev_wait_for_detach; + pdev->iface.free = udev_free; } -static IUDEVICE* udev_init(UDEVICE* pdev, UINT16 bus_number, UINT16 dev_number) +static int udev_get_hub_handle(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UDEVICE* pdev, + UINT16 bus_number, UINT16 dev_number) { - int status, num; + int error; + ssize_t i, total_device; + uint8_t port_numbers[16]; + LIBUSB_DEVICE** libusb_list; + total_device = libusb_get_device_list(ctx, &libusb_list); + /* Look for device. */ + error = -1; + + for (i = 0; i < total_device; i++) + { + LIBUSB_DEVICE_HANDLE* handle; + uint8_t cbus = libusb_get_bus_number(libusb_list[i]); + uint8_t caddr = libusb_get_device_address(libusb_list[i]); + + if ((bus_number != cbus) || (dev_number != caddr)) + continue; + + error = libusb_open(libusb_list[i], &handle); + + if (log_libusb_result(urbdrc->log, WLOG_ERROR, "libusb_open", error)) + break; + + /* get port number */ + error = libusb_get_port_numbers(libusb_list[i], port_numbers, sizeof(port_numbers)); + libusb_close(handle); + + if (error < 1) + { + /* Prevent open hub, treat as error. */ + log_libusb_result(urbdrc->log, WLOG_ERROR, "libusb_get_port_numbers", error); + break; + } + + pdev->port_number = port_numbers[(error - 1)]; + error = 0; + WLog_Print(urbdrc->log, WLOG_DEBUG, " Port: %d", pdev->port_number); + /* gen device path */ + sprintf(pdev->path, "%" PRIu16 "-%" PRIu16 "", bus_number, pdev->port_number); + + WLog_Print(urbdrc->log, WLOG_DEBUG, " DevPath: %s", pdev->path); + break; + } + + /* Look for device hub. */ + if (error == 0) + { + error = -1; + + for (i = 0; i < total_device; i++) + { + LIBUSB_DEVICE_HANDLE* handle; + uint8_t cbus = libusb_get_bus_number(libusb_list[i]); + uint8_t caddr = libusb_get_device_address(libusb_list[i]); + + if ((bus_number != cbus) || (1 != caddr)) /* Root hub allways first on bus. */ + continue; + + WLog_Print(urbdrc->log, WLOG_DEBUG, " Open hub: %" PRIu16 "", bus_number); + error = libusb_open(libusb_list[i], &handle); + + if (!log_libusb_result(urbdrc->log, WLOG_ERROR, "libusb_open", error)) + pdev->hub_handle = handle; + + break; + } + } + + libusb_free_device_list(libusb_list, 1); + + if (error < 0) + return -1; + + return 0; +} + +static void request_free(void* value) +{ + ASYNC_TRANSFER_USER_DATA* user_data; + struct libusb_transfer* transfer = (struct libusb_transfer*)value; + if (!transfer) + return; + + user_data = (ASYNC_TRANSFER_USER_DATA*)transfer->user_data; + async_transfer_user_data_free(user_data); +} + +static IUDEVICE* udev_init(URBDRC_PLUGIN* urbdrc, libusb_context* context, LIBUSB_DEVICE* device, + BYTE bus_number, BYTE dev_number) +{ + UDEVICE* pdev; + int status = LIBUSB_ERROR_OTHER; LIBUSB_DEVICE_DESCRIPTOR* devDescriptor; LIBUSB_CONFIG_DESCRIPTOR* config_temp; LIBUSB_INTERFACE_DESCRIPTOR interface_temp; + pdev = (PUDEVICE)calloc(1, sizeof(UDEVICE)); + + if (!pdev) + return NULL; + + pdev->urbdrc = urbdrc; + udev_load_interface(pdev); + + if (device) + pdev->libusb_dev = device; + else + pdev->libusb_dev = udev_get_libusb_dev(context, bus_number, dev_number); + + if (pdev->libusb_dev == NULL) + goto fail; + + if (urbdrc->listener_callback) + udev_set_channelManager(&pdev->iface, urbdrc->listener_callback->channel_mgr); + /* Get HUB handle */ - status = udev_get_hub_handle(pdev, bus_number, dev_number); + status = udev_get_hub_handle(urbdrc, context, pdev, bus_number, dev_number); if (status < 0) - { - WLog_ERR(TAG, "USB init: Error to get HUB handle!!"); pdev->hub_handle = NULL; + + { + struct libusb_device_descriptor desc; + const uint8_t bus = libusb_get_bus_number(pdev->libusb_dev); + const uint8_t port = libusb_get_port_number(pdev->libusb_dev); + const uint8_t addr = libusb_get_device_address(pdev->libusb_dev); + libusb_get_device_descriptor(pdev->libusb_dev, &desc); + + status = libusb_open(pdev->libusb_dev, &pdev->libusb_handle); + + if (status != LIBUSB_SUCCESS) + { + log_libusb_result(urbdrc->log, WLOG_ERROR, + "libusb_open [b=0x%02X,p=0x%02X,a=0x%02X,VID=0x%04X,PID=0x%04X]", + status, bus, port, addr, desc.idVendor, desc.idProduct); + goto fail; + } } - pdev->devDescriptor = udev_new_descript(pdev->libusb_dev); + pdev->devDescriptor = udev_new_descript(urbdrc, pdev->libusb_dev); if (!pdev->devDescriptor) - { - WLog_ERR(TAG, "USB init: Error to get device descriptor!!"); - zfree(pdev); - return NULL; - } + goto fail; - num = pdev->devDescriptor->bNumConfigurations; status = libusb_get_active_config_descriptor(pdev->libusb_dev, &pdev->LibusbConfig); + if (status == LIBUSB_ERROR_NOT_FOUND) + status = libusb_get_config_descriptor(pdev->libusb_dev, 0, &pdev->LibusbConfig); + if (status < 0) - { - WLog_ERR(TAG, "libusb_get_descriptor: ERROR!!ret:%d", status); - zfree(pdev); - return NULL; - } + goto fail; config_temp = pdev->LibusbConfig; /* get the first interface and first altsetting */ interface_temp = config_temp->interface[0].altsetting[0]; - WLog_DBG(TAG, "Registered Device: Vid: 0x%04"PRIX16" Pid: 0x%04"PRIX16"" - " InterfaceClass = 0x%02"PRIX8"", - pdev->devDescriptor->idVendor, - pdev->devDescriptor->idProduct, - interface_temp.bInterfaceClass); - - /* Denied list */ - switch (interface_temp.bInterfaceClass) - { - case CLASS_RESERVE: - - //case CLASS_COMMUNICATION_IF: - //case CLASS_HID: - //case CLASS_PHYSICAL: - case CLASS_MASS_STORAGE: - case CLASS_HUB: - - //case CLASS_COMMUNICATION_DATA_IF: - case CLASS_SMART_CARD: - case CLASS_CONTENT_SECURITY: - //case CLASS_WIRELESS_CONTROLLER: - //case CLASS_ELSE_DEVICE: - WLog_ERR(TAG, " Device is not supported!!"); - zfree(pdev); - return NULL; - - default: - break; - } - + WLog_Print(urbdrc->log, WLOG_DEBUG, + "Registered Device: Vid: 0x%04" PRIX16 " Pid: 0x%04" PRIX16 "" + " InterfaceClass = %s", + pdev->devDescriptor->idVendor, pdev->devDescriptor->idProduct, + usb_interface_class_to_string(interface_temp.bInterfaceClass)); /* Check composite device */ devDescriptor = pdev->devDescriptor; - if ((devDescriptor->bNumConfigurations == 1) && - (config_temp->bNumInterfaces > 1) && - (devDescriptor->bDeviceClass == 0x0)) + if ((devDescriptor->bNumConfigurations == 1) && (config_temp->bNumInterfaces > 1) && + (devDescriptor->bDeviceClass == LIBUSB_CLASS_PER_INTERFACE)) { pdev->isCompositeDevice = 1; } else if ((devDescriptor->bDeviceClass == 0xef) && - (devDescriptor->bDeviceSubClass == 0x02) && + (devDescriptor->bDeviceSubClass == LIBUSB_CLASS_COMM) && (devDescriptor->bDeviceProtocol == 0x01)) { pdev->isCompositeDevice = 1; } else - { pdev->isCompositeDevice = 0; - } /* set device class to first interface class */ devDescriptor->bDeviceClass = interface_temp.bInterfaceClass; devDescriptor->bDeviceSubClass = interface_temp.bInterfaceSubClass; devDescriptor->bDeviceProtocol = interface_temp.bInterfaceProtocol; /* initialize pdev */ - pdev->prev = NULL; - pdev->next = NULL; pdev->bus_number = bus_number; pdev->dev_number = dev_number; - pdev->status = 0; - pdev->ReqCompletion = 0; - pdev->channel_id = 0xffff; - pdev->request_queue = request_queue_new(); - pdev->isoch_queue = NULL; - sem_init(&pdev->sem_id, 0, 0); + pdev->request_queue = HashTable_New(TRUE); + + if (!pdev->request_queue) + goto fail; + + pdev->request_queue->valueFree = request_free; + /* set config of windows */ pdev->MsConfig = msusb_msconfig_new(); - pthread_mutex_init(&pdev->mutex_isoch, NULL); - //deb_config_msg(pdev->libusb_dev, config_temp, devDescriptor->bNumConfigurations); - udev_load_interface(pdev); - return (IUDEVICE*) pdev; + + if (!pdev->MsConfig) + goto fail; + + // deb_config_msg(pdev->libusb_dev, config_temp, devDescriptor->bNumConfigurations); + return (IUDEVICE*)pdev; +fail: + pdev->iface.free((IUDEVICE*)pdev); + return NULL; } -int udev_new_by_id(UINT16 idVendor, UINT16 idProduct, IUDEVICE** * devArray) +size_t udev_new_by_id(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UINT16 idVendor, UINT16 idProduct, + IUDEVICE*** devArray) { - LIBUSB_DEVICE_DESCRIPTOR* descriptor; LIBUSB_DEVICE** libusb_list; UDEVICE** array; UINT16 bus_number; UINT16 dev_number; ssize_t i, total_device; - int status, num = 0; - WLog_INFO(TAG, "VID: 0x%04"PRIX16", PID: 0x%04"PRIX16"", idVendor, idProduct); - array = (UDEVICE**) malloc(16 * sizeof(UDEVICE*)); - total_device = libusb_get_device_list(NULL, &libusb_list); + size_t num = 0; + + if (!urbdrc || !devArray) + return 0; + + WLog_Print(urbdrc->log, WLOG_INFO, "VID: 0x%04" PRIX16 ", PID: 0x%04" PRIX16 "", idVendor, + idProduct); + array = (UDEVICE**)calloc(16, sizeof(UDEVICE*)); + + if (!array) + return 0; + + total_device = libusb_get_device_list(ctx, &libusb_list); for (i = 0; i < total_device; i++) { - descriptor = udev_new_descript(libusb_list[i]); + LIBUSB_DEVICE_DESCRIPTOR* descriptor = udev_new_descript(urbdrc, libusb_list[i]); if ((descriptor->idVendor == idVendor) && (descriptor->idProduct == idProduct)) { - bus_number = 0; - dev_number = 0; - array[num] = (PUDEVICE) malloc(sizeof(UDEVICE)); - array[num]->libusb_dev = libusb_list[i]; - status = libusb_open(libusb_list[i], &array[num]->libusb_handle); - - if (status < 0) - { - WLog_ERR(TAG, "libusb_open: (by id) error: 0x%08X (%d)", status, status); - zfree(descriptor); - zfree(array[num]); - continue; - } - bus_number = libusb_get_bus_number(libusb_list[i]); dev_number = libusb_get_device_address(libusb_list[i]); - array[num] = (PUDEVICE) udev_init(array[num], bus_number, dev_number); + array[num] = (PUDEVICE)udev_init(urbdrc, ctx, libusb_list[i], bus_number, dev_number); if (array[num] != NULL) num++; } - zfree(descriptor); + free(descriptor); } libusb_free_device_list(libusb_list, 1); - *devArray = (IUDEVICE**) array; + *devArray = (IUDEVICE**)array; return num; } -IUDEVICE* udev_new_by_addr(int bus_number, int dev_number) +IUDEVICE* udev_new_by_addr(URBDRC_PLUGIN* urbdrc, libusb_context* context, BYTE bus_number, + BYTE dev_number) { - int status; - UDEVICE* pDev; - WLog_DBG(TAG, "bus:%d dev:%d", bus_number, dev_number); - pDev = (PUDEVICE) malloc(sizeof(UDEVICE)); - pDev->libusb_dev = udev_get_libusb_dev(bus_number, dev_number); - - if (pDev->libusb_dev == NULL) - { - WLog_ERR(TAG, "libusb_device_new: ERROR!!"); - zfree(pDev); - return NULL; - } - - status = libusb_open(pDev->libusb_dev, &pDev->libusb_handle); - - if (status < 0) - { - WLog_ERR(TAG, "libusb_open: (by addr) ERROR!!"); - zfree(pDev); - return NULL; - } - - return udev_init(pDev, bus_number, dev_number); + WLog_Print(urbdrc->log, WLOG_DEBUG, "bus:%d dev:%d", bus_number, dev_number); + return udev_init(urbdrc, context, NULL, bus_number, dev_number); } diff --git a/channels/urbdrc/client/libusb/libusb_udevice.h b/channels/urbdrc/client/libusb/libusb_udevice.h index c79dfca..bf5b403 100644 --- a/channels/urbdrc/client/libusb/libusb_udevice.h +++ b/channels/urbdrc/client/libusb/libusb_udevice.h @@ -18,28 +18,22 @@ * limitations under the License. */ - - #ifndef FREERDP_CHANNEL_URBDRC_CLIENT_LIBUSB_UDEVICE_H #define FREERDP_CHANNEL_URBDRC_CLIENT_LIBUSB_UDEVICE_H -#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) +#include #include -#else -#include -#endif #include "urbdrc_types.h" -#include "request_queue.h" #include "urbdrc_main.h" -typedef struct libusb_device LIBUSB_DEVICE; -typedef struct libusb_device_handle LIBUSB_DEVICE_HANDLE; -typedef struct libusb_device_descriptor LIBUSB_DEVICE_DESCRIPTOR; -typedef struct libusb_config_descriptor LIBUSB_CONFIG_DESCRIPTOR; -typedef struct libusb_interface LIBUSB_INTERFACE; -typedef struct libusb_interface_descriptor LIBUSB_INTERFACE_DESCRIPTOR; -typedef struct libusb_endpoint_descriptor LIBUSB_ENDPOINT_DESCEIPTOR; +typedef struct libusb_device LIBUSB_DEVICE; +typedef struct libusb_device_handle LIBUSB_DEVICE_HANDLE; +typedef struct libusb_device_descriptor LIBUSB_DEVICE_DESCRIPTOR; +typedef struct libusb_config_descriptor LIBUSB_CONFIG_DESCRIPTOR; +typedef struct libusb_interface LIBUSB_INTERFACE; +typedef struct libusb_interface_descriptor LIBUSB_INTERFACE_DESCRIPTOR; +typedef struct libusb_endpoint_descriptor LIBUSB_ENDPOINT_DESCEIPTOR; typedef struct _UDEVICE UDEVICE; @@ -47,39 +41,38 @@ struct _UDEVICE { IUDEVICE iface; - void * udev; - void * prev; - void * next; - - UINT32 UsbDevice; /* An unique interface ID */ - UINT32 ReqCompletion; /* An unique interface ID */ - UINT32 channel_id; - UINT16 status; - UINT16 bus_number; - UINT16 dev_number; - char path[17]; - int port_number; - int isCompositeDevice; - - LIBUSB_DEVICE_HANDLE * libusb_handle; - LIBUSB_DEVICE_HANDLE * hub_handle; - LIBUSB_DEVICE * libusb_dev; - LIBUSB_DEVICE_DESCRIPTOR * devDescriptor; - MSUSB_CONFIG_DESCRIPTOR * MsConfig; - LIBUSB_CONFIG_DESCRIPTOR * LibusbConfig; - - REQUEST_QUEUE * request_queue; - /* Used in isochronous transfer */ - void * isoch_queue; - - pthread_mutex_t mutex_isoch; - sem_t sem_id; + void* udev; + void* prev; + void* next; + + UINT32 UsbDevice; /* An unique interface ID */ + UINT32 ReqCompletion; /* An unique interface ID */ + IWTSVirtualChannelManager* channelManager; + UINT32 channelID; + UINT16 status; + BYTE bus_number; + BYTE dev_number; + char path[17]; + int port_number; + int isCompositeDevice; + + LIBUSB_DEVICE_HANDLE* libusb_handle; + LIBUSB_DEVICE_HANDLE* hub_handle; + LIBUSB_DEVICE* libusb_dev; + LIBUSB_DEVICE_DESCRIPTOR* devDescriptor; + MSUSB_CONFIG_DESCRIPTOR* MsConfig; + LIBUSB_CONFIG_DESCRIPTOR* LibusbConfig; + + wHashTable* request_queue; + + URBDRC_PLUGIN* urbdrc; }; -typedef UDEVICE * PUDEVICE; - -int udev_new_by_id(UINT16 idVendor, UINT16 idProduct, IUDEVICE ***devArray); -IUDEVICE* udev_new_by_addr(int bus_number, int dev_number); +typedef UDEVICE* PUDEVICE; -extern int libusb_debug; +size_t udev_new_by_id(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UINT16 idVendor, UINT16 idProduct, + IUDEVICE*** devArray); +IUDEVICE* udev_new_by_addr(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, BYTE bus_number, + BYTE dev_number); +const char* usb_interface_class_to_string(uint8_t class); #endif /* FREERDP_CHANNEL_URBDRC_CLIENT_LIBUSB_UDEVICE_H */ diff --git a/channels/urbdrc/client/libusb/libusb_udevman.c b/channels/urbdrc/client/libusb/libusb_udevman.c index b0d0fbc..2eebc1a 100644 --- a/channels/urbdrc/client/libusb/libusb_udevman.c +++ b/channels/urbdrc/client/libusb/libusb_udevman.c @@ -21,9 +21,11 @@ #include #include #include +#include #include #include +#include #include @@ -32,24 +34,36 @@ #include "libusb_udevice.h" -int libusb_debug; - -#define BASIC_STATE_FUNC_DEFINED(_arg, _type) \ - static _type udevman_get_##_arg (IUDEVMAN* idevman) \ - { \ - UDEVMAN * udevman = (UDEVMAN *) idevman; \ - return udevman->_arg; \ - } \ - static void udevman_set_##_arg (IUDEVMAN* idevman, _type _t) \ - { \ - UDEVMAN * udevman = (UDEVMAN *) idevman; \ - udevman->_arg = _t; \ +#include + +#if !defined(LIBUSB_HOTPLUG_NO_FLAGS) +#define LIBUSB_HOTPLUG_NO_FLAGS 0 +#endif + +#define BASIC_STATE_FUNC_DEFINED(_arg, _type) \ + static _type udevman_get_##_arg(IUDEVMAN* idevman) \ + { \ + UDEVMAN* udevman = (UDEVMAN*)idevman; \ + return udevman->_arg; \ + } \ + static void udevman_set_##_arg(IUDEVMAN* idevman, _type _t) \ + { \ + UDEVMAN* udevman = (UDEVMAN*)idevman; \ + udevman->_arg = _t; \ } -#define BASIC_STATE_FUNC_REGISTER(_arg, _man) \ +#define BASIC_STATE_FUNC_REGISTER(_arg, _man) \ _man->iface.get_##_arg = udevman_get_##_arg; \ _man->iface.set_##_arg = udevman_set_##_arg +typedef struct _VID_PID_PAIR VID_PID_PAIR; + +struct _VID_PID_PAIR +{ + UINT16 vid; + UINT16 pid; +}; + typedef struct _UDEVMAN UDEVMAN; struct _UDEVMAN @@ -60,135 +74,156 @@ struct _UDEVMAN IUDEVICE* head; /* head device in linked list */ IUDEVICE* tail; /* tail device in linked list */ - UINT32 defUsbDevice; + LPSTR devices_vid_pid; + LPSTR devices_addr; + wArrayList* hotplug_vid_pids; UINT16 flags; - int device_num; - int sem_timeout; - - pthread_mutex_t devman_loading; - sem_t sem_urb_lock; + UINT32 device_num; + UINT32 next_device_id; + UINT32 channel_id; + + HANDLE devman_loading; + libusb_context* context; + HANDLE thread; + BOOL running; }; typedef UDEVMAN* PUDEVMAN; +static BOOL poll_libusb_events(UDEVMAN* udevman); + static void udevman_rewind(IUDEVMAN* idevman) { - UDEVMAN* udevman = (UDEVMAN*) idevman; + UDEVMAN* udevman = (UDEVMAN*)idevman; udevman->idev = udevman->head; } -static int udevman_has_next(IUDEVMAN* idevman) +static BOOL udevman_has_next(IUDEVMAN* idevman) { - UDEVMAN* udevman = (UDEVMAN*) idevman; + UDEVMAN* udevman = (UDEVMAN*)idevman; - if (udevman->idev == NULL) - return 0; + if (!udevman || !udevman->idev) + return FALSE; else - return 1; + return TRUE; } static IUDEVICE* udevman_get_next(IUDEVMAN* idevman) { - UDEVMAN* udevman = (UDEVMAN*) idevman; + UDEVMAN* udevman = (UDEVMAN*)idevman; IUDEVICE* pdev; pdev = udevman->idev; - udevman->idev = (IUDEVICE*)((UDEVICE*) udevman->idev)->next; + udevman->idev = (IUDEVICE*)((UDEVICE*)udevman->idev)->next; return pdev; } -static IUDEVICE* udevman_get_udevice_by_addr(IUDEVMAN* idevman, int bus_number, int dev_number) +static IUDEVICE* udevman_get_udevice_by_addr(IUDEVMAN* idevman, BYTE bus_number, BYTE dev_number) { - IUDEVICE* pdev; + IUDEVICE* dev = NULL; + + if (!idevman) + return NULL; + idevman->loading_lock(idevman); idevman->rewind(idevman); while (idevman->has_next(idevman)) { - pdev = idevman->get_next(idevman); + IUDEVICE* pdev = idevman->get_next(idevman); - if ((pdev->get_bus_number(pdev) == bus_number) && (pdev->get_dev_number(pdev) == dev_number)) + if ((pdev->get_bus_number(pdev) == bus_number) && + (pdev->get_dev_number(pdev) == dev_number)) { - idevman->loading_unlock(idevman); - return pdev; + dev = pdev; + break; } } idevman->loading_unlock(idevman); - WLog_WARN(TAG, "bus:%d dev:%d not exist in udevman", - bus_number, dev_number); - return NULL; + return dev; } -static int udevman_register_udevice(IUDEVMAN* idevman, int bus_number, int dev_number, - int UsbDevice, UINT16 idVendor, UINT16 idProduct, int flag) +static size_t udevman_register_udevice(IUDEVMAN* idevman, BYTE bus_number, BYTE dev_number, + UINT16 idVendor, UINT16 idProduct, UINT32 flag) { - UDEVMAN* udevman = (UDEVMAN*) idevman; + UDEVMAN* udevman = (UDEVMAN*)idevman; IUDEVICE* pdev = NULL; IUDEVICE** devArray; - int i, num, addnum = 0; - pdev = (IUDEVICE*) udevman_get_udevice_by_addr(idevman, bus_number, dev_number); + URBDRC_PLUGIN* urbdrc; + size_t i, num, addnum = 0; + + if (!idevman || !idevman->plugin) + return 0; + + urbdrc = (URBDRC_PLUGIN*)idevman->plugin; + pdev = (IUDEVICE*)udevman_get_udevice_by_addr(idevman, bus_number, dev_number); if (pdev != NULL) return 0; - if (flag == UDEVMAN_FLAG_ADD_BY_ADDR) + if (flag & UDEVMAN_FLAG_ADD_BY_ADDR) { - pdev = udev_new_by_addr(bus_number, dev_number); + UINT32 id; + IUDEVICE* tdev = udev_new_by_addr(urbdrc, udevman->context, bus_number, dev_number); - if (pdev == NULL) + if (tdev == NULL) return 0; - pdev->set_UsbDevice(pdev, UsbDevice); + id = idevman->get_next_device_id(idevman); + tdev->set_UsbDevice(tdev, id); idevman->loading_lock(idevman); if (udevman->head == NULL) { /* linked list is empty */ - udevman->head = pdev; - udevman->tail = pdev; + udevman->head = tdev; + udevman->tail = tdev; } else { /* append device to the end of the linked list */ - udevman->tail->set_p_next(udevman->tail, pdev); - pdev->set_p_prev(pdev, udevman->tail); - udevman->tail = pdev; + udevman->tail->set_p_next(udevman->tail, tdev); + tdev->set_p_prev(tdev, udevman->tail); + udevman->tail = tdev; } udevman->device_num += 1; idevman->loading_unlock(idevman); } - else if (flag == UDEVMAN_FLAG_ADD_BY_VID_PID) + else if (flag & UDEVMAN_FLAG_ADD_BY_VID_PID) { addnum = 0; /* register all device that match pid vid */ - num = udev_new_by_id(idVendor, idProduct, &devArray); + num = udev_new_by_id(urbdrc, udevman->context, idVendor, idProduct, &devArray); for (i = 0; i < num; i++) { - pdev = devArray[i]; + UINT32 id; + IUDEVICE* tdev = devArray[i]; - if (udevman_get_udevice_by_addr(idevman, - pdev->get_bus_number(pdev), pdev->get_dev_number(pdev)) != NULL) + if (udevman_get_udevice_by_addr(idevman, tdev->get_bus_number(tdev), + tdev->get_dev_number(tdev)) != NULL) { - zfree(pdev); + tdev->free(tdev); + devArray[i] = NULL; continue; } - pdev->set_UsbDevice(pdev, UsbDevice); + id = idevman->get_next_device_id(idevman); + tdev->set_UsbDevice(tdev, id); idevman->loading_lock(idevman); if (udevman->head == NULL) { /* linked list is empty */ - udevman->head = pdev; - udevman->tail = pdev; + udevman->head = tdev; + udevman->tail = tdev; } else { /* append device to the end of the linked list */ - udevman->tail->set_p_next(udevman->tail, pdev); - pdev->set_p_prev(pdev, udevman->tail); - udevman->tail = pdev; + udevman->tail->set_p_next(udevman->tail, tdev); + tdev->set_p_prev(tdev, udevman->tail); + udevman->tail = tdev; } udevman->device_num += 1; @@ -196,30 +231,34 @@ static int udevman_register_udevice(IUDEVMAN* idevman, int bus_number, int dev_n addnum++; } - zfree(devArray); + free(devArray); return addnum; } else { - WLog_ERR(TAG, "udevman_register_udevice: function error!!"); + WLog_Print(urbdrc->log, WLOG_ERROR, "udevman_register_udevice: Invalid flag=%08 " PRIx32, + flag); return 0; } return 1; } -static int udevman_unregister_udevice(IUDEVMAN* idevman, int bus_number, int dev_number) +static BOOL udevman_unregister_udevice(IUDEVMAN* idevman, BYTE bus_number, BYTE dev_number) { - UDEVMAN* udevman = (UDEVMAN*) idevman; - UDEVICE* pdev, * dev; - int ret = 0, err = 0; - dev = (UDEVICE*) udevman_get_udevice_by_addr(idevman, bus_number, dev_number); + UDEVMAN* udevman = (UDEVMAN*)idevman; + UDEVICE* pdev; + UDEVICE* dev = (UDEVICE*)udevman_get_udevice_by_addr(idevman, bus_number, dev_number); + + if (!dev || !idevman) + return FALSE; + idevman->loading_lock(idevman); idevman->rewind(idevman); - while (idevman->has_next(idevman) != 0) + while (idevman->has_next(idevman)) { - pdev = (UDEVICE*) idevman->get_next(idevman); + pdev = (UDEVICE*)idevman->get_next(idevman); if (pdev == dev) /* device exists */ { @@ -259,285 +298,443 @@ static int udevman_unregister_udevice(IUDEVMAN* idevman, int bus_number, int dev if (dev) { - /* reset device */ - if (err != LIBUSB_ERROR_NO_DEVICE) - { - ret = libusb_reset_device(dev->libusb_handle); + dev->iface.free(&dev->iface); + return TRUE; /* unregistration successful */ + } - if (ret < 0) - { - WLog_ERR(TAG, "libusb_reset_device: ERROR!!ret:%d", ret); - } - } + /* if we reach this point, the device wasn't found */ + return FALSE; +} - /* release all interface and attach kernel driver */ - dev->iface.attach_kernel_driver((IUDEVICE*)dev); +static BOOL udevman_unregister_all_udevices(IUDEVMAN* idevman) +{ + UDEVMAN* udevman = (UDEVMAN*)idevman; - if (dev->request_queue) zfree(dev->request_queue); + if (!idevman) + return FALSE; - /* free the config descriptor that send from windows */ - msusb_msconfig_free(dev->MsConfig); - libusb_close(dev->libusb_handle); - libusb_close(dev->hub_handle); - sem_destroy(&dev->sem_id); + if (!udevman->head) + return TRUE; - /* free device info */ - if (dev->devDescriptor) - zfree(dev->devDescriptor); + idevman->loading_lock(idevman); + idevman->rewind(idevman); - if (dev) - zfree(dev); + while (idevman->has_next(idevman)) + { + UDEVICE* dev = (UDEVICE*)idevman->get_next(idevman); - return 1; /* unregistration successful */ - } + if (!dev) + continue; - /* if we reach this point, the device wasn't found */ - return 0; -} + /* set previous device to point to next device */ + if (dev->prev != NULL) + { + /* unregistered device is not the head */ + UDEVICE* pdev = dev->prev; + pdev->next = dev->next; + } + else + { + /* unregistered device is the head, update head */ + udevman->head = (IUDEVICE*)dev->next; + } -static void udevman_parse_device_addr(char* str, int* id1, int* id2, char sign) -{ - char s1[8]; - char* s2; - ZeroMemory(s1, sizeof(s1)); - s2 = (strchr(str, sign)) + 1; - strncpy(s1, str, strlen(str) - (strlen(s2) + 1)); - *id1 = strtol(s1, NULL, 0); - *id2 = strtol(s2, NULL, 0); -} + /* set next device to point to previous device */ -static void udevman_parse_device_pid_vid(char* str, int* id1, int* id2, char sign) -{ - char s1[8]; - char* s2; - ZeroMemory(s1, sizeof(s1)); - s2 = (strchr(str, sign)) + 1; - strncpy(s1, str, strlen(str) - (strlen(s2) + 1)); - *id1 = strtol(s1, NULL, 16); - *id2 = strtol(s2, NULL, 16); -} + if (dev->next != NULL) + { + /* unregistered device is not the tail */ + UDEVICE* pdev = (UDEVICE*)dev->next; + pdev->prev = dev->prev; + } + else + { + /* unregistered device is the tail, update tail */ + udevman->tail = (IUDEVICE*)dev->prev; + } -static int udevman_check_device_exist_by_id(IUDEVMAN* idevman, UINT16 idVendor, UINT16 idProduct) -{ - if (libusb_open_device_with_vid_pid(NULL, idVendor, idProduct)) - return 1; + dev->iface.free(&dev->iface); + udevman->device_num--; + } - return 0; + idevman->loading_unlock(idevman); + + return TRUE; } static int udevman_is_auto_add(IUDEVMAN* idevman) { - UDEVMAN* udevman = (UDEVMAN*) idevman; + UDEVMAN* udevman = (UDEVMAN*)idevman; return (udevman->flags & UDEVMAN_FLAG_ADD_BY_AUTO) ? 1 : 0; } -static IUDEVICE* udevman_get_udevice_by_UsbDevice_try_again(IUDEVMAN* idevman, UINT32 UsbDevice) +static IUDEVICE* udevman_get_udevice_by_UsbDevice(IUDEVMAN* idevman, UINT32 UsbDevice) { UDEVICE* pdev; + URBDRC_PLUGIN* urbdrc; + + if (!idevman || !idevman->plugin) + return NULL; + + /* Mask highest 2 bits, must be ignored */ + UsbDevice = UsbDevice & INTERFACE_ID_MASK; + urbdrc = (URBDRC_PLUGIN*)idevman->plugin; idevman->loading_lock(idevman); idevman->rewind(idevman); while (idevman->has_next(idevman)) { - pdev = (UDEVICE*) idevman->get_next(idevman); + pdev = (UDEVICE*)idevman->get_next(idevman); if (pdev->UsbDevice == UsbDevice) { idevman->loading_unlock(idevman); - return (IUDEVICE*) pdev; + return (IUDEVICE*)pdev; } } idevman->loading_unlock(idevman); + WLog_Print(urbdrc->log, WLOG_WARN, "Failed to find a USB device mapped to deviceId=%08" PRIx32, + UsbDevice); return NULL; } -static IUDEVICE* udevman_get_udevice_by_UsbDevice(IUDEVMAN* idevman, UINT32 UsbDevice) +static void udevman_loading_lock(IUDEVMAN* idevman) { - UDEVICE* pdev; - idevman->loading_lock(idevman); - idevman->rewind(idevman); + UDEVMAN* udevman = (UDEVMAN*)idevman; + WaitForSingleObject(udevman->devman_loading, INFINITE); +} - while (idevman->has_next(idevman)) - { - pdev = (UDEVICE*) idevman->get_next(idevman); +static void udevman_loading_unlock(IUDEVMAN* idevman) +{ + UDEVMAN* udevman = (UDEVMAN*)idevman; + ReleaseMutex(udevman->devman_loading); +} - if (pdev->UsbDevice == UsbDevice) - { - idevman->loading_unlock(idevman); - return (IUDEVICE*) pdev; - } - } +BASIC_STATE_FUNC_DEFINED(device_num, UINT32) - idevman->loading_unlock(idevman); - /* try again */ - pdev = (UDEVICE*) idevman->get_udevice_by_UsbDevice_try_again(idevman, UsbDevice); +static UINT32 udevman_get_next_device_id(IUDEVMAN* idevman) +{ + UDEVMAN* udevman = (UDEVMAN*)idevman; + return udevman->next_device_id++; +} + +static void udevman_set_next_device_id(IUDEVMAN* idevman, UINT32 _t) +{ + UDEVMAN* udevman = (UDEVMAN*)idevman; + udevman->next_device_id = _t; +} + +static void udevman_free(IUDEVMAN* idevman) +{ + UDEVMAN* udevman = (UDEVMAN*)idevman; - if (pdev) + if (!udevman) + return; + + udevman->running = FALSE; + if (udevman->thread) { - return (IUDEVICE*) pdev; + WaitForSingleObject(udevman->thread, INFINITE); + CloseHandle(udevman->thread); } - WLog_ERR(TAG, "0x%"PRIx32" ERROR!!", UsbDevice); - return NULL; + udevman_unregister_all_udevices(idevman); + + if (udevman->devman_loading) + CloseHandle(udevman->devman_loading); + + libusb_exit(udevman->context); + + ArrayList_Free(udevman->hotplug_vid_pids); + free(udevman); } -static void udevman_loading_lock(IUDEVMAN* idevman) +static BOOL filter_by_class(uint8_t bDeviceClass, uint8_t bDeviceSubClass) { - UDEVMAN* udevman = (UDEVMAN*) idevman; - pthread_mutex_lock(&udevman->devman_loading); + switch (bDeviceClass) + { + case LIBUSB_CLASS_AUDIO: + case LIBUSB_CLASS_HID: + case LIBUSB_CLASS_MASS_STORAGE: + case LIBUSB_CLASS_HUB: + case LIBUSB_CLASS_SMART_CARD: + return TRUE; + default: + break; + } + + switch (bDeviceSubClass) + { + default: + break; + } + + return FALSE; } -static void udevman_loading_unlock(IUDEVMAN* idevman) +static BOOL append(char* dst, size_t length, const char* src) { - UDEVMAN* udevman = (UDEVMAN*) idevman; - pthread_mutex_unlock(&udevman->devman_loading); + size_t slen = strlen(src); + size_t dlen = strnlen(dst, length); + if (dlen + slen >= length) + return FALSE; + strcat(dst, src); + return TRUE; } -static void udevman_wait_urb(IUDEVMAN* idevman) +static BOOL device_is_filtered(struct libusb_device* dev, + const struct libusb_device_descriptor* desc, + libusb_hotplug_event event) { - UDEVMAN* udevman = (UDEVMAN*) idevman; - sem_wait(&udevman->sem_urb_lock); + char buffer[8192] = { 0 }; + char* what; + BOOL filtered = FALSE; + append(buffer, sizeof(buffer), usb_interface_class_to_string(desc->bDeviceClass)); + if (filter_by_class(desc->bDeviceClass, desc->bDeviceSubClass)) + filtered = TRUE; + + switch (desc->bDeviceClass) + { + case LIBUSB_CLASS_PER_INTERFACE: + { + struct libusb_config_descriptor* config = NULL; + int rc = libusb_get_active_config_descriptor(dev, &config); + if (rc == LIBUSB_SUCCESS) + { + uint8_t x; + + for (x = 0; x < config->bNumInterfaces; x++) + { + uint8_t y; + const struct libusb_interface* ifc = &config->interface[x]; + for (y = 0; y < ifc->num_altsetting; y++) + { + const struct libusb_interface_descriptor* const alt = &ifc->altsetting[y]; + if (filter_by_class(alt->bInterfaceClass, alt->bInterfaceSubClass)) + filtered = TRUE; + + append(buffer, sizeof(buffer), "|"); + append(buffer, sizeof(buffer), + usb_interface_class_to_string(alt->bInterfaceClass)); + } + } + } + libusb_free_config_descriptor(config); + } + break; + default: + break; + } + + if (filtered) + what = "Filtered"; + else + { + switch (event) + { + case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT: + what = "Hotplug remove"; + break; + case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED: + what = "Hotplug add"; + break; + default: + what = "Hotplug unknown"; + break; + } + } + + WLog_DBG(TAG, "%s device VID=0x%04X,PID=0x%04X class %s", what, desc->idVendor, desc->idProduct, + buffer); + return filtered; } -static void udevman_push_urb(IUDEVMAN* idevman) +static int hotplug_callback(struct libusb_context* ctx, struct libusb_device* dev, + libusb_hotplug_event event, void* user_data) { - UDEVMAN* udevman = (UDEVMAN*) idevman; - sem_post(&udevman->sem_urb_lock); -} + VID_PID_PAIR pair; + struct libusb_device_descriptor desc; + UDEVMAN* udevman = (UDEVMAN*)user_data; + const uint8_t bus = libusb_get_bus_number(dev); + const uint8_t addr = libusb_get_device_address(dev); + int rc = libusb_get_device_descriptor(dev, &desc); -BASIC_STATE_FUNC_DEFINED(defUsbDevice, UINT32) -BASIC_STATE_FUNC_DEFINED(device_num, int) -BASIC_STATE_FUNC_DEFINED(sem_timeout, int) + WINPR_UNUSED(ctx); -static void udevman_free(IUDEVMAN* idevman) -{ - UDEVMAN* udevman = (UDEVMAN*) idevman; - pthread_mutex_destroy(&udevman->devman_loading); - sem_destroy(&udevman->sem_urb_lock); - libusb_exit(NULL); + if (rc != LIBUSB_SUCCESS) + return rc; - /* free udevman */ + switch (event) + { + case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED: + pair.vid = desc.idVendor; + pair.pid = desc.idProduct; + if ((ArrayList_Contains(udevman->hotplug_vid_pids, &pair)) || + (udevman->iface.isAutoAdd(&udevman->iface) && + !device_is_filtered(dev, &desc, event))) + { + add_device(&udevman->iface, DEVICE_ADD_FLAG_ALL, bus, addr, desc.idVendor, + desc.idProduct); + } + break; + + case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT: + del_device(&udevman->iface, DEVICE_ADD_FLAG_ALL, bus, addr, desc.idVendor, + desc.idProduct); + break; - if (udevman) - zfree(udevman); + default: + break; + } + + return 0; } -static void udevman_load_interface(UDEVMAN* udevman) +static BOOL udevman_initialize(IUDEVMAN* idevman, UINT32 channelId) { - /* standard */ - udevman->iface.free = udevman_free; - /* manage devices */ - udevman->iface.rewind = udevman_rewind; - udevman->iface.get_next = udevman_get_next; - udevman->iface.has_next = udevman_has_next; - udevman->iface.register_udevice = udevman_register_udevice; - udevman->iface.unregister_udevice = udevman_unregister_udevice; - udevman->iface.get_udevice_by_UsbDevice = udevman_get_udevice_by_UsbDevice; - udevman->iface.get_udevice_by_UsbDevice_try_again = - udevman_get_udevice_by_UsbDevice_try_again; - /* Extension */ - udevman->iface.check_device_exist_by_id = udevman_check_device_exist_by_id; - udevman->iface.isAutoAdd = udevman_is_auto_add; - /* Basic state */ - BASIC_STATE_FUNC_REGISTER(defUsbDevice, udevman); - BASIC_STATE_FUNC_REGISTER(device_num, udevman); - BASIC_STATE_FUNC_REGISTER(sem_timeout, udevman); - /* control semaphore or mutex lock */ - udevman->iface.loading_lock = udevman_loading_lock; - udevman->iface.loading_unlock = udevman_loading_unlock; - udevman->iface.push_urb = udevman_push_urb; - udevman->iface.wait_urb = udevman_wait_urb; + UDEVMAN* udevman = (UDEVMAN*)idevman; + + if (!udevman) + return FALSE; + + idevman->status &= ~URBDRC_DEVICE_CHANNEL_CLOSED; + idevman->controlChannelId = channelId; + return TRUE; } -COMMAND_LINE_ARGUMENT_A urbdrc_udevman_args[] = +static BOOL udevman_vid_pid_pair_equals(const void* objA, const void* objB) { - { "dbg", COMMAND_LINE_VALUE_FLAG, "", NULL, BoolValueFalse, -1, NULL, "debug" }, - { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "device list" }, - { "id", COMMAND_LINE_VALUE_FLAG, "", NULL, BoolValueFalse, -1, NULL, "FLAG_ADD_BY_VID_PID" }, - { "addr", COMMAND_LINE_VALUE_FLAG, "", NULL, BoolValueFalse, -1, NULL, "FLAG_ADD_BY_ADDR" }, - { "auto", COMMAND_LINE_VALUE_FLAG, "", NULL, BoolValueFalse, -1, NULL, "FLAG_ADD_BY_AUTO" }, - { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } -}; + const VID_PID_PAIR* a = objA; + const VID_PID_PAIR* b = objB; + + return (a->vid == b->vid) && (a->pid == b->pid); +} -static void urbdrc_udevman_register_devices(UDEVMAN* udevman, char* devices) +static BOOL udevman_parse_device_id_addr(const char** str, UINT16* id1, UINT16* id2, UINT16 max, + char split_sign, char delimiter) { - char* token; - int idVendor; - int idProduct; - int bus_number; - int dev_number; - int success = 0; - char hardware_id[16]; - char* default_devices = "id"; - UINT32 UsbDevice = BASE_USBDEVICE_NUM; - - if (!devices) - devices = default_devices; - - /* register all usb devices */ - token = strtok(devices, "#"); - - while (token) + char* mid; + char* end; + unsigned long rc; + + rc = strtoul(*str, &mid, 16); + + if ((mid == *str) || (*mid != split_sign) || (rc > max)) + return FALSE; + + *id1 = (UINT16)rc; + rc = strtoul(++mid, &end, 16); + + if ((end == mid) || (rc > max)) + return FALSE; + + *id2 = (UINT16)rc; + + *str += end - *str; + if (*end == '\0') + return TRUE; + if (*end == delimiter) { - bus_number = 0; - dev_number = 0; - idVendor = 0; - idProduct = 0; - sprintf_s(hardware_id, ARRAYSIZE(hardware_id), "%s", token); - token = strtok(NULL, "#"); + (*str)++; + return TRUE; + } - if (udevman->flags & UDEVMAN_FLAG_ADD_BY_VID_PID) + return FALSE; +} + +static BOOL urbdrc_udevman_register_devices(UDEVMAN* udevman, const char* devices, BOOL add_by_addr) +{ + const char* pos = devices; + VID_PID_PAIR* idpair; + UINT16 id1, id2; + + while (*pos != '\0') + { + if (!udevman_parse_device_id_addr(&pos, &id1, &id2, (add_by_addr) ? UINT8_MAX : UINT16_MAX, + ':', '#')) { - udevman_parse_device_pid_vid(hardware_id, &idVendor, &idProduct, ':'); - success = udevman->iface.register_udevice((IUDEVMAN*) udevman, - 0, 0, UsbDevice, (UINT16) idVendor, (UINT16) idProduct, UDEVMAN_FLAG_ADD_BY_VID_PID); + WLog_ERR(TAG, "Invalid device argument: \"%s\"", devices); + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; } - else if (udevman->flags & UDEVMAN_FLAG_ADD_BY_ADDR) + + if (add_by_addr) { - udevman_parse_device_addr(hardware_id, &bus_number, &dev_number, ':'); - success = udevman->iface.register_udevice((IUDEVMAN*) udevman, - bus_number, dev_number, UsbDevice, 0, 0, UDEVMAN_FLAG_ADD_BY_ADDR); + add_device(&udevman->iface, DEVICE_ADD_FLAG_BUS | DEVICE_ADD_FLAG_DEV, (UINT8)id1, + (UINT8)id2, 0, 0); } + else + { + idpair = calloc(1, sizeof(VID_PID_PAIR)); + if (!idpair) + return CHANNEL_RC_NO_MEMORY; + idpair->vid = id1; + idpair->pid = id2; + if (ArrayList_Add(udevman->hotplug_vid_pids, idpair) == -1) + { + free(idpair); + return CHANNEL_RC_NO_MEMORY; + } - if (success) - UsbDevice++; + add_device(&udevman->iface, DEVICE_ADD_FLAG_VENDOR | DEVICE_ADD_FLAG_PRODUCT, 0, 0, id1, + id2); + } } - udevman->defUsbDevice = UsbDevice; + return CHANNEL_RC_OK; } -static void urbdrc_udevman_parse_addin_args(UDEVMAN* udevman, ADDIN_ARGV* args) +static UINT urbdrc_udevman_parse_addin_args(UDEVMAN* udevman, ADDIN_ARGV* args) { int status; - DWORD flags; + LPSTR devices = NULL; COMMAND_LINE_ARGUMENT_A* arg; - flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON; - status = CommandLineParseArgumentsA(args->argc, args->argv, - urbdrc_udevman_args, flags, udevman, NULL, NULL); + COMMAND_LINE_ARGUMENT_A urbdrc_udevman_args[] = { + { "dbg", COMMAND_LINE_VALUE_FLAG, "", NULL, BoolValueFalse, -1, NULL, "debug" }, + { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "device list" }, + { "id", COMMAND_LINE_VALUE_OPTIONAL, "", NULL, BoolValueFalse, -1, NULL, + "FLAG_ADD_BY_VID_PID" }, + { "addr", COMMAND_LINE_VALUE_OPTIONAL, "", NULL, BoolValueFalse, -1, NULL, + "FLAG_ADD_BY_ADDR" }, + { "auto", COMMAND_LINE_VALUE_FLAG, "", NULL, BoolValueFalse, -1, NULL, "FLAG_ADD_BY_AUTO" }, + { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } + }; + + status = CommandLineParseArgumentsA(args->argc, args->argv, urbdrc_udevman_args, + COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON, + udevman, NULL, NULL); + + if (status != CHANNEL_RC_OK) + return status; + arg = urbdrc_udevman_args; do { - if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) + if (!(arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT)) continue; - CommandLineSwitchStart(arg) - CommandLineSwitchCase(arg, "dbg") + CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "dbg") { WLog_SetLogLevel(WLog_Get(TAG), WLOG_TRACE); } CommandLineSwitchCase(arg, "dev") { - urbdrc_udevman_register_devices(udevman, arg->Value); + devices = arg->Value; } CommandLineSwitchCase(arg, "id") { - udevman->flags = UDEVMAN_FLAG_ADD_BY_VID_PID; + if (arg->Value) + udevman->devices_vid_pid = arg->Value; + else + udevman->flags = UDEVMAN_FLAG_ADD_BY_VID_PID; } CommandLineSwitchCase(arg, "addr") { - udevman->flags = UDEVMAN_FLAG_ADD_BY_ADDR; + if (arg->Value) + udevman->devices_addr = arg->Value; + else + udevman->flags = UDEVMAN_FLAG_ADD_BY_ADDR; } CommandLineSwitchCase(arg, "auto") { @@ -547,40 +744,200 @@ static void urbdrc_udevman_parse_addin_args(UDEVMAN* udevman, ADDIN_ARGV* args) { } CommandLineSwitchEnd(arg) + } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + + if (devices) + { + if (udevman->flags & UDEVMAN_FLAG_ADD_BY_VID_PID) + udevman->devices_vid_pid = devices; + else if (udevman->flags & UDEVMAN_FLAG_ADD_BY_ADDR) + udevman->devices_addr = devices; } - while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + + return CHANNEL_RC_OK; +} + +static UINT udevman_listener_created_callback(IUDEVMAN* iudevman) +{ + UINT status; + UDEVMAN* udevman = (UDEVMAN*)iudevman; + + if (udevman->devices_vid_pid) + { + status = urbdrc_udevman_register_devices(udevman, udevman->devices_vid_pid, FALSE); + if (status != CHANNEL_RC_OK) + return status; + } + + if (udevman->devices_addr) + return urbdrc_udevman_register_devices(udevman, udevman->devices_addr, TRUE); + + return CHANNEL_RC_OK; +} + +static void udevman_load_interface(UDEVMAN* udevman) +{ + /* standard */ + udevman->iface.free = udevman_free; + /* manage devices */ + udevman->iface.rewind = udevman_rewind; + udevman->iface.get_next = udevman_get_next; + udevman->iface.has_next = udevman_has_next; + udevman->iface.register_udevice = udevman_register_udevice; + udevman->iface.unregister_udevice = udevman_unregister_udevice; + udevman->iface.get_udevice_by_UsbDevice = udevman_get_udevice_by_UsbDevice; + /* Extension */ + udevman->iface.isAutoAdd = udevman_is_auto_add; + /* Basic state */ + BASIC_STATE_FUNC_REGISTER(device_num, udevman); + BASIC_STATE_FUNC_REGISTER(next_device_id, udevman); + + /* control semaphore or mutex lock */ + udevman->iface.loading_lock = udevman_loading_lock; + udevman->iface.loading_unlock = udevman_loading_unlock; + udevman->iface.initialize = udevman_initialize; + udevman->iface.listener_created_callback = udevman_listener_created_callback; +} + +static BOOL poll_libusb_events(UDEVMAN* udevman) +{ + int rc = LIBUSB_SUCCESS; + struct timeval tv = { 0, 500 }; + if (libusb_try_lock_events(udevman->context)) + { + if (libusb_event_handling_ok(udevman->context)) + { + rc = libusb_handle_events_locked(udevman->context, &tv); + if (rc != LIBUSB_SUCCESS) + WLog_WARN(TAG, "libusb_handle_events_locked %d", rc); + } + libusb_unlock_events(udevman->context); + } + else + { + libusb_lock_event_waiters(udevman->context); + if (libusb_event_handler_active(udevman->context)) + { + rc = libusb_wait_for_event(udevman->context, &tv); + if (rc < LIBUSB_SUCCESS) + WLog_WARN(TAG, "libusb_wait_for_event %d", rc); + } + libusb_unlock_event_waiters(udevman->context); + } + + return rc > 0; +} + +static DWORD poll_thread(LPVOID lpThreadParameter) +{ + libusb_hotplug_callback_handle handle; + UDEVMAN* udevman = (UDEVMAN*)lpThreadParameter; + BOOL hasHotplug = libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG); + + if (hasHotplug) + { + int rc = libusb_hotplug_register_callback( + udevman->context, + LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, + LIBUSB_HOTPLUG_NO_FLAGS, LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY, + LIBUSB_HOTPLUG_MATCH_ANY, hotplug_callback, udevman, &handle); + + if (rc != LIBUSB_SUCCESS) + udevman->running = FALSE; + } + else + WLog_WARN(TAG, "Platform does not support libusb hotplug. USB devices plugged in later " + "will not be detected."); + + while (udevman->running) + { + poll_libusb_events(udevman); + } + + if (hasHotplug) + libusb_hotplug_deregister_callback(udevman->context, handle); + + /* Process remaining usb events */ + while (poll_libusb_events(udevman)) + ; + + ExitThread(0); + return 0; } #ifdef BUILTIN_CHANNELS -#define freerdp_urbdrc_client_subsystem_entry libusb_freerdp_urbdrc_client_subsystem_entry +#define freerdp_urbdrc_client_subsystem_entry libusb_freerdp_urbdrc_client_subsystem_entry #else -#define freerdp_urbdrc_client_subsystem_entry FREERDP_API freerdp_urbdrc_client_subsystem_entry +#define freerdp_urbdrc_client_subsystem_entry FREERDP_API freerdp_urbdrc_client_subsystem_entry #endif - -int freerdp_urbdrc_client_subsystem_entry(PFREERDP_URBDRC_SERVICE_ENTRY_POINTS pEntryPoints) +UINT freerdp_urbdrc_client_subsystem_entry(PFREERDP_URBDRC_SERVICE_ENTRY_POINTS pEntryPoints) { + UINT rc; + UINT status; UDEVMAN* udevman; ADDIN_ARGV* args = pEntryPoints->args; - libusb_init(NULL); - udevman = (PUDEVMAN) malloc(sizeof(UDEVMAN)); + udevman = (PUDEVMAN)calloc(1, sizeof(UDEVMAN)); if (!udevman) - return -1; + goto fail; + + udevman->hotplug_vid_pids = ArrayList_New(TRUE); + if (!udevman->hotplug_vid_pids) + goto fail; + ArrayList_Object(udevman->hotplug_vid_pids)->fnObjectFree = free; + ArrayList_Object(udevman->hotplug_vid_pids)->fnObjectEquals = udevman_vid_pid_pair_equals; + + udevman->next_device_id = BASE_USBDEVICE_NUM; + udevman->iface.plugin = pEntryPoints->plugin; + rc = libusb_init(&udevman->context); + + if (rc != LIBUSB_SUCCESS) + goto fail; + +#ifdef _WIN32 +#if LIBUSB_API_VERSION >= 0x01000106 + /* Prefer usbDK backend on windows. Not supported on other platforms. */ + rc = libusb_set_option(udevman->context, LIBUSB_OPTION_USE_USBDK); + switch (rc) + { + case LIBUSB_SUCCESS: + break; + case LIBUSB_ERROR_NOT_FOUND: + case LIBUSB_ERROR_NOT_SUPPORTED: + WLog_WARN(TAG, "LIBUSB_OPTION_USE_USBDK %s [%d]", libusb_strerror(rc), rc); + break; + default: + WLog_ERR(TAG, "LIBUSB_OPTION_USE_USBDK %s [%d]", libusb_strerror(rc), rc); + goto fail; + } +#endif +#endif - udevman->device_num = 0; - udevman->idev = NULL; - udevman->head = NULL; - udevman->tail = NULL; - udevman->sem_timeout = 0; udevman->flags = UDEVMAN_FLAG_ADD_BY_VID_PID; - pthread_mutex_init(&udevman->devman_loading, NULL); - sem_init(&udevman->sem_urb_lock, 0, MAX_URB_REQUSET_NUM); + udevman->devman_loading = CreateMutexA(NULL, FALSE, "devman_loading"); + + if (!udevman->devman_loading) + goto fail; + /* load usb device service management */ udevman_load_interface(udevman); - /* set debug flag, to enable Debug message for usb data transfer */ - libusb_debug = 10; - urbdrc_udevman_parse_addin_args(udevman, args); - pEntryPoints->pRegisterUDEVMAN(pEntryPoints->plugin, (IUDEVMAN*) udevman); + status = urbdrc_udevman_parse_addin_args(udevman, args); + + if (status != CHANNEL_RC_OK) + goto fail; + + udevman->running = TRUE; + udevman->thread = CreateThread(NULL, 0, poll_thread, udevman, 0, NULL); + + if (!udevman->thread) + goto fail; + + if (!pEntryPoints->pRegisterUDEVMAN(pEntryPoints->plugin, (IUDEVMAN*)udevman)) + goto fail; + WLog_DBG(TAG, "UDEVMAN device registered."); return 0; +fail: + udevman_free(&udevman->iface); + return ERROR_INTERNAL_ERROR; } diff --git a/channels/urbdrc/client/urbdrc_main.c b/channels/urbdrc/client/urbdrc_main.c index 19b78b1..2ed6a6f 100644 --- a/channels/urbdrc/client/urbdrc_main.c +++ b/channels/urbdrc/client/urbdrc_main.c @@ -22,20 +22,10 @@ #include #include #include -#include -#include #include -#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) -#include -#include -#include -#include -#include -#endif -#if defined(__linux__) -#include -#endif +#include +#include #include #include @@ -45,103 +35,58 @@ #include #include #include +#include #include "urbdrc_types.h" #include "urbdrc_main.h" #include "data_transfer.h" -#include "searchman.h" -static int func_hardware_id_format(IUDEVICE* pdev, char(*HardwareIds)[DEVICE_HARDWARE_ID_SIZE]) -{ - char str[DEVICE_HARDWARE_ID_SIZE]; - UINT16 idVendor, idProduct, bcdDevice; - idVendor = (UINT16)pdev->query_device_descriptor(pdev, ID_VENDOR); - idProduct = (UINT16)pdev->query_device_descriptor(pdev, ID_PRODUCT); - bcdDevice = (UINT16)pdev->query_device_descriptor(pdev, BCD_DEVICE); - sprintf_s(str, sizeof(str), "USB\\VID_%04"PRIX16"&PID_%04"PRIX16"", idVendor, idProduct); - strncpy(HardwareIds[1], str, DEVICE_HARDWARE_ID_SIZE); - sprintf_s(str, sizeof(str), "%s&REV_%04"PRIX16"", HardwareIds[1], bcdDevice); - strncpy(HardwareIds[0], str, DEVICE_HARDWARE_ID_SIZE); - return 0; -} +#include -static int func_compat_id_format(IUDEVICE* pdev, - char(*CompatibilityIds)[DEVICE_COMPATIBILITY_ID_SIZE]) +static BOOL Stream_Write_UTF16_String_From_Utf8(wStream* s, const char* utf8, size_t len) { - char str[DEVICE_COMPATIBILITY_ID_SIZE]; - UINT8 bDeviceClass, bDeviceSubClass, bDeviceProtocol; - bDeviceClass = (UINT8)pdev->query_device_descriptor(pdev, B_DEVICE_CLASS); - bDeviceSubClass = (UINT8)pdev->query_device_descriptor(pdev, B_DEVICE_SUBCLASS); - bDeviceProtocol = (UINT8)pdev->query_device_descriptor(pdev, B_DEVICE_PROTOCOL); + BOOL ret; + WCHAR* utf16; + int rc; - if (!(pdev->isCompositeDevice(pdev))) - { - sprintf_s(str, sizeof(str), "USB\\Class_%02"PRIX8"", bDeviceClass); - strncpy(CompatibilityIds[2], str, DEVICE_COMPATIBILITY_ID_SIZE); - sprintf_s(str, sizeof(str), "%s&SubClass_%02"PRIX8"", CompatibilityIds[2], bDeviceSubClass); - strncpy(CompatibilityIds[1], str, DEVICE_COMPATIBILITY_ID_SIZE); - sprintf_s(str, sizeof(str), "%s&Prot_%02"PRIX8"", CompatibilityIds[1], bDeviceProtocol); - strncpy(CompatibilityIds[0], str, DEVICE_COMPATIBILITY_ID_SIZE); - } - else - { - sprintf_s(str, sizeof(str), "USB\\DevClass_00"); - strncpy(CompatibilityIds[2], str, DEVICE_COMPATIBILITY_ID_SIZE); - sprintf_s(str, sizeof(str), "%s&SubClass_00", CompatibilityIds[2]); - strncpy(CompatibilityIds[1], str, DEVICE_COMPATIBILITY_ID_SIZE); - sprintf_s(str, sizeof(str), "%s&Prot_00", CompatibilityIds[1]); - strncpy(CompatibilityIds[0], str, DEVICE_COMPATIBILITY_ID_SIZE); - } + if (len > INT_MAX) + return FALSE; - return 0; -} + rc = ConvertToUnicode(CP_UTF8, 0, utf8, (int)len, &utf16, 0); -static void func_close_udevice(USB_SEARCHMAN* searchman, IUDEVICE* pdev) -{ - int idVendor = 0; - int idProduct = 0; - URBDRC_PLUGIN* urbdrc = searchman->urbdrc; - pdev->SigToEnd(pdev); - idVendor = pdev->query_device_descriptor(pdev, ID_VENDOR); - idProduct = pdev->query_device_descriptor(pdev, ID_PRODUCT); - searchman->add(searchman, (UINT16) idVendor, (UINT16) idProduct); - pdev->cancel_all_transfer_request(pdev); - pdev->wait_action_completion(pdev); -#if ISOCH_FIFO - { - /* free isoch queue */ - ISOCH_CALLBACK_QUEUE* isoch_queue = pdev->get_isoch_queue(pdev); + if (rc < 0) + return FALSE; - if (isoch_queue) - isoch_queue->free(isoch_queue); - } -#endif - urbdrc->udevman->unregister_udevice(urbdrc->udevman, - pdev->get_bus_number(pdev), - pdev->get_dev_number(pdev)); + ret = Stream_Write_UTF16_String(s, utf16, (size_t)rc); + free(utf16); + return ret; } -static int fun_device_string_send_set(char* out_data, int out_offset, char* str) +static IWTSVirtualChannel* get_channel(IUDEVMAN* idevman) { - int i = 0; - int offset = 0; + IWTSVirtualChannelManager* channel_mgr; + URBDRC_PLUGIN* urbdrc; - while (str[i]) - { - data_write_UINT16(out_data + out_offset + offset, str[i]); /* str */ - i++; - offset += 2; - } + if (!idevman) + return NULL; + + urbdrc = (URBDRC_PLUGIN*)idevman->plugin; - data_write_UINT16(out_data + out_offset + offset, 0x0000); /* add "\0" */ - offset += 2; - return offset + out_offset; + if (!urbdrc || !urbdrc->listener_callback) + return NULL; + + channel_mgr = urbdrc->listener_callback->channel_mgr; + + if (!channel_mgr) + return NULL; + + return channel_mgr->FindChannelById(channel_mgr, idevman->controlChannelId); } static int func_container_id_generate(IUDEVICE* pdev, char* strContainerId) { - char* p, *path; - UINT8 containerId[17]; + char *p, *path; + UINT8 containerId[17] = { 0 }; UINT16 idVendor, idProduct; idVendor = (UINT16)pdev->query_device_descriptor(pdev, ID_VENDOR); idProduct = (UINT16)pdev->query_device_descriptor(pdev, ID_PRODUCT); @@ -152,102 +97,72 @@ static int func_container_id_generate(IUDEVICE* pdev, char* strContainerId) else p = path; - ZeroMemory(containerId, sizeof(containerId)); - sprintf_s((char*)containerId, sizeof(containerId), "%04"PRIX16"%04"PRIX16"%s", idVendor, idProduct, - p); + sprintf_s((char*)containerId, sizeof(containerId), "%04" PRIX16 "%04" PRIX16 "%s", idVendor, + idProduct, p); /* format */ sprintf_s(strContainerId, DEVICE_CONTAINER_STR_SIZE, - "{%02"PRIx8"%02"PRIx8"%02"PRIx8"%02"PRIx8"-%02"PRIx8"%02"PRIx8"-%02"PRIx8"%02"PRIx8"-%02"PRIx8"%02"PRIx8"-%02"PRIx8"%02"PRIx8"%02"PRIx8"%02"PRIx8"%02"PRIx8"%02"PRIx8"}", - containerId[0], containerId[1], containerId[2], containerId[3], - containerId[4], containerId[5], containerId[6], containerId[7], - containerId[8], containerId[9], containerId[10], containerId[11], - containerId[12], containerId[13], containerId[14], containerId[15]); + "{%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "-%02" PRIx8 "%02" PRIx8 "-%02" PRIx8 + "%02" PRIx8 "-%02" PRIx8 "%02" PRIx8 "-%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 + "%02" PRIx8 "%02" PRIx8 "}", + containerId[0], containerId[1], containerId[2], containerId[3], containerId[4], + containerId[5], containerId[6], containerId[7], containerId[8], containerId[9], + containerId[10], containerId[11], containerId[12], containerId[13], containerId[14], + containerId[15]); return 0; } -static int func_instance_id_generate(IUDEVICE* pdev, char* strInstanceId) +static int func_instance_id_generate(IUDEVICE* pdev, char* strInstanceId, size_t len) { - UINT8 instanceId[17]; - ZeroMemory(instanceId, sizeof(instanceId)); - sprintf_s((char*)instanceId, sizeof(instanceId), "\\%s", pdev->getPath(pdev)); + char instanceId[17] = { 0 }; + sprintf_s(instanceId, sizeof(instanceId), "\\%s", pdev->getPath(pdev)); /* format */ - sprintf_s(strInstanceId, DEVICE_INSTANCE_STR_SIZE, - "%02"PRIx8"%02"PRIx8"%02"PRIx8"%02"PRIx8"-%02"PRIx8"%02"PRIx8"-%02"PRIx8"%02"PRIx8"-%02"PRIx8"%02"PRIx8"-%02"PRIx8"%02"PRIx8"%02"PRIx8"%02"PRIx8"%02"PRIx8"%02"PRIx8"", - instanceId[0], instanceId[1], instanceId[2], instanceId[3], - instanceId[4], instanceId[5], instanceId[6], instanceId[7], - instanceId[8], instanceId[9], instanceId[10], instanceId[11], - instanceId[12], instanceId[13], instanceId[14], instanceId[15]); + sprintf_s(strInstanceId, len, + "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "-%02" PRIx8 "%02" PRIx8 "-%02" PRIx8 + "%02" PRIx8 "-%02" PRIx8 "%02" PRIx8 "-%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 + "%02" PRIx8 "%02" PRIx8 "", + instanceId[0], instanceId[1], instanceId[2], instanceId[3], instanceId[4], + instanceId[5], instanceId[6], instanceId[7], instanceId[8], instanceId[9], + instanceId[10], instanceId[11], instanceId[12], instanceId[13], instanceId[14], + instanceId[15]); return 0; } -#if ISOCH_FIFO - -static void func_lock_isoch_mutex(TRANSFER_DATA* transfer_data) -{ - int noAck = 0; - IUDEVICE* pdev; - UINT32 FunctionId; - UINT32 RequestField; - UINT16 URB_Function; - IUDEVMAN* udevman = transfer_data->udevman; - - if (transfer_data->cbSize >= 8) - { - data_read_UINT32(transfer_data->pBuffer + 4, FunctionId); - - if ((FunctionId == TRANSFER_IN_REQUEST || - FunctionId == TRANSFER_OUT_REQUEST) && - transfer_data->cbSize >= 16) - { - data_read_UINT16(transfer_data->pBuffer + 14, URB_Function); - - if (URB_Function == URB_FUNCTION_ISOCH_TRANSFER && - transfer_data->cbSize >= 20) - { - data_read_UINT32(transfer_data->pBuffer + 16, RequestField); - noAck = (RequestField & 0x80000000) >> 31; - - if (!noAck) - { - pdev = udevman->get_udevice_by_UsbDevice(udevman, transfer_data->UsbDevice); - pdev->lock_fifo_isoch(pdev); - } - } - } - } -} - -#endif - /** * Function description * * @return 0 on success, otherwise a Win32 error code */ -static UINT urbdrc_process_capability_request(URBDRC_CHANNEL_CALLBACK* callback, char* data, - UINT32 data_sizem, UINT32 MessageId) +static UINT urbdrc_process_capability_request(URBDRC_CHANNEL_CALLBACK* callback, wStream* s, + UINT32 MessageId) { UINT32 InterfaceId; UINT32 Version; UINT32 out_size; - char* out_data; - UINT ret; - WLog_VRB(TAG, ""); - data_read_UINT32(data + 0, Version); + wStream* out; + + if (!callback || !s) + return ERROR_INVALID_PARAMETER; + + if (Stream_GetRemainingLength(s) < 4) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, Version); + + if (Version > RIM_CAPABILITY_VERSION_01) + Version = RIM_CAPABILITY_VERSION_01; + InterfaceId = ((STREAM_ID_NONE << 30) | CAPABILITIES_NEGOTIATOR); out_size = 16; - out_data = (char*) calloc(1, out_size); + out = Stream_New(NULL, out_size); - if (!out_data) + if (!out) return ERROR_OUTOFMEMORY; - data_write_UINT32(out_data + 0, InterfaceId); /* interface id */ - data_write_UINT32(out_data + 4, MessageId); /* message id */ - data_write_UINT32(out_data + 8, Version); /* usb protocol version */ - data_write_UINT32(out_data + 12, 0x00000000); /* HRESULT */ - ret = callback->channel->Write(callback->channel, out_size, (BYTE*) out_data, NULL); - zfree(out_data); - return ret; + Stream_Write_UINT32(out, InterfaceId); /* interface id */ + Stream_Write_UINT32(out, MessageId); /* message id */ + Stream_Write_UINT32(out, Version); /* usb protocol version */ + Stream_Write_UINT32(out, 0x00000000); /* HRESULT */ + return stream_write_and_free(callback->plugin, callback->channel, out); } /** @@ -255,56 +170,68 @@ static UINT urbdrc_process_capability_request(URBDRC_CHANNEL_CALLBACK* callback, * * @return 0 on success, otherwise a Win32 error code */ -static UINT urbdrc_process_channel_create(URBDRC_CHANNEL_CALLBACK* callback, char* data, - UINT32 data_sizem, UINT32 MessageId) +static UINT urbdrc_process_channel_create(URBDRC_CHANNEL_CALLBACK* callback, wStream* s, + UINT32 MessageId) { UINT32 InterfaceId; UINT32 out_size; UINT32 MajorVersion; UINT32 MinorVersion; UINT32 Capabilities; - char* out_data; - UINT ret; - WLog_VRB(TAG, ""); - data_read_UINT32(data + 0, MajorVersion); - data_read_UINT32(data + 4, MinorVersion); - data_read_UINT32(data + 8, Capabilities); + wStream* out; + URBDRC_PLUGIN* urbdrc; + + if (!callback || !s || !callback->plugin) + return ERROR_INVALID_PARAMETER; + + urbdrc = (URBDRC_PLUGIN*)callback->plugin; + + if (Stream_GetRemainingLength(s) < 12) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, MajorVersion); + Stream_Read_UINT32(s, MinorVersion); + Stream_Read_UINT32(s, Capabilities); + + /* Version check, we only support version 1.0 */ + if ((MajorVersion != 1) || (MinorVersion != 0)) + { + WLog_Print(urbdrc->log, WLOG_WARN, + "server supports USB channel version %" PRIu32 ".%" PRIu32); + WLog_Print(urbdrc->log, WLOG_WARN, "we only support channel version 1.0"); + MajorVersion = 1; + MinorVersion = 0; + } + InterfaceId = ((STREAM_ID_PROXY << 30) | CLIENT_CHANNEL_NOTIFICATION); out_size = 24; - out_data = (char*) calloc(1, out_size); + out = Stream_New(NULL, out_size); - if (!out_data) + if (!out) return ERROR_OUTOFMEMORY; - data_write_UINT32(out_data + 0, InterfaceId); /* interface id */ - data_write_UINT32(out_data + 4, MessageId); /* message id */ - data_write_UINT32(out_data + 8, CHANNEL_CREATED); /* function id */ - data_write_UINT32(out_data + 12, MajorVersion); - data_write_UINT32(out_data + 16, MinorVersion); - data_write_UINT32(out_data + 20, Capabilities); /* capabilities version */ - ret = callback->channel->Write(callback->channel, out_size, (BYTE*)out_data, NULL); - zfree(out_data); - return ret; + Stream_Write_UINT32(out, InterfaceId); /* interface id */ + Stream_Write_UINT32(out, MessageId); /* message id */ + Stream_Write_UINT32(out, CHANNEL_CREATED); /* function id */ + Stream_Write_UINT32(out, MajorVersion); + Stream_Write_UINT32(out, MinorVersion); + Stream_Write_UINT32(out, Capabilities); /* capabilities version */ + return stream_write_and_free(callback->plugin, callback->channel, out); } -static int urdbrc_send_virtual_channel_add(IWTSVirtualChannel* channel, UINT32 MessageId) +static UINT urdbrc_send_virtual_channel_add(IWTSPlugin* plugin, IWTSVirtualChannel* channel, + UINT32 MessageId) { - UINT32 out_size; - UINT32 InterfaceId; - char* out_data; - WLog_VRB(TAG, ""); - assert(NULL != channel); - assert(NULL != channel->Write); - InterfaceId = ((STREAM_ID_PROXY << 30) | CLIENT_DEVICE_SINK); - out_size = 12; - out_data = (char*) malloc(out_size); - memset(out_data, 0, out_size); - data_write_UINT32(out_data + 0, InterfaceId); /* interface */ - data_write_UINT32(out_data + 4, MessageId); /* message id */ - data_write_UINT32(out_data + 8, ADD_VIRTUAL_CHANNEL); /* function id */ - channel->Write(channel, out_size, (BYTE*) out_data, NULL); - zfree(out_data); - return 0; + const UINT32 InterfaceId = ((STREAM_ID_PROXY << 30) | CLIENT_DEVICE_SINK); + wStream* out = Stream_New(NULL, 12); + + if (!out) + return ERROR_OUTOFMEMORY; + + Stream_Write_UINT32(out, InterfaceId); /* interface */ + Stream_Write_UINT32(out, MessageId); /* message id */ + Stream_Write_UINT32(out, ADD_VIRTUAL_CHANNEL); /* function id */ + return stream_write_and_free(plugin, channel, out); } /** @@ -314,106 +241,133 @@ static int urdbrc_send_virtual_channel_add(IWTSVirtualChannel* channel, UINT32 M */ static UINT urdbrc_send_usb_device_add(URBDRC_CHANNEL_CALLBACK* callback, IUDEVICE* pdev) { - char* out_data; + wStream* out; UINT32 InterfaceId; - char HardwareIds[2][DEVICE_HARDWARE_ID_SIZE]; - char CompatibilityIds[3][DEVICE_COMPATIBILITY_ID_SIZE]; - char strContainerId[DEVICE_CONTAINER_STR_SIZE]; - char strInstanceId[DEVICE_INSTANCE_STR_SIZE]; - char* composite_str = "USB\\COMPOSITE"; - int size, out_offset, cchCompatIds, bcdUSB; - ISOCH_CALLBACK_QUEUE* cb_queue; - UINT ret; - WLog_VRB(TAG, ""); + char HardwareIds[2][DEVICE_HARDWARE_ID_SIZE] = { { 0 } }; + char CompatibilityIds[3][DEVICE_COMPATIBILITY_ID_SIZE] = { { 0 } }; + char strContainerId[DEVICE_CONTAINER_STR_SIZE] = { 0 }; + char strInstanceId[DEVICE_INSTANCE_STR_SIZE] = { 0 }; + const char* composite_str = "USB\\COMPOSITE"; + const size_t composite_len = 13; + size_t size; + size_t CompatibilityIdLen[3]; + size_t HardwareIdsLen[2]; + size_t ContainerIdLen, InstanceIdLen; + size_t cchCompatIds; + UINT32 bcdUSB; InterfaceId = ((STREAM_ID_PROXY << 30) | CLIENT_DEVICE_SINK); /* USB kernel driver detach!! */ pdev->detach_kernel_driver(pdev); -#if ISOCH_FIFO - /* create/initial isoch queue */ - cb_queue = isoch_queue_new(); - - if (!cb_queue) - return ERROR_OUTOFMEMORY; + { + const UINT16 idVendor = (UINT16)pdev->query_device_descriptor(pdev, ID_VENDOR); + const UINT16 idProduct = (UINT16)pdev->query_device_descriptor(pdev, ID_PRODUCT); + const UINT16 bcdDevice = (UINT16)pdev->query_device_descriptor(pdev, BCD_DEVICE); + sprintf_s(HardwareIds[1], DEVICE_HARDWARE_ID_SIZE, + "USB\\VID_%04" PRIX16 "&PID_%04" PRIX16 "", idVendor, idProduct); + sprintf_s(HardwareIds[0], DEVICE_HARDWARE_ID_SIZE, + "USB\\VID_%04" PRIX16 "&PID_%04" PRIX16 "&REV_%04" PRIX16 "", idVendor, idProduct, + bcdDevice); + } + { + const UINT8 bDeviceClass = (UINT8)pdev->query_device_descriptor(pdev, B_DEVICE_CLASS); + const UINT8 bDeviceSubClass = (UINT8)pdev->query_device_descriptor(pdev, B_DEVICE_SUBCLASS); + const UINT8 bDeviceProtocol = (UINT8)pdev->query_device_descriptor(pdev, B_DEVICE_PROTOCOL); - pdev->set_isoch_queue(pdev, (void*)cb_queue); -#endif - func_hardware_id_format(pdev, HardwareIds); - func_compat_id_format(pdev, CompatibilityIds); - func_instance_id_generate(pdev, strInstanceId); + if (!(pdev->isCompositeDevice(pdev))) + { + sprintf_s(CompatibilityIds[2], DEVICE_COMPATIBILITY_ID_SIZE, "USB\\Class_%02" PRIX8 "", + bDeviceClass); + sprintf_s(CompatibilityIds[1], DEVICE_COMPATIBILITY_ID_SIZE, + "USB\\Class_%02" PRIX8 "&SubClass_%02" PRIX8 "", bDeviceClass, + bDeviceSubClass); + sprintf_s(CompatibilityIds[0], DEVICE_COMPATIBILITY_ID_SIZE, + "USB\\Class_%02" PRIX8 "&SubClass_%02" PRIX8 "&Prot_%02" PRIX8 "", + bDeviceClass, bDeviceSubClass, bDeviceProtocol); + } + else + { + sprintf_s(CompatibilityIds[2], DEVICE_COMPATIBILITY_ID_SIZE, "USB\\DevClass_00"); + sprintf_s(CompatibilityIds[1], DEVICE_COMPATIBILITY_ID_SIZE, + "USB\\DevClass_00&SubClass_00"); + sprintf_s(CompatibilityIds[0], DEVICE_COMPATIBILITY_ID_SIZE, + "USB\\DevClass_00&SubClass_00&Prot_00"); + } + } + func_instance_id_generate(pdev, strInstanceId, DEVICE_INSTANCE_STR_SIZE); func_container_id_generate(pdev, strContainerId); - cchCompatIds = strlen(CompatibilityIds[0]) + 1 + - strlen(CompatibilityIds[1]) + 1 + - strlen(CompatibilityIds[2]) + 2; + CompatibilityIdLen[0] = strnlen(CompatibilityIds[0], sizeof(CompatibilityIds[0])); + CompatibilityIdLen[1] = strnlen(CompatibilityIds[1], sizeof(CompatibilityIds[1])); + CompatibilityIdLen[2] = strnlen(CompatibilityIds[2], sizeof(CompatibilityIds[2])); + HardwareIdsLen[0] = strnlen(HardwareIds[0], sizeof(HardwareIds[0])); + HardwareIdsLen[1] = strnlen(HardwareIds[1], sizeof(HardwareIds[1])); + cchCompatIds = + CompatibilityIdLen[0] + 1 + CompatibilityIdLen[1] + 1 + CompatibilityIdLen[2] + 2; + InstanceIdLen = strnlen(strInstanceId, sizeof(strInstanceId)); + ContainerIdLen = strnlen(strContainerId, sizeof(strContainerId)); if (pdev->isCompositeDevice(pdev)) - cchCompatIds += strlen(composite_str) + 1; + cchCompatIds += composite_len + 1; - out_offset = 24; size = 24; - size += (strlen(strInstanceId) + 1) * 2 + - (strlen(HardwareIds[0]) + 1) * 2 + 4 + - (strlen(HardwareIds[1]) + 1) * 2 + 2 + - 4 + (cchCompatIds) * 2 + - (strlen(strContainerId) + 1) * 2 + 4 + 28; - out_data = (char*)calloc(1, size); - - if (!out_data) + size += (InstanceIdLen + 1) * 2 + (HardwareIdsLen[0] + 1) * 2 + 4 + + (HardwareIdsLen[1] + 1) * 2 + 2 + 4 + (cchCompatIds)*2 + (ContainerIdLen + 1) * 2 + 4 + + 28; + out = Stream_New(NULL, size); + + if (!out) return ERROR_OUTOFMEMORY; - data_write_UINT32(out_data + 0, InterfaceId); /* interface */ - /* data_write_UINT32(out_data + 4, 0);*/ /* message id */ - data_write_UINT32(out_data + 8, ADD_DEVICE); /* function id */ - data_write_UINT32(out_data + 12, 0x00000001); /* NumUsbDevice */ - data_write_UINT32(out_data + 16, pdev->get_UsbDevice(pdev)); /* UsbDevice */ - data_write_UINT32(out_data + 20, 0x00000025); /* cchDeviceInstanceId */ - out_offset = fun_device_string_send_set(out_data, out_offset, strInstanceId); - data_write_UINT32(out_data + out_offset, 0x00000036); /* cchHwIds */ - out_offset += 4; + Stream_Write_UINT32(out, InterfaceId); /* interface */ + Stream_Write_UINT32(out, 0); + Stream_Write_UINT32(out, ADD_DEVICE); /* function id */ + Stream_Write_UINT32(out, 0x00000001); /* NumUsbDevice */ + Stream_Write_UINT32(out, pdev->get_UsbDevice(pdev)); /* UsbDevice */ + Stream_Write_UINT32(out, (UINT32)InstanceIdLen + 1); /* cchDeviceInstanceId */ + Stream_Write_UTF16_String_From_Utf8(out, strInstanceId, InstanceIdLen); + Stream_Write_UINT16(out, 0); + Stream_Write_UINT32(out, HardwareIdsLen[0] + HardwareIdsLen[1] + 3); /* cchHwIds */ /* HardwareIds 1 */ - out_offset = fun_device_string_send_set(out_data, out_offset, HardwareIds[0]); - /* HardwareIds 2 */ - out_offset = fun_device_string_send_set(out_data, out_offset, HardwareIds[1]); - /*data_write_UINT16(out_data + out_offset, 0x0000);*/ /* add "\0" */ - out_offset += 2; - data_write_UINT32(out_data + out_offset, cchCompatIds); /* cchCompatIds */ - out_offset += 4; - /* CompatibilityIds 1 */ - out_offset = fun_device_string_send_set(out_data, out_offset, CompatibilityIds[0]); - /* CompatibilityIds 2 */ - out_offset = fun_device_string_send_set(out_data, out_offset, CompatibilityIds[1]); - /* CompatibilityIds 3 */ - out_offset = fun_device_string_send_set(out_data, out_offset, CompatibilityIds[2]); + Stream_Write_UTF16_String_From_Utf8(out, HardwareIds[0], HardwareIdsLen[0]); + Stream_Write_UINT16(out, 0); + Stream_Write_UTF16_String_From_Utf8(out, HardwareIds[1], HardwareIdsLen[1]); + Stream_Write_UINT16(out, 0); + Stream_Write_UINT16(out, 0); /* add "\0" */ + Stream_Write_UINT32(out, (UINT32)cchCompatIds); /* cchCompatIds */ + /* CompatibilityIds */ + Stream_Write_UTF16_String_From_Utf8(out, CompatibilityIds[0], CompatibilityIdLen[0]); + Stream_Write_UINT16(out, 0); + Stream_Write_UTF16_String_From_Utf8(out, CompatibilityIds[1], CompatibilityIdLen[1]); + Stream_Write_UINT16(out, 0); + Stream_Write_UTF16_String_From_Utf8(out, CompatibilityIds[2], CompatibilityIdLen[2]); + Stream_Write_UINT16(out, 0); if (pdev->isCompositeDevice(pdev)) - out_offset = fun_device_string_send_set(out_data, out_offset, composite_str); + { + Stream_Write_UTF16_String_From_Utf8(out, composite_str, composite_len); + Stream_Write_UINT16(out, 0); + } - /*data_write_UINT16(out_data + out_offset, 0x0000);*/ /* add "\0" */ - out_offset += 2; - data_write_UINT32(out_data + out_offset, 0x00000027); /* cchContainerId */ - out_offset += 4; + Stream_Write_UINT16(out, 0x0000); /* add "\0" */ + Stream_Write_UINT32(out, (UINT32)ContainerIdLen + 1); /* cchContainerId */ /* ContainerId */ - out_offset = fun_device_string_send_set(out_data, out_offset, strContainerId); + Stream_Write_UTF16_String_From_Utf8(out, strContainerId, ContainerIdLen); + Stream_Write_UINT16(out, 0); /* USB_DEVICE_CAPABILITIES 28 bytes */ - data_write_UINT32(out_data + out_offset, 0x0000001c); /* CbSize */ - data_write_UINT32(out_data + out_offset + 4, 2); /* UsbBusInterfaceVersion, 0 ,1 or 2 */ - data_write_UINT32(out_data + out_offset + 8, 0x600); /* USBDI_Version, 0x500 or 0x600 */ + Stream_Write_UINT32(out, 0x0000001c); /* CbSize */ + Stream_Write_UINT32(out, 2); /* UsbBusInterfaceVersion, 0 ,1 or 2 */ // TODO: Get from libusb + Stream_Write_UINT32(out, 0x600); /* USBDI_Version, 0x500 or 0x600 */ // TODO: Get from libusb /* Supported_USB_Version, 0x110,0x110 or 0x200(usb2.0) */ bcdUSB = pdev->query_device_descriptor(pdev, BCD_USB); - data_write_UINT32(out_data + out_offset + 12, bcdUSB); - data_write_UINT32(out_data + out_offset + 16, - 0x00000000); /* HcdCapabilities, MUST always be zero */ + Stream_Write_UINT32(out, bcdUSB); + Stream_Write_UINT32(out, 0x00000000); /* HcdCapabilities, MUST always be zero */ if (bcdUSB < 0x200) - data_write_UINT32(out_data + out_offset + 20, 0x00000000); /* DeviceIsHighSpeed */ + Stream_Write_UINT32(out, 0x00000000); /* DeviceIsHighSpeed */ else - data_write_UINT32(out_data + out_offset + 20, 0x00000001); /* DeviceIsHighSpeed */ + Stream_Write_UINT32(out, 0x00000001); /* DeviceIsHighSpeed */ - data_write_UINT32(out_data + out_offset + 24, - 0x50); /* NoAckIsochWriteJitterBufferSizeInMs, >=10 or <=512 */ - out_offset += 28; - ret = callback->channel->Write(callback->channel, out_offset, (BYTE*)out_data, NULL); - zfree(out_data); - return ret; + Stream_Write_UINT32(out, 0x50); /* NoAckIsochWriteJitterBufferSizeInMs, >=10 or <=512 */ + return stream_write_and_free(callback->plugin, callback->channel, out); } /** @@ -421,23 +375,34 @@ static UINT urdbrc_send_usb_device_add(URBDRC_CHANNEL_CALLBACK* callback, IUDEVI * * @return 0 on success, otherwise a Win32 error code */ -static UINT urbdrc_exchange_capabilities(URBDRC_CHANNEL_CALLBACK* callback, char* pBuffer, - UINT32 cbSize) +static UINT urbdrc_exchange_capabilities(URBDRC_CHANNEL_CALLBACK* callback, wStream* data) { UINT32 MessageId; UINT32 FunctionId; + UINT32 InterfaceId; UINT error = CHANNEL_RC_OK; - data_read_UINT32(pBuffer + 0, MessageId); - data_read_UINT32(pBuffer + 4, FunctionId); + + if (!data) + return ERROR_INVALID_PARAMETER; + + if (Stream_GetRemainingLength(data) < 8) + return ERROR_INVALID_DATA; + + Stream_Rewind_UINT32(data); + Stream_Read_UINT32(data, InterfaceId); + Stream_Read_UINT32(data, MessageId); + Stream_Read_UINT32(data, FunctionId); switch (FunctionId) { case RIM_EXCHANGE_CAPABILITY_REQUEST: - error = urbdrc_process_capability_request(callback, pBuffer + 8, cbSize - 8, MessageId); + error = urbdrc_process_capability_request(callback, data, MessageId); + break; + + case RIMCALL_RELEASE: break; default: - WLog_ERR(TAG, "%s: unknown FunctionId 0x%"PRIX32"", __FUNCTION__, FunctionId); error = ERROR_NOT_FOUND; break; } @@ -445,665 +410,59 @@ static UINT urbdrc_exchange_capabilities(URBDRC_CHANNEL_CALLBACK* callback, char return error; } -#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) -static char* devd_get_val(char* buf, size_t buf_size, const char* val_name, size_t val_name_size, - size_t* val_size) +static BOOL urbdrc_announce_devices(IUDEVMAN* udevman) { - char* ret, *buf_end, *ptr; - buf_end = (buf + buf_size); - - for (ret = buf; ret != NULL && ret < buf_end;) - { - ret = memmem(ret, (buf_end - ret), val_name, val_name_size); - - if (ret == NULL) - return NULL; + UINT error = ERROR_SUCCESS; - /* Found. */ - /* Check: space before or buf+1. */ - if ((buf + 1) < ret && ret[-1] != ' ') - { - ret += val_name_size; - continue; - } - - /* Check: = after name and size for value. */ - ret += val_name_size; - - if ((ret + 1) >= buf_end) - return NULL; - - if (ret[0] != '=') - continue; - - ret ++; - break; - } - - if (ret == NULL || val_size == NULL) - return ret; - - /* Calc value data size. */ - ptr = memchr(ret, ' ', (buf_end - ret)); - - if (ptr == NULL) /* End of string/last value. */ - ptr = buf_end; - - (*val_size) = (ptr - ret); - return ret; -} - -static void* urbdrc_search_usb_device(void* arg) -{ - USB_SEARCHMAN* searchman = (USB_SEARCHMAN*)arg; - URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)searchman->urbdrc; - IUDEVMAN* udevman = urbdrc->udevman; - IWTSVirtualChannelManager* channel_mgr = urbdrc->listener_callback->channel_mgr; - IWTSVirtualChannel* dvc_channel; - USB_SEARCHDEV* sdev; - IUDEVICE* pdev; - HANDLE listobj[2]; - HANDLE mon_fd; - int devd_skt; - char buf[4096], *val, *ptr, *end_val; - ssize_t data_size; - size_t val_size, tm; - long idVendor, idProduct; - long busnum, devnum; - int action, success, error, found, on_close; - struct sockaddr_un sun; - DWORD status; - UINT32 error; - WLog_DBG(TAG, "urbdrc_search_usb_device - devd: start"); - devd_skt = socket(PF_LOCAL, SOCK_SEQPACKET, 0); - - if (devd_skt == -1) - { - WLog_ERR(TAG, "Can't create devd socket: error = %i", errno); - goto err_out; - } - - memset(&sun, 0, sizeof(sun)); - sun.sun_family = PF_LOCAL; - sun.sun_len = sizeof(sun); - strlcpy(sun.sun_path, "/var/run/devd.seqpacket.pipe", sizeof(sun.sun_path)); - - if (-1 == connect(devd_skt, (struct sockaddr*)&sun, sizeof(sun))) - { - WLog_ERR(TAG, "Can't connect devd socket: error = %i - %s", errno, strerror(errno)); - goto err_out; - } - - /* Get the file descriptor (fd) for the monitor. - This fd will get passed to select() */ - mon_fd = CreateFileDescriptorEvent(NULL, TRUE, FALSE, devd_skt); - listobj[0] = searchman->term_event; - listobj[1] = mon_fd; + udevman->loading_lock(udevman); + udevman->rewind(udevman); - while (WaitForMultipleObjects(2, listobj, FALSE, INFINITE) != WAIT_OBJECT_0) + while (udevman->has_next(udevman)) { - status = WaitForMultipleObjects(2, listobj, FALSE, INFINITE); + IUDEVICE* pdev = udevman->get_next(udevman); - if (status == WAIT_FAILED) + if (!pdev->isAlreadySend(pdev)) { - error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); - return 0; - } - - if (status == WAIT_OBJECT_0) - break; - - errno = 0; - WLog_DBG(TAG, "======= SEARCH ======= "); - /* !system=USB subsystem=DEVICE type=ATTACH ugen=ugen3.3 cdev=ugen3.3 vendor=0x046d product=0x082d devclass=0xef devsubclass=0x02 sernum="6E7D726F" release=0x0011 mode=host port=4 parent=ugen3.1 */ - /* !system=USB subsystem=DEVICE type=DETACH ugen=ugen3.3 cdev=ugen3.3 vendor=0x046d product=0x082d devclass=0xef devsubclass=0x02 sernum="6E7D726F" release=0x0011 mode=host port=4 parent=ugen3.1 */ - data_size = read(devd_skt, buf, (sizeof(buf) - 1)); - - if (data_size == -1) - { - WLog_ERR(TAG, "devd socket read: error = %i", errno); - break; - } - - buf[data_size] = 0; - WLog_DBG(TAG, "devd event: %s", buf); - - if (buf[0] != '!') /* Skeep non notify events. */ - continue; - - /* Check: system=USB */ - val = devd_get_val(buf, data_size, "system", 6, &val_size); - - if (val == NULL || val_size != 3 || memcmp(val, "USB", 3) != 0) - continue; - - /* Check: subsystem=DEVICE */ - val = devd_get_val(buf, data_size, "subsystem", 9, &val_size); - - if (val == NULL || val_size != 6 || memcmp(val, "DEVICE", 6) != 0) - continue; - - /* Get event type. */ - val = devd_get_val(buf, data_size, "type", 4, &val_size); - - if (val == NULL || val_size != 6) - continue; - - action = -1; - - if (memcmp(val, "ATTACH", 6) == 0) - action = 0; - - if (memcmp(val, "DETACH", 6) == 0) - action = 1; - - if (action == -1) - continue; /* Skeep other actions. */ - - /* Get bus and dev num. */ - /* ugen=ugen3.3 */ - val = devd_get_val(buf, data_size, "ugen", 4, &val_size); - - if (val == NULL || val_size < 7 || memcmp(val, "ugen", 4) != 0) - continue; - - val += 4; - val_size -= 4; - ptr = memchr(val, '.', val_size); - - if (ptr == NULL) - continue; - - /* Prepare strings. */ - ptr[0] = 0; - ptr ++; - val[val_size] = 0; - /* Extract numbers. */ - busnum = strtol(val, NULL, 0); - - if (errno != 0) - continue; - - devnum = strtol(ptr, NULL, 0); - - if (errno != 0) - continue; - - /* Restore spaces. */ - ptr[-1] = ' '; - val[val_size] = ' '; - /* Handle event. */ - dvc_channel = NULL; - - switch (action) - { - case 0: /* ATTACH */ - sdev = NULL; - success = 0; - found = 0; - /* vendor=0x046d */ - val = devd_get_val(buf, data_size, "vendor", 6, &val_size); - - if (val == NULL || val_size < 1) - continue; - - val[val_size] = 0; - idVendor = strtol(val, NULL, 16); - - if (errno != 0) - continue; - - val[val_size] = ' '; - /* product=0x082d */ - val = devd_get_val(buf, data_size, "product", 7, &val_size); - - if (val == NULL || val_size < 1) - continue; - - val[val_size] = 0; - idProduct = strtol(val, NULL, 16); - - if (errno != 0) - continue; - - val[val_size] = ' '; - WLog_DBG(TAG, "ATTACH: bus: %i, dev: %i, ven: %i, prod: %i", busnum, devnum, idVendor, idProduct); - dvc_channel = channel_mgr->FindChannelById(channel_mgr, urbdrc->first_channel_id); - searchman->rewind(searchman); - - while (dvc_channel && searchman->has_next(searchman)) - { - sdev = searchman->get_next(searchman); - - if (sdev->idVendor == idVendor && - sdev->idProduct == idProduct) - { - WLog_VRB(TAG, "Searchman Found Device: %04"PRIx16":%04"PRIx16"", - sdev->idVendor, sdev->idProduct); - found = 1; - break; - } - } - - if (!found && udevman->isAutoAdd(udevman)) - { - WLog_VRB(TAG, "Auto Find Device: %04x:%04x ", - idVendor, idProduct); - found = 2; - } - - if (found) - { - success = udevman->register_udevice(udevman, busnum, devnum, - searchman->UsbDevice, 0, 0, UDEVMAN_FLAG_ADD_BY_ADDR); - } - - if (success) - { - searchman->UsbDevice ++; - usleep(400000); - error = urdbrc_send_virtual_channel_add(dvc_channel, 0); - - if (found == 1) - searchman->remove(searchman, sdev->idVendor, sdev->idProduct); - } - - break; - - case 1: /* DETACH */ - pdev = NULL; - on_close = 0; - WLog_DBG(TAG, "DETACH: bus: %i, dev: %i", busnum, devnum); - usleep(500000); - udevman->loading_lock(udevman); - udevman->rewind(udevman); - - while (udevman->has_next(udevman)) - { - pdev = udevman->get_next(udevman); - - if (pdev->get_bus_number(pdev) == busnum && - pdev->get_dev_number(pdev) == devnum) - { - dvc_channel = channel_mgr->FindChannelById(channel_mgr, pdev->get_channel_id(pdev)); - - if (dvc_channel == NULL) - { - WLog_ERR(TAG, "SEARCH: dvc_channel %d is NULL!!", pdev->get_channel_id(pdev)); - func_close_udevice(searchman, pdev); - break; - } - - if (!pdev->isSigToEnd(pdev)) - { - dvc_channel->Write(dvc_channel, 0, NULL, NULL); - pdev->SigToEnd(pdev); - } - - on_close = 1; - break; - } - } - - udevman->loading_unlock(udevman); - usleep(300000); - - if (pdev && on_close && dvc_channel && - pdev->isSigToEnd(pdev) && - !(pdev->isChannelClosed(pdev))) - { - dvc_channel->Close(dvc_channel); - } + const UINT32 deviceId = pdev->get_UsbDevice(pdev); + UINT error = + urdbrc_send_virtual_channel_add(udevman->plugin, get_channel(udevman), deviceId); + if (error != ERROR_SUCCESS) break; } } - CloseHandle(mon_fd); -err_out: - close(devd_skt); - sem_post(&searchman->sem_term); - WLog_DBG(TAG, "urbdrc_search_usb_device - devd: end"); - return 0; -} -#endif -#if defined (__linux__) -static void* urbdrc_search_usb_device(void* arg) -{ - USB_SEARCHMAN* searchman = (USB_SEARCHMAN*) arg; - URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*) searchman->urbdrc; - IUDEVMAN* udevman = urbdrc->udevman; - IWTSVirtualChannelManager* channel_mgr; - IWTSVirtualChannel* dvc_channel; - USB_SEARCHDEV* sdev; - IUDEVICE* pdev = NULL; - HANDLE listobj[2]; - HANDLE mon_fd; - int numobj, timeout; - long busnum, devnum; - int success = 0, on_close = 0, found = 0; - WLog_VRB(TAG, ""); - channel_mgr = urbdrc->listener_callback->channel_mgr; - DWORD status; - DWORD dwError; - /* init usb monitor */ - struct udev* udev; - struct udev_device* dev; - struct udev_monitor* mon; - udev = udev_new(); - - if (!udev) - { - WLog_ERR(TAG, "Can't create udev"); - return 0; - } - - /* Set up a monitor to monitor usb devices */ - mon = udev_monitor_new_from_netlink(udev, "udev"); - udev_monitor_filter_add_match_subsystem_devtype(mon, "usb", "usb_device"); - udev_monitor_enable_receiving(mon); - /* Get the file descriptor (fd) for the monitor. - This fd will get passed to select() */ - mon_fd = CreateFileDescriptorEvent(NULL, TRUE, FALSE, - udev_monitor_get_fd(mon), WINPR_FD_READ); - - if (!mon_fd) - goto fail_create_monfd_event; - - while (1) - { - WLog_VRB(TAG, "======= SEARCH ======= "); - busnum = 0; - devnum = 0; - sdev = NULL; - pdev = NULL; - dvc_channel = NULL; - on_close = 0; - listobj[0] = searchman->term_event; - listobj[1] = mon_fd; - numobj = 2; - status = WaitForMultipleObjects(numobj, listobj, FALSE, INFINITE); - - if (status == WAIT_FAILED) - { - dwError = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"!", dwError); - goto out; - } - - status = WaitForSingleObject(searchman->term_event, 0); - - if (status == WAIT_FAILED) - { - dwError = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", dwError); - goto out; - } - - if (status == WAIT_OBJECT_0) - { - sem_post(&searchman->sem_term); - goto out; - } - - status = WaitForSingleObject(mon_fd, 0); - - if (status == WAIT_FAILED) - { - dwError = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", dwError); - goto out; - } - - if (status == WAIT_OBJECT_0) - { - dev = udev_monitor_receive_device(mon); - - if (dev) - { - const char* action = udev_device_get_action(dev); - - if (strcmp(action, "add") == 0) - { - long idVendor, idProduct; - success = 0; - found = 0; - idVendor = strtol(udev_device_get_sysattr_value(dev, "idVendor"), NULL, 16); - - if (errno != 0) - continue; - - idProduct = strtol(udev_device_get_sysattr_value(dev, "idProduct"), NULL, 16); - - if (errno != 0) - continue; - - if (idVendor < 0 || idProduct < 0) - { - udev_device_unref(dev); - continue; - } - - busnum = strtol(udev_device_get_property_value(dev, "BUSNUM"), NULL, 0); - - if (errno != 0) - continue; - - devnum = strtol(udev_device_get_property_value(dev, "DEVNUM"), NULL, 0); - - if (errno != 0) - continue; - - dvc_channel = channel_mgr->FindChannelById(channel_mgr, - urbdrc->first_channel_id); - searchman->rewind(searchman); - - while (dvc_channel && searchman->has_next(searchman)) - { - sdev = searchman->get_next(searchman); - - if (sdev->idVendor == idVendor && - sdev->idProduct == idProduct) - { - WLog_VRB(TAG, "Searchman Find Device: %04"PRIx16":%04"PRIx16"", - sdev->idVendor, sdev->idProduct); - found = 1; - break; - } - } - - if (!found && udevman->isAutoAdd(udevman)) - { - WLog_VRB(TAG, "Auto Find Device: %04x:%04x ", - idVendor, idProduct); - found = 2; - } - - if (found) - { - success = udevman->register_udevice(udevman, busnum, devnum, - searchman->UsbDevice, 0, 0, UDEVMAN_FLAG_ADD_BY_ADDR); - } - - if (success) - { - searchman->UsbDevice++; - /* when we send the usb device add request, - * we will detach the device driver at same - * time. But, if the time of detach the - * driver and attach driver is too close, - * the system will crash. workaround: we - * wait it for some time to avoid system - * crash. */ - listobj[0] = searchman->term_event; - numobj = 1; - timeout = 4000; /* milliseconds */ - status = WaitForMultipleObjects(numobj, listobj, FALSE, timeout); - - if (status == WAIT_FAILED) - { - dwError = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"!", dwError); - goto out; - } - - status = WaitForSingleObject(searchman->term_event, 0); - - if (status == WAIT_FAILED) - { - dwError = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"!", dwError); - goto out; - } - - if (status == WAIT_OBJECT_0) - { - CloseHandle(mon_fd); - sem_post(&searchman->sem_term); - return 0; - } - - urdbrc_send_virtual_channel_add(dvc_channel, 0); - - if (found == 1) - searchman->remove(searchman, sdev->idVendor, sdev->idProduct); - } - } - else if (strcmp(action, "remove") == 0) - { - busnum = strtol(udev_device_get_property_value(dev, "BUSNUM"), NULL, 0); - - if (errno != 0) - goto out; - - devnum = strtol(udev_device_get_property_value(dev, "DEVNUM"), NULL, 0); - - if (errno != 0) - goto out; - - usleep(500000); - udevman->loading_lock(udevman); - udevman->rewind(udevman); - - while (udevman->has_next(udevman)) - { - pdev = udevman->get_next(udevman); - - if (pdev->get_bus_number(pdev) == busnum && pdev->get_dev_number(pdev) == devnum) - { - dvc_channel = channel_mgr->FindChannelById(channel_mgr, pdev->get_channel_id(pdev)); - - if (dvc_channel == NULL) - { - WLog_ERR(TAG, "SEARCH: dvc_channel %d is NULL!!", pdev->get_channel_id(pdev)); - func_close_udevice(searchman, pdev); - break; - } - - if (!pdev->isSigToEnd(pdev)) - { - dvc_channel->Write(dvc_channel, 0, NULL, NULL); - pdev->SigToEnd(pdev); - } - - on_close = 1; - break; - } - } - - udevman->loading_unlock(udevman); - listobj[0] = searchman->term_event; - numobj = 1; - timeout = 3000; /* milliseconds */ - status = WaitForMultipleObjects(numobj, listobj, FALSE, timeout); - - if (status == WAIT_FAILED) - { - dwError = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"!", dwError); - goto out; - } - - status = WaitForSingleObject(searchman->term_event, 0); - - if (status == WAIT_FAILED) - { - dwError = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", dwError); - goto out; - } - - if (status == WAIT_OBJECT_0) - { - CloseHandle(mon_fd); - sem_post(&searchman->sem_term); - return 0; - } - - if (pdev && on_close && dvc_channel && pdev->isSigToEnd(pdev) && !(pdev->isChannelClosed(pdev))) - { - on_close = 0; - dvc_channel->Close(dvc_channel); - } - } - - udev_device_unref(dev); - } - else - { - WLog_ERR(TAG, "No Device from receive_device(). An error occurred."); - } - } - } + udevman->loading_unlock(udevman); -out: - CloseHandle(mon_fd); -fail_create_monfd_event: - sem_post(&searchman->sem_term); - return 0; + return error == ERROR_SUCCESS; } -#endif -void* urbdrc_new_device_create(void* arg) +static UINT urbdrc_device_control_channel(URBDRC_CHANNEL_CALLBACK* callback, wStream* s) { - TRANSFER_DATA* transfer_data = (TRANSFER_DATA*) arg; - URBDRC_CHANNEL_CALLBACK* callback = transfer_data->callback; - IWTSVirtualChannelManager* channel_mgr; - URBDRC_PLUGIN* urbdrc = transfer_data->urbdrc; - USB_SEARCHMAN* searchman = urbdrc->searchman; - BYTE* pBuffer = transfer_data->pBuffer; - IUDEVMAN* udevman = transfer_data->udevman; + URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)callback->plugin; + IUDEVMAN* udevman = urbdrc->udevman; + IWTSVirtualChannel* channel = callback->channel; IUDEVICE* pdev = NULL; - UINT32 ChannelId = 0; - UINT32 MessageId; - UINT32 FunctionId; - int i = 0, found = 0; - WLog_DBG(TAG, "..."); - channel_mgr = urbdrc->listener_callback->channel_mgr; - ChannelId = channel_mgr->GetChannelId(callback->channel); - data_read_UINT32(pBuffer + 0, MessageId); - data_read_UINT32(pBuffer + 4, FunctionId); - int error = 0; + BOOL found = FALSE; + UINT error = ERROR_INTERNAL_ERROR; + UINT32 channelId = callback->channel_mgr->GetChannelId(channel); switch (urbdrc->vchannel_status) { case INIT_CHANNEL_IN: - urbdrc->first_channel_id = ChannelId; - - if (!searchman->start(searchman, urbdrc_search_usb_device)) - { - WLog_ERR(TAG, "unable to start searchman thread"); - return 0; - } + /* Control channel was established */ + error = ERROR_SUCCESS; + udevman->initialize(udevman, channelId); - for (i = 0; i < udevman->get_device_num(udevman); i++) - error = urdbrc_send_virtual_channel_add(callback->channel, MessageId); + if (!urbdrc_announce_devices(udevman)) + goto fail; urbdrc->vchannel_status = INIT_CHANNEL_OUT; break; case INIT_CHANNEL_OUT: + /* A new device channel was created, add the channel + * to the device */ udevman->loading_lock(udevman); udevman->rewind(udevman); @@ -1113,36 +472,31 @@ void* urbdrc_new_device_create(void* arg) if (!pdev->isAlreadySend(pdev)) { - found = 1; + const UINT32 channelID = callback->channel_mgr->GetChannelId(channel); + found = TRUE; pdev->setAlreadySend(pdev); - pdev->set_channel_id(pdev, ChannelId); + pdev->set_channelManager(pdev, callback->channel_mgr); + pdev->set_channelID(pdev, channelID); break; } } udevman->loading_unlock(udevman); + error = ERROR_SUCCESS; if (found && pdev->isAlreadySend(pdev)) - { - /* when we send the usb device add request, we will detach - * the device driver at same time. But, if the time of detach the - * driver and attach driver is too close, the system will crash. - * workaround: we wait it for some time to avoid system crash. */ - error = pdev->wait_for_detach(pdev); - - if (error >= 0) - urdbrc_send_usb_device_add(callback, pdev); - } + error = urdbrc_send_usb_device_add(callback, pdev); break; default: - WLog_ERR(TAG, "vchannel_status unknown value %"PRIu32"", - urbdrc->vchannel_status); + WLog_Print(urbdrc->log, WLOG_ERROR, "vchannel_status unknown value %" PRIu32 "", + urbdrc->vchannel_status); break; } - return 0; +fail: + return error; } /** @@ -1150,63 +504,45 @@ void* urbdrc_new_device_create(void* arg) * * @return 0 on success, otherwise a Win32 error code */ -static UINT urbdrc_process_channel_notification(URBDRC_CHANNEL_CALLBACK* callback, char* pBuffer, - UINT32 cbSize) +static UINT urbdrc_process_channel_notification(URBDRC_CHANNEL_CALLBACK* callback, wStream* data) { - int i; UINT32 MessageId; UINT32 FunctionId; + UINT32 InterfaceId; UINT error = CHANNEL_RC_OK; - URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*) callback->plugin; - WLog_DBG(TAG, "..."); - data_read_UINT32(pBuffer + 0, MessageId); - data_read_UINT32(pBuffer + 4, FunctionId); + URBDRC_PLUGIN* urbdrc; - switch (FunctionId) - { - case CHANNEL_CREATED: - error = urbdrc_process_channel_create(callback, pBuffer + 8, cbSize - 8, MessageId); - break; + if (!callback || !data) + return ERROR_INVALID_PARAMETER; - case RIMCALL_RELEASE: - WLog_VRB(TAG, "recv RIMCALL_RELEASE"); - pthread_t thread; - TRANSFER_DATA* transfer_data; - transfer_data = (TRANSFER_DATA*)malloc(sizeof(TRANSFER_DATA)); + urbdrc = (URBDRC_PLUGIN*)callback->plugin; - if (!transfer_data) - return ERROR_OUTOFMEMORY; + if (!urbdrc) + return ERROR_INVALID_PARAMETER; - transfer_data->callback = callback; - transfer_data->urbdrc = urbdrc; - transfer_data->udevman = urbdrc->udevman; - transfer_data->urbdrc = urbdrc; - transfer_data->cbSize = cbSize; - transfer_data->pBuffer = (BYTE*) malloc((cbSize)); - - if (!transfer_data->pBuffer) - { - free(transfer_data); - return ERROR_OUTOFMEMORY; - } + if (Stream_GetRemainingLength(data) < 8) + return ERROR_INVALID_DATA; - for (i = 0; i < (cbSize); i++) - { - transfer_data->pBuffer[i] = pBuffer[i]; - } + Stream_Rewind(data, 4); + Stream_Read_UINT32(data, InterfaceId); + Stream_Read_UINT32(data, MessageId); + Stream_Read_UINT32(data, FunctionId); + WLog_Print(urbdrc->log, WLOG_TRACE, "%s [%" PRIu32 "]", + call_to_string(FALSE, InterfaceId, FunctionId), FunctionId); - if (pthread_create(&thread, 0, urbdrc_new_device_create, transfer_data) != 0) - { - free(transfer_data->pBuffer); - free(transfer_data); - return ERROR_INVALID_OPERATION; - } + switch (FunctionId) + { + case CHANNEL_CREATED: + error = urbdrc_process_channel_create(callback, data, MessageId); + break; - pthread_detach(thread); + case RIMCALL_RELEASE: + error = urbdrc_device_control_channel(callback, data); break; default: - WLog_VRB(TAG, "%s: unknown FunctionId 0x%"PRIX32"", __FUNCTION__, FunctionId); + WLog_Print(urbdrc->log, WLOG_TRACE, "%s: unknown FunctionId 0x%" PRIX32 "", + __FUNCTION__, FunctionId); error = 1; break; } @@ -1221,90 +557,49 @@ static UINT urbdrc_process_channel_notification(URBDRC_CHANNEL_CALLBACK* callbac */ static UINT urbdrc_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data) { - URBDRC_CHANNEL_CALLBACK* callback = (URBDRC_CHANNEL_CALLBACK*) pChannelCallback; + URBDRC_CHANNEL_CALLBACK* callback = (URBDRC_CHANNEL_CALLBACK*)pChannelCallback; URBDRC_PLUGIN* urbdrc; IUDEVMAN* udevman; - UINT32 InterfaceTemp; UINT32 InterfaceId; - UINT32 Mask; - UINT error = CHANNEL_RC_OK; - char* pBuffer = (char*)Stream_Pointer(data); - UINT32 cbSize = Stream_GetRemainingLength(data); + UINT error = ERROR_INTERNAL_ERROR; if (callback == NULL) - return 0; + return ERROR_INVALID_PARAMETER; if (callback->plugin == NULL) - return 0; + return error; - urbdrc = (URBDRC_PLUGIN*) callback->plugin; + urbdrc = (URBDRC_PLUGIN*)callback->plugin; if (urbdrc->udevman == NULL) - return 0; + return error; - udevman = (IUDEVMAN*) urbdrc->udevman; - data_read_UINT32(pBuffer + 0, InterfaceTemp); - InterfaceId = (InterfaceTemp & 0x0fffffff); - Mask = ((InterfaceTemp & 0xf0000000) >> 30); - WLog_VRB(TAG, "Size=%"PRIu32" InterfaceId=0x%"PRIX32" Mask=0x%"PRIX32"", cbSize, InterfaceId, Mask); + udevman = (IUDEVMAN*)urbdrc->udevman; + if (Stream_GetRemainingLength(data) < 12) + return ERROR_INVALID_DATA; + + urbdrc_dump_message(urbdrc->log, FALSE, FALSE, data); + Stream_Read_UINT32(data, InterfaceId); + + /* Need to check InterfaceId and mask values */ switch (InterfaceId) { - case CAPABILITIES_NEGOTIATOR: - error = urbdrc_exchange_capabilities(callback, pBuffer + 4, cbSize - 4); + case CAPABILITIES_NEGOTIATOR | (STREAM_ID_NONE << 30): + error = urbdrc_exchange_capabilities(callback, data); break; - case SERVER_CHANNEL_NOTIFICATION: - error = urbdrc_process_channel_notification(callback, pBuffer + 4, cbSize - 4); + case SERVER_CHANNEL_NOTIFICATION | (STREAM_ID_PROXY << 30): + error = urbdrc_process_channel_notification(callback, data); break; default: - WLog_VRB(TAG, "InterfaceId 0x%"PRIX32" Start matching devices list", InterfaceId); - pthread_t thread; - TRANSFER_DATA* transfer_data; - transfer_data = (TRANSFER_DATA*)malloc(sizeof(TRANSFER_DATA)); - - if (!transfer_data) - { - WLog_ERR(TAG, "transfer_data is NULL!!"); - return ERROR_OUTOFMEMORY; - } - - transfer_data->callback = callback; - transfer_data->urbdrc = urbdrc; - transfer_data->udevman = udevman; - transfer_data->cbSize = cbSize - 4; - transfer_data->UsbDevice = InterfaceId; - transfer_data->pBuffer = (BYTE*)malloc((cbSize - 4)); - - if (!transfer_data->pBuffer) - { - free(transfer_data); - return ERROR_OUTOFMEMORY; - } - - memcpy(transfer_data->pBuffer, pBuffer + 4, (cbSize - 4)); - /* To ensure that not too many urb requests at the same time */ - udevman->wait_urb(udevman); -#if ISOCH_FIFO - /* lock isoch mutex */ - func_lock_isoch_mutex(transfer_data); -#endif - error = pthread_create(&thread, 0, urbdrc_process_udev_data_transfer, transfer_data); - - if (error != 0) - { - WLog_ERR(TAG, "Create Data Transfer Thread got error = %"PRIu32"", error); - free(transfer_data->pBuffer); - free(transfer_data); - return ERROR_INVALID_OPERATION; - } - - pthread_detach(thread); + error = urbdrc_process_udev_data_transfer(callback, urbdrc, udevman, data); + error = ERROR_SUCCESS; /* Ignore errors, the device may have been unplugged. */ break; } - return 0; + return error; } /** @@ -1314,39 +609,22 @@ static UINT urbdrc_on_data_received(IWTSVirtualChannelCallback* pChannelCallback */ static UINT urbdrc_on_close(IWTSVirtualChannelCallback* pChannelCallback) { - URBDRC_CHANNEL_CALLBACK* callback = (URBDRC_CHANNEL_CALLBACK*) pChannelCallback; - URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*) callback->plugin; - IUDEVMAN* udevman = (IUDEVMAN*) urbdrc->udevman; - USB_SEARCHMAN* searchman = (USB_SEARCHMAN*) urbdrc->searchman; - IUDEVICE* pdev = NULL; - UINT32 ChannelId = 0; - int found = 0; - ChannelId = callback->channel_mgr->GetChannelId(callback->channel); - WLog_INFO(TAG, "urbdrc_on_close: channel id %"PRIu32"", ChannelId); - udevman->loading_lock(udevman); - udevman->rewind(udevman); - - while (udevman->has_next(udevman)) + URBDRC_CHANNEL_CALLBACK* callback = (URBDRC_CHANNEL_CALLBACK*)pChannelCallback; + if (callback) { - pdev = udevman->get_next(udevman); - - if (pdev->get_channel_id(pdev) == ChannelId) + URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)callback->plugin; + if (urbdrc) { - found = 1; - break; + IUDEVMAN* udevman = urbdrc->udevman; + if (udevman && callback->channel_mgr) + { + UINT32 control = callback->channel_mgr->GetChannelId(callback->channel); + if (udevman->controlChannelId == control) + udevman->status |= URBDRC_DEVICE_CHANNEL_CLOSED; + } } } - - udevman->loading_unlock(udevman); - - if (found && pdev && !(pdev->isChannelClosed(pdev))) - { - pdev->setChannelClosed(pdev); - func_close_udevice(searchman, pdev); - } - - zfree(callback); - WLog_DBG(TAG, "success"); + free(callback); return CHANNEL_RC_OK; } @@ -1356,12 +634,17 @@ static UINT urbdrc_on_close(IWTSVirtualChannelCallback* pChannelCallback) * @return 0 on success, otherwise a Win32 error code */ static UINT urbdrc_on_new_channel_connection(IWTSListenerCallback* pListenerCallback, - IWTSVirtualChannel* pChannel, BYTE* pData, BOOL* pbAccept, IWTSVirtualChannelCallback** ppCallback) + IWTSVirtualChannel* pChannel, BYTE* pData, + BOOL* pbAccept, + IWTSVirtualChannelCallback** ppCallback) { - URBDRC_LISTENER_CALLBACK* listener_callback = (URBDRC_LISTENER_CALLBACK*) pListenerCallback; + URBDRC_LISTENER_CALLBACK* listener_callback = (URBDRC_LISTENER_CALLBACK*)pListenerCallback; URBDRC_CHANNEL_CALLBACK* callback; - WLog_VRB(TAG, ""); - callback = (URBDRC_CHANNEL_CALLBACK*) calloc(1, sizeof(URBDRC_CHANNEL_CALLBACK)); + + if (!ppCallback) + return ERROR_INVALID_PARAMETER; + + callback = (URBDRC_CHANNEL_CALLBACK*)calloc(1, sizeof(URBDRC_CHANNEL_CALLBACK)); if (!callback) return ERROR_OUTOFMEMORY; @@ -1371,7 +654,7 @@ static UINT urbdrc_on_new_channel_connection(IWTSListenerCallback* pListenerCall callback->plugin = listener_callback->plugin; callback->channel_mgr = listener_callback->channel_mgr; callback->channel = pChannel; - *ppCallback = (IWTSVirtualChannelCallback*) callback; + *ppCallback = (IWTSVirtualChannelCallback*)callback; return CHANNEL_RC_OK; } @@ -1382,11 +665,17 @@ static UINT urbdrc_on_new_channel_connection(IWTSListenerCallback* pListenerCall */ static UINT urbdrc_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr) { - URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*) pPlugin; - IUDEVMAN* udevman = NULL; - USB_SEARCHMAN* searchman = NULL; - WLog_VRB(TAG, ""); - urbdrc->listener_callback = (URBDRC_LISTENER_CALLBACK*) calloc(1, sizeof(URBDRC_LISTENER_CALLBACK)); + UINT status; + URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)pPlugin; + IUDEVMAN* udevman; + char channelName[sizeof(URBDRC_CHANNEL_NAME)] = { URBDRC_CHANNEL_NAME }; + + if (!urbdrc || !urbdrc->udevman) + return ERROR_INVALID_PARAMETER; + + udevman = urbdrc->udevman; + urbdrc->listener_callback = + (URBDRC_LISTENER_CALLBACK*)calloc(1, sizeof(URBDRC_LISTENER_CALLBACK)); if (!urbdrc->listener_callback) return CHANNEL_RC_NO_MEMORY; @@ -1394,20 +683,18 @@ static UINT urbdrc_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelMana urbdrc->listener_callback->iface.OnNewChannelConnection = urbdrc_on_new_channel_connection; urbdrc->listener_callback->plugin = pPlugin; urbdrc->listener_callback->channel_mgr = pChannelMgr; - /* Init searchman */ - udevman = urbdrc->udevman; - searchman = searchman_new((void*) urbdrc, udevman->get_defUsbDevice(udevman)); - if (!searchman) - { - free(urbdrc->listener_callback); - urbdrc->listener_callback = NULL; - return CHANNEL_RC_NO_MEMORY; - } + /* [MS-RDPEUSB] 2.1 Transport defines the channel name in uppercase letters */ + CharUpperA(channelName); + status = pChannelMgr->CreateListener(pChannelMgr, channelName, 0, + &urbdrc->listener_callback->iface, &urbdrc->listener); + if (status != CHANNEL_RC_OK) + return status; - urbdrc->searchman = searchman; - return pChannelMgr->CreateListener(pChannelMgr, "URBDRC", 0, - (IWTSListenerCallback*) urbdrc->listener_callback, NULL); + if (udevman->listener_created_callback) + return udevman->listener_created_callback(udevman); + + return CHANNEL_RC_OK; } /** @@ -1417,28 +704,18 @@ static UINT urbdrc_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelMana */ static UINT urbdrc_plugin_terminated(IWTSPlugin* pPlugin) { - URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*) pPlugin; - IUDEVMAN* udevman = urbdrc->udevman; - USB_SEARCHMAN* searchman = urbdrc->searchman; - WLog_VRB(TAG, ""); + URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)pPlugin; + IUDEVMAN* udevman; - if (searchman) + if (!urbdrc) + return ERROR_INVALID_DATA; + if (urbdrc->listener_callback) { - /* close searchman */ - searchman->close(searchman); - - /* free searchman */ - if (searchman->started) - { - struct timespec ts; - ts.tv_sec = time(NULL) + 10; - ts.tv_nsec = 0; - sem_timedwait(&searchman->sem_term, &ts); - } - - searchman->free(searchman); - searchman = NULL; + IWTSVirtualChannelManager* mgr = urbdrc->listener_callback->channel_mgr; + if (mgr) + IFCALL(mgr->DestroyListener, mgr, urbdrc->listener); } + udevman = urbdrc->udevman; if (udevman) { @@ -1446,27 +723,25 @@ static UINT urbdrc_plugin_terminated(IWTSPlugin* pPlugin) udevman = NULL; } - if (urbdrc->listener_callback) - zfree(urbdrc->listener_callback); - - if (urbdrc) - zfree(urbdrc); - + free(urbdrc->subsystem); + free(urbdrc->listener_callback); + free(urbdrc); return CHANNEL_RC_OK; } -static void urbdrc_register_udevman_addin(IWTSPlugin* pPlugin, IUDEVMAN* udevman) +static BOOL urbdrc_register_udevman_addin(IWTSPlugin* pPlugin, IUDEVMAN* udevman) { - URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*) pPlugin; + URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)pPlugin; if (urbdrc->udevman) { - WLog_ERR(TAG, "existing device, abort."); - return; + WLog_Print(urbdrc->log, WLOG_ERROR, "existing device, abort."); + return FALSE; } DEBUG_DVC("device registered."); urbdrc->udevman = udevman; + return TRUE; } /** @@ -1474,12 +749,13 @@ static void urbdrc_register_udevman_addin(IWTSPlugin* pPlugin, IUDEVMAN* udevman * * @return 0 on success, otherwise a Win32 error code */ -static UINT urbdrc_load_udevman_addin(IWTSPlugin* pPlugin, const char* name, ADDIN_ARGV* args) +static UINT urbdrc_load_udevman_addin(IWTSPlugin* pPlugin, LPCSTR name, ADDIN_ARGV* args) { + URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)pPlugin; PFREERDP_URBDRC_DEVICE_ENTRY entry; FREERDP_URBDRC_SERVICE_ENTRY_POINTS entryPoints; - entry = (PFREERDP_URBDRC_DEVICE_ENTRY) freerdp_load_channel_addin_entry("urbdrc", (LPSTR) name, - NULL, 0); + entry = (PFREERDP_URBDRC_DEVICE_ENTRY)freerdp_load_channel_addin_entry(URBDRC_CHANNEL_NAME, + name, NULL, 0); if (!entry) return ERROR_INVALID_OPERATION; @@ -1490,40 +766,39 @@ static UINT urbdrc_load_udevman_addin(IWTSPlugin* pPlugin, const char* name, ADD if (entry(&entryPoints) != 0) { - WLog_ERR(TAG, "%s entry returns error.", name); + WLog_Print(urbdrc->log, WLOG_ERROR, "%s entry returns error.", name); return ERROR_INVALID_OPERATION; } return CHANNEL_RC_OK; } -BOOL urbdrc_set_subsystem(URBDRC_PLUGIN* urbdrc, char* subsystem) +static BOOL urbdrc_set_subsystem(URBDRC_PLUGIN* urbdrc, const char* subsystem) { free(urbdrc->subsystem); urbdrc->subsystem = _strdup(subsystem); return (urbdrc->subsystem != NULL); } -COMMAND_LINE_ARGUMENT_A urbdrc_args[] = -{ - { "dbg", COMMAND_LINE_VALUE_FLAG, "", NULL, BoolValueFalse, -1, NULL, "debug" }, - { "sys", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "subsystem" }, - { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } -}; - /** * Function description * * @return 0 on success, otherwise a Win32 error code */ -static UINT urbdrc_process_addin_args(URBDRC_PLUGIN* urbdrc, ADDIN_ARGV* args) +static UINT urbdrc_process_addin_args(URBDRC_PLUGIN* urbdrc, const ADDIN_ARGV* args) { int status; - DWORD flags; + COMMAND_LINE_ARGUMENT_A urbdrc_args[] = { + { "dbg", COMMAND_LINE_VALUE_FLAG, "", NULL, BoolValueFalse, -1, NULL, "debug" }, + { "sys", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "subsystem" }, + { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } + }; + + const DWORD flags = + COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; COMMAND_LINE_ARGUMENT_A* arg; - flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON; - status = CommandLineParseArgumentsA(args->argc, args->argv, - urbdrc_args, flags, urbdrc, NULL, NULL); + status = + CommandLineParseArgumentsA(args->argc, args->argv, urbdrc_args, flags, urbdrc, NULL, NULL); if (status < 0) return ERROR_INVALID_DATA; @@ -1535,10 +810,9 @@ static UINT urbdrc_process_addin_args(URBDRC_PLUGIN* urbdrc, ADDIN_ARGV* args) if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) continue; - CommandLineSwitchStart(arg) - CommandLineSwitchCase(arg, "dbg") + CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "dbg") { - WLog_SetLogLevel(WLog_Get(TAG), WLOG_TRACE); + WLog_SetLogLevel(urbdrc->log, WLOG_TRACE); } CommandLineSwitchCase(arg, "sys") { @@ -1549,12 +823,105 @@ static UINT urbdrc_process_addin_args(URBDRC_PLUGIN* urbdrc, ADDIN_ARGV* args) { } CommandLineSwitchEnd(arg) - } - while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); return CHANNEL_RC_OK; } +BOOL add_device(IUDEVMAN* idevman, UINT32 flags, BYTE busnum, BYTE devnum, UINT16 idVendor, + UINT16 idProduct) +{ + size_t success = 0; + URBDRC_PLUGIN* urbdrc; + UINT32 mask, regflags = 0; + + if (!idevman) + return FALSE; + + urbdrc = (URBDRC_PLUGIN*)idevman->plugin; + + if (!urbdrc || !urbdrc->listener_callback) + return FALSE; + + mask = (DEVICE_ADD_FLAG_VENDOR | DEVICE_ADD_FLAG_PRODUCT); + if ((flags & mask) == mask) + regflags |= UDEVMAN_FLAG_ADD_BY_VID_PID; + mask = (DEVICE_ADD_FLAG_BUS | DEVICE_ADD_FLAG_DEV); + if ((flags & mask) == mask) + regflags |= UDEVMAN_FLAG_ADD_BY_ADDR; + + success = idevman->register_udevice(idevman, busnum, devnum, idVendor, idProduct, regflags); + + if ((success > 0) && (flags & DEVICE_ADD_FLAG_REGISTER)) + { + if (!urbdrc_announce_devices(idevman)) + return FALSE; + } + + return TRUE; +} + +BOOL del_device(IUDEVMAN* idevman, UINT32 flags, BYTE busnum, BYTE devnum, UINT16 idVendor, + UINT16 idProduct) +{ + IUDEVICE* pdev = NULL; + URBDRC_PLUGIN* urbdrc; + + if (!idevman) + return FALSE; + + urbdrc = (URBDRC_PLUGIN*)idevman->plugin; + + if (!urbdrc || !urbdrc->listener_callback) + return FALSE; + + idevman->loading_lock(idevman); + idevman->rewind(idevman); + + while (idevman->has_next(idevman)) + { + BOOL match = TRUE; + IUDEVICE* dev = idevman->get_next(idevman); + + if ((flags & (DEVICE_ADD_FLAG_BUS | DEVICE_ADD_FLAG_DEV | DEVICE_ADD_FLAG_VENDOR | + DEVICE_ADD_FLAG_PRODUCT)) == 0) + match = FALSE; + if (flags & DEVICE_ADD_FLAG_BUS) + { + if (dev->get_bus_number(dev) != busnum) + match = FALSE; + } + if (flags & DEVICE_ADD_FLAG_DEV) + { + if (dev->get_dev_number(dev) != devnum) + match = FALSE; + } + if (flags & DEVICE_ADD_FLAG_VENDOR) + { + int vid = dev->query_device_descriptor(dev, ID_VENDOR); + if (vid != idVendor) + match = FALSE; + } + if (flags & DEVICE_ADD_FLAG_PRODUCT) + { + int pid = dev->query_device_descriptor(dev, ID_PRODUCT); + if (pid != idProduct) + match = FALSE; + } + + if (match) + { + pdev = dev; + break; + } + } + + if (pdev) + pdev->setChannelClosed(pdev); + + idevman->loading_unlock(idevman); + return TRUE; +} #ifdef BUILTIN_CHANNELS #define DVCPluginEntry urbdrc_DVCPluginEntry #else @@ -1571,46 +938,67 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) UINT status = 0; ADDIN_ARGV* args; URBDRC_PLUGIN* urbdrc; - urbdrc = (URBDRC_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "urbdrc"); + urbdrc = (URBDRC_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, URBDRC_CHANNEL_NAME); args = pEntryPoints->GetPluginData(pEntryPoints); if (urbdrc == NULL) { - urbdrc = (URBDRC_PLUGIN*) calloc(1, sizeof(URBDRC_PLUGIN)); + urbdrc = (URBDRC_PLUGIN*)calloc(1, sizeof(URBDRC_PLUGIN)); if (!urbdrc) return CHANNEL_RC_NO_MEMORY; urbdrc->iface.Initialize = urbdrc_plugin_initialize; - urbdrc->iface.Connected = NULL; - urbdrc->iface.Disconnected = NULL; urbdrc->iface.Terminated = urbdrc_plugin_terminated; - urbdrc->searchman = NULL; urbdrc->vchannel_status = INIT_CHANNEL_IN; - status = pEntryPoints->RegisterPlugin(pEntryPoints, "urbdrc", (IWTSPlugin*) urbdrc); + status = + pEntryPoints->RegisterPlugin(pEntryPoints, URBDRC_CHANNEL_NAME, (IWTSPlugin*)urbdrc); if (status != CHANNEL_RC_OK) - goto error_register; + goto fail; + + urbdrc->log = WLog_Get(TAG); + + if (!urbdrc->log) + goto fail; } status = urbdrc_process_addin_args(urbdrc, args); if (status != CHANNEL_RC_OK) + goto fail; + + if (!urbdrc->subsystem && !urbdrc_set_subsystem(urbdrc, "libusb")) + goto fail; + + return urbdrc_load_udevman_addin((IWTSPlugin*)urbdrc, urbdrc->subsystem, args); +fail: + urbdrc_plugin_terminated(&urbdrc->iface); + return status; +} + +UINT stream_write_and_free(IWTSPlugin* plugin, IWTSVirtualChannel* channel, wStream* out) +{ + UINT rc; + URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)plugin; + + if (!out) + return ERROR_INVALID_PARAMETER; + + if (!channel || !out || !urbdrc) { - /* TODO: we should unregister the plugin ? */ - WLog_ERR(TAG, "error processing arguments"); - //return status; + Stream_Free(out, TRUE); + return ERROR_INVALID_PARAMETER; } - if (!urbdrc->subsystem && !urbdrc_set_subsystem(urbdrc, "libusb")) + if (!channel->Write) { - /* TODO: we should unregister the plugin ? */ - WLog_ERR(TAG, "error setting subsystem"); - return ERROR_OUTOFMEMORY; + Stream_Free(out, TRUE); + return ERROR_INTERNAL_ERROR; } - return urbdrc_load_udevman_addin((IWTSPlugin*) urbdrc, urbdrc->subsystem, args); -error_register: - free(urbdrc); - return status; + urbdrc_dump_message(urbdrc->log, TRUE, TRUE, out); + rc = channel->Write(channel, Stream_GetPosition(out), Stream_Buffer(out), NULL); + Stream_Free(out, TRUE); + return rc; } diff --git a/channels/urbdrc/client/urbdrc_main.h b/channels/urbdrc/client/urbdrc_main.h index 129b844..2b643f7 100644 --- a/channels/urbdrc/client/urbdrc_main.h +++ b/channels/urbdrc/client/urbdrc_main.h @@ -18,29 +18,37 @@ * limitations under the License. */ - - #ifndef FREERDP_CHANNEL_URBDRC_CLIENT_MAIN_H #define FREERDP_CHANNEL_URBDRC_CLIENT_MAIN_H -#include "searchman.h" -#include "isoch_queue.h" +#include +#include + +#define DEVICE_HARDWARE_ID_SIZE 32 +#define DEVICE_COMPATIBILITY_ID_SIZE 36 +#define DEVICE_INSTANCE_STR_SIZE 37 +#define DEVICE_CONTAINER_STR_SIZE 39 -#define DEVICE_HARDWARE_ID_SIZE 32 -#define DEVICE_COMPATIBILITY_ID_SIZE 36 -#define DEVICE_INSTANCE_STR_SIZE 37 -#define DEVICE_CONTAINER_STR_SIZE 39 +#define TAG CHANNELS_TAG("urbdrc.client") +#ifdef WITH_DEBUG_DVC +#define DEBUG_DVC(...) WLog_DBG(TAG, __VA_ARGS__) +#else +#define DEBUG_DVC(...) \ + do \ + { \ + } while (0) +#endif typedef struct _IUDEVICE IUDEVICE; typedef struct _IUDEVMAN IUDEVMAN; #define BASIC_DEV_STATE_DEFINED(_arg, _type) \ - _type (*get_##_arg) (IUDEVICE* pdev); \ - void (*set_##_arg) (IUDEVICE* pdev, _type _arg) + _type (*get_##_arg)(IUDEVICE * pdev); \ + void (*set_##_arg)(IUDEVICE * pdev, _type _arg) #define BASIC_DEVMAN_STATE_DEFINED(_arg, _type) \ - _type (*get_##_arg) (IUDEVMAN* udevman); \ - void (*set_##_arg) (IUDEVMAN* udevman, _type _arg) + _type (*get_##_arg)(IUDEVMAN * udevman); \ + void (*set_##_arg)(IUDEVMAN * udevman, _type _arg) typedef struct _URBDRC_LISTENER_CALLBACK URBDRC_LISTENER_CALLBACK; @@ -72,14 +80,14 @@ struct _URBDRC_PLUGIN URBDRC_LISTENER_CALLBACK* listener_callback; IUDEVMAN* udevman; - USB_SEARCHMAN* searchman; - UINT32 first_channel_id; UINT32 vchannel_status; char* subsystem; -}; -typedef void (*PREGISTERURBDRCSERVICE)(IWTSPlugin* plugin, IUDEVMAN* udevman); + wLog* log; + IWTSListener* listener; +}; +typedef BOOL (*PREGISTERURBDRCSERVICE)(IWTSPlugin* plugin, IUDEVMAN* udevman); struct _FREERDP_URBDRC_SERVICE_ENTRY_POINTS { IWTSPlugin* plugin; @@ -98,130 +106,139 @@ struct _TRANSFER_DATA URBDRC_CHANNEL_CALLBACK* callback; URBDRC_PLUGIN* urbdrc; IUDEVMAN* udevman; - BYTE* pBuffer; - UINT32 cbSize; - UINT32 UsbDevice; + IWTSVirtualChannel* channel; + wStream* s; }; +typedef void (*t_isoch_transfer_cb)(IUDEVICE* idev, URBDRC_CHANNEL_CALLBACK* callback, wStream* out, + UINT32 InterfaceId, BOOL noAck, UINT32 MessageId, + UINT32 RequestId, UINT32 NumberOfPackets, UINT32 status, + UINT32 StartFrame, UINT32 ErrorCount, UINT32 OutputBufferSize); + struct _IUDEVICE { /* Transfer */ - int (*isoch_transfer) (IUDEVICE* idev, UINT32 RequestId, - UINT32 EndpointAddress, UINT32 TransferFlags, int NoAck, UINT32* ErrorCount, - UINT32* UrbdStatus, UINT32* StartFrame, UINT32 NumberOfPackets, - BYTE* IsoPacket, UINT32* BufferSize, BYTE* Buffer, int Timeout); - - int (*control_transfer) (IUDEVICE* idev, UINT32 RequestId, - UINT32 EndpointAddress, UINT32 TransferFlags, BYTE bmRequestType, BYTE Request, UINT16 Value, - UINT16 Index, UINT32* UrbdStatus, UINT32* BufferSize, BYTE* Buffer, UINT32 Timeout); + int (*isoch_transfer)(IUDEVICE* idev, URBDRC_CHANNEL_CALLBACK* callback, UINT32 MessageId, + UINT32 RequestId, UINT32 EndpointAddress, UINT32 TransferFlags, + UINT32 StartFrame, UINT32 ErrorCount, BOOL NoAck, + const BYTE* packetDescriptorData, UINT32 NumberOfPackets, + UINT32 BufferSize, const BYTE* Buffer, t_isoch_transfer_cb cb, + UINT32 Timeout); - int (*bulk_or_interrupt_transfer) (IUDEVICE* idev, UINT32 RequestId, UINT32 EndpointAddress, - UINT32 TransferFlags, UINT32* UsbdStatus, UINT32* BufferSize, BYTE* Buffer, UINT32 Timeout); + BOOL(*control_transfer) + (IUDEVICE* idev, UINT32 RequestId, UINT32 EndpointAddress, UINT32 TransferFlags, + BYTE bmRequestType, BYTE Request, UINT16 Value, UINT16 Index, UINT32* UrbdStatus, + UINT32* BufferSize, BYTE* Buffer, UINT32 Timeout); - int (*select_configuration) (IUDEVICE* idev, UINT32 bConfigurationValue); + int (*bulk_or_interrupt_transfer)(IUDEVICE* idev, URBDRC_CHANNEL_CALLBACK* callback, + UINT32 MessageId, UINT32 RequestId, UINT32 EndpointAddress, + UINT32 TransferFlags, BOOL NoAck, UINT32 BufferSize, + t_isoch_transfer_cb cb, UINT32 Timeout); - int (*select_interface) (IUDEVICE* idev, BYTE InterfaceNumber, - BYTE AlternateSetting); + int (*select_configuration)(IUDEVICE* idev, UINT32 bConfigurationValue); - int (*control_pipe_request) (IUDEVICE* idev, UINT32 RequestId, - UINT32 EndpointAddress, UINT32* UsbdStatus, int command); + int (*select_interface)(IUDEVICE* idev, BYTE InterfaceNumber, BYTE AlternateSetting); - int (*control_query_device_text) (IUDEVICE* idev, UINT32 TextType, - UINT32 LocaleId, UINT32*BufferSize, BYTE* Buffer); + int (*control_pipe_request)(IUDEVICE* idev, UINT32 RequestId, UINT32 EndpointAddress, + UINT32* UsbdStatus, int command); - int (*os_feature_descriptor_request) (IUDEVICE* idev, UINT32 RequestId, BYTE Recipient, - BYTE InterfaceNumber, BYTE Ms_PageIndex, UINT16 Ms_featureDescIndex, UINT32* UsbdStatus, - UINT32* BufferSize, BYTE* Buffer, int Timeout); + UINT32(*control_query_device_text) + (IUDEVICE* idev, UINT32 TextType, UINT16 LocaleId, UINT8* BufferSize, BYTE* Buffer); - void (*cancel_all_transfer_request) (IUDEVICE* idev); + int (*os_feature_descriptor_request)(IUDEVICE* idev, UINT32 RequestId, BYTE Recipient, + BYTE InterfaceNumber, BYTE Ms_PageIndex, + UINT16 Ms_featureDescIndex, UINT32* UsbdStatus, + UINT32* BufferSize, BYTE* Buffer, int Timeout); - int (*cancel_transfer_request) (IUDEVICE* idev, UINT32 RequestId); + void (*cancel_all_transfer_request)(IUDEVICE* idev); - int (*query_device_descriptor) (IUDEVICE* idev, int offset); + int (*cancel_transfer_request)(IUDEVICE* idev, UINT32 RequestId); - void (*detach_kernel_driver) (IUDEVICE* idev); + int (*query_device_descriptor)(IUDEVICE* idev, int offset); - void (*attach_kernel_driver) (IUDEVICE* idev); + BOOL (*detach_kernel_driver)(IUDEVICE* idev); - int (*wait_action_completion) (IUDEVICE* idev); + BOOL (*attach_kernel_driver)(IUDEVICE* idev); - void (*push_action) (IUDEVICE* idev); + int (*query_device_port_status)(IUDEVICE* idev, UINT32* UsbdStatus, UINT32* BufferSize, + BYTE* Buffer); - void (*complete_action) (IUDEVICE* idev); - - /* Wait for 5 sec */ - int (*wait_for_detach) (IUDEVICE* idev); + MSUSB_CONFIG_DESCRIPTOR* (*complete_msconfig_setup)(IUDEVICE* idev, + MSUSB_CONFIG_DESCRIPTOR* MsConfig); + /* Basic state */ + int (*isCompositeDevice)(IUDEVICE* idev); - /* FIXME: Currently this is a way of stupid, SHOULD to improve it. - * Isochronous transfer must to FIFO */ - void (*lock_fifo_isoch) (IUDEVICE* idev); - void (*unlock_fifo_isoch) (IUDEVICE* idev); + int (*isExist)(IUDEVICE* idev); + int (*isAlreadySend)(IUDEVICE* idev); + int (*isChannelClosed)(IUDEVICE* idev); - int (*query_device_port_status) (IUDEVICE* idev, UINT32 *UsbdStatus, - UINT32* BufferSize, - BYTE* Buffer); + void (*setAlreadySend)(IUDEVICE* idev); + void (*setChannelClosed)(IUDEVICE* idev); + char* (*getPath)(IUDEVICE* idev); - int (*request_queue_is_none) (IUDEVICE* idev); + void (*free)(IUDEVICE* idev); - MSUSB_CONFIG_DESCRIPTOR* (*complete_msconfig_setup) (IUDEVICE* idev, - MSUSB_CONFIG_DESCRIPTOR* MsConfig); - /* Basic state */ - int (*isCompositeDevice) (IUDEVICE* idev); - int (*isSigToEnd) (IUDEVICE* idev); - int (*isExist) (IUDEVICE* idev); - int (*isAlreadySend) (IUDEVICE* idev); - int (*isChannelClosed) (IUDEVICE* idev); - void (*SigToEnd) (IUDEVICE* idev); - void (*setAlreadySend) (IUDEVICE* idev); - void (*setChannelClosed) (IUDEVICE* idev); - char *(*getPath) (IUDEVICE* idev); - - BASIC_DEV_STATE_DEFINED(channel_id, UINT32); + BASIC_DEV_STATE_DEFINED(channelManager, IWTSVirtualChannelManager*); + BASIC_DEV_STATE_DEFINED(channelID, UINT32); BASIC_DEV_STATE_DEFINED(UsbDevice, UINT32); BASIC_DEV_STATE_DEFINED(ReqCompletion, UINT32); - BASIC_DEV_STATE_DEFINED(bus_number, UINT16); - BASIC_DEV_STATE_DEFINED(dev_number, UINT16); + BASIC_DEV_STATE_DEFINED(bus_number, BYTE); + BASIC_DEV_STATE_DEFINED(dev_number, BYTE); BASIC_DEV_STATE_DEFINED(port_number, int); - BASIC_DEV_STATE_DEFINED(isoch_queue, void*); BASIC_DEV_STATE_DEFINED(MsConfig, MSUSB_CONFIG_DESCRIPTOR*); BASIC_DEV_STATE_DEFINED(p_udev, void*); BASIC_DEV_STATE_DEFINED(p_prev, void*); BASIC_DEV_STATE_DEFINED(p_next, void*); - - /* Control semaphore or mutex lock */ - }; struct _IUDEVMAN { /* Standard */ - void (*free) (IUDEVMAN* idevman); + void (*free)(IUDEVMAN* idevman); /* Manage devices */ - void (*rewind) (IUDEVMAN* idevman); - int (*has_next) (IUDEVMAN* idevman); - int (*unregister_udevice) (IUDEVMAN* idevman, int bus_number, int dev_number); - int (*register_udevice) (IUDEVMAN* idevman, int bus_number, - int dev_number, int UsbDevice, UINT16 idVendor, UINT16 idProduct, int flag); - IUDEVICE *(*get_next) (IUDEVMAN* idevman); - IUDEVICE *(*get_udevice_by_UsbDevice) (IUDEVMAN* idevman, UINT32 UsbDevice); - IUDEVICE *(*get_udevice_by_UsbDevice_try_again) (IUDEVMAN* idevman, UINT32 UsbDevice); + void (*rewind)(IUDEVMAN* idevman); + BOOL (*has_next)(IUDEVMAN* idevman); + BOOL (*unregister_udevice)(IUDEVMAN* idevman, BYTE bus_number, BYTE dev_number); + size_t (*register_udevice)(IUDEVMAN* idevman, BYTE bus_number, BYTE dev_number, UINT16 idVendor, + UINT16 idProduct, UINT32 flag); + IUDEVICE* (*get_next)(IUDEVMAN* idevman); + IUDEVICE* (*get_udevice_by_UsbDevice)(IUDEVMAN* idevman, UINT32 UsbDevice); /* Extension */ - int (*check_device_exist_by_id) (IUDEVMAN* idevman, UINT16 idVendor, UINT16 idProduct); - int (*isAutoAdd) (IUDEVMAN* idevman); + int (*isAutoAdd)(IUDEVMAN* idevman); /* Basic state */ - BASIC_DEVMAN_STATE_DEFINED(defUsbDevice, UINT32); - BASIC_DEVMAN_STATE_DEFINED(device_num, int); - BASIC_DEVMAN_STATE_DEFINED(sem_timeout, int); + BASIC_DEVMAN_STATE_DEFINED(device_num, UINT32); + BASIC_DEVMAN_STATE_DEFINED(next_device_id, UINT32); /* control semaphore or mutex lock */ - void (*loading_lock) (IUDEVMAN* idevman); - void (*loading_unlock) (IUDEVMAN* idevman); - void (*push_urb) (IUDEVMAN* idevman); - void (*wait_urb) (IUDEVMAN* idevman); + void (*loading_lock)(IUDEVMAN* idevman); + void (*loading_unlock)(IUDEVMAN* idevman); + BOOL (*initialize)(IUDEVMAN* idevman, UINT32 channelId); + UINT (*listener_created_callback)(IUDEVMAN* idevman); + + IWTSPlugin* plugin; + UINT32 controlChannelId; + UINT32 status; }; +#define DEVICE_ADD_FLAG_BUS 0x01 +#define DEVICE_ADD_FLAG_DEV 0x02 +#define DEVICE_ADD_FLAG_VENDOR 0x04 +#define DEVICE_ADD_FLAG_PRODUCT 0x08 +#define DEVICE_ADD_FLAG_REGISTER 0x10 + +#define DEVICE_ADD_FLAG_ALL \ + (DEVICE_ADD_FLAG_BUS | DEVICE_ADD_FLAG_DEV | DEVICE_ADD_FLAG_VENDOR | \ + DEVICE_ADD_FLAG_PRODUCT | DEVICE_ADD_FLAG_REGISTER) + +FREERDP_API BOOL add_device(IUDEVMAN* idevman, UINT32 flags, BYTE busnum, BYTE devnum, + UINT16 idVendor, UINT16 idProduct); +FREERDP_API BOOL del_device(IUDEVMAN* idevman, UINT32 flags, BYTE busnum, BYTE devnum, + UINT16 idVendor, UINT16 idProduct); + +UINT stream_write_and_free(IWTSPlugin* plugin, IWTSVirtualChannel* channel, wStream* s); + #endif /* FREERDP_CHANNEL_URBDRC_CLIENT_MAIN_H */ diff --git a/channels/urbdrc/common/CMakeLists.txt b/channels/urbdrc/common/CMakeLists.txt new file mode 100644 index 0000000..0e7b448 --- /dev/null +++ b/channels/urbdrc/common/CMakeLists.txt @@ -0,0 +1,26 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# 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. + +set(SRCS + urbdrc_types.h + urbdrc_helpers.h + urbdrc_helpers.c + msusb.h + msusb.c) + +add_library(urbdrc-common OBJECT ${SRCS}) diff --git a/channels/urbdrc/common/msusb.c b/channels/urbdrc/common/msusb.c new file mode 100644 index 0000000..bb517ce --- /dev/null +++ b/channels/urbdrc/common/msusb.c @@ -0,0 +1,402 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * RemoteFX USB Redirection + * + * Copyright 2012 Atrust corp. + * Copyright 2012 Alfred Liu + * + * 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 + +#define TAG FREERDP_TAG("utils") + +static MSUSB_PIPE_DESCRIPTOR* msusb_mspipe_new() +{ + return (MSUSB_PIPE_DESCRIPTOR*)calloc(1, sizeof(MSUSB_PIPE_DESCRIPTOR)); +} + +static void msusb_mspipes_free(MSUSB_PIPE_DESCRIPTOR** MsPipes, UINT32 NumberOfPipes) +{ + UINT32 pnum = 0; + + if (MsPipes) + { + for (pnum = 0; pnum < NumberOfPipes && MsPipes[pnum]; pnum++) + free(MsPipes[pnum]); + + free(MsPipes); + } +} + +BOOL msusb_mspipes_replace(MSUSB_INTERFACE_DESCRIPTOR* MsInterface, + MSUSB_PIPE_DESCRIPTOR** NewMsPipes, UINT32 NewNumberOfPipes) +{ + if (!MsInterface || !NewMsPipes) + return FALSE; + + /* free orignal MsPipes */ + msusb_mspipes_free(MsInterface->MsPipes, MsInterface->NumberOfPipes); + /* And replace it */ + MsInterface->MsPipes = NewMsPipes; + MsInterface->NumberOfPipes = NewNumberOfPipes; + return TRUE; +} + +static MSUSB_PIPE_DESCRIPTOR** msusb_mspipes_read(wStream* s, UINT32 NumberOfPipes) +{ + UINT32 pnum; + MSUSB_PIPE_DESCRIPTOR** MsPipes; + + if (Stream_GetRemainingCapacity(s) / 12 < NumberOfPipes) + return NULL; + + MsPipes = (MSUSB_PIPE_DESCRIPTOR**)calloc(NumberOfPipes, sizeof(MSUSB_PIPE_DESCRIPTOR*)); + + if (!MsPipes) + return NULL; + + for (pnum = 0; pnum < NumberOfPipes; pnum++) + { + MSUSB_PIPE_DESCRIPTOR* MsPipe = msusb_mspipe_new(); + + if (!MsPipe) + goto out_error; + + Stream_Read_UINT16(s, MsPipe->MaximumPacketSize); + Stream_Seek(s, 2); + Stream_Read_UINT32(s, MsPipe->MaximumTransferSize); + Stream_Read_UINT32(s, MsPipe->PipeFlags); + /* Already set to zero by memset + MsPipe->PipeHandle = 0; + MsPipe->bEndpointAddress = 0; + MsPipe->bInterval = 0; + MsPipe->PipeType = 0; + MsPipe->InitCompleted = 0; + */ + MsPipes[pnum] = MsPipe; + } + + return MsPipes; +out_error: + + for (pnum = 0; pnum < NumberOfPipes; pnum++) + free(MsPipes[pnum]); + + free(MsPipes); + return NULL; +} + +static MSUSB_INTERFACE_DESCRIPTOR* msusb_msinterface_new() +{ + return (MSUSB_INTERFACE_DESCRIPTOR*)calloc(1, sizeof(MSUSB_INTERFACE_DESCRIPTOR)); +} + +static void msusb_msinterface_free(MSUSB_INTERFACE_DESCRIPTOR* MsInterface) +{ + if (MsInterface) + { + msusb_mspipes_free(MsInterface->MsPipes, MsInterface->NumberOfPipes); + MsInterface->MsPipes = NULL; + free(MsInterface); + } +} + +static void msusb_msinterface_free_list(MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces, + UINT32 NumInterfaces) +{ + UINT32 inum = 0; + + if (MsInterfaces) + { + for (inum = 0; inum < NumInterfaces; inum++) + { + msusb_msinterface_free(MsInterfaces[inum]); + } + + free(MsInterfaces); + } +} + +BOOL msusb_msinterface_replace(MSUSB_CONFIG_DESCRIPTOR* MsConfig, BYTE InterfaceNumber, + MSUSB_INTERFACE_DESCRIPTOR* NewMsInterface) +{ + if (!MsConfig || !MsConfig->MsInterfaces) + return FALSE; + + msusb_msinterface_free(MsConfig->MsInterfaces[InterfaceNumber]); + MsConfig->MsInterfaces[InterfaceNumber] = NewMsInterface; + return TRUE; +} + +MSUSB_INTERFACE_DESCRIPTOR* msusb_msinterface_read(wStream* s) +{ + MSUSB_INTERFACE_DESCRIPTOR* MsInterface; + + if (Stream_GetRemainingCapacity(s) < 12) + return NULL; + + MsInterface = msusb_msinterface_new(); + + if (!MsInterface) + return NULL; + + Stream_Read_UINT16(s, MsInterface->Length); + Stream_Read_UINT16(s, MsInterface->NumberOfPipesExpected); + Stream_Read_UINT8(s, MsInterface->InterfaceNumber); + Stream_Read_UINT8(s, MsInterface->AlternateSetting); + Stream_Seek(s, 2); + Stream_Read_UINT32(s, MsInterface->NumberOfPipes); + MsInterface->InterfaceHandle = 0; + MsInterface->bInterfaceClass = 0; + MsInterface->bInterfaceSubClass = 0; + MsInterface->bInterfaceProtocol = 0; + MsInterface->InitCompleted = 0; + MsInterface->MsPipes = NULL; + + if (MsInterface->NumberOfPipes > 0) + { + MsInterface->MsPipes = msusb_mspipes_read(s, MsInterface->NumberOfPipes); + + if (!MsInterface->MsPipes) + goto out_error; + } + + return MsInterface; +out_error: + msusb_msinterface_free(MsInterface); + return NULL; +} + +BOOL msusb_msinterface_write(MSUSB_INTERFACE_DESCRIPTOR* MsInterface, wStream* out) +{ + MSUSB_PIPE_DESCRIPTOR** MsPipes; + MSUSB_PIPE_DESCRIPTOR* MsPipe; + UINT32 pnum = 0; + + if (!MsInterface) + return FALSE; + + if (!Stream_EnsureRemainingCapacity(out, 16 + MsInterface->NumberOfPipes * 20)) + return FALSE; + + /* Length */ + Stream_Write_UINT16(out, MsInterface->Length); + /* InterfaceNumber */ + Stream_Write_UINT8(out, MsInterface->InterfaceNumber); + /* AlternateSetting */ + Stream_Write_UINT8(out, MsInterface->AlternateSetting); + /* bInterfaceClass */ + Stream_Write_UINT8(out, MsInterface->bInterfaceClass); + /* bInterfaceSubClass */ + Stream_Write_UINT8(out, MsInterface->bInterfaceSubClass); + /* bInterfaceProtocol */ + Stream_Write_UINT8(out, MsInterface->bInterfaceProtocol); + /* Padding */ + Stream_Write_UINT8(out, 0); + /* InterfaceHandle */ + Stream_Write_UINT32(out, MsInterface->InterfaceHandle); + /* NumberOfPipes */ + Stream_Write_UINT32(out, MsInterface->NumberOfPipes); + /* Pipes */ + MsPipes = MsInterface->MsPipes; + + for (pnum = 0; pnum < MsInterface->NumberOfPipes; pnum++) + { + MsPipe = MsPipes[pnum]; + /* MaximumPacketSize */ + Stream_Write_UINT16(out, MsPipe->MaximumPacketSize); + /* EndpointAddress */ + Stream_Write_UINT8(out, MsPipe->bEndpointAddress); + /* Interval */ + Stream_Write_UINT8(out, MsPipe->bInterval); + /* PipeType */ + Stream_Write_UINT32(out, MsPipe->PipeType); + /* PipeHandle */ + Stream_Write_UINT32(out, MsPipe->PipeHandle); + /* MaximumTransferSize */ + Stream_Write_UINT32(out, MsPipe->MaximumTransferSize); + /* PipeFlags */ + Stream_Write_UINT32(out, MsPipe->PipeFlags); + } + + return TRUE; +} + +static MSUSB_INTERFACE_DESCRIPTOR** msusb_msinterface_read_list(wStream* s, UINT32 NumInterfaces) +{ + UINT32 inum; + MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces; + MsInterfaces = + (MSUSB_INTERFACE_DESCRIPTOR**)calloc(NumInterfaces, sizeof(MSUSB_INTERFACE_DESCRIPTOR*)); + + if (!MsInterfaces) + return NULL; + + for (inum = 0; inum < NumInterfaces; inum++) + { + MsInterfaces[inum] = msusb_msinterface_read(s); + + if (!MsInterfaces[inum]) + goto fail; + } + + return MsInterfaces; +fail: + + for (inum = 0; inum < NumInterfaces; inum++) + msusb_msinterface_free(MsInterfaces[inum]); + + free(MsInterfaces); + return NULL; +} + +BOOL msusb_msconfig_write(MSUSB_CONFIG_DESCRIPTOR* MsConfg, wStream* out) +{ + UINT32 inum = 0; + MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces; + MSUSB_INTERFACE_DESCRIPTOR* MsInterface; + + if (!MsConfg) + return FALSE; + + if (!Stream_EnsureRemainingCapacity(out, 8)) + return FALSE; + + /* ConfigurationHandle*/ + Stream_Write_UINT32(out, MsConfg->ConfigurationHandle); + /* NumInterfaces*/ + Stream_Write_UINT32(out, MsConfg->NumInterfaces); + /* Interfaces */ + MsInterfaces = MsConfg->MsInterfaces; + + for (inum = 0; inum < MsConfg->NumInterfaces; inum++) + { + MsInterface = MsInterfaces[inum]; + + if (!msusb_msinterface_write(MsInterface, out)) + return FALSE; + } + + return TRUE; +} + +MSUSB_CONFIG_DESCRIPTOR* msusb_msconfig_new(void) +{ + return (MSUSB_CONFIG_DESCRIPTOR*)calloc(1, sizeof(MSUSB_CONFIG_DESCRIPTOR)); +} + +void msusb_msconfig_free(MSUSB_CONFIG_DESCRIPTOR* MsConfig) +{ + if (MsConfig) + { + msusb_msinterface_free_list(MsConfig->MsInterfaces, MsConfig->NumInterfaces); + MsConfig->MsInterfaces = NULL; + free(MsConfig); + } +} + +MSUSB_CONFIG_DESCRIPTOR* msusb_msconfig_read(wStream* s, UINT32 NumInterfaces) +{ + MSUSB_CONFIG_DESCRIPTOR* MsConfig; + BYTE lenConfiguration, typeConfiguration; + + if (Stream_GetRemainingCapacity(s) < 6ULL + NumInterfaces * 2ULL) + return NULL; + + MsConfig = msusb_msconfig_new(); + + if (!MsConfig) + goto fail; + + MsConfig->MsInterfaces = msusb_msinterface_read_list(s, NumInterfaces); + + if (!MsConfig->MsInterfaces) + goto fail; + + Stream_Read_UINT8(s, lenConfiguration); + Stream_Read_UINT8(s, typeConfiguration); + + if (lenConfiguration != 0x9 || typeConfiguration != 0x2) + { + WLog_ERR(TAG, "len and type must be 0x9 and 0x2 , but it is 0x%" PRIx8 " and 0x%" PRIx8 "", + lenConfiguration, typeConfiguration); + goto fail; + } + + Stream_Read_UINT16(s, MsConfig->wTotalLength); + Stream_Seek(s, 1); + Stream_Read_UINT8(s, MsConfig->bConfigurationValue); + MsConfig->NumInterfaces = NumInterfaces; + return MsConfig; +fail: + msusb_msconfig_free(MsConfig); + return NULL; +} + +void msusb_msconfig_dump(MSUSB_CONFIG_DESCRIPTOR* MsConfig) +{ + MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces; + MSUSB_INTERFACE_DESCRIPTOR* MsInterface; + MSUSB_PIPE_DESCRIPTOR** MsPipes; + MSUSB_PIPE_DESCRIPTOR* MsPipe; + UINT32 inum = 0, pnum = 0; + WLog_INFO(TAG, "=================MsConfig:========================"); + WLog_INFO(TAG, "wTotalLength:%" PRIu16 "", MsConfig->wTotalLength); + WLog_INFO(TAG, "bConfigurationValue:%" PRIu8 "", MsConfig->bConfigurationValue); + WLog_INFO(TAG, "ConfigurationHandle:0x%08" PRIx32 "", MsConfig->ConfigurationHandle); + WLog_INFO(TAG, "InitCompleted:%d", MsConfig->InitCompleted); + WLog_INFO(TAG, "MsOutSize:%d", MsConfig->MsOutSize); + WLog_INFO(TAG, "NumInterfaces:%" PRIu32 "", MsConfig->NumInterfaces); + MsInterfaces = MsConfig->MsInterfaces; + + for (inum = 0; inum < MsConfig->NumInterfaces; inum++) + { + MsInterface = MsInterfaces[inum]; + WLog_INFO(TAG, " Interface: %" PRIu8 "", MsInterface->InterfaceNumber); + WLog_INFO(TAG, " Length: %" PRIu16 "", MsInterface->Length); + WLog_INFO(TAG, " NumberOfPipesExpected: %" PRIu16 "", + MsInterface->NumberOfPipesExpected); + WLog_INFO(TAG, " AlternateSetting: %" PRIu8 "", MsInterface->AlternateSetting); + WLog_INFO(TAG, " NumberOfPipes: %" PRIu32 "", MsInterface->NumberOfPipes); + WLog_INFO(TAG, " InterfaceHandle: 0x%08" PRIx32 "", MsInterface->InterfaceHandle); + WLog_INFO(TAG, " bInterfaceClass: 0x%02" PRIx8 "", MsInterface->bInterfaceClass); + WLog_INFO(TAG, " bInterfaceSubClass: 0x%02" PRIx8 "", MsInterface->bInterfaceSubClass); + WLog_INFO(TAG, " bInterfaceProtocol: 0x%02" PRIx8 "", MsInterface->bInterfaceProtocol); + WLog_INFO(TAG, " InitCompleted: %d", MsInterface->InitCompleted); + MsPipes = MsInterface->MsPipes; + + for (pnum = 0; pnum < MsInterface->NumberOfPipes; pnum++) + { + MsPipe = MsPipes[pnum]; + WLog_INFO(TAG, " Pipe: %d", pnum); + WLog_INFO(TAG, " MaximumPacketSize: 0x%04" PRIx16 "", MsPipe->MaximumPacketSize); + WLog_INFO(TAG, " MaximumTransferSize: 0x%08" PRIx32 "", + MsPipe->MaximumTransferSize); + WLog_INFO(TAG, " PipeFlags: 0x%08" PRIx32 "", MsPipe->PipeFlags); + WLog_INFO(TAG, " PipeHandle: 0x%08" PRIx32 "", MsPipe->PipeHandle); + WLog_INFO(TAG, " bEndpointAddress: 0x%02" PRIx8 "", MsPipe->bEndpointAddress); + WLog_INFO(TAG, " bInterval: %" PRIu8 "", MsPipe->bInterval); + WLog_INFO(TAG, " PipeType: 0x%02" PRIx8 "", MsPipe->PipeType); + WLog_INFO(TAG, " InitCompleted: %d", MsPipe->InitCompleted); + } + } + + WLog_INFO(TAG, "=================================================="); +} diff --git a/channels/urbdrc/common/msusb.h b/channels/urbdrc/common/msusb.h new file mode 100644 index 0000000..89f1a2b --- /dev/null +++ b/channels/urbdrc/common/msusb.h @@ -0,0 +1,97 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * RemoteFX USB Redirection + * + * Copyright 2012 Atrust corp. + * Copyright 2012 Alfred Liu + * + * 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_UTILS_MSCONFIG_H +#define FREERDP_UTILS_MSCONFIG_H + +#include +#include + +typedef struct _MSUSB_INTERFACE_DESCRIPTOR MSUSB_INTERFACE_DESCRIPTOR; +typedef struct _MSUSB_PIPE_DESCRIPTOR MSUSB_PIPE_DESCRIPTOR; +typedef struct _MSUSB_CONFIG_DESCRIPTOR MSUSB_CONFIG_DESCRIPTOR; + +struct _MSUSB_PIPE_DESCRIPTOR +{ + UINT16 MaximumPacketSize; + UINT32 MaximumTransferSize; + UINT32 PipeFlags; + UINT32 PipeHandle; + BYTE bEndpointAddress; + BYTE bInterval; + BYTE PipeType; + int InitCompleted; +}; + +struct _MSUSB_INTERFACE_DESCRIPTOR +{ + UINT16 Length; + UINT16 NumberOfPipesExpected; + BYTE InterfaceNumber; + BYTE AlternateSetting; + UINT32 NumberOfPipes; + UINT32 InterfaceHandle; + BYTE bInterfaceClass; + BYTE bInterfaceSubClass; + BYTE bInterfaceProtocol; + MSUSB_PIPE_DESCRIPTOR** MsPipes; + int InitCompleted; +}; + +struct _MSUSB_CONFIG_DESCRIPTOR +{ + UINT16 wTotalLength; + BYTE bConfigurationValue; + UINT32 ConfigurationHandle; + UINT32 NumInterfaces; + MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces; + int InitCompleted; + int MsOutSize; +}; + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* MSUSB_PIPE exported functions */ + FREERDP_API BOOL msusb_mspipes_replace(MSUSB_INTERFACE_DESCRIPTOR* MsInterface, + MSUSB_PIPE_DESCRIPTOR** NewMsPipes, + UINT32 NewNumberOfPipes); + + /* MSUSB_INTERFACE exported functions */ + FREERDP_API BOOL msusb_msinterface_replace(MSUSB_CONFIG_DESCRIPTOR* MsConfig, + BYTE InterfaceNumber, + MSUSB_INTERFACE_DESCRIPTOR* NewMsInterface); + FREERDP_API MSUSB_INTERFACE_DESCRIPTOR* msusb_msinterface_read(wStream* out); + FREERDP_API BOOL msusb_msinterface_write(MSUSB_INTERFACE_DESCRIPTOR* MsInterface, wStream* out); + + /* MSUSB_CONFIG exported functions */ + FREERDP_API MSUSB_CONFIG_DESCRIPTOR* msusb_msconfig_new(void); + FREERDP_API void msusb_msconfig_free(MSUSB_CONFIG_DESCRIPTOR* MsConfig); + FREERDP_API MSUSB_CONFIG_DESCRIPTOR* msusb_msconfig_read(wStream* s, UINT32 NumInterfaces); + FREERDP_API BOOL msusb_msconfig_write(MSUSB_CONFIG_DESCRIPTOR* MsConfg, wStream* out); + FREERDP_API void msusb_msconfig_dump(MSUSB_CONFIG_DESCRIPTOR* MsConfg); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_UTILS_MSCONFIG_H */ diff --git a/channels/urbdrc/common/urbdrc_helpers.c b/channels/urbdrc/common/urbdrc_helpers.c new file mode 100644 index 0000000..80d6149 --- /dev/null +++ b/channels/urbdrc/common/urbdrc_helpers.c @@ -0,0 +1,421 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Server USB redirection channel - helper functions + * + * 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 "urbdrc_helpers.h" +#include "urbdrc_types.h" +#include + +const char* mask_to_string(UINT32 mask) +{ + switch (mask) + { + case STREAM_ID_NONE: + return "STREAM_ID_NONE"; + + case STREAM_ID_PROXY: + return "STREAM_ID_PROXY"; + + case STREAM_ID_STUB: + return "STREAM_ID_STUB"; + + default: + return "UNKNOWN"; + } +} +const char* interface_to_string(UINT32 id) +{ + switch (id) + { + case CAPABILITIES_NEGOTIATOR: + return "CAPABILITIES_NEGOTIATOR"; + + case SERVER_CHANNEL_NOTIFICATION: + return "SERVER_CHANNEL_NOTIFICATION"; + + case CLIENT_CHANNEL_NOTIFICATION: + return "CLIENT_CHANNEL_NOTIFICATION"; + + default: + return "DEVICE_MESSAGE"; + } +} + +static const char* call_to_string_none(BOOL client, UINT32 interfaceId, UINT32 functionId) +{ + WINPR_UNUSED(interfaceId); + + if (client) + return "RIM_EXCHANGE_CAPABILITY_RESPONSE [none |client]"; + else + { + switch (functionId) + { + case RIM_EXCHANGE_CAPABILITY_REQUEST: + return "RIM_EXCHANGE_CAPABILITY_REQUEST [none |server]"; + + case RIMCALL_RELEASE: + return "RIMCALL_RELEASE [none |server]"; + + case RIMCALL_QUERYINTERFACE: + return "RIMCALL_QUERYINTERFACE [none |server]"; + + default: + return "UNKNOWN [none |server]"; + } + } +} + +static const char* call_to_string_proxy_server(UINT32 functionId) +{ + switch (functionId) + { + case QUERY_DEVICE_TEXT: + return "QUERY_DEVICE_TEXT [proxy|server]"; + + case INTERNAL_IO_CONTROL: + return "INTERNAL_IO_CONTROL [proxy|server]"; + + case IO_CONTROL: + return "IO_CONTROL [proxy|server]"; + + case REGISTER_REQUEST_CALLBACK: + return "REGISTER_REQUEST_CALLBACK [proxy|server]"; + + case CANCEL_REQUEST: + return "CANCEL_REQUEST [proxy|server]"; + + case RETRACT_DEVICE: + return "RETRACT_DEVICE [proxy|server]"; + + case TRANSFER_IN_REQUEST: + return "TRANSFER_IN_REQUEST [proxy|server]"; + + default: + return "UNKNOWN [proxy|server]"; + } +} + +static const char* call_to_string_proxy_client(UINT32 functionId) +{ + switch (functionId) + { + case URB_COMPLETION_NO_DATA: + return "URB_COMPLETION_NO_DATA [proxy|client]"; + + case URB_COMPLETION: + return "URB_COMPLETION [proxy|client]"; + + case IOCONTROL_COMPLETION: + return "IOCONTROL_COMPLETION [proxy|client]"; + + case TRANSFER_OUT_REQUEST: + return "TRANSFER_OUT_REQUEST [proxy|client]"; + + default: + return "UNKNOWN [proxy|client]"; + } +} + +static const char* call_to_string_proxy(BOOL client, UINT32 interfaceId, UINT32 functionId) +{ + switch (interfaceId & INTERFACE_ID_MASK) + { + case CLIENT_DEVICE_SINK: + switch (functionId) + { + case ADD_VIRTUAL_CHANNEL: + return "ADD_VIRTUAL_CHANNEL [proxy|sink ]"; + + case ADD_DEVICE: + return "ADD_DEVICE [proxy|sink ]"; + case RIMCALL_RELEASE: + return "RIMCALL_RELEASE [proxy|sink ]"; + + case RIMCALL_QUERYINTERFACE: + return "RIMCALL_QUERYINTERFACE [proxy|sink ]"; + default: + return "UNKNOWN [proxy|sink ]"; + } + + case SERVER_CHANNEL_NOTIFICATION: + switch (functionId) + { + case CHANNEL_CREATED: + return "CHANNEL_CREATED [proxy|server]"; + + case RIMCALL_RELEASE: + return "RIMCALL_RELEASE [proxy|server]"; + + case RIMCALL_QUERYINTERFACE: + return "RIMCALL_QUERYINTERFACE [proxy|server]"; + + default: + return "UNKNOWN [proxy|server]"; + } + + case CLIENT_CHANNEL_NOTIFICATION: + switch (functionId) + { + case CHANNEL_CREATED: + return "CHANNEL_CREATED [proxy|client]"; + case RIMCALL_RELEASE: + return "RIMCALL_RELEASE [proxy|client]"; + case RIMCALL_QUERYINTERFACE: + return "RIMCALL_QUERYINTERFACE [proxy|client]"; + default: + return "UNKNOWN [proxy|client]"; + } + + default: + if (client) + return call_to_string_proxy_client(functionId); + else + return call_to_string_proxy_server(functionId); + } +} + +static const char* call_to_string_stub(BOOL client, UINT32 interfaceId, UINT32 functionId) +{ + return "QUERY_DEVICE_TEXT_RSP [stub |client]"; +} + +const char* call_to_string(BOOL client, UINT32 interface, UINT32 functionId) +{ + const UINT32 mask = (interface & STREAM_ID_MASK) >> 30; + const UINT32 interfaceId = interface & INTERFACE_ID_MASK; + + switch (mask) + { + case STREAM_ID_NONE: + return call_to_string_none(client, interfaceId, functionId); + + case STREAM_ID_PROXY: + return call_to_string_proxy(client, interfaceId, functionId); + + case STREAM_ID_STUB: + return call_to_string_stub(client, interfaceId, functionId); + + default: + return "UNKNOWN[mask]"; + } +} + +const char* urb_function_string(UINT16 urb) +{ + switch (urb) + { + case TS_URB_SELECT_CONFIGURATION: + return "TS_URB_SELECT_CONFIGURATION"; + + case TS_URB_SELECT_INTERFACE: + return "TS_URB_SELECT_INTERFACE"; + + case TS_URB_PIPE_REQUEST: + return "TS_URB_PIPE_REQUEST"; + + case TS_URB_TAKE_FRAME_LENGTH_CONTROL: + return "TS_URB_TAKE_FRAME_LENGTH_CONTROL"; + + case TS_URB_RELEASE_FRAME_LENGTH_CONTROL: + return "TS_URB_RELEASE_FRAME_LENGTH_CONTROL"; + + case TS_URB_GET_FRAME_LENGTH: + return "TS_URB_GET_FRAME_LENGTH"; + + case TS_URB_SET_FRAME_LENGTH: + return "TS_URB_SET_FRAME_LENGTH"; + + case TS_URB_GET_CURRENT_FRAME_NUMBER: + return "TS_URB_GET_CURRENT_FRAME_NUMBER"; + + case TS_URB_CONTROL_TRANSFER: + return "TS_URB_CONTROL_TRANSFER"; + + case TS_URB_BULK_OR_INTERRUPT_TRANSFER: + return "TS_URB_BULK_OR_INTERRUPT_TRANSFER"; + + case TS_URB_ISOCH_TRANSFER: + return "TS_URB_ISOCH_TRANSFER"; + + case TS_URB_GET_DESCRIPTOR_FROM_DEVICE: + return "TS_URB_GET_DESCRIPTOR_FROM_DEVICE"; + + case TS_URB_SET_DESCRIPTOR_TO_DEVICE: + return "TS_URB_SET_DESCRIPTOR_TO_DEVICE"; + + case TS_URB_SET_FEATURE_TO_DEVICE: + return "TS_URB_SET_FEATURE_TO_DEVICE"; + + case TS_URB_SET_FEATURE_TO_INTERFACE: + return "TS_URB_SET_FEATURE_TO_INTERFACE"; + + case TS_URB_SET_FEATURE_TO_ENDPOINT: + return "TS_URB_SET_FEATURE_TO_ENDPOINT"; + + case TS_URB_CLEAR_FEATURE_TO_DEVICE: + return "TS_URB_CLEAR_FEATURE_TO_DEVICE"; + + case TS_URB_CLEAR_FEATURE_TO_INTERFACE: + return "TS_URB_CLEAR_FEATURE_TO_INTERFACE"; + + case TS_URB_CLEAR_FEATURE_TO_ENDPOINT: + return "TS_URB_CLEAR_FEATURE_TO_ENDPOINT"; + + case TS_URB_GET_STATUS_FROM_DEVICE: + return "TS_URB_GET_STATUS_FROM_DEVICE"; + + case TS_URB_GET_STATUS_FROM_INTERFACE: + return "TS_URB_GET_STATUS_FROM_INTERFACE"; + + case TS_URB_GET_STATUS_FROM_ENDPOINT: + return "TS_URB_GET_STATUS_FROM_ENDPOINT"; + + case TS_URB_RESERVED_0X0016: + return "TS_URB_RESERVED_0X0016"; + + case TS_URB_VENDOR_DEVICE: + return "TS_URB_VENDOR_DEVICE"; + + case TS_URB_VENDOR_INTERFACE: + return "TS_URB_VENDOR_INTERFACE"; + + case TS_URB_VENDOR_ENDPOINT: + return "TS_URB_VENDOR_ENDPOINT"; + + case TS_URB_CLASS_DEVICE: + return "TS_URB_CLASS_DEVICE"; + + case TS_URB_CLASS_INTERFACE: + return "TS_URB_CLASS_INTERFACE"; + + case TS_URB_CLASS_ENDPOINT: + return "TS_URB_CLASS_ENDPOINT"; + + case TS_URB_RESERVE_0X001D: + return "TS_URB_RESERVE_0X001D"; + + case TS_URB_SYNC_RESET_PIPE_AND_CLEAR_STALL: + return "TS_URB_SYNC_RESET_PIPE_AND_CLEAR_STALL"; + + case TS_URB_CLASS_OTHER: + return "TS_URB_CLASS_OTHER"; + + case TS_URB_VENDOR_OTHER: + return "TS_URB_VENDOR_OTHER"; + + case TS_URB_GET_STATUS_FROM_OTHER: + return "TS_URB_GET_STATUS_FROM_OTHER"; + + case TS_URB_CLEAR_FEATURE_TO_OTHER: + return "TS_URB_CLEAR_FEATURE_TO_OTHER"; + + case TS_URB_SET_FEATURE_TO_OTHER: + return "TS_URB_SET_FEATURE_TO_OTHER"; + + case TS_URB_GET_DESCRIPTOR_FROM_ENDPOINT: + return "TS_URB_GET_DESCRIPTOR_FROM_ENDPOINT"; + + case TS_URB_SET_DESCRIPTOR_TO_ENDPOINT: + return "TS_URB_SET_DESCRIPTOR_TO_ENDPOINT"; + + case TS_URB_CONTROL_GET_CONFIGURATION_REQUEST: + return "TS_URB_CONTROL_GET_CONFIGURATION_REQUEST"; + + case TS_URB_CONTROL_GET_INTERFACE_REQUEST: + return "TS_URB_CONTROL_GET_INTERFACE_REQUEST"; + + case TS_URB_GET_DESCRIPTOR_FROM_INTERFACE: + return "TS_URB_GET_DESCRIPTOR_FROM_INTERFACE"; + + case TS_URB_SET_DESCRIPTOR_TO_INTERFACE: + return "TS_URB_SET_DESCRIPTOR_TO_INTERFACE"; + + case TS_URB_GET_OS_FEATURE_DESCRIPTOR_REQUEST: + return "TS_URB_GET_OS_FEATURE_DESCRIPTOR_REQUEST"; + + case TS_URB_RESERVE_0X002B: + return "TS_URB_RESERVE_0X002B"; + + case TS_URB_RESERVE_0X002C: + return "TS_URB_RESERVE_0X002C"; + + case TS_URB_RESERVE_0X002D: + return "TS_URB_RESERVE_0X002D"; + + case TS_URB_RESERVE_0X002E: + return "TS_URB_RESERVE_0X002E"; + + case TS_URB_RESERVE_0X002F: + return "TS_URB_RESERVE_0X002F"; + + case TS_URB_SYNC_RESET_PIPE: + return "TS_URB_SYNC_RESET_PIPE"; + + case TS_URB_SYNC_CLEAR_STALL: + return "TS_URB_SYNC_CLEAR_STALL"; + + case TS_URB_CONTROL_TRANSFER_EX: + return "TS_URB_CONTROL_TRANSFER_EX"; + + default: + return "UNKNOWN"; + } +} + +void urbdrc_dump_message(wLog* log, BOOL client, BOOL write, wStream* s) +{ + const char* type = write ? "WRITE" : "READ"; + UINT32 InterfaceId, MessageId, FunctionId; + size_t length, pos; + + pos = Stream_GetPosition(s); + if (write) + { + length = Stream_GetPosition(s); + Stream_SetPosition(s, 0); + } + else + length = Stream_GetRemainingLength(s); + + if (length < 12) + return; + + Stream_Read_UINT32(s, InterfaceId); + Stream_Read_UINT32(s, MessageId); + Stream_Read_UINT32(s, FunctionId); + Stream_SetPosition(s, pos); + + WLog_Print(log, WLOG_DEBUG, + "[%-5s] %s [%08" PRIx32 "] InterfaceId=%08" PRIx32 ", MessageId=%08" PRIx32 + ", FunctionId=%08" PRIx32 ", length=%" PRIdz, + type, call_to_string(client, InterfaceId, FunctionId), FunctionId, InterfaceId, + MessageId, FunctionId, length); +#if defined(WITH_DEBUG_URBDRC) + if (write) + WLog_Print(log, WLOG_TRACE, "-------------------------- URBDRC sent: ---"); + else + WLog_Print(log, WLOG_TRACE, "-------------------------- URBDRC received:"); + winpr_HexLogDump(log, WLOG_TRACE, Stream_Buffer(s), length); + WLog_Print(log, WLOG_TRACE, "-------------------------- URBDRC end -----"); +#endif +} diff --git a/channels/urbdrc/common/urbdrc_helpers.h b/channels/urbdrc/common/urbdrc_helpers.h new file mode 100644 index 0000000..e9e25af --- /dev/null +++ b/channels/urbdrc/common/urbdrc_helpers.h @@ -0,0 +1,45 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Server USB redirection channel - helper functions + * + * 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. + */ + +#ifndef FREERDP_CHANNEL_URBDRC_HELPERS_H +#define FREERDP_CHANNEL_URBDRC_HELPERS_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include + + const char* urb_function_string(UINT16 urb); + const char* mask_to_string(UINT32 mask); + const char* interface_to_string(UINT32 id); + const char* call_to_string(BOOL client, UINT32 interface, UINT32 functionId); + + void urbdrc_dump_message(wLog* log, BOOL client, BOOL write, wStream* s); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_CHANNEL_URBDRC_HELPERS_H */ diff --git a/channels/urbdrc/common/urbdrc_types.h b/channels/urbdrc/common/urbdrc_types.h new file mode 100644 index 0000000..c120715 --- /dev/null +++ b/channels/urbdrc/common/urbdrc_types.h @@ -0,0 +1,308 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * RemoteFX USB Redirection + * + * Copyright 2012 Atrust corp. + * Copyright 2012 Alfred Liu + * + * 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_CHANNEL_URBDRC_CLIENT_TYPES_H +#define FREERDP_CHANNEL_URBDRC_CLIENT_TYPES_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include + +#include + +#define RIM_CAPABILITY_VERSION_01 0x00000001 + +#define CAPABILITIES_NEGOTIATOR 0x00000000 +#define CLIENT_DEVICE_SINK 0x00000001 +#define SERVER_CHANNEL_NOTIFICATION 0x00000002 +#define CLIENT_CHANNEL_NOTIFICATION 0x00000003 +#define BASE_USBDEVICE_NUM 0x00000005 + +#define RIMCALL_RELEASE 0x00000001 +#define RIMCALL_QUERYINTERFACE 0x00000002 +#define RIM_EXCHANGE_CAPABILITY_REQUEST 0x00000100 +#define CHANNEL_CREATED 0x00000100 +#define ADD_VIRTUAL_CHANNEL 0x00000100 +#define ADD_DEVICE 0x00000101 + +#define INIT_CHANNEL_IN 1 +#define INIT_CHANNEL_OUT 0 + +/* InterfaceClass */ +#define CLASS_RESERVE 0x00 +#define CLASS_AUDIO 0x01 +#define CLASS_COMMUNICATION_IF 0x02 +#define CLASS_HID 0x03 +#define CLASS_PHYSICAL 0x05 +#define CLASS_IMAGE 0x06 +#define CLASS_PRINTER 0x07 +#define CLASS_MASS_STORAGE 0x08 +#define CLASS_HUB 0x09 +#define CLASS_COMMUNICATION_DATA_IF 0x0a +#define CLASS_SMART_CARD 0x0b +#define CLASS_CONTENT_SECURITY 0x0d +#define CLASS_VIDEO 0x0e +#define CLASS_PERSONAL_HEALTHCARE 0x0f +#define CLASS_DIAGNOSTIC 0xdc +#define CLASS_WIRELESS_CONTROLLER 0xe0 +#define CLASS_ELSE_DEVICE 0xef +#define CLASS_DEPENDENCE 0xfe +#define CLASS_VENDOR_DEPENDENCE 0xff + +/* usb version */ +#define USB_v1_0 0x100 +#define USB_v1_1 0x110 +#define USB_v2_0 0x200 +#define USB_v3_0 0x300 + +#define STREAM_ID_NONE 0x0UL +#define STREAM_ID_PROXY 0x1UL +#define STREAM_ID_STUB 0x2UL +#define STREAM_ID_MASK 0xC0000000 +#define INTERFACE_ID_MASK 0x3FFFFFFF + +#define CANCEL_REQUEST 0x00000100 +#define REGISTER_REQUEST_CALLBACK 0x00000101 +#define IO_CONTROL 0x00000102 +#define INTERNAL_IO_CONTROL 0x00000103 +#define QUERY_DEVICE_TEXT 0x00000104 + +#define TRANSFER_IN_REQUEST 0x00000105 +#define TRANSFER_OUT_REQUEST 0x00000106 +#define RETRACT_DEVICE 0x00000107 + +#define IOCONTROL_COMPLETION 0x00000100 +#define URB_COMPLETION 0x00000101 +#define URB_COMPLETION_NO_DATA 0x00000102 + +/* The USB device is to be stopped from being redirected because the + * device is blocked by the server's policy. */ +#define UsbRetractReason_BlockedByPolicy 0x00000001 + +enum device_text_type +{ + DeviceTextDescription = 0, + DeviceTextLocationInformation = 1, +}; + +enum device_descriptor_table +{ + B_LENGTH = 0, + B_DESCRIPTOR_TYPE = 1, + BCD_USB = 2, + B_DEVICE_CLASS = 4, + B_DEVICE_SUBCLASS = 5, + B_DEVICE_PROTOCOL = 6, + B_MAX_PACKET_SIZE0 = 7, + ID_VENDOR = 8, + ID_PRODUCT = 10, + BCD_DEVICE = 12, + I_MANUFACTURER = 14, + I_PRODUCT = 15, + I_SERIAL_NUMBER = 16, + B_NUM_CONFIGURATIONS = 17 +}; + +#define PIPE_CANCEL 0 +#define PIPE_RESET 1 + +#define IOCTL_INTERNAL_USB_SUBMIT_URB 0x00220003 +#define IOCTL_INTERNAL_USB_RESET_PORT 0x00220007 +#define IOCTL_INTERNAL_USB_GET_PORT_STATUS 0x00220013 +#define IOCTL_INTERNAL_USB_CYCLE_PORT 0x0022001F +#define IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION 0x00220027 + +#define TS_URB_SELECT_CONFIGURATION 0x0000 +#define TS_URB_SELECT_INTERFACE 0x0001 +#define TS_URB_PIPE_REQUEST 0x0002 +#define TS_URB_TAKE_FRAME_LENGTH_CONTROL 0x0003 +#define TS_URB_RELEASE_FRAME_LENGTH_CONTROL 0x0004 +#define TS_URB_GET_FRAME_LENGTH 0x0005 +#define TS_URB_SET_FRAME_LENGTH 0x0006 +#define TS_URB_GET_CURRENT_FRAME_NUMBER 0x0007 +#define TS_URB_CONTROL_TRANSFER 0x0008 +#define TS_URB_BULK_OR_INTERRUPT_TRANSFER 0x0009 +#define TS_URB_ISOCH_TRANSFER 0x000A +#define TS_URB_GET_DESCRIPTOR_FROM_DEVICE 0x000B +#define TS_URB_SET_DESCRIPTOR_TO_DEVICE 0x000C +#define TS_URB_SET_FEATURE_TO_DEVICE 0x000D +#define TS_URB_SET_FEATURE_TO_INTERFACE 0x000E +#define TS_URB_SET_FEATURE_TO_ENDPOINT 0x000F +#define TS_URB_CLEAR_FEATURE_TO_DEVICE 0x0010 +#define TS_URB_CLEAR_FEATURE_TO_INTERFACE 0x0011 +#define TS_URB_CLEAR_FEATURE_TO_ENDPOINT 0x0012 +#define TS_URB_GET_STATUS_FROM_DEVICE 0x0013 +#define TS_URB_GET_STATUS_FROM_INTERFACE 0x0014 +#define TS_URB_GET_STATUS_FROM_ENDPOINT 0x0015 +#define TS_URB_RESERVED_0X0016 0x0016 +#define TS_URB_VENDOR_DEVICE 0x0017 +#define TS_URB_VENDOR_INTERFACE 0x0018 +#define TS_URB_VENDOR_ENDPOINT 0x0019 +#define TS_URB_CLASS_DEVICE 0x001A +#define TS_URB_CLASS_INTERFACE 0x001B +#define TS_URB_CLASS_ENDPOINT 0x001C +#define TS_URB_RESERVE_0X001D 0x001D +#define TS_URB_SYNC_RESET_PIPE_AND_CLEAR_STALL 0x001E +#define TS_URB_CLASS_OTHER 0x001F +#define TS_URB_VENDOR_OTHER 0x0020 +#define TS_URB_GET_STATUS_FROM_OTHER 0x0021 +#define TS_URB_CLEAR_FEATURE_TO_OTHER 0x0022 +#define TS_URB_SET_FEATURE_TO_OTHER 0x0023 +#define TS_URB_GET_DESCRIPTOR_FROM_ENDPOINT 0x0024 +#define TS_URB_SET_DESCRIPTOR_TO_ENDPOINT 0x0025 +#define TS_URB_CONTROL_GET_CONFIGURATION_REQUEST 0x0026 +#define TS_URB_CONTROL_GET_INTERFACE_REQUEST 0x0027 +#define TS_URB_GET_DESCRIPTOR_FROM_INTERFACE 0x0028 +#define TS_URB_SET_DESCRIPTOR_TO_INTERFACE 0x0029 +#define TS_URB_GET_OS_FEATURE_DESCRIPTOR_REQUEST 0x002A +#define TS_URB_RESERVE_0X002B 0x002B +#define TS_URB_RESERVE_0X002C 0x002C +#define TS_URB_RESERVE_0X002D 0x002D +#define TS_URB_RESERVE_0X002E 0x002E +#define TS_URB_RESERVE_0X002F 0x002F +// USB 2.0 calls start at 0x0030 +#define TS_URB_SYNC_RESET_PIPE 0x0030 +#define TS_URB_SYNC_CLEAR_STALL 0x0031 +#define TS_URB_CONTROL_TRANSFER_EX 0x0032 + +#define USBD_STATUS_SUCCESS 0x0 +#define USBD_STATUS_PENDING 0x40000000 +#define USBD_STATUS_CANCELED 0xC0010000 + +#define USBD_STATUS_INVALID_URB_FUNCTION 0x80000200 +#define USBD_STATUS_CRC 0xC0000001 +#define USBD_STATUS_BTSTUFF 0xC0000002 +#define USBD_STATUS_DATA_TOGGLE_MISMATCH 0xC0000003 +#define USBD_STATUS_STALL_PID 0xC0000004 +#define USBD_STATUS_DEV_NOT_RESPONDING 0xC0000005 +#define USBD_STATUS_PID_CHECK_FAILURE 0xC0000006 +#define USBD_STATUS_UNEXPECTED_PID 0xC0000007 +#define USBD_STATUS_DATA_OVERRUN 0xC0000008 +#define USBD_STATUS_DATA_UNDERRUN 0xC0000009 +#define USBD_STATUS_RESERVED1 0xC000000A +#define USBD_STATUS_RESERVED2 0xC000000B +#define USBD_STATUS_BUFFER_OVERRUN 0xC000000C +#define USBD_STATUS_BUFFER_UNDERRUN 0xC000000D + +/* unknown */ +#define USBD_STATUS_NO_DATA 0xC000000E + +#define USBD_STATUS_NOT_ACCESSED 0xC000000F +#define USBD_STATUS_FIFO 0xC0000010 +#define USBD_STATUS_XACT_ERROR 0xC0000011 +#define USBD_STATUS_BABBLE_DETECTED 0xC0000012 +#define USBD_STATUS_DATA_BUFFER_ERROR 0xC0000013 + +#define USBD_STATUS_NOT_SUPPORTED 0xC0000E00 +#define USBD_STATUS_BUFFER_TOO_SMALL 0xC0003000 +#define USBD_STATUS_TIMEOUT 0xC0006000 +#define USBD_STATUS_DEVICE_GONE 0xC0007000 + +#define USBD_STATUS_NO_MEMORY 0x80000100 +#define USBD_STATUS_INVALID_URB_FUNCTION 0x80000200 +#define USBD_STATUS_INVALID_PARAMETER 0x80000300 +#define USBD_STATUS_REQUEST_FAILED 0x80000500 +#define USBD_STATUS_INVALID_PIPE_HANDLE 0x80000600 +#define USBD_STATUS_ERROR_SHORT_TRANSFER 0x80000900 + +// Values for URB TransferFlags Field +// + +/* + Set if data moves device->host +*/ +#define USBD_TRANSFER_DIRECTION 0x00000001 +/* + This bit if not set indicates that a short packet, and hence, + a short transfer is an error condition +*/ +#define USBD_SHORT_TRANSFER_OK 0x00000002 +/* + Subit the iso transfer on the next frame +*/ +#define USBD_START_ISO_TRANSFER_ASAP 0x00000004 +#define USBD_DEFAULT_PIPE_TRANSFER 0x00000008 + +#define USBD_TRANSFER_DIRECTION_FLAG(flags) ((flags)&USBD_TRANSFER_DIRECTION) + +#define USBD_TRANSFER_DIRECTION_OUT 0 +#define USBD_TRANSFER_DIRECTION_IN 1 + +#define VALID_TRANSFER_FLAGS_MASK USBD_SHORT_TRANSFER_OK | \ + USBD_TRANSFER_DIRECTION | \ + USBD_START_ISO_TRANSFER_ASAP | \ + USBD_DEFAULT_PIPE_TRANSFER) + +#define ENDPOINT_HALT 0x00 +#define DEVICE_REMOTE_WAKEUP 0x01 + +/* transfer type */ +#define CONTROL_TRANSFER 0x00 +#define ISOCHRONOUS_TRANSFER 0x01 +#define BULK_TRANSFER 0x02 +#define INTERRUPT_TRANSFER 0x03 + +#define ClearHubFeature (0x2000 | LIBUSB_REQUEST_CLEAR_FEATURE) +#define ClearPortFeature (0x2300 | LIBUSB_REQUEST_CLEAR_FEATURE) +#define GetHubDescriptor (0xa000 | LIBUSB_REQUEST_GET_DESCRIPTOR) +#define GetHubStatus (0xa000 | LIBUSB_REQUEST_GET_STATUS) +#define GetPortStatus (0xa300 | LIBUSB_REQUEST_GET_STATUS) +#define SetHubFeature (0x2000 | LIBUSB_REQUEST_SET_FEATURE) +#define SetPortFeature (0x2300 | LIBUSB_REQUEST_SET_FEATURE) + +#define USBD_PF_CHANGE_MAX_PACKET 0x00000001 +#define USBD_PF_SHORT_PACKET_OPT 0x00000002 +#define USBD_PF_ENABLE_RT_THREAD_ACCESS 0x00000004 +#define USBD_PF_MAP_ADD_TRANSFERS 0x00000008 + +/* feature request */ +#define URB_SET_FEATURE 0x00 +#define URB_CLEAR_FEATURE 0x01 + +#define USBD_PF_CHANGE_MAX_PACKET 0x00000001 +#define USBD_PF_SHORT_PACKET_OPT 0x00000002 +#define USBD_PF_ENABLE_RT_THREAD_ACCESS 0x00000004 +#define USBD_PF_MAP_ADD_TRANSFERS 0x00000008 + +#define URB_CONTROL_TRANSFER_EXTERNAL 0x1 +#define URB_CONTROL_TRANSFER_NONEXTERNAL 0x0 + +#define USBFS_URB_SHORT_NOT_OK 0x01 +#define USBFS_URB_ISO_ASAP 0x02 +#define USBFS_URB_BULK_CONTINUATION 0x04 +#define USBFS_URB_QUEUE_BULK 0x10 + +#define URBDRC_DEVICE_INITIALIZED 0x01 +#define URBDRC_DEVICE_NOT_FOUND 0x02 +#define URBDRC_DEVICE_CHANNEL_CLOSED 0x08 +#define URBDRC_DEVICE_ALREADY_SEND 0x10 +#define URBDRC_DEVICE_DETACH_KERNEL 0x20 + +#define UDEVMAN_FLAG_ADD_BY_VID_PID 0x01 +#define UDEVMAN_FLAG_ADD_BY_ADDR 0x02 +#define UDEVMAN_FLAG_ADD_BY_AUTO 0x04 +#define UDEVMAN_FLAG_DEBUG 0x08 + +#endif /* FREERDP_CHANNEL_URBDRC_CLIENT_TYPES_H */ diff --git a/channels/video/client/video_main.c b/channels/video/client/video_main.c index 2258750..9a68d92 100644 --- a/channels/video/client/video_main.c +++ b/channels/video/client/video_main.c @@ -42,7 +42,6 @@ #include #include - #define TAG CHANNELS_TAG("video") #include "video_main.h" @@ -76,36 +75,31 @@ struct _VIDEO_PLUGIN VIDEO_LISTENER_CALLBACK* control_callback; VIDEO_LISTENER_CALLBACK* data_callback; - VideoClientContext *context; + VideoClientContext* context; }; typedef struct _VIDEO_PLUGIN VIDEO_PLUGIN; - #define XF_VIDEO_UNLIMITED_RATE 31 -static const BYTE MFVideoFormat_H264[] = {'H', '2', '6', '4', - 0x00, 0x00, - 0x10, 0x00, - 0x80, 0x00, - 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71}; +static const BYTE MFVideoFormat_H264[] = { 'H', '2', '6', '4', 0x00, 0x00, 0x10, 0x00, + 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 }; typedef struct _PresentationContext PresentationContext; typedef struct _VideoFrame VideoFrame; - /** @brief private data for the channel */ struct _VideoClientContextPriv { - VideoClientContext *video; - GeometryClientContext *geometry; - wQueue *frames; + VideoClientContext* video; + GeometryClientContext* geometry; + wQueue* frames; CRITICAL_SECTION framesLock; - wBufferPool *surfacePool; + wBufferPool* surfacePool; UINT32 publishedFrames; UINT32 droppedFrames; UINT32 lastSentRate; UINT64 nextFeedbackTime; - PresentationContext *currentPresentation; + PresentationContext* currentPresentation; }; /** @brief */ @@ -113,50 +107,49 @@ struct _VideoFrame { UINT64 publishTime; UINT64 hnsDuration; - MAPPED_GEOMETRY *geometry; + MAPPED_GEOMETRY* geometry; UINT32 w, h; - BYTE *surfaceData; - PresentationContext *presentation; + BYTE* surfaceData; + PresentationContext* presentation; }; /** @brief */ struct _PresentationContext { - VideoClientContext *video; + VideoClientContext* video; BYTE PresentationId; UINT32 SourceWidth, SourceHeight; UINT32 ScaledWidth, ScaledHeight; - MAPPED_GEOMETRY *geometry; + MAPPED_GEOMETRY* geometry; UINT64 startTimeStamp; UINT64 publishOffset; - H264_CONTEXT *h264; - YUV_CONTEXT *yuv; - wStream *currentSample; + H264_CONTEXT* h264; + YUV_CONTEXT* yuv; + wStream* currentSample; UINT64 lastPublishTime, nextPublishTime; volatile LONG refCounter; - BYTE *surfaceData; - VideoSurface *surface; + BYTE* surfaceData; + VideoSurface* surface; }; - -static const char *video_command_name(BYTE cmd) +static const char* video_command_name(BYTE cmd) { - switch(cmd) + switch (cmd) { - case TSMM_START_PRESENTATION: - return "start"; - case TSMM_STOP_PRESENTATION: - return "stop"; - default: - return ""; + case TSMM_START_PRESENTATION: + return "start"; + case TSMM_STOP_PRESENTATION: + return "stop"; + default: + return ""; } } -static BOOL yuv_to_rgb(PresentationContext *presentation, BYTE *dest) +static BOOL yuv_to_rgb(PresentationContext* presentation, BYTE* dest) { const BYTE* pYUVPoint[3]; - H264_CONTEXT *h264 = presentation->h264; + H264_CONTEXT* h264 = presentation->h264; BYTE** ppYUVData; ppYUVData = h264->pYUVData; @@ -165,7 +158,8 @@ static BOOL yuv_to_rgb(PresentationContext *presentation, BYTE *dest) pYUVPoint[1] = ppYUVData[1]; pYUVPoint[2] = ppYUVData[2]; - if (!yuv_context_decode(presentation->yuv, pYUVPoint, h264->iStride, PIXEL_FORMAT_BGRX32, dest, h264->width * 4)) + if (!yuv_context_decode(presentation->yuv, pYUVPoint, h264->iStride, PIXEL_FORMAT_BGRX32, dest, + h264->width * 4)) { WLog_ERR(TAG, "error in yuv_to_rgb conversion"); return FALSE; @@ -174,15 +168,15 @@ static BOOL yuv_to_rgb(PresentationContext *presentation, BYTE *dest) return TRUE; } - -static void video_client_context_set_geometry(VideoClientContext *video, GeometryClientContext *geometry) +static void video_client_context_set_geometry(VideoClientContext* video, + GeometryClientContext* geometry) { video->priv->geometry = geometry; } -VideoClientContextPriv *VideoClientContextPriv_new(VideoClientContext *video) +static VideoClientContextPriv* VideoClientContextPriv_new(VideoClientContext* video) { - VideoClientContextPriv *ret = calloc(1, sizeof(*ret)); + VideoClientContextPriv* ret = calloc(1, sizeof(*ret)); if (!ret) return NULL; @@ -208,9 +202,9 @@ VideoClientContextPriv *VideoClientContextPriv_new(VideoClientContext *video) ret->video = video; - /* don't set to unlimited so that we have the chance to send a feedback in - * the first second (for servers that want feedback directly) - */ + /* don't set to unlimited so that we have the chance to send a feedback in + * the first second (for servers that want feedback directly) + */ ret->lastSentRate = 30; return ret; @@ -223,12 +217,17 @@ error_frames: return NULL; } - -static PresentationContext *PresentationContext_new(VideoClientContext *video, BYTE PresentationId, - UINT32 x, UINT32 y, UINT32 width, UINT32 height) +static PresentationContext* PresentationContext_new(VideoClientContext* video, BYTE PresentationId, + UINT32 x, UINT32 y, UINT32 width, UINT32 height) { - VideoClientContextPriv *priv = video->priv; - PresentationContext *ret = calloc(1, sizeof(*ret)); + size_t s; + VideoClientContextPriv* priv = video->priv; + PresentationContext* ret; + s = width * height * 4ULL; + if (s > INT32_MAX) + return NULL; + + ret = calloc(1, sizeof(*ret)); if (!ret) return NULL; @@ -250,7 +249,7 @@ static PresentationContext *PresentationContext_new(VideoClientContext *video, B goto error_currentSample; } - ret->surfaceData = BufferPool_Take(priv->surfacePool, width * height * 4); + ret->surfaceData = BufferPool_Take(priv->surfacePool, s); if (!ret->surfaceData) { WLog_ERR(TAG, "unable to allocate surfaceData"); @@ -288,11 +287,10 @@ error_h264: return NULL; } - -static void PresentationContext_unref(PresentationContext *presentation) +static void PresentationContext_unref(PresentationContext* presentation) { - VideoClientContextPriv *priv; - MAPPED_GEOMETRY *geometry; + VideoClientContextPriv* priv; + MAPPED_GEOMETRY* geometry; if (!presentation) return; @@ -319,10 +317,9 @@ static void PresentationContext_unref(PresentationContext *presentation) free(presentation); } - -static void VideoFrame_free(VideoFrame **pframe) +static void VideoFrame_free(VideoFrame** pframe) { - VideoFrame *frame = *pframe; + VideoFrame* frame = *pframe; mappedGeometryUnref(frame->geometry); BufferPool_Return(frame->presentation->video->priv->surfacePool, frame->surfaceData); @@ -331,13 +328,12 @@ static void VideoFrame_free(VideoFrame **pframe) *pframe = NULL; } - -static void VideoClientContextPriv_free(VideoClientContextPriv *priv) +static void VideoClientContextPriv_free(VideoClientContextPriv* priv) { EnterCriticalSection(&priv->framesLock); while (Queue_Count(priv->frames)) { - VideoFrame *frame = Queue_Dequeue(priv->frames); + VideoFrame* frame = Queue_Dequeue(priv->frames); if (frame) VideoFrame_free(&frame); } @@ -354,12 +350,12 @@ static void VideoClientContextPriv_free(VideoClientContextPriv *priv) free(priv); } - -static UINT video_control_send_presentation_response(VideoClientContext *context, TSMM_PRESENTATION_RESPONSE *resp) +static UINT video_control_send_presentation_response(VideoClientContext* context, + TSMM_PRESENTATION_RESPONSE* resp) { BYTE buf[12]; - wStream *s; - VIDEO_PLUGIN* video = (VIDEO_PLUGIN *)context->handle; + wStream* s; + VIDEO_PLUGIN* video = (VIDEO_PLUGIN*)context->handle; IWTSVirtualChannel* channel; UINT ret; @@ -367,7 +363,7 @@ static UINT video_control_send_presentation_response(VideoClientContext *context if (!s) return CHANNEL_RC_NO_MEMORY; - Stream_Write_UINT32(s, 12); /* cbSize */ + Stream_Write_UINT32(s, 12); /* cbSize */ Stream_Write_UINT32(s, TSMM_PACKET_TYPE_PRESENTATION_RESPONSE); /* PacketType */ Stream_Write_UINT8(s, resp->PresentationId); Stream_Zero(s, 3); @@ -380,19 +376,19 @@ static UINT video_control_send_presentation_response(VideoClientContext *context return ret; } -static BOOL video_onMappedGeometryUpdate(MAPPED_GEOMETRY *geometry) +static BOOL video_onMappedGeometryUpdate(MAPPED_GEOMETRY* geometry) { - PresentationContext *presentation = (PresentationContext *)geometry->custom; - RDP_RECT *r = &geometry->geometry.boundingRect; + PresentationContext* presentation = (PresentationContext*)geometry->custom; + RDP_RECT* r = &geometry->geometry.boundingRect; WLog_DBG(TAG, "geometry updated topGeom=(%d,%d-%dx%d) geom=(%d,%d-%dx%d) rects=(%d,%d-%dx%d)", - geometry->topLevelLeft, geometry->topLevelTop, - geometry->topLevelRight - geometry->topLevelLeft, geometry->topLevelBottom - geometry->topLevelTop, + geometry->topLevelLeft, geometry->topLevelTop, + geometry->topLevelRight - geometry->topLevelLeft, + geometry->topLevelBottom - geometry->topLevelTop, - geometry->left, geometry->top, - geometry->right - geometry->left, geometry->bottom - geometry->top, + geometry->left, geometry->top, geometry->right - geometry->left, + geometry->bottom - geometry->top, - r->x, r->y, r->width, r->height - ); + r->x, r->y, r->width, r->height); presentation->surface->x = geometry->topLevelLeft + geometry->left; presentation->surface->y = geometry->topLevelTop + geometry->top; @@ -400,26 +396,26 @@ static BOOL video_onMappedGeometryUpdate(MAPPED_GEOMETRY *geometry) return TRUE; } -static BOOL video_onMappedGeometryClear(MAPPED_GEOMETRY *geometry) +static BOOL video_onMappedGeometryClear(MAPPED_GEOMETRY* geometry) { - PresentationContext *presentation = (PresentationContext *)geometry->custom; + PresentationContext* presentation = (PresentationContext*)geometry->custom; mappedGeometryUnref(presentation->geometry); presentation->geometry = NULL; return TRUE; } -static UINT video_PresentationRequest(VideoClientContext* video, TSMM_PRESENTATION_REQUEST *req) +static UINT video_PresentationRequest(VideoClientContext* video, TSMM_PRESENTATION_REQUEST* req) { - VideoClientContextPriv *priv = video->priv; - PresentationContext *presentation; + VideoClientContextPriv* priv = video->priv; + PresentationContext* presentation; UINT ret = CHANNEL_RC_OK; presentation = priv->currentPresentation; if (req->Command == TSMM_START_PRESENTATION) { - MAPPED_GEOMETRY *geom; + MAPPED_GEOMETRY* geom; TSMM_PRESENTATION_RESPONSE resp; if (memcmp(req->VideoSubtypeId, MFVideoFormat_H264, 16) != 0) @@ -432,7 +428,8 @@ static UINT video_PresentationRequest(VideoClientContext* video, TSMM_PRESENTATI { if (presentation->PresentationId == req->PresentationId) { - WLog_ERR(TAG, "ignoring start request for existing presentation %d", req->PresentationId); + WLog_ERR(TAG, "ignoring start request for existing presentation %d", + req->PresentationId); return CHANNEL_RC_OK; } @@ -450,15 +447,14 @@ static UINT video_PresentationRequest(VideoClientContext* video, TSMM_PRESENTATI geom = HashTable_GetItemValue(priv->geometry->geometries, &(req->GeometryMappingId)); if (!geom) { - WLog_ERR(TAG, "geometry mapping 0x%"PRIx64" not registered", req->GeometryMappingId); + WLog_ERR(TAG, "geometry mapping 0x%" PRIx64 " not registered", req->GeometryMappingId); return CHANNEL_RC_OK; } WLog_DBG(TAG, "creating presentation 0x%x", req->PresentationId); - presentation = PresentationContext_new(video, req->PresentationId, - geom->topLevelLeft + geom->left, - geom->topLevelTop + geom->top, - req->SourceWidth, req->SourceHeight); + presentation = PresentationContext_new( + video, req->PresentationId, geom->topLevelLeft + geom->left, + geom->topLevelTop + geom->top, req->SourceWidth, req->SourceHeight); if (!presentation) { WLog_ERR(TAG, "unable to create presentation video"); @@ -498,11 +494,10 @@ static UINT video_PresentationRequest(VideoClientContext* video, TSMM_PRESENTATI PresentationContext_unref(presentation); } - return CHANNEL_RC_OK; + return ret; } - -static UINT video_read_tsmm_presentation_req(VideoClientContext *context, wStream *s) +static UINT video_read_tsmm_presentation_req(VideoClientContext* context, wStream* s) { TSMM_PRESENTATION_REQUEST req; @@ -538,38 +533,38 @@ static UINT video_read_tsmm_presentation_req(VideoClientContext *context, wStrea req.pExtraData = Stream_Pointer(s); - WLog_DBG(TAG, "presentationReq: id:%"PRIu8" version:%"PRIu8" command:%s srcWidth/srcHeight=%"PRIu32"x%"PRIu32 - " scaled Width/Height=%"PRIu32"x%"PRIu32" timestamp=%"PRIu64" mappingId=%"PRIx64"", - req.PresentationId, req.Version, video_command_name(req.Command), - req.SourceWidth, req.SourceHeight, req.ScaledWidth, req.ScaledHeight, - req.hnsTimestampOffset, req.GeometryMappingId); + WLog_DBG(TAG, + "presentationReq: id:%" PRIu8 " version:%" PRIu8 + " command:%s srcWidth/srcHeight=%" PRIu32 "x%" PRIu32 " scaled Width/Height=%" PRIu32 + "x%" PRIu32 " timestamp=%" PRIu64 " mappingId=%" PRIx64 "", + req.PresentationId, req.Version, video_command_name(req.Command), req.SourceWidth, + req.SourceHeight, req.ScaledWidth, req.ScaledHeight, req.hnsTimestampOffset, + req.GeometryMappingId); return video_PresentationRequest(context, &req); } - - /** * Function description * * @return 0 on success, otherwise a Win32 error code */ -static UINT video_control_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *s) +static UINT video_control_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* s) { - VIDEO_CHANNEL_CALLBACK* callback = (VIDEO_CHANNEL_CALLBACK*) pChannelCallback; + VIDEO_CHANNEL_CALLBACK* callback = (VIDEO_CHANNEL_CALLBACK*)pChannelCallback; VIDEO_PLUGIN* video; - VideoClientContext *context; + VideoClientContext* context; UINT ret = CHANNEL_RC_OK; UINT32 cbSize, packetType; - video = (VIDEO_PLUGIN*) callback->plugin; - context = (VideoClientContext *)video->wtsPlugin.pInterface; + video = (VIDEO_PLUGIN*)callback->plugin; + context = (VideoClientContext*)video->wtsPlugin.pInterface; if (Stream_GetRemainingLength(s) < 4) return ERROR_INVALID_DATA; Stream_Read_UINT32(s, cbSize); - if (cbSize < 8 || Stream_GetRemainingLength(s) < (cbSize-4)) + if (cbSize < 8 || Stream_GetRemainingLength(s) < (cbSize - 4)) { WLog_ERR(TAG, "invalid cbSize"); return ERROR_INVALID_DATA; @@ -578,23 +573,24 @@ static UINT video_control_on_data_received(IWTSVirtualChannelCallback* pChannelC Stream_Read_UINT32(s, packetType); switch (packetType) { - case TSMM_PACKET_TYPE_PRESENTATION_REQUEST: - ret = video_read_tsmm_presentation_req(context, s); - break; - default: - WLog_ERR(TAG, "not expecting packet type %"PRIu32"", packetType); - ret = ERROR_UNSUPPORTED_TYPE; - break; + case TSMM_PACKET_TYPE_PRESENTATION_REQUEST: + ret = video_read_tsmm_presentation_req(context, s); + break; + default: + WLog_ERR(TAG, "not expecting packet type %" PRIu32 "", packetType); + ret = ERROR_UNSUPPORTED_TYPE; + break; } return ret; } -static UINT video_control_send_client_notification(VideoClientContext *context, TSMM_CLIENT_NOTIFICATION *notif) +static UINT video_control_send_client_notification(VideoClientContext* context, + TSMM_CLIENT_NOTIFICATION* notif) { BYTE buf[100]; - wStream *s; - VIDEO_PLUGIN* video = (VIDEO_PLUGIN *)context->handle; + wStream* s; + VIDEO_PLUGIN* video = (VIDEO_PLUGIN*)context->handle; IWTSVirtualChannel* channel; UINT ret; UINT32 cbSize; @@ -604,7 +600,7 @@ static UINT video_control_send_client_notification(VideoClientContext *context, return CHANNEL_RC_NO_MEMORY; cbSize = 16; - Stream_Seek_UINT32(s); /* cbSize */ + Stream_Seek_UINT32(s); /* cbSize */ Stream_Write_UINT32(s, TSMM_PACKET_TYPE_CLIENT_NOTIFICATION); /* PacketType */ Stream_Write_UINT8(s, notif->PresentationId); Stream_Write_UINT8(s, notif->NotificationType); @@ -636,16 +632,16 @@ static UINT video_control_send_client_notification(VideoClientContext *context, return ret; } -static void video_timer(VideoClientContext *video, UINT64 now) +static void video_timer(VideoClientContext* video, UINT64 now) { - PresentationContext *presentation; - VideoClientContextPriv *priv = video->priv; + PresentationContext* presentation; + VideoClientContextPriv* priv = video->priv; VideoFrame *peekFrame, *frame = NULL; EnterCriticalSection(&priv->framesLock); do { - peekFrame = (VideoFrame *)Queue_Peek(priv->frames); + peekFrame = (VideoFrame*)Queue_Peek(priv->frames); if (!peekFrame) break; @@ -654,14 +650,13 @@ static void video_timer(VideoClientContext *video, UINT64 now) if (frame) { - WLog_DBG(TAG, "dropping frame @%"PRIu64, frame->publishTime); + WLog_DBG(TAG, "dropping frame @%" PRIu64, frame->publishTime); priv->droppedFrames++; VideoFrame_free(&frame); } frame = peekFrame; Queue_Dequeue(priv->frames); - } - while (1); + } while (1); LeaveCriticalSection(&priv->framesLock); if (!frame) @@ -709,7 +704,7 @@ treat_feedback: /** * we treat all frames ok, so either ask the server to send more, * or stay unlimited - */ + */ if (priv->lastSentRate == XF_VIDEO_UNLIMITED_RATE) computedRate = XF_VIDEO_UNLIMITED_RATE; /* stay unlimited */ else @@ -739,15 +734,15 @@ treat_feedback: video_control_send_client_notification(video, ¬if); priv->lastSentRate = computedRate; - WLog_DBG(TAG, "server notified with rate %d published=%d dropped=%d", priv->lastSentRate, - priv->publishedFrames, priv->droppedFrames); + WLog_DBG(TAG, "server notified with rate %d published=%d dropped=%d", + priv->lastSentRate, priv->publishedFrames, priv->droppedFrames); } PresentationContext_unref(priv->currentPresentation); } WLog_DBG(TAG, "currentRate=%d published=%d dropped=%d", priv->lastSentRate, - priv->publishedFrames, priv->droppedFrames); + priv->publishedFrames, priv->droppedFrames); priv->droppedFrames = 0; priv->publishedFrames = 0; @@ -755,11 +750,10 @@ treat_feedback: } } - -static UINT video_VideoData(VideoClientContext* context, TSMM_VIDEO_DATA *data) +static UINT video_VideoData(VideoClientContext* context, TSMM_VIDEO_DATA* data) { - VideoClientContextPriv *priv = context->priv; - PresentationContext *presentation; + VideoClientContextPriv* priv = context->priv; + PresentationContext* presentation; int status; presentation = priv->currentPresentation; @@ -771,8 +765,8 @@ static UINT video_VideoData(VideoClientContext* context, TSMM_VIDEO_DATA *data) if (presentation->PresentationId != data->PresentationId) { - WLog_ERR(TAG, "current presentation id=%d doesn't match data id=%d", presentation->PresentationId, - data->PresentationId); + WLog_ERR(TAG, "current presentation id=%d doesn't match data id=%d", + presentation->PresentationId, data->PresentationId); return CHANNEL_RC_OK; } @@ -786,15 +780,15 @@ static UINT video_VideoData(VideoClientContext* context, TSMM_VIDEO_DATA *data) if (data->CurrentPacketIndex == data->PacketsInSample) { - H264_CONTEXT *h264 = presentation->h264; + H264_CONTEXT* h264 = presentation->h264; UINT64 startTime = GetTickCount64(), timeAfterH264; - MAPPED_GEOMETRY *geom = presentation->geometry; + MAPPED_GEOMETRY* geom = presentation->geometry; Stream_SealLength(presentation->currentSample); Stream_SetPosition(presentation->currentSample, 0); status = h264->subsystem->Decompress(h264, Stream_Pointer(presentation->currentSample), - Stream_Length(presentation->currentSample)); + Stream_Length(presentation->currentSample)); if (status == 0) return CHANNEL_RC_OK; @@ -823,7 +817,7 @@ static UINT video_VideoData(VideoClientContext* context, TSMM_VIDEO_DATA *data) EnterCriticalSection(&priv->framesLock); while (Queue_Count(priv->frames) > 0) { - VideoFrame *frame = Queue_Dequeue(priv->frames); + VideoFrame* frame = Queue_Dequeue(priv->frames); if (frame) { priv->droppedFrames++; @@ -839,7 +833,7 @@ static UINT video_VideoData(VideoClientContext* context, TSMM_VIDEO_DATA *data) else { BOOL enqueueResult; - VideoFrame *frame = calloc(1, sizeof(*frame)); + VideoFrame* frame = calloc(1, sizeof(*frame)); if (!frame) { WLog_ERR(TAG, "unable to create frame"); @@ -884,31 +878,29 @@ static UINT video_VideoData(VideoClientContext* context, TSMM_VIDEO_DATA *data) return CHANNEL_RC_NO_MEMORY; } - WLog_DBG(TAG, "scheduling frame in %"PRIu32" ms", (frame->publishTime-startTime)); + WLog_DBG(TAG, "scheduling frame in %" PRIu32 " ms", (frame->publishTime - startTime)); } } return CHANNEL_RC_OK; } - - -static UINT video_data_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *s) +static UINT video_data_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* s) { - VIDEO_CHANNEL_CALLBACK* callback = (VIDEO_CHANNEL_CALLBACK*) pChannelCallback; + VIDEO_CHANNEL_CALLBACK* callback = (VIDEO_CHANNEL_CALLBACK*)pChannelCallback; VIDEO_PLUGIN* video; - VideoClientContext *context; + VideoClientContext* context; UINT32 cbSize, packetType; TSMM_VIDEO_DATA data; - video = (VIDEO_PLUGIN*) callback->plugin; - context = (VideoClientContext *)video->wtsPlugin.pInterface; + video = (VIDEO_PLUGIN*)callback->plugin; + context = (VideoClientContext*)video->wtsPlugin.pInterface; if (Stream_GetRemainingLength(s) < 4) return ERROR_INVALID_DATA; Stream_Read_UINT32(s, cbSize); - if (cbSize < 8 || Stream_GetRemainingLength(s) < (cbSize-4)) + if (cbSize < 8 || Stream_GetRemainingLength(s) < (cbSize - 4)) { WLog_ERR(TAG, "invalid cbSize"); return ERROR_INVALID_DATA; @@ -939,17 +931,17 @@ static UINT video_data_on_data_received(IWTSVirtualChannelCallback* pChannelCall Stream_Read_UINT32(s, data.cbSample); data.pSample = Stream_Pointer(s); -/* - WLog_DBG(TAG, "videoData: id:%"PRIu8" version:%"PRIu8" flags:0x%"PRIx8" timestamp=%"PRIu64" duration=%"PRIu64 - " curPacketIndex:%"PRIu16" packetInSample:%"PRIu16" sampleNumber:%"PRIu32" cbSample:%"PRIu32"", - data.PresentationId, data.Version, data.Flags, data.hnsTimestamp, data.hnsDuration, - data.CurrentPacketIndex, data.PacketsInSample, data.SampleNumber, data.cbSample); -*/ + /* + WLog_DBG(TAG, "videoData: id:%"PRIu8" version:%"PRIu8" flags:0x%"PRIx8" timestamp=%"PRIu64" + duration=%"PRIu64 " curPacketIndex:%"PRIu16" packetInSample:%"PRIu16" sampleNumber:%"PRIu32" + cbSample:%"PRIu32"", data.PresentationId, data.Version, data.Flags, data.hnsTimestamp, + data.hnsDuration, data.CurrentPacketIndex, data.PacketsInSample, data.SampleNumber, + data.cbSample); + */ return video_VideoData(context, &data); } - /** * Function description * @@ -973,13 +965,17 @@ static UINT video_data_on_close(IWTSVirtualChannelCallback* pChannelCallback) * @return 0 on success, otherwise a Win32 error code */ static UINT video_control_on_new_channel_connection(IWTSListenerCallback* listenerCallback, - IWTSVirtualChannel* channel, BYTE* Data, BOOL* pbAccept, - IWTSVirtualChannelCallback** ppCallback) + IWTSVirtualChannel* channel, BYTE* Data, + BOOL* pbAccept, + IWTSVirtualChannelCallback** ppCallback) { VIDEO_CHANNEL_CALLBACK* callback; - VIDEO_LISTENER_CALLBACK* listener_callback = (VIDEO_LISTENER_CALLBACK*) listenerCallback; + VIDEO_LISTENER_CALLBACK* listener_callback = (VIDEO_LISTENER_CALLBACK*)listenerCallback; - callback = (VIDEO_CHANNEL_CALLBACK*) calloc(1, sizeof(VIDEO_CHANNEL_CALLBACK)); + WINPR_UNUSED(Data); + WINPR_UNUSED(pbAccept); + + callback = (VIDEO_CHANNEL_CALLBACK*)calloc(1, sizeof(VIDEO_CHANNEL_CALLBACK)); if (!callback) { WLog_ERR(TAG, "calloc failed!"); @@ -993,19 +989,23 @@ static UINT video_control_on_new_channel_connection(IWTSListenerCallback* listen callback->channel = channel; listener_callback->channel_callback = callback; - *ppCallback = (IWTSVirtualChannelCallback*) callback; + *ppCallback = (IWTSVirtualChannelCallback*)callback; return CHANNEL_RC_OK; } static UINT video_data_on_new_channel_connection(IWTSListenerCallback* pListenerCallback, - IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept, - IWTSVirtualChannelCallback** ppCallback) + IWTSVirtualChannel* pChannel, BYTE* Data, + BOOL* pbAccept, + IWTSVirtualChannelCallback** ppCallback) { VIDEO_CHANNEL_CALLBACK* callback; - VIDEO_LISTENER_CALLBACK* listener_callback = (VIDEO_LISTENER_CALLBACK*) pListenerCallback; + VIDEO_LISTENER_CALLBACK* listener_callback = (VIDEO_LISTENER_CALLBACK*)pListenerCallback; + + WINPR_UNUSED(Data); + WINPR_UNUSED(pbAccept); - callback = (VIDEO_CHANNEL_CALLBACK*) calloc(1, sizeof(VIDEO_CHANNEL_CALLBACK)); + callback = (VIDEO_CHANNEL_CALLBACK*)calloc(1, sizeof(VIDEO_CHANNEL_CALLBACK)); if (!callback) { WLog_ERR(TAG, "calloc failed!"); @@ -1019,12 +1019,11 @@ static UINT video_data_on_new_channel_connection(IWTSListenerCallback* pListener callback->channel = pChannel; listener_callback->channel_callback = callback; - *ppCallback = (IWTSVirtualChannelCallback*) callback; + *ppCallback = (IWTSVirtualChannelCallback*)callback; return CHANNEL_RC_OK; } - /** * Function description * @@ -1033,10 +1032,11 @@ static UINT video_data_on_new_channel_connection(IWTSListenerCallback* pListener static UINT video_plugin_initialize(IWTSPlugin* plugin, IWTSVirtualChannelManager* channelMgr) { UINT status; - VIDEO_PLUGIN* video = (VIDEO_PLUGIN *)plugin; - VIDEO_LISTENER_CALLBACK *callback; + VIDEO_PLUGIN* video = (VIDEO_PLUGIN*)plugin; + VIDEO_LISTENER_CALLBACK* callback; - video->control_callback = callback = (VIDEO_LISTENER_CALLBACK*) calloc(1, sizeof(VIDEO_LISTENER_CALLBACK)); + video->control_callback = callback = + (VIDEO_LISTENER_CALLBACK*)calloc(1, sizeof(VIDEO_LISTENER_CALLBACK)); if (!callback) { WLog_ERR(TAG, "calloc for control callback failed!"); @@ -1048,14 +1048,14 @@ static UINT video_plugin_initialize(IWTSPlugin* plugin, IWTSVirtualChannelManage callback->channel_mgr = channelMgr; status = channelMgr->CreateListener(channelMgr, VIDEO_CONTROL_DVC_CHANNEL_NAME, 0, - (IWTSListenerCallback*)callback, &(video->controlListener)); + &callback->iface, &(video->controlListener)); if (status != CHANNEL_RC_OK) return status; video->controlListener->pInterface = video->wtsPlugin.pInterface; - - video->data_callback = callback = (VIDEO_LISTENER_CALLBACK*) calloc(1, sizeof(VIDEO_LISTENER_CALLBACK)); + video->data_callback = callback = + (VIDEO_LISTENER_CALLBACK*)calloc(1, sizeof(VIDEO_LISTENER_CALLBACK)); if (!callback) { WLog_ERR(TAG, "calloc for data callback failed!"); @@ -1067,7 +1067,7 @@ static UINT video_plugin_initialize(IWTSPlugin* plugin, IWTSVirtualChannelManage callback->channel_mgr = channelMgr; status = channelMgr->CreateListener(channelMgr, VIDEO_DATA_DVC_CHANNEL_NAME, 0, - (IWTSListenerCallback*)callback, &(video->dataListener)); + &callback->iface, &(video->dataListener)); if (status == CHANNEL_RC_OK) video->dataListener->pInterface = video->wtsPlugin.pInterface; @@ -1082,7 +1082,20 @@ static UINT video_plugin_initialize(IWTSPlugin* plugin, IWTSVirtualChannelManage */ static UINT video_plugin_terminated(IWTSPlugin* pPlugin) { - VIDEO_PLUGIN* video = (VIDEO_PLUGIN*) pPlugin; + VIDEO_PLUGIN* video = (VIDEO_PLUGIN*)pPlugin; + + if (video->control_callback) + { + IWTSVirtualChannelManager* mgr = video->control_callback->channel_mgr; + if (mgr) + IFCALL(mgr->DestroyListener, mgr, video->controlListener); + } + if (video->data_callback) + { + IWTSVirtualChannelManager* mgr = video->data_callback->channel_mgr; + if (mgr) + IFCALL(mgr->DestroyListener, mgr, video->dataListener); + } if (video->context) VideoClientContextPriv_free(video->context->priv); @@ -1098,11 +1111,10 @@ static UINT video_plugin_terminated(IWTSPlugin* pPlugin) * Channel Client Interface */ - #ifdef BUILTIN_CHANNELS -#define DVCPluginEntry video_DVCPluginEntry +#define DVCPluginEntry video_DVCPluginEntry #else -#define DVCPluginEntry FREERDP_API DVCPluginEntry +#define DVCPluginEntry FREERDP_API DVCPluginEntry #endif /** @@ -1115,12 +1127,12 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) UINT error = CHANNEL_RC_OK; VIDEO_PLUGIN* videoPlugin; VideoClientContext* videoContext; - VideoClientContextPriv *priv; + VideoClientContextPriv* priv; - videoPlugin = (VIDEO_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "video"); + videoPlugin = (VIDEO_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "video"); if (!videoPlugin) { - videoPlugin = (VIDEO_PLUGIN*) calloc(1, sizeof(VIDEO_PLUGIN)); + videoPlugin = (VIDEO_PLUGIN*)calloc(1, sizeof(VIDEO_PLUGIN)); if (!videoPlugin) { WLog_ERR(TAG, "calloc failed!"); @@ -1132,7 +1144,7 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) videoPlugin->wtsPlugin.Disconnected = NULL; videoPlugin->wtsPlugin.Terminated = video_plugin_terminated; - videoContext = (VideoClientContext*) calloc(1, sizeof(VideoClientContext)); + videoContext = (VideoClientContext*)calloc(1, sizeof(VideoClientContext)); if (!videoContext) { WLog_ERR(TAG, "calloc failed!"); @@ -1149,15 +1161,15 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) return CHANNEL_RC_NO_MEMORY; } - videoContext->handle = (void*) videoPlugin; + videoContext->handle = (void*)videoPlugin; videoContext->priv = priv; videoContext->timer = video_timer; videoContext->setGeometry = video_client_context_set_geometry; - videoPlugin->wtsPlugin.pInterface = (void*) videoContext; + videoPlugin->wtsPlugin.pInterface = (void*)videoContext; videoPlugin->context = videoContext; - error = pEntryPoints->RegisterPlugin(pEntryPoints, "video", (IWTSPlugin*) videoPlugin); + error = pEntryPoints->RegisterPlugin(pEntryPoints, "video", (IWTSPlugin*)videoPlugin); } else { diff --git a/channels/video/client/video_main.h b/channels/video/client/video_main.h index f5e5ac9..1814566 100644 --- a/channels/video/client/video_main.h +++ b/channels/video/client/video_main.h @@ -30,6 +30,4 @@ #include - #endif /* FREERDP_CHANNEL_GEOMETRY_CLIENT_MAIN_H */ - diff --git a/ci/cmake-preloads/config-android.txt b/ci/cmake-preloads/config-android.txt index 38833e7..bcb3446 100644 --- a/ci/cmake-preloads/config-android.txt +++ b/ci/cmake-preloads/config-android.txt @@ -1,5 +1,5 @@ message("PRELOADING android cache") -set(CMAKE_TOOLCHAIN_FILE "cmake/AndroidToolchain.cmake" CACHE PATH "ToolChain file") +set(CMAKE_TOOLCHAIN_FILE "$ANDROID_NDK/build/cmake/android.toolchain.cmake" CACHE PATH "ToolChain file") set(WITH_SANITIZE_ADDRESS ON) set(FREERDP_EXTERNAL_SSL_PATH $ENV{ANDROID_SSL_PATH} CACHE PATH "android ssl") # ANDROID_NDK and ANDROID_SDK must be set as environment variable diff --git a/ci/cmake-preloads/config-linux-all.txt b/ci/cmake-preloads/config-linux-all.txt index 16d3f9f..408059c 100644 --- a/ci/cmake-preloads/config-linux-all.txt +++ b/ci/cmake-preloads/config-linux-all.txt @@ -9,7 +9,7 @@ set (BUILTIN_CHANNELS ON CACHE BOOL "static channels") set (WITH_CUPS ON CACHE BOOL "cups") set (WITH_GSSAPI ON CACHE BOOL "Kerberos support") set (WITH_PCSC ON CACHE BOOL "PCSC") -set (WITH_JPEG ON CACHE BOOL "jepg") +set (WITH_JPEG ON CACHE BOOL "jpeg") set (WITH_GSTREAMER_0_10 ON CACHE BOOL "gstreamer") set (WITH_GSM ON CACHE BOOL "gsm") set (CHANNEL_URBDRC ON CACHE BOOL "urbdrc") @@ -20,6 +20,7 @@ set (WITH_DEBUG_CAPABILITIES OFF CACHE BOOL "enable debug") set (WITH_DEBUG_CERTIFICATE OFF CACHE BOOL "enable debug") set (WITH_DEBUG_CHANNELS OFF CACHE BOOL "enable debug") set (WITH_DEBUG_CLIPRDR OFF CACHE BOOL "enable debug") +set (WITH_DEBUG_RDPGFX OFF CACHE BOOL "enable debug") set (WITH_DEBUG_DVC OFF CACHE BOOL "enable debug") set (WITH_DEBUG_KBD OFF CACHE BOOL "enable debug") set (WITH_DEBUG_LICENSE OFF CACHE BOOL "enable debug") @@ -48,3 +49,4 @@ set (WITH_DEBUG_XV OFF CACHE BOOL "enable debug") set (WITH_SAMPLE ON CACHE BOOL "samples") set (WITH_NO_UNDEFINED ON CACHE BOOL "don't link with undefined symbols") set (WITH_SANITIZE_ADDRESS ON) +set (WITH_PROXY_MODULES OFF CACHE BOOL "compile proxy modules") diff --git a/ci/cmake-preloads/config-macosx.txt b/ci/cmake-preloads/config-macosx.txt index 8c68aed..a004dd9 100644 --- a/ci/cmake-preloads/config-macosx.txt +++ b/ci/cmake-preloads/config-macosx.txt @@ -2,6 +2,7 @@ message("PRELOADING mac cache") set (WITH_MANPAGES OFF CACHE BOOL "man pages") set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "build type") set (WITH_CUPS ON CACHE BOOL "CUPS printing") +set (CHANNEL_URBDRC OFF CACHE BOOL "USB redirection") set (WITH_X11 ON CACHE BOOL "Enable X11") set (BUILD_TESTING ON CACHE BOOL "build testing") set (WITH_SANITIZE_ADDRESS ON) diff --git a/ci/cmake-preloads/config-windows.txt b/ci/cmake-preloads/config-windows.txt index 33dc8b4..fcc78ae 100644 --- a/ci/cmake-preloads/config-windows.txt +++ b/ci/cmake-preloads/config-windows.txt @@ -1,5 +1,6 @@ message("PRELOADING windows cache") set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "build type") set (WITH_SERVER "ON" CACHE BOOL "Build server binaries") +set (CHANNEL_URBDRC OFF CACHE BOOL "USB redirection") set (BUILD_TESTING ON CACHE BOOL "build testing") set (WITH_SANITIZE_ADDRESS ON) diff --git a/client/.gitignore b/client/.gitignore new file mode 100644 index 0000000..7c1ea95 --- /dev/null +++ b/client/.gitignore @@ -0,0 +1,12 @@ +/* +!/Android +!/common +!/iOS +!/Mac +!/Sample +!/Windows +!/X11 +!/Wayland +!/CMakeLists.txt +!*.in +Wayland/wlfreerdp.1 diff --git a/client/Android/BuildFlags.java.in b/client/Android/BuildFlags.java.in new file mode 100644 index 0000000..9b15e47 --- /dev/null +++ b/client/Android/BuildFlags.java.in @@ -0,0 +1,6 @@ +package com.freerdp.freerdpcore.utils; + +public class BuildFlags +{ + private final static boolean USE_OPENSSL_DEFAULT_NAMES = @USE_OPENSSL_DEFAULT_NAMES@; +} diff --git a/client/Android/Studio/aFreeRDP/build.gradle b/client/Android/Studio/aFreeRDP/build.gradle index be32859..fc3dba2 100644 --- a/client/Android/Studio/aFreeRDP/build.gradle +++ b/client/Android/Studio/aFreeRDP/build.gradle @@ -1,15 +1,15 @@ apply plugin: 'com.android.application' android { - compileSdkVersion = 27 - buildToolsVersion = "27.0.3" + compileSdkVersion = 28 + buildToolsVersion = "28.0.3" defaultConfig { applicationId "com.freerdp.afreerdp" - minSdkVersion 14 - targetSdkVersion 27 + minSdkVersion 21 + targetSdkVersion 28 vectorDrawables.useSupportLibrary = true - versionCode = 14 + versionCode = rootProject.ext.versionCode versionName = rootProject.ext.versionName } @@ -37,5 +37,5 @@ android { } dependencies { - compile project(':freeRDPCore') + implementation project(':freeRDPCore') } diff --git a/client/Android/Studio/aFreeRDP/src/main/java/com/freerdp/afreerdp/application/GlobalApp.java b/client/Android/Studio/aFreeRDP/src/main/java/com/freerdp/afreerdp/application/GlobalApp.java index c0b36f0..7d44959 100644 --- a/client/Android/Studio/aFreeRDP/src/main/java/com/freerdp/afreerdp/application/GlobalApp.java +++ b/client/Android/Studio/aFreeRDP/src/main/java/com/freerdp/afreerdp/application/GlobalApp.java @@ -1,6 +1,5 @@ package com.freerdp.afreerdp.application; - -public class GlobalApp extends com.freerdp.freerdpcore.application.GlobalApp { - +public class GlobalApp extends com.freerdp.freerdpcore.application.GlobalApp +{ } diff --git a/client/Android/Studio/build.gradle b/client/Android/Studio/build.gradle index f6174c8..c1d7dd2 100644 --- a/client/Android/Studio/build.gradle +++ b/client/Android/Studio/build.gradle @@ -6,7 +6,7 @@ if (file.canRead()) { } if (!hasProperty('RELEASE_STORE_FILE')) { - ext.RELEASE_STORE_FILE='' + ext.RELEASE_STORE_FILE='nokeyfile' } if (!hasProperty('RELEASE_KEY_ALIAS')) { ext.RELEASE_KEY_ALIAS='' @@ -29,9 +29,11 @@ def getVersionName = { -> ext { versionName = properties.get('VERSION_NAME', getVersionName()) + versionCode = properties.get('VERSION_CODE', 19) println '----------------- Project configuration -------------------' println 'VERSION_NAME: ' + versionName + println 'VERSION_CODE: ' + versionCode println 'RELEASE_STORE_FILE: '+ RELEASE_STORE_FILE println 'RELEASE_KEY_ALIAS: '+ RELEASE_KEY_ALIAS println '-----------------------------------------------------------' @@ -43,7 +45,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:3.0.1' + classpath 'com.android.tools.build:gradle:3.2.1' } } diff --git a/client/Android/Studio/freeRDPCore/build.gradle b/client/Android/Studio/freeRDPCore/build.gradle index 28c2e6b..c275b39 100644 --- a/client/Android/Studio/freeRDPCore/build.gradle +++ b/client/Android/Studio/freeRDPCore/build.gradle @@ -1,14 +1,14 @@ apply plugin: 'com.android.library' android { - compileSdkVersion = 27 - buildToolsVersion = "27.0.3" + compileSdkVersion = 28 + buildToolsVersion = "28.0.3" defaultConfig { - minSdkVersion 14 - targetSdkVersion 27 + minSdkVersion 21 + targetSdkVersion 28 vectorDrawables.useSupportLibrary = true - versionCode = 14 + versionCode = rootProject.ext.versionCode versionName = rootProject.ext.versionName } @@ -25,7 +25,7 @@ android { } dependencies { - compile 'com.android.support:appcompat-v7:27.0.2' - compile 'com.android.support:support-v4:27.0.2' - compile 'com.android.support:support-vector-drawable:27.0.2' + implementation 'com.android.support:appcompat-v7:28.0.0' + implementation 'com.android.support:support-v4:28.0.0' + implementation 'com.android.support:support-vector-drawable:28.0.0' } diff --git a/client/Android/Studio/freeRDPCore/src/main/AndroidManifest.xml b/client/Android/Studio/freeRDPCore/src/main/AndroidManifest.xml index 570cdc5..ef59325 100644 --- a/client/Android/Studio/freeRDPCore/src/main/AndroidManifest.xml +++ b/client/Android/Studio/freeRDPCore/src/main/AndroidManifest.xml @@ -68,7 +68,7 @@ diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/application/GlobalApp.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/application/GlobalApp.java index ce6c4d8..e71a86e 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/application/GlobalApp.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/application/GlobalApp.java @@ -3,8 +3,9 @@ Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.application; @@ -32,159 +33,179 @@ import java.util.Map; import java.util.Timer; import java.util.TimerTask; -public class GlobalApp extends Application implements LibFreeRDP.EventListener { - // event notification defines - public static final String EVENT_TYPE = "EVENT_TYPE"; - public static final String EVENT_PARAM = "EVENT_PARAM"; - public static final String EVENT_STATUS = "EVENT_STATUS"; - public static final String EVENT_ERROR = "EVENT_ERROR"; - public static final String ACTION_EVENT_FREERDP = "com.freerdp.freerdp.event.freerdp"; - public static final int FREERDP_EVENT_CONNECTION_SUCCESS = 1; - public static final int FREERDP_EVENT_CONNECTION_FAILURE = 2; - public static final int FREERDP_EVENT_DISCONNECTED = 3; - private static final String TAG = "GlobalApp"; - public static boolean ConnectedTo3G = false; - private static Map sessionMap; - private static BookmarkDB bookmarkDB; - private static ManualBookmarkGateway manualBookmarkGateway; - - private static HistoryDB historyDB; - private static QuickConnectHistoryGateway quickConnectHistoryGateway; - - // timer for disconnecting sessions after the screen was turned off - private static Timer disconnectTimer = null; - - public static ManualBookmarkGateway getManualBookmarkGateway() { - return manualBookmarkGateway; - } - - public static QuickConnectHistoryGateway getQuickConnectHistoryGateway() { - return quickConnectHistoryGateway; - } - - // Disconnect handling for Screen on/off events - public void startDisconnectTimer() { - final int timeoutMinutes = ApplicationSettingsActivity.getDisconnectTimeout(this); - if (timeoutMinutes > 0) { - // start disconnect timeout... - disconnectTimer = new Timer(); - disconnectTimer.schedule(new DisconnectTask(), timeoutMinutes * 60 * 1000); - } - } - - static public void cancelDisconnectTimer() { - // cancel any pending timer events - if (disconnectTimer != null) { - disconnectTimer.cancel(); - disconnectTimer.purge(); - disconnectTimer = null; - } - } - - // RDP session handling - static public SessionState createSession(BookmarkBase bookmark, Context context) { - SessionState session = new SessionState(LibFreeRDP.newInstance(context), bookmark); - sessionMap.put(Long.valueOf(session.getInstance()), session); - return session; - } - - static public SessionState createSession(Uri openUri, Context context) { - SessionState session = new SessionState(LibFreeRDP.newInstance(context), openUri); - sessionMap.put(Long.valueOf(session.getInstance()), session); - return session; - } - - static public SessionState getSession(long instance) { - return sessionMap.get(instance); - } - - static public Collection getSessions() { - // return a copy of the session items - return new ArrayList(sessionMap.values()); - } - - static public void freeSession(long instance) { - if (GlobalApp.sessionMap.containsKey(instance)) { - GlobalApp.sessionMap.remove(instance); - LibFreeRDP.freeInstance(instance); - } - } - - @Override - public void onCreate() { - super.onCreate(); - - /* Initialize preferences. */ - ApplicationSettingsActivity.get(this); - - sessionMap = Collections.synchronizedMap(new HashMap()); - - LibFreeRDP.setEventListener(this); - - bookmarkDB = new BookmarkDB(this); - - manualBookmarkGateway = new ManualBookmarkGateway(bookmarkDB); - - historyDB = new HistoryDB(this); - quickConnectHistoryGateway = new QuickConnectHistoryGateway(historyDB); - - ConnectedTo3G = NetworkStateReceiver.isConnectedTo3G(this); - - // init screen receiver here (this can't be declared in AndroidManifest - refer to: - // http://thinkandroid.wordpress.com/2010/01/24/handling-screen-off-and-screen-on-intents/ - IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON); - filter.addAction(Intent.ACTION_SCREEN_OFF); - registerReceiver(new ScreenReceiver(), filter); - } - - // helper to send FreeRDP notifications - private void sendRDPNotification(int type, long param) { - // send broadcast - Intent intent = new Intent(ACTION_EVENT_FREERDP); - intent.putExtra(EVENT_TYPE, type); - intent.putExtra(EVENT_PARAM, param); - sendBroadcast(intent); - } - - @Override - public void OnPreConnect(long instance) { - Log.v(TAG, "OnPreConnect"); - } - - // ////////////////////////////////////////////////////////////////////// - // Implementation of LibFreeRDP.EventListener - public void OnConnectionSuccess(long instance) { - Log.v(TAG, "OnConnectionSuccess"); - sendRDPNotification(FREERDP_EVENT_CONNECTION_SUCCESS, instance); - } - - public void OnConnectionFailure(long instance) { - Log.v(TAG, "OnConnectionFailure"); - - // send notification to session activity - sendRDPNotification(FREERDP_EVENT_CONNECTION_FAILURE, instance); - } - - public void OnDisconnecting(long instance) { - Log.v(TAG, "OnDisconnecting"); - } - - public void OnDisconnected(long instance) { - Log.v(TAG, "OnDisconnected"); - sendRDPNotification(FREERDP_EVENT_DISCONNECTED, instance); - } - - // TimerTask for disconnecting sessions after screen was turned off - private static class DisconnectTask extends TimerTask { - @Override - public void run() { - Log.v("DisconnectTask", "Doing action"); - - // disconnect any running rdp session - Collection sessions = GlobalApp.getSessions(); - for (SessionState session : sessions) { - LibFreeRDP.disconnect(session.getInstance()); - } - } - } +public class GlobalApp extends Application implements LibFreeRDP.EventListener +{ + // event notification defines + public static final String EVENT_TYPE = "EVENT_TYPE"; + public static final String EVENT_PARAM = "EVENT_PARAM"; + public static final String EVENT_STATUS = "EVENT_STATUS"; + public static final String EVENT_ERROR = "EVENT_ERROR"; + public static final String ACTION_EVENT_FREERDP = "com.freerdp.freerdp.event.freerdp"; + public static final int FREERDP_EVENT_CONNECTION_SUCCESS = 1; + public static final int FREERDP_EVENT_CONNECTION_FAILURE = 2; + public static final int FREERDP_EVENT_DISCONNECTED = 3; + private static final String TAG = "GlobalApp"; + public static boolean ConnectedTo3G = false; + private static Map sessionMap; + private static BookmarkDB bookmarkDB; + private static ManualBookmarkGateway manualBookmarkGateway; + + private static HistoryDB historyDB; + private static QuickConnectHistoryGateway quickConnectHistoryGateway; + + // timer for disconnecting sessions after the screen was turned off + private static Timer disconnectTimer = null; + + public static ManualBookmarkGateway getManualBookmarkGateway() + { + return manualBookmarkGateway; + } + + public static QuickConnectHistoryGateway getQuickConnectHistoryGateway() + { + return quickConnectHistoryGateway; + } + + // Disconnect handling for Screen on/off events + public void startDisconnectTimer() + { + final int timeoutMinutes = ApplicationSettingsActivity.getDisconnectTimeout(this); + if (timeoutMinutes > 0) + { + // start disconnect timeout... + disconnectTimer = new Timer(); + disconnectTimer.schedule(new DisconnectTask(), timeoutMinutes * 60 * 1000); + } + } + + static public void cancelDisconnectTimer() + { + // cancel any pending timer events + if (disconnectTimer != null) + { + disconnectTimer.cancel(); + disconnectTimer.purge(); + disconnectTimer = null; + } + } + + // RDP session handling + static public SessionState createSession(BookmarkBase bookmark, Context context) + { + SessionState session = new SessionState(LibFreeRDP.newInstance(context), bookmark); + sessionMap.put(Long.valueOf(session.getInstance()), session); + return session; + } + + static public SessionState createSession(Uri openUri, Context context) + { + SessionState session = new SessionState(LibFreeRDP.newInstance(context), openUri); + sessionMap.put(Long.valueOf(session.getInstance()), session); + return session; + } + + static public SessionState getSession(long instance) + { + return sessionMap.get(instance); + } + + static public Collection getSessions() + { + // return a copy of the session items + return new ArrayList(sessionMap.values()); + } + + static public void freeSession(long instance) + { + if (GlobalApp.sessionMap.containsKey(instance)) + { + GlobalApp.sessionMap.remove(instance); + LibFreeRDP.freeInstance(instance); + } + } + + @Override public void onCreate() + { + super.onCreate(); + + /* Initialize preferences. */ + ApplicationSettingsActivity.get(this); + + sessionMap = Collections.synchronizedMap(new HashMap()); + + LibFreeRDP.setEventListener(this); + + bookmarkDB = new BookmarkDB(this); + + manualBookmarkGateway = new ManualBookmarkGateway(bookmarkDB); + + historyDB = new HistoryDB(this); + quickConnectHistoryGateway = new QuickConnectHistoryGateway(historyDB); + + ConnectedTo3G = NetworkStateReceiver.isConnectedTo3G(this); + + // init screen receiver here (this can't be declared in AndroidManifest - refer to: + // http://thinkandroid.wordpress.com/2010/01/24/handling-screen-off-and-screen-on-intents/ + IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON); + filter.addAction(Intent.ACTION_SCREEN_OFF); + registerReceiver(new ScreenReceiver(), filter); + } + + // helper to send FreeRDP notifications + private void sendRDPNotification(int type, long param) + { + // send broadcast + Intent intent = new Intent(ACTION_EVENT_FREERDP); + intent.putExtra(EVENT_TYPE, type); + intent.putExtra(EVENT_PARAM, param); + sendBroadcast(intent); + } + + @Override public void OnPreConnect(long instance) + { + Log.v(TAG, "OnPreConnect"); + } + + // ////////////////////////////////////////////////////////////////////// + // Implementation of LibFreeRDP.EventListener + public void OnConnectionSuccess(long instance) + { + Log.v(TAG, "OnConnectionSuccess"); + sendRDPNotification(FREERDP_EVENT_CONNECTION_SUCCESS, instance); + } + + public void OnConnectionFailure(long instance) + { + Log.v(TAG, "OnConnectionFailure"); + + // send notification to session activity + sendRDPNotification(FREERDP_EVENT_CONNECTION_FAILURE, instance); + } + + public void OnDisconnecting(long instance) + { + Log.v(TAG, "OnDisconnecting"); + } + + public void OnDisconnected(long instance) + { + Log.v(TAG, "OnDisconnected"); + sendRDPNotification(FREERDP_EVENT_DISCONNECTED, instance); + } + + // TimerTask for disconnecting sessions after screen was turned off + private static class DisconnectTask extends TimerTask + { + @Override public void run() + { + Log.v("DisconnectTask", "Doing action"); + + // disconnect any running rdp session + Collection sessions = GlobalApp.getSessions(); + for (SessionState session : sessions) + { + LibFreeRDP.disconnect(session.getInstance()); + } + } + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/application/NetworkStateReceiver.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/application/NetworkStateReceiver.java index 38a98a6..ea3d663 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/application/NetworkStateReceiver.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/application/NetworkStateReceiver.java @@ -3,8 +3,9 @@ Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.application; @@ -16,34 +17,42 @@ import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.util.Log; -public class NetworkStateReceiver extends BroadcastReceiver { - - public static boolean isConnectedTo3G(Context context) { - ConnectivityManager connectivity = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo info = connectivity.getActiveNetworkInfo(); - - // no connection or background data disabled - if (info == null || !info.isConnected()) - return false; - - return (info.getType() != ConnectivityManager.TYPE_WIFI && info.getType() != ConnectivityManager.TYPE_WIMAX); - } - - @Override - public void onReceive(Context context, Intent intent) { - - // check if we are connected via 3g or wlan - if (intent.getExtras() != null) { - NetworkInfo info = (NetworkInfo) intent.getExtras().get(ConnectivityManager.EXTRA_NETWORK_INFO); - - // are we connected at all? - if (info != null && info.isConnected()) { - // see if we are connected through 3G or WiFi - Log.d("app", "Connected via type " + info.getTypeName()); - GlobalApp.ConnectedTo3G = (info.getType() != ConnectivityManager.TYPE_WIFI && info.getType() != ConnectivityManager.TYPE_WIMAX); - } - - Log.v("NetworkState", info.toString()); - } - } +public class NetworkStateReceiver extends BroadcastReceiver +{ + + public static boolean isConnectedTo3G(Context context) + { + ConnectivityManager connectivity = + (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo info = connectivity.getActiveNetworkInfo(); + + // no connection or background data disabled + if (info == null || !info.isConnected()) + return false; + + return (info.getType() != ConnectivityManager.TYPE_WIFI && + info.getType() != ConnectivityManager.TYPE_WIMAX); + } + + @Override public void onReceive(Context context, Intent intent) + { + + // check if we are connected via 3g or wlan + if (intent.getExtras() != null) + { + NetworkInfo info = + (NetworkInfo)intent.getExtras().get(ConnectivityManager.EXTRA_NETWORK_INFO); + + // are we connected at all? + if (info != null && info.isConnected()) + { + // see if we are connected through 3G or WiFi + Log.d("app", "Connected via type " + info.getTypeName()); + GlobalApp.ConnectedTo3G = (info.getType() != ConnectivityManager.TYPE_WIFI && + info.getType() != ConnectivityManager.TYPE_WIMAX); + } + + Log.v("NetworkState", info.toString()); + } + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/application/ScreenReceiver.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/application/ScreenReceiver.java index f4b36fb..d1330ca 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/application/ScreenReceiver.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/application/ScreenReceiver.java @@ -3,8 +3,9 @@ Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.application; @@ -14,16 +15,16 @@ import android.content.Context; import android.content.Intent; import android.util.Log; -public class ScreenReceiver extends BroadcastReceiver { - - @Override - public void onReceive(Context context, Intent intent) { - GlobalApp app = (GlobalApp) context.getApplicationContext(); - Log.v("ScreenReceiver", "Received action: " + intent.getAction()); - if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) - app.startDisconnectTimer(); - else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) - app.cancelDisconnectTimer(); - } +public class ScreenReceiver extends BroadcastReceiver +{ + @Override public void onReceive(Context context, Intent intent) + { + GlobalApp app = (GlobalApp)context.getApplicationContext(); + Log.v("ScreenReceiver", "Received action: " + intent.getAction()); + if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) + app.startDisconnectTimer(); + else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) + app.cancelDisconnectTimer(); + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/application/SessionState.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/application/SessionState.java index 75c9015..1e1431c 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/application/SessionState.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/application/SessionState.java @@ -3,8 +3,9 @@ Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.application; @@ -19,93 +20,110 @@ import android.os.Parcelable; import com.freerdp.freerdpcore.domain.BookmarkBase; import com.freerdp.freerdpcore.services.LibFreeRDP; -public class SessionState implements Parcelable { - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public SessionState createFromParcel(Parcel in) { - return new SessionState(in); - } - - @Override - public SessionState[] newArray(int size) { - return new SessionState[size]; - } - }; - private long instance; - private BookmarkBase bookmark; - private Uri openUri; - private BitmapDrawable surface; - private LibFreeRDP.UIEventListener uiEventListener; - - public SessionState(Parcel parcel) { - instance = parcel.readLong(); - bookmark = parcel.readParcelable(null); - openUri = parcel.readParcelable(null); - - Bitmap bitmap = parcel.readParcelable(null); - surface = new BitmapDrawable(bitmap); - } - - public SessionState(long instance, BookmarkBase bookmark) { - this.instance = instance; - this.bookmark = bookmark; - this.openUri = null; - this.uiEventListener = null; - } - - public SessionState(long instance, Uri openUri) { - this.instance = instance; - this.bookmark = null; - this.openUri = openUri; - this.uiEventListener = null; - } - - public void connect(Context context) { - if (bookmark != null) { - LibFreeRDP.setConnectionInfo(context, instance, bookmark); - } else { - LibFreeRDP.setConnectionInfo(context, instance, openUri); - } - LibFreeRDP.connect(instance); - } - - public long getInstance() { - return instance; - } - - public BookmarkBase getBookmark() { - return bookmark; - } - - public Uri getOpenUri() { - return openUri; - } - - public LibFreeRDP.UIEventListener getUIEventListener() { - return uiEventListener; - } - - public void setUIEventListener(LibFreeRDP.UIEventListener uiEventListener) { - this.uiEventListener = uiEventListener; - } - - public BitmapDrawable getSurface() { - return surface; - } - - public void setSurface(BitmapDrawable surface) { - this.surface = surface; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeLong(instance); - out.writeParcelable(bookmark, flags); - out.writeParcelable(openUri, flags); - out.writeParcelable(surface.getBitmap(), flags); - } +public class SessionState implements Parcelable +{ + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public SessionState createFromParcel(Parcel in) + { + return new SessionState(in); + } + + @Override public SessionState[] newArray(int size) + { + return new SessionState[size]; + } + }; + private long instance; + private BookmarkBase bookmark; + private Uri openUri; + private BitmapDrawable surface; + private LibFreeRDP.UIEventListener uiEventListener; + + public SessionState(Parcel parcel) + { + instance = parcel.readLong(); + bookmark = parcel.readParcelable(null); + openUri = parcel.readParcelable(null); + + Bitmap bitmap = parcel.readParcelable(null); + surface = new BitmapDrawable(bitmap); + } + + public SessionState(long instance, BookmarkBase bookmark) + { + this.instance = instance; + this.bookmark = bookmark; + this.openUri = null; + this.uiEventListener = null; + } + + public SessionState(long instance, Uri openUri) + { + this.instance = instance; + this.bookmark = null; + this.openUri = openUri; + this.uiEventListener = null; + } + + public void connect(Context context) + { + if (bookmark != null) + { + LibFreeRDP.setConnectionInfo(context, instance, bookmark); + } + else + { + LibFreeRDP.setConnectionInfo(context, instance, openUri); + } + LibFreeRDP.connect(instance); + } + + public long getInstance() + { + return instance; + } + + public BookmarkBase getBookmark() + { + return bookmark; + } + + public Uri getOpenUri() + { + return openUri; + } + + public LibFreeRDP.UIEventListener getUIEventListener() + { + return uiEventListener; + } + + public void setUIEventListener(LibFreeRDP.UIEventListener uiEventListener) + { + this.uiEventListener = uiEventListener; + } + + public BitmapDrawable getSurface() + { + return surface; + } + + public void setSurface(BitmapDrawable surface) + { + this.surface = surface; + } + + @Override public int describeContents() + { + return 0; + } + + @Override public void writeToParcel(Parcel out, int flags) + { + out.writeLong(instance); + out.writeParcelable(bookmark, flags); + out.writeParcelable(openUri, flags); + out.writeParcelable(surface.getBitmap(), flags); + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/domain/BookmarkBase.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/domain/BookmarkBase.java index f45cc50..171f279 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/domain/BookmarkBase.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/domain/BookmarkBase.java @@ -3,8 +3,9 @@ Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.domain; @@ -17,953 +18,1046 @@ import com.freerdp.freerdpcore.application.GlobalApp; import java.util.Locale; -public class BookmarkBase implements Parcelable, Cloneable { - public static final int TYPE_INVALID = -1; - public static final int TYPE_MANUAL = 1; - public static final int TYPE_QUICKCONNECT = 2; - public static final int TYPE_PLACEHOLDER = 3; - public static final int TYPE_CUSTOM_BASE = 1000; - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public BookmarkBase createFromParcel(Parcel in) { - return new BookmarkBase(in); - } - - @Override - public BookmarkBase[] newArray(int size) { - return new BookmarkBase[size]; - } - }; - protected int type; - private long id; - private String label; - private String username; - private String password; - private String domain; - private ScreenSettings screenSettings; - private PerformanceFlags performanceFlags; - private AdvancedSettings advancedSettings; - private DebugSettings debugSettings; - - public BookmarkBase(Parcel parcel) { - type = parcel.readInt(); - id = parcel.readLong(); - label = parcel.readString(); - username = parcel.readString(); - password = parcel.readString(); - domain = parcel.readString(); - - screenSettings = parcel.readParcelable(ScreenSettings.class - .getClassLoader()); - performanceFlags = parcel.readParcelable(PerformanceFlags.class - .getClassLoader()); - advancedSettings = parcel.readParcelable(AdvancedSettings.class - .getClassLoader()); - debugSettings = parcel.readParcelable(DebugSettings.class - .getClassLoader()); - } - - public BookmarkBase() { - init(); - } - - private void init() { - type = TYPE_INVALID; - id = -1; - label = ""; - username = ""; - password = ""; - domain = ""; - - screenSettings = new ScreenSettings(); - performanceFlags = new PerformanceFlags(); - advancedSettings = new AdvancedSettings(); - debugSettings = new DebugSettings(); - } - - @SuppressWarnings("unchecked") - public T get() { - return (T) this; - } - - public int getType() { - return type; - } - - public long getId() { - return id; - } - - public void setId(long id) { - this.id = id; - } - - public String getLabel() { - return label; - } - - public void setLabel(String label) { - this.label = label; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - public String getDomain() { - return domain; - } - - public void setDomain(String domain) { - this.domain = domain; - } - - public ScreenSettings getScreenSettings() { - return screenSettings; - } - - public void setScreenSettings(ScreenSettings screenSettings) { - this.screenSettings = screenSettings; - } - - public PerformanceFlags getPerformanceFlags() { - return performanceFlags; - } - - public void setPerformanceFlags(PerformanceFlags performanceFlags) { - this.performanceFlags = performanceFlags; - } - - public AdvancedSettings getAdvancedSettings() { - return advancedSettings; - } - - public void setAdvancedSettings(AdvancedSettings advancedSettings) { - this.advancedSettings = advancedSettings; - } - - public DebugSettings getDebugSettings() { - return debugSettings; - } - - public void setDebugSettings(DebugSettings debugSettings) { - this.debugSettings = debugSettings; - } - - public ScreenSettings getActiveScreenSettings() { - return (GlobalApp.ConnectedTo3G && advancedSettings - .getEnable3GSettings()) ? advancedSettings.getScreen3G() - : screenSettings; - } - - public PerformanceFlags getActivePerformanceFlags() { - return (GlobalApp.ConnectedTo3G && advancedSettings - .getEnable3GSettings()) ? advancedSettings.getPerformance3G() - : performanceFlags; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(type); - out.writeLong(id); - out.writeString(label); - out.writeString(username); - out.writeString(password); - out.writeString(domain); - - out.writeParcelable(screenSettings, flags); - out.writeParcelable(performanceFlags, flags); - out.writeParcelable(advancedSettings, flags); - out.writeParcelable(debugSettings, flags); - } - - // write to shared preferences - public void writeToSharedPreferences(SharedPreferences sharedPrefs) { - - Locale locale = Locale.ENGLISH; - - SharedPreferences.Editor editor = sharedPrefs.edit(); - editor.clear(); - editor.putString("bookmark.label", label); - editor.putString("bookmark.username", username); - editor.putString("bookmark.password", password); - editor.putString("bookmark.domain", domain); - - editor.putInt("bookmark.colors", screenSettings.getColors()); - editor.putString("bookmark.resolution", screenSettings - .getResolutionString().toLowerCase(locale)); - editor.putInt("bookmark.width", screenSettings.getWidth()); - editor.putInt("bookmark.height", screenSettings.getHeight()); - - editor.putBoolean("bookmark.perf_remotefx", - performanceFlags.getRemoteFX()); - editor.putBoolean("bookmark.perf_gfx", - performanceFlags.getGfx()); - editor.putBoolean("bookmark.perf_gfx_h264", - performanceFlags.getH264()); - editor.putBoolean("bookmark.perf_wallpaper", - performanceFlags.getWallpaper()); - editor.putBoolean("bookmark.perf_font_smoothing", - performanceFlags.getFontSmoothing()); - editor.putBoolean("bookmark.perf_desktop_composition", - performanceFlags.getDesktopComposition()); - editor.putBoolean("bookmark.perf_window_dragging", - performanceFlags.getFullWindowDrag()); - editor.putBoolean("bookmark.perf_menu_animation", - performanceFlags.getMenuAnimations()); - editor.putBoolean("bookmark.perf_themes", performanceFlags.getTheming()); - - editor.putBoolean("bookmark.enable_3g_settings", - advancedSettings.getEnable3GSettings()); - - editor.putInt("bookmark.colors_3g", advancedSettings.getScreen3G() - .getColors()); - editor.putString("bookmark.resolution_3g", advancedSettings - .getScreen3G().getResolutionString().toLowerCase(locale)); - editor.putInt("bookmark.width_3g", advancedSettings.getScreen3G() - .getWidth()); - editor.putInt("bookmark.height_3g", advancedSettings.getScreen3G() - .getHeight()); - - editor.putBoolean("bookmark.perf_remotefx_3g", advancedSettings - .getPerformance3G().getRemoteFX()); - editor.putBoolean("bookmark.perf_gfx_3g", advancedSettings - .getPerformance3G().getGfx()); - editor.putBoolean("bookmark.perf_gfx_h264_3g", advancedSettings - .getPerformance3G().getH264()); - editor.putBoolean("bookmark.perf_wallpaper_3g", advancedSettings - .getPerformance3G().getWallpaper()); - editor.putBoolean("bookmark.perf_font_smoothing_3g", advancedSettings - .getPerformance3G().getFontSmoothing()); - editor.putBoolean("bookmark.perf_desktop_composition_3g", - advancedSettings.getPerformance3G().getDesktopComposition()); - editor.putBoolean("bookmark.perf_window_dragging_3g", advancedSettings - .getPerformance3G().getFullWindowDrag()); - editor.putBoolean("bookmark.perf_menu_animation_3g", advancedSettings - .getPerformance3G().getMenuAnimations()); - editor.putBoolean("bookmark.perf_themes_3g", advancedSettings - .getPerformance3G().getTheming()); - - editor.putBoolean("bookmark.redirect_sdcard", - advancedSettings.getRedirectSDCard()); - editor.putInt("bookmark.redirect_sound", - advancedSettings.getRedirectSound()); - editor.putBoolean("bookmark.redirect_microphone", - advancedSettings.getRedirectMicrophone()); - editor.putInt("bookmark.security", advancedSettings.getSecurity()); - editor.putString("bookmark.remote_program", - advancedSettings.getRemoteProgram()); - editor.putString("bookmark.work_dir", advancedSettings.getWorkDir()); - editor.putBoolean("bookmark.console_mode", - advancedSettings.getConsoleMode()); - - editor.putBoolean("bookmark.async_channel", debugSettings.getAsyncChannel()); - editor.putBoolean("bookmark.async_input", debugSettings.getAsyncInput()); - editor.putBoolean("bookmark.async_update", debugSettings.getAsyncUpdate()); - editor.putString("bookmark.debug_level", - debugSettings.getDebugLevel()); - - editor.apply(); - } - - // read from shared preferences - public void readFromSharedPreferences(SharedPreferences sharedPrefs) { - label = sharedPrefs.getString("bookmark.label", ""); - username = sharedPrefs.getString("bookmark.username", ""); - password = sharedPrefs.getString("bookmark.password", ""); - domain = sharedPrefs.getString("bookmark.domain", ""); - - screenSettings.setColors(sharedPrefs.getInt("bookmark.colors", 16)); - screenSettings.setResolution( - sharedPrefs.getString("bookmark.resolution", "automatic"), - sharedPrefs.getInt("bookmark.width", 800), - sharedPrefs.getInt("bookmark.height", 600)); - - performanceFlags.setRemoteFX(sharedPrefs.getBoolean( - "bookmark.perf_remotefx", false)); - performanceFlags.setGfx(sharedPrefs.getBoolean( - "bookmark.perf_gfx", false)); - performanceFlags.setH264(sharedPrefs.getBoolean( - "bookmark.perf_gfx_h264", false)); - performanceFlags.setWallpaper(sharedPrefs.getBoolean( - "bookmark.perf_wallpaper", false)); - performanceFlags.setFontSmoothing(sharedPrefs.getBoolean( - "bookmark.perf_font_smoothing", false)); - performanceFlags.setDesktopComposition(sharedPrefs.getBoolean( - "bookmark.perf_desktop_composition", false)); - performanceFlags.setFullWindowDrag(sharedPrefs.getBoolean( - "bookmark.perf_window_dragging", false)); - performanceFlags.setMenuAnimations(sharedPrefs.getBoolean( - "bookmark.perf_menu_animation", false)); - performanceFlags.setTheming(sharedPrefs.getBoolean( - "bookmark.perf_themes", false)); - - advancedSettings.setEnable3GSettings(sharedPrefs.getBoolean( - "bookmark.enable_3g_settings", false)); - - advancedSettings.getScreen3G().setColors( - sharedPrefs.getInt("bookmark.colors_3g", 16)); - advancedSettings.getScreen3G().setResolution( - sharedPrefs.getString("bookmark.resolution_3g", "automatic"), - sharedPrefs.getInt("bookmark.width_3g", 800), - sharedPrefs.getInt("bookmark.height_3g", 600)); - - advancedSettings.getPerformance3G().setRemoteFX( - sharedPrefs.getBoolean("bookmark.perf_remotefx_3g", false)); - advancedSettings.getPerformance3G().setGfx(sharedPrefs.getBoolean( - "bookmark.perf_gfx_3g", false)); - advancedSettings.getPerformance3G().setH264(sharedPrefs.getBoolean( - "bookmark.perf_gfx_h264_3g", false)); - advancedSettings.getPerformance3G().setWallpaper( - sharedPrefs.getBoolean("bookmark.perf_wallpaper_3g", false)); - advancedSettings.getPerformance3G().setFontSmoothing( - sharedPrefs - .getBoolean("bookmark.perf_font_smoothing_3g", false)); - advancedSettings.getPerformance3G().setDesktopComposition( - sharedPrefs.getBoolean("bookmark.perf_desktop_composition_3g", - false)); - advancedSettings.getPerformance3G().setFullWindowDrag( - sharedPrefs.getBoolean("bookmark.perf_window_dragging_3g", - false)); - advancedSettings.getPerformance3G().setMenuAnimations( - sharedPrefs - .getBoolean("bookmark.perf_menu_animation_3g", false)); - advancedSettings.getPerformance3G().setTheming( - sharedPrefs.getBoolean("bookmark.perf_themes_3g", false)); - - advancedSettings.setRedirectSDCard(sharedPrefs.getBoolean("bookmark.redirect_sdcard", false)); - advancedSettings.setRedirectSound(sharedPrefs.getInt("bookmark.redirect_sound", 0)); - advancedSettings.setRedirectMicrophone(sharedPrefs.getBoolean("bookmark.redirect_microphone", false)); - advancedSettings.setSecurity(sharedPrefs.getInt("bookmark.security", 0)); - advancedSettings.setRemoteProgram(sharedPrefs.getString("bookmark.remote_program", "")); - advancedSettings.setWorkDir(sharedPrefs.getString("bookmark.work_dir", "")); - advancedSettings.setConsoleMode(sharedPrefs.getBoolean("bookmark.console_mode", false)); - - debugSettings.setAsyncChannel(sharedPrefs.getBoolean("bookmark.async_channel", true)); - debugSettings.setAsyncInput(sharedPrefs.getBoolean("bookmark.async_input", true)); - debugSettings.setAsyncUpdate(sharedPrefs.getBoolean("bookmark.async_update", true)); - debugSettings.setDebugLevel(sharedPrefs.getString("bookmark.debug_level", "INFO")); - } - - // Cloneable - public Object clone() { - try { - return super.clone(); - } catch (CloneNotSupportedException e) { - return null; - } - } - - // performance flags - public static class PerformanceFlags implements Parcelable { - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public PerformanceFlags createFromParcel(Parcel in) { - return new PerformanceFlags(in); - } - - @Override - public PerformanceFlags[] newArray(int size) { - return new PerformanceFlags[size]; - } - }; - private boolean remotefx; - private boolean gfx; - private boolean h264; - private boolean wallpaper; - private boolean theming; - private boolean fullWindowDrag; - private boolean menuAnimations; - private boolean fontSmoothing; - private boolean desktopComposition; - - public PerformanceFlags() { - remotefx = false; - gfx = false; - h264 = false; - wallpaper = false; - theming = false; - fullWindowDrag = false; - menuAnimations = false; - fontSmoothing = false; - desktopComposition = false; - } - - public PerformanceFlags(Parcel parcel) { - remotefx = parcel.readInt() == 1; - gfx = parcel.readInt() == 1; - h264 = parcel.readInt() == 1; - wallpaper = parcel.readInt() == 1; - theming = parcel.readInt() == 1; - fullWindowDrag = (parcel.readInt() == 1); - menuAnimations = parcel.readInt() == 1; - fontSmoothing = parcel.readInt() == 1; - desktopComposition = parcel.readInt() == 1; - } - - public boolean getRemoteFX() { - return remotefx; - } - - public void setRemoteFX(boolean remotefx) { - this.remotefx = remotefx; - } - - public boolean getGfx() { - return gfx; - } - - public void setGfx(boolean gfx) { - this.gfx = gfx; - } - - public boolean getH264() { - return h264; - } - - public void setH264(boolean h264) { - this.h264 = h264; - } - - public boolean getWallpaper() { - return wallpaper; - } - - public void setWallpaper(boolean wallpaper) { - this.wallpaper = wallpaper; - } - - public boolean getTheming() { - return theming; - } - - public void setTheming(boolean theming) { - this.theming = theming; - } - - public boolean getFullWindowDrag() { - return fullWindowDrag; - } - - public void setFullWindowDrag(boolean fullWindowDrag) { - this.fullWindowDrag = fullWindowDrag; - } - - public boolean getMenuAnimations() { - return menuAnimations; - } - - public void setMenuAnimations(boolean menuAnimations) { - this.menuAnimations = menuAnimations; - } - - public boolean getFontSmoothing() { - return fontSmoothing; - } - - public void setFontSmoothing(boolean fontSmoothing) { - this.fontSmoothing = fontSmoothing; - } - - public boolean getDesktopComposition() { - return desktopComposition; - } - - public void setDesktopComposition(boolean desktopComposition) { - this.desktopComposition = desktopComposition; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(remotefx ? 1 : 0); - out.writeInt(gfx ? 1 : 0); - out.writeInt(h264 ? 1 : 0); - out.writeInt(wallpaper ? 1 : 0); - out.writeInt(theming ? 1 : 0); - out.writeInt(fullWindowDrag ? 1 : 0); - out.writeInt(menuAnimations ? 1 : 0); - out.writeInt(fontSmoothing ? 1 : 0); - out.writeInt(desktopComposition ? 1 : 0); - } - } - - // Screen Settings class - public static class ScreenSettings implements Parcelable { - public static final int FITSCREEN = -2; - public static final int AUTOMATIC = -1; - public static final int CUSTOM = 0; - public static final int PREDEFINED = 1; - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public ScreenSettings createFromParcel(Parcel in) { - return new ScreenSettings(in); - } - - @Override - public ScreenSettings[] newArray(int size) { - return new ScreenSettings[size]; - } - }; - private int resolution; - private int colors; - private int width; - private int height; - - public ScreenSettings() { - init(); - } - - public ScreenSettings(Parcel parcel) { - resolution = parcel.readInt(); - colors = parcel.readInt(); - width = parcel.readInt(); - height = parcel.readInt(); - } - - private void validate() { - switch (colors) { - case 32: - case 24: - case 16: - case 15: - case 8: - break; - default: - colors = 32; - break; - } - - if ((width <= 0) || (width > 65536)) { - width = 1024; - } - - if ((height <= 0) || (height > 65536)) { - height = 768; - } - - switch(resolution) { - case FITSCREEN: - case AUTOMATIC: - case CUSTOM: - case PREDEFINED: - break; - default: - resolution = AUTOMATIC; - break; - } - } - - private void init() { - resolution = AUTOMATIC; - colors = 16; - width = 0; - height = 0; - } - - public void setResolution(String resolution, int width, int height) { - if (resolution.contains("x")) { - String[] dimensions = resolution.split("x"); - this.width = Integer.valueOf(dimensions[0]); - this.height = Integer.valueOf(dimensions[1]); - this.resolution = PREDEFINED; - } else if (resolution.equalsIgnoreCase("custom")) { - this.width = width; - this.height = height; - this.resolution = CUSTOM; - } else if (resolution.equalsIgnoreCase("fitscreen")) { - this.width = this.height = 0; - this.resolution = FITSCREEN; - } else { - this.width = this.height = 0; - this.resolution = AUTOMATIC; - } - } - - public int getResolution() { - return resolution; - } - - public void setResolution(int resolution) { - this.resolution = resolution; - - if (resolution == AUTOMATIC || resolution == FITSCREEN) { - width = 0; - height = 0; - } - } - - public String getResolutionString() { - if (isPredefined()) - return (width + "x" + height); - - return (isFitScreen() ? "fitscreen" : isAutomatic() ? "automatic" - : "custom"); - } - - public boolean isPredefined() { - validate(); - return (resolution == PREDEFINED); - } - - public boolean isAutomatic() { - validate(); - return (resolution == AUTOMATIC); - } - - public boolean isFitScreen() { - validate(); - return (resolution == FITSCREEN); - } - - public boolean isCustom() { - validate(); - return (resolution == CUSTOM); - } - - public int getWidth() { - validate(); - return width; - } - - public void setWidth(int width) { - this.width = width; - } - - public int getHeight() { - validate(); - return height; - } - - public void setHeight(int height) { - this.height = height; - } - - public int getColors() { - validate(); - return colors; - } - - public void setColors(int colors) { - this.colors = colors; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(resolution); - out.writeInt(colors); - out.writeInt(width); - out.writeInt(height); - } - } - - public static class DebugSettings implements Parcelable { - - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public DebugSettings createFromParcel(Parcel in) { - return new DebugSettings(in); - } - - @Override - public DebugSettings[] newArray(int size) { - return new DebugSettings[size]; - } - }; - private String debug; - private boolean asyncChannel; - private boolean asyncTransport; - private boolean asyncInput; - private boolean asyncUpdate; - - public DebugSettings() { - init(); - } - - // Session Settings - public DebugSettings(Parcel parcel) { - asyncChannel = parcel.readInt() == 1; - asyncTransport = parcel.readInt() == 1; - asyncInput = parcel.readInt() == 1; - asyncUpdate = parcel.readInt() == 1; - debug = parcel.readString(); - } - - private void init() { - debug = "INFO"; - asyncChannel = true; - asyncTransport = false; - asyncInput = true; - asyncUpdate = true; - } - - private void validate() { - final String[] levels = { - "OFF", - "FATAL", - "ERROR", - "WARN", - "INFO", - "DEBUG", - "TRACE" - }; - - for (String level : levels) { - if (level.equalsIgnoreCase(this.debug)) { - return; - } - } - - this.debug = "INFO"; - } - - public String getDebugLevel() { - validate(); - return debug; - } - - public void setDebugLevel(String debug) { - this.debug = debug; - } - - public boolean getAsyncUpdate() { - return asyncUpdate; - } - - public void setAsyncUpdate(boolean enabled) { - asyncUpdate = enabled; - } - - public boolean getAsyncInput() { - return asyncInput; - } - - public void setAsyncInput(boolean enabled) { - asyncInput = enabled; - } - - public boolean getAsyncChannel() { - return asyncChannel; - } - - public void setAsyncChannel(boolean enabled) { - asyncChannel = enabled; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(asyncChannel ? 1 : 0); - out.writeInt(asyncTransport ? 1 : 0); - out.writeInt(asyncInput ? 1 : 0); - out.writeInt(asyncUpdate ? 1 : 0); - out.writeString(debug); - } - } - - // Session Settings - public static class AdvancedSettings implements Parcelable { - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public AdvancedSettings createFromParcel(Parcel in) { - return new AdvancedSettings(in); - } - - @Override - public AdvancedSettings[] newArray(int size) { - return new AdvancedSettings[size]; - } - }; - private boolean enable3GSettings; - private ScreenSettings screen3G; - private PerformanceFlags performance3G; - private boolean redirectSDCard; - private int redirectSound; - private boolean redirectMicrophone; - private int security; - private boolean consoleMode; - private String remoteProgram; - private String workDir; - - public AdvancedSettings() { - init(); - } - - public AdvancedSettings(Parcel parcel) { - enable3GSettings = parcel.readInt() == 1; - screen3G = parcel.readParcelable(ScreenSettings.class - .getClassLoader()); - performance3G = parcel.readParcelable(PerformanceFlags.class - .getClassLoader()); - redirectSDCard = parcel.readInt() == 1; - redirectSound = parcel.readInt(); - redirectMicrophone = parcel.readInt() == 1; - security = parcel.readInt(); - consoleMode = parcel.readInt() == 1; - remoteProgram = parcel.readString(); - workDir = parcel.readString(); - } - - private void init() { - enable3GSettings = false; - screen3G = new ScreenSettings(); - performance3G = new PerformanceFlags(); - redirectSDCard = false; - redirectSound = 0; - redirectMicrophone = false; - security = 0; - consoleMode = false; - remoteProgram = ""; - workDir = ""; - } - - private void validate() { - switch (redirectSound) { - case 0: - case 1: - case 2: - break; - default: - redirectSound = 0; - break; - } - - switch (security) { - case 0: - case 1: - case 2: - case 3: - break; - default: - security = 0; - break; - } - } - - public boolean getEnable3GSettings() { - return enable3GSettings; - } - - public void setEnable3GSettings(boolean enable3GSettings) { - this.enable3GSettings = enable3GSettings; - } - - public ScreenSettings getScreen3G() { - return screen3G; - } - - public void setScreen3G(ScreenSettings screen3G) { - this.screen3G = screen3G; - } - - public PerformanceFlags getPerformance3G() { - return performance3G; - } - - public void setPerformance3G(PerformanceFlags performance3G) { - this.performance3G = performance3G; - } - - public boolean getRedirectSDCard() { - return redirectSDCard; - } - - public void setRedirectSDCard(boolean redirectSDCard) { - this.redirectSDCard = redirectSDCard; - } - - public int getRedirectSound() { - validate(); - return redirectSound; - } - - public void setRedirectSound(int redirect) { - this.redirectSound = redirect; - } - - public boolean getRedirectMicrophone() { - return redirectMicrophone; - } - - public void setRedirectMicrophone(boolean redirect) { - this.redirectMicrophone = redirect; - } - - public int getSecurity() { - validate(); - return security; - } - - public void setSecurity(int security) { - this.security = security; - } - - public boolean getConsoleMode() { - return consoleMode; - } - - public void setConsoleMode(boolean consoleMode) { - this.consoleMode = consoleMode; - } - - public String getRemoteProgram() { - return remoteProgram; - } - - public void setRemoteProgram(String remoteProgram) { - this.remoteProgram = remoteProgram; - } - - public String getWorkDir() { - return workDir; - } - - public void setWorkDir(String workDir) { - this.workDir = workDir; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(enable3GSettings ? 1 : 0); - out.writeParcelable(screen3G, flags); - out.writeParcelable(performance3G, flags); - out.writeInt(redirectSDCard ? 1 : 0); - out.writeInt(redirectSound); - out.writeInt(redirectMicrophone ? 1 : 0); - out.writeInt(security); - out.writeInt(consoleMode ? 1 : 0); - out.writeString(remoteProgram); - out.writeString(workDir); - } - } +public class BookmarkBase implements Parcelable, Cloneable +{ + public static final int TYPE_INVALID = -1; + public static final int TYPE_MANUAL = 1; + public static final int TYPE_QUICKCONNECT = 2; + public static final int TYPE_PLACEHOLDER = 3; + public static final int TYPE_CUSTOM_BASE = 1000; + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public BookmarkBase createFromParcel(Parcel in) + { + return new BookmarkBase(in); + } + + @Override public BookmarkBase[] newArray(int size) + { + return new BookmarkBase[size]; + } + }; + protected int type; + private long id; + private String label; + private String username; + private String password; + private String domain; + private ScreenSettings screenSettings; + private PerformanceFlags performanceFlags; + private AdvancedSettings advancedSettings; + private DebugSettings debugSettings; + + public BookmarkBase(Parcel parcel) + { + type = parcel.readInt(); + id = parcel.readLong(); + label = parcel.readString(); + username = parcel.readString(); + password = parcel.readString(); + domain = parcel.readString(); + + screenSettings = parcel.readParcelable(ScreenSettings.class.getClassLoader()); + performanceFlags = parcel.readParcelable(PerformanceFlags.class.getClassLoader()); + advancedSettings = parcel.readParcelable(AdvancedSettings.class.getClassLoader()); + debugSettings = parcel.readParcelable(DebugSettings.class.getClassLoader()); + } + + public BookmarkBase() + { + init(); + } + + private void init() + { + type = TYPE_INVALID; + id = -1; + label = ""; + username = ""; + password = ""; + domain = ""; + + screenSettings = new ScreenSettings(); + performanceFlags = new PerformanceFlags(); + advancedSettings = new AdvancedSettings(); + debugSettings = new DebugSettings(); + } + + @SuppressWarnings("unchecked") public T get() + { + return (T)this; + } + + public int getType() + { + return type; + } + + public long getId() + { + return id; + } + + public void setId(long id) + { + this.id = id; + } + + public String getLabel() + { + return label; + } + + public void setLabel(String label) + { + this.label = label; + } + + public String getUsername() + { + return username; + } + + public void setUsername(String username) + { + this.username = username; + } + + public String getPassword() + { + return password; + } + + public void setPassword(String password) + { + this.password = password; + } + + public String getDomain() + { + return domain; + } + + public void setDomain(String domain) + { + this.domain = domain; + } + + public ScreenSettings getScreenSettings() + { + return screenSettings; + } + + public void setScreenSettings(ScreenSettings screenSettings) + { + this.screenSettings = screenSettings; + } + + public PerformanceFlags getPerformanceFlags() + { + return performanceFlags; + } + + public void setPerformanceFlags(PerformanceFlags performanceFlags) + { + this.performanceFlags = performanceFlags; + } + + public AdvancedSettings getAdvancedSettings() + { + return advancedSettings; + } + + public void setAdvancedSettings(AdvancedSettings advancedSettings) + { + this.advancedSettings = advancedSettings; + } + + public DebugSettings getDebugSettings() + { + return debugSettings; + } + + public void setDebugSettings(DebugSettings debugSettings) + { + this.debugSettings = debugSettings; + } + + public ScreenSettings getActiveScreenSettings() + { + return (GlobalApp.ConnectedTo3G && advancedSettings.getEnable3GSettings()) + ? advancedSettings.getScreen3G() + : screenSettings; + } + + public PerformanceFlags getActivePerformanceFlags() + { + return (GlobalApp.ConnectedTo3G && advancedSettings.getEnable3GSettings()) + ? advancedSettings.getPerformance3G() + : performanceFlags; + } + + @Override public int describeContents() + { + return 0; + } + + @Override public void writeToParcel(Parcel out, int flags) + { + out.writeInt(type); + out.writeLong(id); + out.writeString(label); + out.writeString(username); + out.writeString(password); + out.writeString(domain); + + out.writeParcelable(screenSettings, flags); + out.writeParcelable(performanceFlags, flags); + out.writeParcelable(advancedSettings, flags); + out.writeParcelable(debugSettings, flags); + } + + // write to shared preferences + public void writeToSharedPreferences(SharedPreferences sharedPrefs) + { + + Locale locale = Locale.ENGLISH; + + SharedPreferences.Editor editor = sharedPrefs.edit(); + editor.clear(); + editor.putString("bookmark.label", label); + editor.putString("bookmark.username", username); + editor.putString("bookmark.password", password); + editor.putString("bookmark.domain", domain); + + editor.putInt("bookmark.colors", screenSettings.getColors()); + editor.putString("bookmark.resolution", + screenSettings.getResolutionString().toLowerCase(locale)); + editor.putInt("bookmark.width", screenSettings.getWidth()); + editor.putInt("bookmark.height", screenSettings.getHeight()); + + editor.putBoolean("bookmark.perf_remotefx", performanceFlags.getRemoteFX()); + editor.putBoolean("bookmark.perf_gfx", performanceFlags.getGfx()); + editor.putBoolean("bookmark.perf_gfx_h264", performanceFlags.getH264()); + editor.putBoolean("bookmark.perf_wallpaper", performanceFlags.getWallpaper()); + editor.putBoolean("bookmark.perf_font_smoothing", performanceFlags.getFontSmoothing()); + editor.putBoolean("bookmark.perf_desktop_composition", + performanceFlags.getDesktopComposition()); + editor.putBoolean("bookmark.perf_window_dragging", performanceFlags.getFullWindowDrag()); + editor.putBoolean("bookmark.perf_menu_animation", performanceFlags.getMenuAnimations()); + editor.putBoolean("bookmark.perf_themes", performanceFlags.getTheming()); + + editor.putBoolean("bookmark.enable_3g_settings", advancedSettings.getEnable3GSettings()); + + editor.putInt("bookmark.colors_3g", advancedSettings.getScreen3G().getColors()); + editor.putString("bookmark.resolution_3g", + advancedSettings.getScreen3G().getResolutionString().toLowerCase(locale)); + editor.putInt("bookmark.width_3g", advancedSettings.getScreen3G().getWidth()); + editor.putInt("bookmark.height_3g", advancedSettings.getScreen3G().getHeight()); + + editor.putBoolean("bookmark.perf_remotefx_3g", + advancedSettings.getPerformance3G().getRemoteFX()); + editor.putBoolean("bookmark.perf_gfx_3g", advancedSettings.getPerformance3G().getGfx()); + editor.putBoolean("bookmark.perf_gfx_h264_3g", + advancedSettings.getPerformance3G().getH264()); + editor.putBoolean("bookmark.perf_wallpaper_3g", + advancedSettings.getPerformance3G().getWallpaper()); + editor.putBoolean("bookmark.perf_font_smoothing_3g", + advancedSettings.getPerformance3G().getFontSmoothing()); + editor.putBoolean("bookmark.perf_desktop_composition_3g", + advancedSettings.getPerformance3G().getDesktopComposition()); + editor.putBoolean("bookmark.perf_window_dragging_3g", + advancedSettings.getPerformance3G().getFullWindowDrag()); + editor.putBoolean("bookmark.perf_menu_animation_3g", + advancedSettings.getPerformance3G().getMenuAnimations()); + editor.putBoolean("bookmark.perf_themes_3g", + advancedSettings.getPerformance3G().getTheming()); + + editor.putBoolean("bookmark.redirect_sdcard", advancedSettings.getRedirectSDCard()); + editor.putInt("bookmark.redirect_sound", advancedSettings.getRedirectSound()); + editor.putBoolean("bookmark.redirect_microphone", advancedSettings.getRedirectMicrophone()); + editor.putInt("bookmark.security", advancedSettings.getSecurity()); + editor.putString("bookmark.remote_program", advancedSettings.getRemoteProgram()); + editor.putString("bookmark.work_dir", advancedSettings.getWorkDir()); + editor.putBoolean("bookmark.console_mode", advancedSettings.getConsoleMode()); + + editor.putBoolean("bookmark.async_channel", debugSettings.getAsyncChannel()); + editor.putBoolean("bookmark.async_input", debugSettings.getAsyncInput()); + editor.putBoolean("bookmark.async_update", debugSettings.getAsyncUpdate()); + editor.putString("bookmark.debug_level", debugSettings.getDebugLevel()); + + editor.apply(); + } + + // read from shared preferences + public void readFromSharedPreferences(SharedPreferences sharedPrefs) + { + label = sharedPrefs.getString("bookmark.label", ""); + username = sharedPrefs.getString("bookmark.username", ""); + password = sharedPrefs.getString("bookmark.password", ""); + domain = sharedPrefs.getString("bookmark.domain", ""); + + screenSettings.setColors(sharedPrefs.getInt("bookmark.colors", 16)); + screenSettings.setResolution(sharedPrefs.getString("bookmark.resolution", "automatic"), + sharedPrefs.getInt("bookmark.width", 800), + sharedPrefs.getInt("bookmark.height", 600)); + + performanceFlags.setRemoteFX(sharedPrefs.getBoolean("bookmark.perf_remotefx", false)); + performanceFlags.setGfx(sharedPrefs.getBoolean("bookmark.perf_gfx", false)); + performanceFlags.setH264(sharedPrefs.getBoolean("bookmark.perf_gfx_h264", false)); + performanceFlags.setWallpaper(sharedPrefs.getBoolean("bookmark.perf_wallpaper", false)); + performanceFlags.setFontSmoothing( + sharedPrefs.getBoolean("bookmark.perf_font_smoothing", false)); + performanceFlags.setDesktopComposition( + sharedPrefs.getBoolean("bookmark.perf_desktop_composition", false)); + performanceFlags.setFullWindowDrag( + sharedPrefs.getBoolean("bookmark.perf_window_dragging", false)); + performanceFlags.setMenuAnimations( + sharedPrefs.getBoolean("bookmark.perf_menu_animation", false)); + performanceFlags.setTheming(sharedPrefs.getBoolean("bookmark.perf_themes", false)); + + advancedSettings.setEnable3GSettings( + sharedPrefs.getBoolean("bookmark.enable_3g_settings", false)); + + advancedSettings.getScreen3G().setColors(sharedPrefs.getInt("bookmark.colors_3g", 16)); + advancedSettings.getScreen3G().setResolution( + sharedPrefs.getString("bookmark.resolution_3g", "automatic"), + sharedPrefs.getInt("bookmark.width_3g", 800), + sharedPrefs.getInt("bookmark.height_3g", 600)); + + advancedSettings.getPerformance3G().setRemoteFX( + sharedPrefs.getBoolean("bookmark.perf_remotefx_3g", false)); + advancedSettings.getPerformance3G().setGfx( + sharedPrefs.getBoolean("bookmark.perf_gfx_3g", false)); + advancedSettings.getPerformance3G().setH264( + sharedPrefs.getBoolean("bookmark.perf_gfx_h264_3g", false)); + advancedSettings.getPerformance3G().setWallpaper( + sharedPrefs.getBoolean("bookmark.perf_wallpaper_3g", false)); + advancedSettings.getPerformance3G().setFontSmoothing( + sharedPrefs.getBoolean("bookmark.perf_font_smoothing_3g", false)); + advancedSettings.getPerformance3G().setDesktopComposition( + sharedPrefs.getBoolean("bookmark.perf_desktop_composition_3g", false)); + advancedSettings.getPerformance3G().setFullWindowDrag( + sharedPrefs.getBoolean("bookmark.perf_window_dragging_3g", false)); + advancedSettings.getPerformance3G().setMenuAnimations( + sharedPrefs.getBoolean("bookmark.perf_menu_animation_3g", false)); + advancedSettings.getPerformance3G().setTheming( + sharedPrefs.getBoolean("bookmark.perf_themes_3g", false)); + + advancedSettings.setRedirectSDCard( + sharedPrefs.getBoolean("bookmark.redirect_sdcard", false)); + advancedSettings.setRedirectSound(sharedPrefs.getInt("bookmark.redirect_sound", 0)); + advancedSettings.setRedirectMicrophone( + sharedPrefs.getBoolean("bookmark.redirect_microphone", false)); + advancedSettings.setSecurity(sharedPrefs.getInt("bookmark.security", 0)); + advancedSettings.setRemoteProgram(sharedPrefs.getString("bookmark.remote_program", "")); + advancedSettings.setWorkDir(sharedPrefs.getString("bookmark.work_dir", "")); + advancedSettings.setConsoleMode(sharedPrefs.getBoolean("bookmark.console_mode", false)); + + debugSettings.setAsyncChannel(sharedPrefs.getBoolean("bookmark.async_channel", true)); + debugSettings.setAsyncInput(sharedPrefs.getBoolean("bookmark.async_input", true)); + debugSettings.setAsyncUpdate(sharedPrefs.getBoolean("bookmark.async_update", true)); + debugSettings.setDebugLevel(sharedPrefs.getString("bookmark.debug_level", "INFO")); + } + + // Cloneable + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException e) + { + return null; + } + } + + // performance flags + public static class PerformanceFlags implements Parcelable + { + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public PerformanceFlags createFromParcel(Parcel in) + { + return new PerformanceFlags(in); + } + + @Override public PerformanceFlags[] newArray(int size) + { + return new PerformanceFlags[size]; + } + }; + private boolean remotefx; + private boolean gfx; + private boolean h264; + private boolean wallpaper; + private boolean theming; + private boolean fullWindowDrag; + private boolean menuAnimations; + private boolean fontSmoothing; + private boolean desktopComposition; + + public PerformanceFlags() + { + remotefx = false; + gfx = false; + h264 = false; + wallpaper = false; + theming = false; + fullWindowDrag = false; + menuAnimations = false; + fontSmoothing = false; + desktopComposition = false; + } + + public PerformanceFlags(Parcel parcel) + { + remotefx = parcel.readInt() == 1; + gfx = parcel.readInt() == 1; + h264 = parcel.readInt() == 1; + wallpaper = parcel.readInt() == 1; + theming = parcel.readInt() == 1; + fullWindowDrag = (parcel.readInt() == 1); + menuAnimations = parcel.readInt() == 1; + fontSmoothing = parcel.readInt() == 1; + desktopComposition = parcel.readInt() == 1; + } + + public boolean getRemoteFX() + { + return remotefx; + } + + public void setRemoteFX(boolean remotefx) + { + this.remotefx = remotefx; + } + + public boolean getGfx() + { + return gfx; + } + + public void setGfx(boolean gfx) + { + this.gfx = gfx; + } + + public boolean getH264() + { + return h264; + } + + public void setH264(boolean h264) + { + this.h264 = h264; + } + + public boolean getWallpaper() + { + return wallpaper; + } + + public void setWallpaper(boolean wallpaper) + { + this.wallpaper = wallpaper; + } + + public boolean getTheming() + { + return theming; + } + + public void setTheming(boolean theming) + { + this.theming = theming; + } + + public boolean getFullWindowDrag() + { + return fullWindowDrag; + } + + public void setFullWindowDrag(boolean fullWindowDrag) + { + this.fullWindowDrag = fullWindowDrag; + } + + public boolean getMenuAnimations() + { + return menuAnimations; + } + + public void setMenuAnimations(boolean menuAnimations) + { + this.menuAnimations = menuAnimations; + } + + public boolean getFontSmoothing() + { + return fontSmoothing; + } + + public void setFontSmoothing(boolean fontSmoothing) + { + this.fontSmoothing = fontSmoothing; + } + + public boolean getDesktopComposition() + { + return desktopComposition; + } + + public void setDesktopComposition(boolean desktopComposition) + { + this.desktopComposition = desktopComposition; + } + + @Override public int describeContents() + { + return 0; + } + + @Override public void writeToParcel(Parcel out, int flags) + { + out.writeInt(remotefx ? 1 : 0); + out.writeInt(gfx ? 1 : 0); + out.writeInt(h264 ? 1 : 0); + out.writeInt(wallpaper ? 1 : 0); + out.writeInt(theming ? 1 : 0); + out.writeInt(fullWindowDrag ? 1 : 0); + out.writeInt(menuAnimations ? 1 : 0); + out.writeInt(fontSmoothing ? 1 : 0); + out.writeInt(desktopComposition ? 1 : 0); + } + } + + // Screen Settings class + public static class ScreenSettings implements Parcelable + { + public static final int FITSCREEN = -2; + public static final int AUTOMATIC = -1; + public static final int CUSTOM = 0; + public static final int PREDEFINED = 1; + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public ScreenSettings createFromParcel(Parcel in) + { + return new ScreenSettings(in); + } + + @Override public ScreenSettings[] newArray(int size) + { + return new ScreenSettings[size]; + } + }; + private int resolution; + private int colors; + private int width; + private int height; + + public ScreenSettings() + { + init(); + } + + public ScreenSettings(Parcel parcel) + { + resolution = parcel.readInt(); + colors = parcel.readInt(); + width = parcel.readInt(); + height = parcel.readInt(); + } + + private void validate() + { + switch (colors) + { + case 32: + case 24: + case 16: + case 15: + case 8: + break; + default: + colors = 32; + break; + } + + if ((width <= 0) || (width > 65536)) + { + width = 1024; + } + + if ((height <= 0) || (height > 65536)) + { + height = 768; + } + + switch (resolution) + { + case FITSCREEN: + case AUTOMATIC: + case CUSTOM: + case PREDEFINED: + break; + default: + resolution = AUTOMATIC; + break; + } + } + + private void init() + { + resolution = AUTOMATIC; + colors = 16; + width = 0; + height = 0; + } + + public void setResolution(String resolution, int width, int height) + { + if (resolution.contains("x")) + { + String[] dimensions = resolution.split("x"); + this.width = Integer.valueOf(dimensions[0]); + this.height = Integer.valueOf(dimensions[1]); + this.resolution = PREDEFINED; + } + else if (resolution.equalsIgnoreCase("custom")) + { + this.width = width; + this.height = height; + this.resolution = CUSTOM; + } + else if (resolution.equalsIgnoreCase("fitscreen")) + { + this.width = this.height = 0; + this.resolution = FITSCREEN; + } + else + { + this.width = this.height = 0; + this.resolution = AUTOMATIC; + } + } + + public int getResolution() + { + return resolution; + } + + public void setResolution(int resolution) + { + this.resolution = resolution; + + if (resolution == AUTOMATIC || resolution == FITSCREEN) + { + width = 0; + height = 0; + } + } + + public String getResolutionString() + { + if (isPredefined()) + return (width + "x" + height); + + return (isFitScreen() ? "fitscreen" : isAutomatic() ? "automatic" : "custom"); + } + + public boolean isPredefined() + { + validate(); + return (resolution == PREDEFINED); + } + + public boolean isAutomatic() + { + validate(); + return (resolution == AUTOMATIC); + } + + public boolean isFitScreen() + { + validate(); + return (resolution == FITSCREEN); + } + + public boolean isCustom() + { + validate(); + return (resolution == CUSTOM); + } + + public int getWidth() + { + validate(); + return width; + } + + public void setWidth(int width) + { + this.width = width; + } + + public int getHeight() + { + validate(); + return height; + } + + public void setHeight(int height) + { + this.height = height; + } + + public int getColors() + { + validate(); + return colors; + } + + public void setColors(int colors) + { + this.colors = colors; + } + + @Override public int describeContents() + { + return 0; + } + + @Override public void writeToParcel(Parcel out, int flags) + { + out.writeInt(resolution); + out.writeInt(colors); + out.writeInt(width); + out.writeInt(height); + } + } + + public static class DebugSettings implements Parcelable + { + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public DebugSettings createFromParcel(Parcel in) + { + return new DebugSettings(in); + } + + @Override public DebugSettings[] newArray(int size) + { + return new DebugSettings[size]; + } + }; + private String debug; + private boolean asyncChannel; + private boolean asyncTransport; + private boolean asyncInput; + private boolean asyncUpdate; + + public DebugSettings() + { + init(); + } + + // Session Settings + public DebugSettings(Parcel parcel) + { + asyncChannel = parcel.readInt() == 1; + asyncTransport = parcel.readInt() == 1; + asyncInput = parcel.readInt() == 1; + asyncUpdate = parcel.readInt() == 1; + debug = parcel.readString(); + } + + private void init() + { + debug = "INFO"; + asyncChannel = true; + asyncTransport = false; + asyncInput = true; + asyncUpdate = true; + } + + private void validate() + { + final String[] levels = { "OFF", "FATAL", "ERROR", "WARN", "INFO", "DEBUG", "TRACE" }; + + for (String level : levels) + { + if (level.equalsIgnoreCase(this.debug)) + { + return; + } + } + + this.debug = "INFO"; + } + + public String getDebugLevel() + { + validate(); + return debug; + } + + public void setDebugLevel(String debug) + { + this.debug = debug; + } + + public boolean getAsyncUpdate() + { + return asyncUpdate; + } + + public void setAsyncUpdate(boolean enabled) + { + asyncUpdate = enabled; + } + + public boolean getAsyncInput() + { + return asyncInput; + } + + public void setAsyncInput(boolean enabled) + { + asyncInput = enabled; + } + + public boolean getAsyncChannel() + { + return asyncChannel; + } + + public void setAsyncChannel(boolean enabled) + { + asyncChannel = enabled; + } + + @Override public int describeContents() + { + return 0; + } + + @Override public void writeToParcel(Parcel out, int flags) + { + out.writeInt(asyncChannel ? 1 : 0); + out.writeInt(asyncTransport ? 1 : 0); + out.writeInt(asyncInput ? 1 : 0); + out.writeInt(asyncUpdate ? 1 : 0); + out.writeString(debug); + } + } + + // Session Settings + public static class AdvancedSettings implements Parcelable + { + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public AdvancedSettings createFromParcel(Parcel in) + { + return new AdvancedSettings(in); + } + + @Override public AdvancedSettings[] newArray(int size) + { + return new AdvancedSettings[size]; + } + }; + private boolean enable3GSettings; + private ScreenSettings screen3G; + private PerformanceFlags performance3G; + private boolean redirectSDCard; + private int redirectSound; + private boolean redirectMicrophone; + private int security; + private boolean consoleMode; + private String remoteProgram; + private String workDir; + + public AdvancedSettings() + { + init(); + } + + public AdvancedSettings(Parcel parcel) + { + enable3GSettings = parcel.readInt() == 1; + screen3G = parcel.readParcelable(ScreenSettings.class.getClassLoader()); + performance3G = parcel.readParcelable(PerformanceFlags.class.getClassLoader()); + redirectSDCard = parcel.readInt() == 1; + redirectSound = parcel.readInt(); + redirectMicrophone = parcel.readInt() == 1; + security = parcel.readInt(); + consoleMode = parcel.readInt() == 1; + remoteProgram = parcel.readString(); + workDir = parcel.readString(); + } + + private void init() + { + enable3GSettings = false; + screen3G = new ScreenSettings(); + performance3G = new PerformanceFlags(); + redirectSDCard = false; + redirectSound = 0; + redirectMicrophone = false; + security = 0; + consoleMode = false; + remoteProgram = ""; + workDir = ""; + } + + private void validate() + { + switch (redirectSound) + { + case 0: + case 1: + case 2: + break; + default: + redirectSound = 0; + break; + } + + switch (security) + { + case 0: + case 1: + case 2: + case 3: + break; + default: + security = 0; + break; + } + } + + public boolean getEnable3GSettings() + { + return enable3GSettings; + } + + public void setEnable3GSettings(boolean enable3GSettings) + { + this.enable3GSettings = enable3GSettings; + } + + public ScreenSettings getScreen3G() + { + return screen3G; + } + + public void setScreen3G(ScreenSettings screen3G) + { + this.screen3G = screen3G; + } + + public PerformanceFlags getPerformance3G() + { + return performance3G; + } + + public void setPerformance3G(PerformanceFlags performance3G) + { + this.performance3G = performance3G; + } + + public boolean getRedirectSDCard() + { + return redirectSDCard; + } + + public void setRedirectSDCard(boolean redirectSDCard) + { + this.redirectSDCard = redirectSDCard; + } + + public int getRedirectSound() + { + validate(); + return redirectSound; + } + + public void setRedirectSound(int redirect) + { + this.redirectSound = redirect; + } + + public boolean getRedirectMicrophone() + { + return redirectMicrophone; + } + + public void setRedirectMicrophone(boolean redirect) + { + this.redirectMicrophone = redirect; + } + + public int getSecurity() + { + validate(); + return security; + } + + public void setSecurity(int security) + { + this.security = security; + } + + public boolean getConsoleMode() + { + return consoleMode; + } + + public void setConsoleMode(boolean consoleMode) + { + this.consoleMode = consoleMode; + } + + public String getRemoteProgram() + { + return remoteProgram; + } + + public void setRemoteProgram(String remoteProgram) + { + this.remoteProgram = remoteProgram; + } + + public String getWorkDir() + { + return workDir; + } + + public void setWorkDir(String workDir) + { + this.workDir = workDir; + } + + @Override public int describeContents() + { + return 0; + } + + @Override public void writeToParcel(Parcel out, int flags) + { + out.writeInt(enable3GSettings ? 1 : 0); + out.writeParcelable(screen3G, flags); + out.writeParcelable(performance3G, flags); + out.writeInt(redirectSDCard ? 1 : 0); + out.writeInt(redirectSound); + out.writeInt(redirectMicrophone ? 1 : 0); + out.writeInt(security); + out.writeInt(consoleMode ? 1 : 0); + out.writeString(remoteProgram); + out.writeString(workDir); + } + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/domain/ConnectionReference.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/domain/ConnectionReference.java index ac8c2fb..3e68776 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/domain/ConnectionReference.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/domain/ConnectionReference.java @@ -1,69 +1,85 @@ /* - A RDP connection reference. References can use bookmark ids or hostnames to connect to a RDP server. + A RDP connection reference. References can use bookmark ids or hostnames to connect to a RDP + server. Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.domain; -public class ConnectionReference { - public static final String PATH_MANUAL_BOOKMARK_ID = "MBMID/"; - public static final String PATH_HOSTNAME = "HOST/"; - public static final String PATH_PLACEHOLDER = "PLCHLD/"; - public static final String PATH_FILE = "FILE/"; - - public static String getManualBookmarkReference(long bookmarkId) { - return (PATH_MANUAL_BOOKMARK_ID + bookmarkId); - } - - public static String getHostnameReference(String hostname) { - return (PATH_HOSTNAME + hostname); - } - - public static String getPlaceholderReference(String name) { - return (PATH_PLACEHOLDER + name); - } - - public static String getFileReference(String uri) { - return (PATH_FILE + uri); - } - - public static boolean isBookmarkReference(String refStr) { - return refStr.startsWith(PATH_MANUAL_BOOKMARK_ID); - } - - public static boolean isManualBookmarkReference(String refStr) { - return refStr.startsWith(PATH_MANUAL_BOOKMARK_ID); - } - - public static boolean isHostnameReference(String refStr) { - return refStr.startsWith(PATH_HOSTNAME); - } - - public static boolean isPlaceholderReference(String refStr) { - return refStr.startsWith(PATH_PLACEHOLDER); - } - - public static boolean isFileReference(String refStr) { - return refStr.startsWith(PATH_FILE); - } - - public static long getManualBookmarkId(String refStr) { - return Integer.parseInt(refStr.substring(PATH_MANUAL_BOOKMARK_ID.length())); - } - - public static String getHostname(String refStr) { - return refStr.substring(PATH_HOSTNAME.length()); - } - - public static String getPlaceholder(String refStr) { - return refStr.substring(PATH_PLACEHOLDER.length()); - } - - public static String getFile(String refStr) { - return refStr.substring(PATH_FILE.length()); - } +public class ConnectionReference +{ + public static final String PATH_MANUAL_BOOKMARK_ID = "MBMID/"; + public static final String PATH_HOSTNAME = "HOST/"; + public static final String PATH_PLACEHOLDER = "PLCHLD/"; + public static final String PATH_FILE = "FILE/"; + + public static String getManualBookmarkReference(long bookmarkId) + { + return (PATH_MANUAL_BOOKMARK_ID + bookmarkId); + } + + public static String getHostnameReference(String hostname) + { + return (PATH_HOSTNAME + hostname); + } + + public static String getPlaceholderReference(String name) + { + return (PATH_PLACEHOLDER + name); + } + + public static String getFileReference(String uri) + { + return (PATH_FILE + uri); + } + + public static boolean isBookmarkReference(String refStr) + { + return refStr.startsWith(PATH_MANUAL_BOOKMARK_ID); + } + + public static boolean isManualBookmarkReference(String refStr) + { + return refStr.startsWith(PATH_MANUAL_BOOKMARK_ID); + } + + public static boolean isHostnameReference(String refStr) + { + return refStr.startsWith(PATH_HOSTNAME); + } + + public static boolean isPlaceholderReference(String refStr) + { + return refStr.startsWith(PATH_PLACEHOLDER); + } + + public static boolean isFileReference(String refStr) + { + return refStr.startsWith(PATH_FILE); + } + + public static long getManualBookmarkId(String refStr) + { + return Integer.parseInt(refStr.substring(PATH_MANUAL_BOOKMARK_ID.length())); + } + + public static String getHostname(String refStr) + { + return refStr.substring(PATH_HOSTNAME.length()); + } + + public static String getPlaceholder(String refStr) + { + return refStr.substring(PATH_PLACEHOLDER.length()); + } + + public static String getFile(String refStr) + { + return refStr.substring(PATH_FILE.length()); + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/domain/ManualBookmark.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/domain/ManualBookmark.java index 0e5b677..874d4e9 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/domain/ManualBookmark.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/domain/ManualBookmark.java @@ -3,8 +3,9 @@ Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.domain; @@ -13,212 +14,242 @@ import android.content.SharedPreferences; import android.os.Parcel; import android.os.Parcelable; -public class ManualBookmark extends BookmarkBase { - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public ManualBookmark createFromParcel(Parcel in) { - return new ManualBookmark(in); - } - - @Override - public ManualBookmark[] newArray(int size) { - return new ManualBookmark[size]; - } - }; - private String hostname; - private int port; - private boolean enableGatewaySettings; - private GatewaySettings gatewaySettings; - - public ManualBookmark(Parcel parcel) { - super(parcel); - type = TYPE_MANUAL; - hostname = parcel.readString(); - port = parcel.readInt(); - - enableGatewaySettings = (parcel.readInt() == 1 ? true : false); - gatewaySettings = parcel.readParcelable(GatewaySettings.class.getClassLoader()); - } - - public ManualBookmark() { - super(); - init(); - } - - private void init() { - type = TYPE_MANUAL; - hostname = ""; - port = 3389; - enableGatewaySettings = false; - gatewaySettings = new GatewaySettings(); - } - - public String getHostname() { - return hostname; - } - - public void setHostname(String hostname) { - this.hostname = hostname; - } - - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } - - public boolean getEnableGatewaySettings() { - return enableGatewaySettings; - } - - public void setEnableGatewaySettings(boolean enableGatewaySettings) { - this.enableGatewaySettings = enableGatewaySettings; - } - - public GatewaySettings getGatewaySettings() { - return gatewaySettings; - } - - public void setGatewaySettings(GatewaySettings gatewaySettings) { - this.gatewaySettings = gatewaySettings; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - super.writeToParcel(out, flags); - out.writeString(hostname); - out.writeInt(port); - out.writeInt(enableGatewaySettings ? 1 : 0); - out.writeParcelable(gatewaySettings, flags); - } - - @Override - public void writeToSharedPreferences(SharedPreferences sharedPrefs) { - super.writeToSharedPreferences(sharedPrefs); - - SharedPreferences.Editor editor = sharedPrefs.edit(); - editor.putString("bookmark.hostname", hostname); - editor.putInt("bookmark.port", port); - editor.putBoolean("bookmark.enable_gateway_settings", enableGatewaySettings); - editor.putString("bookmark.gateway_hostname", gatewaySettings.getHostname()); - editor.putInt("bookmark.gateway_port", gatewaySettings.getPort()); - editor.putString("bookmark.gateway_username", gatewaySettings.getUsername()); - editor.putString("bookmark.gateway_password", gatewaySettings.getPassword()); - editor.putString("bookmark.gateway_domain", gatewaySettings.getDomain()); - editor.commit(); - } - - @Override - public void readFromSharedPreferences(SharedPreferences sharedPrefs) { - super.readFromSharedPreferences(sharedPrefs); - - hostname = sharedPrefs.getString("bookmark.hostname", ""); - port = sharedPrefs.getInt("bookmark.port", 3389); - enableGatewaySettings = sharedPrefs.getBoolean("bookmark.enable_gateway_settings", false); - gatewaySettings.setHostname(sharedPrefs.getString("bookmark.gateway_hostname", "")); - gatewaySettings.setPort(sharedPrefs.getInt("bookmark.gateway_port", 443)); - gatewaySettings.setUsername(sharedPrefs.getString("bookmark.gateway_username", "")); - gatewaySettings.setPassword(sharedPrefs.getString("bookmark.gateway_password", "")); - gatewaySettings.setDomain(sharedPrefs.getString("bookmark.gateway_domain", "")); - } - - // Cloneable - public Object clone() { - return super.clone(); - } - - // Gateway Settings class - public static class GatewaySettings implements Parcelable { - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public GatewaySettings createFromParcel(Parcel in) { - return new GatewaySettings(in); - } - - @Override - public GatewaySettings[] newArray(int size) { - return new GatewaySettings[size]; - } - }; - private String hostname; - private int port; - private String username; - private String password; - private String domain; - - public GatewaySettings() { - hostname = ""; - port = 443; - username = ""; - password = ""; - domain = ""; - } - - public GatewaySettings(Parcel parcel) { - hostname = parcel.readString(); - port = parcel.readInt(); - username = parcel.readString(); - password = parcel.readString(); - domain = parcel.readString(); - } - - public String getHostname() { - return hostname; - } - - public void setHostname(String hostname) { - this.hostname = hostname; - } - - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - public String getDomain() { - return domain; - } - - public void setDomain(String domain) { - this.domain = domain; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeString(hostname); - out.writeInt(port); - out.writeString(username); - out.writeString(password); - out.writeString(domain); - } - } +public class ManualBookmark extends BookmarkBase +{ + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public ManualBookmark createFromParcel(Parcel in) + { + return new ManualBookmark(in); + } + + @Override public ManualBookmark[] newArray(int size) + { + return new ManualBookmark[size]; + } + }; + private String hostname; + private int port; + private boolean enableGatewaySettings; + private GatewaySettings gatewaySettings; + + public ManualBookmark(Parcel parcel) + { + super(parcel); + type = TYPE_MANUAL; + hostname = parcel.readString(); + port = parcel.readInt(); + + enableGatewaySettings = (parcel.readInt() == 1 ? true : false); + gatewaySettings = parcel.readParcelable(GatewaySettings.class.getClassLoader()); + } + + public ManualBookmark() + { + super(); + init(); + } + + private void init() + { + type = TYPE_MANUAL; + hostname = ""; + port = 3389; + enableGatewaySettings = false; + gatewaySettings = new GatewaySettings(); + } + + public String getHostname() + { + return hostname; + } + + public void setHostname(String hostname) + { + this.hostname = hostname; + } + + public int getPort() + { + return port; + } + + public void setPort(int port) + { + this.port = port; + } + + public boolean getEnableGatewaySettings() + { + return enableGatewaySettings; + } + + public void setEnableGatewaySettings(boolean enableGatewaySettings) + { + this.enableGatewaySettings = enableGatewaySettings; + } + + public GatewaySettings getGatewaySettings() + { + return gatewaySettings; + } + + public void setGatewaySettings(GatewaySettings gatewaySettings) + { + this.gatewaySettings = gatewaySettings; + } + + @Override public int describeContents() + { + return 0; + } + + @Override public void writeToParcel(Parcel out, int flags) + { + super.writeToParcel(out, flags); + out.writeString(hostname); + out.writeInt(port); + out.writeInt(enableGatewaySettings ? 1 : 0); + out.writeParcelable(gatewaySettings, flags); + } + + @Override public void writeToSharedPreferences(SharedPreferences sharedPrefs) + { + super.writeToSharedPreferences(sharedPrefs); + + SharedPreferences.Editor editor = sharedPrefs.edit(); + editor.putString("bookmark.hostname", hostname); + editor.putInt("bookmark.port", port); + editor.putBoolean("bookmark.enable_gateway_settings", enableGatewaySettings); + editor.putString("bookmark.gateway_hostname", gatewaySettings.getHostname()); + editor.putInt("bookmark.gateway_port", gatewaySettings.getPort()); + editor.putString("bookmark.gateway_username", gatewaySettings.getUsername()); + editor.putString("bookmark.gateway_password", gatewaySettings.getPassword()); + editor.putString("bookmark.gateway_domain", gatewaySettings.getDomain()); + editor.commit(); + } + + @Override public void readFromSharedPreferences(SharedPreferences sharedPrefs) + { + super.readFromSharedPreferences(sharedPrefs); + + hostname = sharedPrefs.getString("bookmark.hostname", ""); + port = sharedPrefs.getInt("bookmark.port", 3389); + enableGatewaySettings = sharedPrefs.getBoolean("bookmark.enable_gateway_settings", false); + gatewaySettings.setHostname(sharedPrefs.getString("bookmark.gateway_hostname", "")); + gatewaySettings.setPort(sharedPrefs.getInt("bookmark.gateway_port", 443)); + gatewaySettings.setUsername(sharedPrefs.getString("bookmark.gateway_username", "")); + gatewaySettings.setPassword(sharedPrefs.getString("bookmark.gateway_password", "")); + gatewaySettings.setDomain(sharedPrefs.getString("bookmark.gateway_domain", "")); + } + + // Cloneable + public Object clone() + { + return super.clone(); + } + + // Gateway Settings class + public static class GatewaySettings implements Parcelable + { + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public GatewaySettings createFromParcel(Parcel in) + { + return new GatewaySettings(in); + } + + @Override public GatewaySettings[] newArray(int size) + { + return new GatewaySettings[size]; + } + }; + private String hostname; + private int port; + private String username; + private String password; + private String domain; + + public GatewaySettings() + { + hostname = ""; + port = 443; + username = ""; + password = ""; + domain = ""; + } + + public GatewaySettings(Parcel parcel) + { + hostname = parcel.readString(); + port = parcel.readInt(); + username = parcel.readString(); + password = parcel.readString(); + domain = parcel.readString(); + } + + public String getHostname() + { + return hostname; + } + + public void setHostname(String hostname) + { + this.hostname = hostname; + } + + public int getPort() + { + return port; + } + + public void setPort(int port) + { + this.port = port; + } + + public String getUsername() + { + return username; + } + + public void setUsername(String username) + { + this.username = username; + } + + public String getPassword() + { + return password; + } + + public void setPassword(String password) + { + this.password = password; + } + + public String getDomain() + { + return domain; + } + + public void setDomain(String domain) + { + this.domain = domain; + } + + @Override public int describeContents() + { + return 0; + } + + @Override public void writeToParcel(Parcel out, int flags) + { + out.writeString(hostname); + out.writeInt(port); + out.writeString(username); + out.writeString(password); + out.writeString(domain); + } + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/domain/PlaceholderBookmark.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/domain/PlaceholderBookmark.java index b181af3..d15aaf7 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/domain/PlaceholderBookmark.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/domain/PlaceholderBookmark.java @@ -3,8 +3,9 @@ Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.domain; @@ -13,64 +14,71 @@ import android.content.SharedPreferences; import android.os.Parcel; import android.os.Parcelable; -public class PlaceholderBookmark extends BookmarkBase { - - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public PlaceholderBookmark createFromParcel(Parcel in) { - return new PlaceholderBookmark(in); - } - - @Override - public PlaceholderBookmark[] newArray(int size) { - return new PlaceholderBookmark[size]; - } - }; - private String name; - - public PlaceholderBookmark(Parcel parcel) { - super(parcel); - type = TYPE_PLACEHOLDER; - name = parcel.readString(); - } - - public PlaceholderBookmark() { - super(); - type = TYPE_PLACEHOLDER; - name = ""; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - super.writeToParcel(out, flags); - out.writeString(name); - } - - @Override - public void writeToSharedPreferences(SharedPreferences sharedPrefs) { - super.writeToSharedPreferences(sharedPrefs); - } - - @Override - public void readFromSharedPreferences(SharedPreferences sharedPrefs) { - super.readFromSharedPreferences(sharedPrefs); - } - - // Cloneable - public Object clone() { - return super.clone(); - } - +public class PlaceholderBookmark extends BookmarkBase +{ + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public PlaceholderBookmark createFromParcel(Parcel in) + { + return new PlaceholderBookmark(in); + } + + @Override public PlaceholderBookmark[] newArray(int size) + { + return new PlaceholderBookmark[size]; + } + }; + private String name; + + public PlaceholderBookmark(Parcel parcel) + { + super(parcel); + type = TYPE_PLACEHOLDER; + name = parcel.readString(); + } + + public PlaceholderBookmark() + { + super(); + type = TYPE_PLACEHOLDER; + name = ""; + } + + public String getName() + { + return name; + } + + public void setName(String name) + { + this.name = name; + } + + @Override public int describeContents() + { + return 0; + } + + @Override public void writeToParcel(Parcel out, int flags) + { + super.writeToParcel(out, flags); + out.writeString(name); + } + + @Override public void writeToSharedPreferences(SharedPreferences sharedPrefs) + { + super.writeToSharedPreferences(sharedPrefs); + } + + @Override public void readFromSharedPreferences(SharedPreferences sharedPrefs) + { + super.readFromSharedPreferences(sharedPrefs); + } + + // Cloneable + public Object clone() + { + return super.clone(); + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/domain/QuickConnectBookmark.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/domain/QuickConnectBookmark.java index 7df9db8..3367b54 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/domain/QuickConnectBookmark.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/domain/QuickConnectBookmark.java @@ -3,8 +3,9 @@ Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.domain; @@ -13,52 +14,57 @@ import android.content.SharedPreferences; import android.os.Parcel; import android.os.Parcelable; -public class QuickConnectBookmark extends ManualBookmark { +public class QuickConnectBookmark extends ManualBookmark +{ - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public QuickConnectBookmark createFromParcel(Parcel in) { - return new QuickConnectBookmark(in); - } + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public QuickConnectBookmark createFromParcel(Parcel in) + { + return new QuickConnectBookmark(in); + } - @Override - public QuickConnectBookmark[] newArray(int size) { - return new QuickConnectBookmark[size]; - } - }; + @Override public QuickConnectBookmark[] newArray(int size) + { + return new QuickConnectBookmark[size]; + } + }; - public QuickConnectBookmark(Parcel parcel) { - super(parcel); - type = TYPE_QUICKCONNECT; - } + public QuickConnectBookmark(Parcel parcel) + { + super(parcel); + type = TYPE_QUICKCONNECT; + } - public QuickConnectBookmark() { - super(); - type = TYPE_QUICKCONNECT; - } + public QuickConnectBookmark() + { + super(); + type = TYPE_QUICKCONNECT; + } - @Override - public int describeContents() { - return 0; - } + @Override public int describeContents() + { + return 0; + } - @Override - public void writeToParcel(Parcel out, int flags) { - super.writeToParcel(out, flags); - } + @Override public void writeToParcel(Parcel out, int flags) + { + super.writeToParcel(out, flags); + } - @Override - public void writeToSharedPreferences(SharedPreferences sharedPrefs) { - super.writeToSharedPreferences(sharedPrefs); - } + @Override public void writeToSharedPreferences(SharedPreferences sharedPrefs) + { + super.writeToSharedPreferences(sharedPrefs); + } - @Override - public void readFromSharedPreferences(SharedPreferences sharedPrefs) { - super.readFromSharedPreferences(sharedPrefs); - } - - // Cloneable - public Object clone() { - return super.clone(); - } + @Override public void readFromSharedPreferences(SharedPreferences sharedPrefs) + { + super.readFromSharedPreferences(sharedPrefs); + } + // Cloneable + public Object clone() + { + return super.clone(); + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/AboutActivity.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/AboutActivity.java index c9320d4..26a4e45 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/AboutActivity.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/AboutActivity.java @@ -22,85 +22,100 @@ import java.util.Formatter; import java.util.IllegalFormatException; import java.util.Locale; -public class AboutActivity extends AppCompatActivity { - private static final String TAG = AboutActivity.class.toString(); - private WebView mWebView; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_about); - mWebView = (WebView) findViewById(R.id.activity_about_webview); - } - - @Override - protected void onResume() { - populate(); - super.onResume(); - } - - private void populate() { - StringBuilder total = new StringBuilder(); - - String filename = "about_phone.html"; - if ((getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE) { - filename = "about.html"; - } - Locale def = Locale.getDefault(); - String prefix = def.getLanguage().toLowerCase(def); - - String dir = prefix + "_about_page/"; - String file = dir + filename; - InputStream is; - try { - is = getAssets().open(file); - is.close(); - } catch (IOException e) { - Log.e(TAG, "Missing localized asset " + file, e); - dir = "about_page/"; - file = dir + filename; - } - - try { - BufferedReader r = new BufferedReader(new InputStreamReader(getAssets().open(file))); - try { - String line; - while ((line = r.readLine()) != null) { - total.append(line); - total.append("\n"); - } - } finally { - r.close(); - } - } catch (IOException e) { - Log.e(TAG, "Could not read about page " + file, e); - } - - // append FreeRDP core version to app version - // get app version - String version; - try { - version = getPackageManager().getPackageInfo(getPackageName(), 0).versionName; - } catch (PackageManager.NameNotFoundException e) { - version = "unknown"; - } - version = version + " (" + LibFreeRDP.getVersion() + ")"; - - WebSettings settings = mWebView.getSettings(); - settings.setDomStorageEnabled(true); - settings.setUseWideViewPort(true); - settings.setLoadWithOverviewMode(true); - settings.setSupportZoom(true); - - final String base = "file:///android_asset/" + dir; - - final String rawHtml = total.toString(); - final String html = rawHtml.replaceAll("%AFREERDP_VERSION%", version) - .replaceAll("%SYSTEM_VERSION%", Build.VERSION.RELEASE) - .replaceAll("%DEVICE_MODEL%", Build.MODEL); - - mWebView.loadDataWithBaseURL(base, html, "text/html", null, - "about:blank"); - } - +public class AboutActivity extends AppCompatActivity +{ + private static final String TAG = AboutActivity.class.toString(); + private WebView mWebView; + + @Override protected void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_about); + mWebView = (WebView)findViewById(R.id.activity_about_webview); + } + + @Override protected void onResume() + { + populate(); + super.onResume(); + } + + private void populate() + { + StringBuilder total = new StringBuilder(); + + String filename = "about_phone.html"; + if ((getResources().getConfiguration().screenLayout & + Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE) + { + filename = "about.html"; + } + Locale def = Locale.getDefault(); + String prefix = def.getLanguage().toLowerCase(def); + + String dir = prefix + "_about_page/"; + String file = dir + filename; + InputStream is; + try + { + is = getAssets().open(file); + is.close(); + } + catch (IOException e) + { + Log.e(TAG, "Missing localized asset " + file, e); + dir = "about_page/"; + file = dir + filename; + } + + try + { + BufferedReader r = new BufferedReader(new InputStreamReader(getAssets().open(file))); + try + { + String line; + while ((line = r.readLine()) != null) + { + total.append(line); + total.append("\n"); + } + } + finally + { + r.close(); + } + } + catch (IOException e) + { + Log.e(TAG, "Could not read about page " + file, e); + } + + // append FreeRDP core version to app version + // get app version + String version; + try + { + version = getPackageManager().getPackageInfo(getPackageName(), 0).versionName; + } + catch (PackageManager.NameNotFoundException e) + { + version = "unknown"; + } + version = version + " (" + LibFreeRDP.getVersion() + ")"; + + WebSettings settings = mWebView.getSettings(); + settings.setDomStorageEnabled(true); + settings.setUseWideViewPort(true); + settings.setLoadWithOverviewMode(true); + settings.setSupportZoom(true); + + final String base = "file:///android_asset/" + dir; + + final String rawHtml = total.toString(); + final String html = rawHtml.replaceAll("%AFREERDP_VERSION%", version) + .replaceAll("%SYSTEM_VERSION%", Build.VERSION.RELEASE) + .replaceAll("%DEVICE_MODEL%", Build.MODEL); + + mWebView.loadDataWithBaseURL(base, html, "text/html", null, "about:blank"); + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/ApplicationSettingsActivity.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/ApplicationSettingsActivity.java index 05fb792..2a4fc5e 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/ApplicationSettingsActivity.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/ApplicationSettingsActivity.java @@ -3,8 +3,9 @@ Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.presentation; @@ -31,217 +32,269 @@ import java.io.File; import java.util.List; import java.util.UUID; -public class ApplicationSettingsActivity extends AppCompatPreferenceActivity { - private static boolean isXLargeTablet(Context context) { - return (context.getResources().getConfiguration().screenLayout - & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE; - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setupActionBar(); - } - - private void setupActionBar() { - android.app.ActionBar actionBar = getActionBar(); - if (actionBar != null) { - actionBar.setDisplayHomeAsUpEnabled(true); - } - } - - @Override - public boolean onIsMultiPane() { - return isXLargeTablet(this); - } - - @Override - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - public void onBuildHeaders(List
target) { - loadHeadersFromResource(R.xml.settings_app_headers, target); - } - - protected boolean isValidFragment(String fragmentName) { - return PreferenceFragment.class.getName().equals(fragmentName) - || ClientPreferenceFragment.class.getName().equals(fragmentName) - || UiPreferenceFragment.class.getName().equals(fragmentName) - || PowerPreferenceFragment.class.getName().equals(fragmentName) - || SecurityPreferenceFragment.class.getName().equals(fragmentName); - } - - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - public static class ClientPreferenceFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.settings_app_client); - SharedPreferences preferences = get(getActivity()); - preferences.registerOnSharedPreferenceChangeListener(this); - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - if (isAdded()) { - final String clientNameKey = getString(R.string.preference_key_client_name); - - get(getActivity()); - if (key.equals(clientNameKey)) { - final String clientNameValue = sharedPreferences.getString(clientNameKey, ""); - EditTextPreference pref = (EditTextPreference) findPreference(clientNameKey); - pref.setText(clientNameValue); - } - } - } - } - - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - public static class UiPreferenceFragment extends PreferenceFragment { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.settings_app_ui); - } - } - - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - public static class PowerPreferenceFragment extends PreferenceFragment { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.settings_app_power); - } - } - - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - public static class SecurityPreferenceFragment extends PreferenceFragment { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.settings_app_security); - } - - @Override - public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { - final String clear = getString(R.string.preference_key_security_clear_certificate_cache); - if (preference.getKey().equals(clear)) { - showDialog(); - return true; - } else { - return super.onPreferenceTreeClick(preferenceScreen, preference); - } - } - - private void showDialog() { - new AlertDialog.Builder(getActivity()) - .setTitle(R.string.dlg_title_clear_cert_cache) - .setMessage(R.string.dlg_msg_clear_cert_cache) - .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - clearCertificateCache(); - dialog.dismiss(); - } - }) - .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - } - }) - .setIcon(android.R.drawable.ic_delete) - .show(); - } - - private boolean deleteDirectory(File dir) { - if (dir.isDirectory()) { - String[] children = dir.list(); - for (String file : children) { - if (!deleteDirectory(new File(dir, file))) - return false; - } - } - return dir.delete(); - } - - private void clearCertificateCache() { - Context context = getActivity(); - if ((new File(context.getFilesDir() + "/.freerdp")).exists()) { - if (deleteDirectory(new File(context.getFilesDir() + "/.freerdp"))) - Toast.makeText(context, R.string.info_reset_success, Toast.LENGTH_LONG).show(); - else - Toast.makeText(context, R.string.info_reset_failed, Toast.LENGTH_LONG).show(); - } else - Toast.makeText(context, R.string.info_reset_success, Toast.LENGTH_LONG).show(); - } - } - - public static SharedPreferences get(Context context) { - Context appContext = context.getApplicationContext(); - PreferenceManager.setDefaultValues(appContext, R.xml.settings_app_client, false); - PreferenceManager.setDefaultValues(appContext, R.xml.settings_app_power, false); - PreferenceManager.setDefaultValues(appContext, R.xml.settings_app_security, false); - PreferenceManager.setDefaultValues(appContext, R.xml.settings_app_ui, false); - SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(appContext); - - final String key = context.getString(R.string.preference_key_client_name); - final String value = preferences.getString(key, ""); - if (value.isEmpty()) { - final String android_id = UUID.randomUUID().toString(); - final String defaultValue = context.getString(R.string.preference_default_client_name); - final String name = defaultValue + "-" + android_id; - preferences.edit().putString(key, name.substring(0, 31)).apply(); - } - - return preferences; - } - - public static int getDisconnectTimeout(Context context) { - SharedPreferences preferences = get(context); - return preferences.getInt(context.getString(R.string.preference_key_power_disconnect_timeout), 0); - } - - public static boolean getHideStatusBar(Context context) { - SharedPreferences preferences = get(context); - return preferences.getBoolean(context.getString(R.string.preference_key_ui_hide_status_bar), false); - } - - public static boolean getHideActionBar(Context context) { - SharedPreferences preferences = get(context); - return preferences.getBoolean(context.getString(R.string.preference_key_ui_hide_action_bar), false); - } - - public static boolean getAcceptAllCertificates(Context context) { - SharedPreferences preferences = get(context); - return preferences.getBoolean(context.getString(R.string.preference_key_accept_certificates), false); - } - - public static boolean getHideZoomControls(Context context) { - SharedPreferences preferences = get(context); - return preferences.getBoolean(context.getString(R.string.preference_key_ui_hide_zoom_controls), false); - } - - public static boolean getSwapMouseButtons(Context context) { - SharedPreferences preferences = get(context); - return preferences.getBoolean(context.getString(R.string.preference_key_ui_swap_mouse_buttons), false); - } - - public static boolean getInvertScrolling(Context context) { - SharedPreferences preferences = get(context); - return preferences.getBoolean(context.getString(R.string.preference_key_ui_invert_scrolling), false); - } - - public static boolean getAskOnExit(Context context) { - SharedPreferences preferences = get(context); - return preferences.getBoolean(context.getString(R.string.preference_key_ui_ask_on_exit), false); - } - - public static boolean getAutoScrollTouchPointer(Context context) { - SharedPreferences preferences = get(context); - return preferences.getBoolean(context.getString(R.string.preference_key_ui_auto_scroll_touchpointer), false); - } - - public static String getClientName(Context context) { - SharedPreferences preferences = get(context); - return preferences.getString(context.getString(R.string.preference_key_client_name), ""); - } +public class ApplicationSettingsActivity extends AppCompatPreferenceActivity +{ + private static boolean isXLargeTablet(Context context) + { + return (context.getResources().getConfiguration().screenLayout & + Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE; + } + + @Override protected void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + setupActionBar(); + } + + private void setupActionBar() + { + android.app.ActionBar actionBar = getActionBar(); + if (actionBar != null) + { + actionBar.setDisplayHomeAsUpEnabled(true); + } + } + + @Override public boolean onIsMultiPane() + { + return isXLargeTablet(this); + } + + @Override + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + public void onBuildHeaders(List
target) + { + loadHeadersFromResource(R.xml.settings_app_headers, target); + } + + protected boolean isValidFragment(String fragmentName) + { + return PreferenceFragment.class.getName().equals(fragmentName) || + ClientPreferenceFragment.class.getName().equals(fragmentName) || + UiPreferenceFragment.class.getName().equals(fragmentName) || + PowerPreferenceFragment.class.getName().equals(fragmentName) || + SecurityPreferenceFragment.class.getName().equals(fragmentName); + } + + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + public static class ClientPreferenceFragment + extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener + { + @Override public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.settings_app_client); + SharedPreferences preferences = get(getActivity()); + preferences.registerOnSharedPreferenceChangeListener(this); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) + { + if (isAdded()) + { + final String clientNameKey = getString(R.string.preference_key_client_name); + + get(getActivity()); + if (key.equals(clientNameKey)) + { + final String clientNameValue = sharedPreferences.getString(clientNameKey, ""); + EditTextPreference pref = (EditTextPreference)findPreference(clientNameKey); + pref.setText(clientNameValue); + } + } + } + } + + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + public static class UiPreferenceFragment extends PreferenceFragment + { + @Override public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.settings_app_ui); + } + } + + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + public static class PowerPreferenceFragment extends PreferenceFragment + { + @Override public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.settings_app_power); + } + } + + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + public static class SecurityPreferenceFragment extends PreferenceFragment + { + @Override public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.settings_app_security); + } + + @Override + public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, + Preference preference) + { + final String clear = + getString(R.string.preference_key_security_clear_certificate_cache); + if (preference.getKey().equals(clear)) + { + showDialog(); + return true; + } + else + { + return super.onPreferenceTreeClick(preferenceScreen, preference); + } + } + + private void showDialog() + { + new AlertDialog.Builder(getActivity()) + .setTitle(R.string.dlg_title_clear_cert_cache) + .setMessage(R.string.dlg_msg_clear_cert_cache) + .setPositiveButton(android.R.string.ok, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) + { + clearCertificateCache(); + dialog.dismiss(); + } + }) + .setNegativeButton(android.R.string.cancel, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) + { + dialog.dismiss(); + } + }) + .setIcon(android.R.drawable.ic_delete) + .show(); + } + + private boolean deleteDirectory(File dir) + { + if (dir.isDirectory()) + { + String[] children = dir.list(); + for (String file : children) + { + if (!deleteDirectory(new File(dir, file))) + return false; + } + } + return dir.delete(); + } + + private void clearCertificateCache() + { + Context context = getActivity(); + if ((new File(context.getFilesDir() + "/.freerdp")).exists()) + { + if (deleteDirectory(new File(context.getFilesDir() + "/.freerdp"))) + Toast.makeText(context, R.string.info_reset_success, Toast.LENGTH_LONG).show(); + else + Toast.makeText(context, R.string.info_reset_failed, Toast.LENGTH_LONG).show(); + } + else + Toast.makeText(context, R.string.info_reset_success, Toast.LENGTH_LONG).show(); + } + } + + public static SharedPreferences get(Context context) + { + Context appContext = context.getApplicationContext(); + PreferenceManager.setDefaultValues(appContext, R.xml.settings_app_client, false); + PreferenceManager.setDefaultValues(appContext, R.xml.settings_app_power, false); + PreferenceManager.setDefaultValues(appContext, R.xml.settings_app_security, false); + PreferenceManager.setDefaultValues(appContext, R.xml.settings_app_ui, false); + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(appContext); + + final String key = context.getString(R.string.preference_key_client_name); + final String value = preferences.getString(key, ""); + if (value.isEmpty()) + { + final String android_id = UUID.randomUUID().toString(); + final String defaultValue = context.getString(R.string.preference_default_client_name); + final String name = defaultValue + "-" + android_id; + preferences.edit().putString(key, name.substring(0, 31)).apply(); + } + + return preferences; + } + + public static int getDisconnectTimeout(Context context) + { + SharedPreferences preferences = get(context); + return preferences.getInt( + context.getString(R.string.preference_key_power_disconnect_timeout), 0); + } + + public static boolean getHideStatusBar(Context context) + { + SharedPreferences preferences = get(context); + return preferences.getBoolean(context.getString(R.string.preference_key_ui_hide_status_bar), + false); + } + + public static boolean getHideActionBar(Context context) + { + SharedPreferences preferences = get(context); + return preferences.getBoolean(context.getString(R.string.preference_key_ui_hide_action_bar), + false); + } + + public static boolean getAcceptAllCertificates(Context context) + { + SharedPreferences preferences = get(context); + return preferences.getBoolean( + context.getString(R.string.preference_key_accept_certificates), false); + } + + public static boolean getHideZoomControls(Context context) + { + SharedPreferences preferences = get(context); + return preferences.getBoolean( + context.getString(R.string.preference_key_ui_hide_zoom_controls), false); + } + + public static boolean getSwapMouseButtons(Context context) + { + SharedPreferences preferences = get(context); + return preferences.getBoolean( + context.getString(R.string.preference_key_ui_swap_mouse_buttons), false); + } + + public static boolean getInvertScrolling(Context context) + { + SharedPreferences preferences = get(context); + return preferences.getBoolean( + context.getString(R.string.preference_key_ui_invert_scrolling), false); + } + + public static boolean getAskOnExit(Context context) + { + SharedPreferences preferences = get(context); + return preferences.getBoolean(context.getString(R.string.preference_key_ui_ask_on_exit), + false); + } + + public static boolean getAutoScrollTouchPointer(Context context) + { + SharedPreferences preferences = get(context); + return preferences.getBoolean( + context.getString(R.string.preference_key_ui_auto_scroll_touchpointer), false); + } + + public static String getClientName(Context context) + { + SharedPreferences preferences = get(context); + return preferences.getString(context.getString(R.string.preference_key_client_name), ""); + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/BookmarkActivity.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/BookmarkActivity.java index 232039d..89ac4d4 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/BookmarkActivity.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/BookmarkActivity.java @@ -3,8 +3,9 @@ Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.presentation; @@ -36,659 +37,707 @@ import java.io.File; import java.io.IOException; import java.util.ArrayList; -public class BookmarkActivity extends PreferenceActivity implements - OnSharedPreferenceChangeListener { - public static final String PARAM_CONNECTION_REFERENCE = "conRef"; - - private static final String TAG = "BookmarkActivity"; - private static final int PREFERENCES_BOOKMARK = 1; - private static final int PREFERENCES_CREDENTIALS = 2; - private static final int PREFERENCES_SCREEN = 3; - private static final int PREFERENCES_PERFORMANCE = 4; - private static final int PREFERENCES_ADVANCED = 5; - private static final int PREFERENCES_SCREEN3G = 6; - private static final int PREFERENCES_PERFORMANCE3G = 7; - private static final int PREFERENCES_GATEWAY = 8; - private static final int PREFERENCES_DEBUG = 9; - // bookmark needs to be static because the activity is started for each - // subview - // (we have to do this because Android has a bug where the style for - // Preferences - // is only applied to the first PreferenceScreen but not to subsequent ones) - private static BookmarkBase bookmark = null; - private static boolean settings_changed = false; - private static boolean new_bookmark = false; - private int current_preferences; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - PreferenceManager mgr = getPreferenceManager(); - // init shared preferences for activity - mgr.setSharedPreferencesName("TEMP"); - mgr.setSharedPreferencesMode(MODE_PRIVATE); - - if (bookmark == null) { - // if we have a bookmark id set in the extras we are in edit mode - Bundle bundle = getIntent().getExtras(); - if (bundle != null) { - // See if we got a connection reference to a bookmark - if (bundle.containsKey(PARAM_CONNECTION_REFERENCE)) { - String refStr = bundle - .getString(PARAM_CONNECTION_REFERENCE); - if (ConnectionReference.isManualBookmarkReference(refStr)) { - bookmark = GlobalApp.getManualBookmarkGateway() - .findById( - ConnectionReference - .getManualBookmarkId(refStr)); - new_bookmark = false; - } else if (ConnectionReference.isHostnameReference(refStr)) { - bookmark = new ManualBookmark(); - bookmark.get().setLabel( - ConnectionReference.getHostname(refStr)); - bookmark.get().setHostname( - ConnectionReference.getHostname(refStr)); - new_bookmark = true; - } else if (ConnectionReference.isFileReference(refStr)) { - String file = ConnectionReference.getFile(refStr); - - bookmark = new ManualBookmark(); - bookmark.setLabel(file); - - try { - RDPFileParser rdpFile = new RDPFileParser(file); - updateBookmarkFromFile((ManualBookmark) bookmark, - rdpFile); - - bookmark.setLabel(new File(file).getName()); - new_bookmark = true; - } catch (IOException e) { - Log.e(TAG, "Failed reading RDP file", e); - } - } - } - } - - // last chance - ensure we really have a valid bookmark - if (bookmark == null) - bookmark = new ManualBookmark(); - - // hide gateway settings if we edit a non-manual bookmark - if (current_preferences == PREFERENCES_ADVANCED - && bookmark.getType() != ManualBookmark.TYPE_MANUAL) { - PreferenceScreen screen = getPreferenceScreen(); - screen.removePreference(findPreference("bookmark.enable_gateway")); - screen.removePreference(findPreference("bookmark.gateway")); - } - - updateH264Preferences(); - - // update preferences from bookmark - bookmark.writeToSharedPreferences(mgr.getSharedPreferences()); - - // no settings changed yet - settings_changed = false; - } - - // load the requested settings resource - if (getIntent() == null || getIntent().getData() == null) { - addPreferencesFromResource(R.xml.bookmark_settings); - current_preferences = PREFERENCES_BOOKMARK; - } else if (getIntent().getData().toString() - .equals("preferences://screen_settings")) { - addPreferencesFromResource(R.xml.screen_settings); - current_preferences = PREFERENCES_SCREEN; - } else if (getIntent().getData().toString() - .equals("preferences://performance_flags")) { - addPreferencesFromResource(R.xml.performance_flags); - current_preferences = PREFERENCES_PERFORMANCE; - } else if (getIntent().getData().toString() - .equals("preferences://screen_settings_3g")) { - addPreferencesFromResource(R.xml.screen_settings_3g); - current_preferences = PREFERENCES_SCREEN3G; - } else if (getIntent().getData().toString() - .equals("preferences://performance_flags_3g")) { - addPreferencesFromResource(R.xml.performance_flags_3g); - current_preferences = PREFERENCES_PERFORMANCE3G; - } else if (getIntent().getData().toString() - .equals("preferences://advanced_settings")) { - addPreferencesFromResource(R.xml.advanced_settings); - current_preferences = PREFERENCES_ADVANCED; - } else if (getIntent().getData().toString() - .equals("preferences://credentials_settings")) { - addPreferencesFromResource(R.xml.credentials_settings); - current_preferences = PREFERENCES_CREDENTIALS; - } else if (getIntent().getData().toString() - .equals("preferences://gateway_settings")) { - addPreferencesFromResource(R.xml.gateway_settings); - current_preferences = PREFERENCES_GATEWAY; - } else if (getIntent().getData().toString() - .equals("preferences://debug_settings")) { - addPreferencesFromResource(R.xml.debug_settings); - current_preferences = PREFERENCES_DEBUG; - } else { - addPreferencesFromResource(R.xml.bookmark_settings); - current_preferences = PREFERENCES_BOOKMARK; - } - - // update UI with bookmark data - SharedPreferences spref = mgr.getSharedPreferences(); - initSettings(spref); - - // register for preferences changed notification - mgr.getSharedPreferences().registerOnSharedPreferenceChangeListener(this); - - // set the correct component names in our preferencescreen settings - setIntentComponentNames(); - - updateH264Preferences(); - } - - private void updateH264Preferences() { - if (!LibFreeRDP.hasH264Support()) { - final int preferenceIdList[] = { - R.string.preference_key_h264, - R.string.preference_key_h264_3g - }; - - PreferenceManager mgr = getPreferenceManager(); - for (int id : preferenceIdList) { - final String key = getString(id); - Preference preference = mgr.findPreference(key); - if (preference != null) { - preference.setEnabled(false); - } - } - } - } - - private void updateBookmarkFromFile(ManualBookmark bookmark, - RDPFileParser rdpFile) { - String s; - Integer i; - - s = rdpFile.getString("full address"); - if (s != null) { - // this gets complicated as it can include port - if (s.lastIndexOf(":") > s.lastIndexOf("]")) { - try { - String port = s.substring(s.lastIndexOf(":") + 1); - bookmark.setPort(Integer.parseInt(port)); - } catch (NumberFormatException e) { - Log.e(TAG, "Malformed address"); - } - - s = s.substring(0, s.lastIndexOf(":")); - } - - // or even be an ipv6 address - if (s.startsWith("[") && s.endsWith("]")) - s = s.substring(1, s.length() - 1); - - bookmark.setHostname(s); - } - - i = rdpFile.getInteger("server port"); - if (i != null) - bookmark.setPort(i); - - s = rdpFile.getString("username"); - if (s != null) - bookmark.setUsername(s); - - s = rdpFile.getString("domain"); - if (s != null) - bookmark.setDomain(s); - - i = rdpFile.getInteger("connect to console"); - if (i != null) - bookmark.getAdvancedSettings().setConsoleMode(i == 1); - } - - private void setIntentComponentNames() { - // we set the component name for our sub-activity calls here because we - // don't know the package - // name of the main app in our library project. - ComponentName compName = new ComponentName(getPackageName(), - BookmarkActivity.class.getName()); - ArrayList prefKeys = new ArrayList(); - - prefKeys.add("bookmark.credentials"); - prefKeys.add("bookmark.screen"); - prefKeys.add("bookmark.performance"); - prefKeys.add("bookmark.advanced"); - prefKeys.add("bookmark.screen_3g"); - prefKeys.add("bookmark.performance_3g"); - prefKeys.add("bookmark.gateway_settings"); - prefKeys.add("bookmark.debug"); - - for (String p : prefKeys) { - Preference pref = findPreference(p); - if (pref != null) - pref.getIntent().setComponent(compName); - } - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, - String key) { - settings_changed = true; - switch (current_preferences) { - case PREFERENCES_DEBUG: - debugSettingsChanged(sharedPreferences, key); - break; - - case PREFERENCES_BOOKMARK: - bookmarkSettingsChanged(sharedPreferences, key); - break; - - case PREFERENCES_ADVANCED: - advancedSettingsChanged(sharedPreferences, key); - break; - - case PREFERENCES_CREDENTIALS: - credentialsSettingsChanged(sharedPreferences, key); - break; - - case PREFERENCES_SCREEN: - case PREFERENCES_SCREEN3G: - screenSettingsChanged(sharedPreferences, key); - break; - - case PREFERENCES_GATEWAY: - gatewaySettingsChanged(sharedPreferences, key); - break; - - default: - break; - } - - } - - private void initSettings(SharedPreferences sharedPreferences) { - switch (current_preferences) { - case PREFERENCES_BOOKMARK: - initBookmarkSettings(sharedPreferences); - break; - - case PREFERENCES_ADVANCED: - initAdvancedSettings(sharedPreferences); - break; - - case PREFERENCES_CREDENTIALS: - initCredentialsSettings(sharedPreferences); - break; - - case PREFERENCES_SCREEN: - initScreenSettings(sharedPreferences); - break; - - case PREFERENCES_SCREEN3G: - initScreenSettings3G(sharedPreferences); - break; - - case PREFERENCES_GATEWAY: - initGatewaySettings(sharedPreferences); - break; - - case PREFERENCES_DEBUG: - initDebugSettings(sharedPreferences); - break; - - default: - break; - } - } - - private void initBookmarkSettings(SharedPreferences sharedPreferences) { - bookmarkSettingsChanged(sharedPreferences, "bookmark.label"); - bookmarkSettingsChanged(sharedPreferences, "bookmark.hostname"); - bookmarkSettingsChanged(sharedPreferences, "bookmark.port"); - bookmarkSettingsChanged(sharedPreferences, "bookmark.username"); - bookmarkSettingsChanged(sharedPreferences, "bookmark.resolution"); - } - - private void bookmarkSettingsChanged(SharedPreferences sharedPreferences, - String key) { - if (key.equals("bookmark.label") && findPreference(key) != null) - findPreference(key) - .setSummary(sharedPreferences.getString(key, "")); - else if (key.equals("bookmark.hostname") && findPreference(key) != null) - findPreference(key) - .setSummary(sharedPreferences.getString(key, "")); - else if (key.equals("bookmark.port") && findPreference(key) != null) - findPreference(key).setSummary( - String.valueOf(sharedPreferences.getInt(key, -1))); - else if (key.equals("bookmark.username")) { - String username = sharedPreferences.getString(key, ""); - if (username.length() == 0) - username = ""; - findPreference("bookmark.credentials").setSummary(username); - } else if (key.equals("bookmark.resolution") - || key.equals("bookmark.colors") - || key.equals("bookmark.width") - || key.equals("bookmark.height")) { - String resolution = sharedPreferences.getString( - "bookmark.resolution", "800x600"); - // compare english string from resolutions_values_array array, - // decode to localized - // text for display - if (resolution.equals("automatic")) { - resolution = getResources().getString( - R.string.resolution_automatic); - } - if (resolution.equals("custom")) { - resolution = getResources().getString( - R.string.resolution_custom); - } - if (resolution.equals("fitscreen")) { - resolution = getResources().getString(R.string.resolution_fit); - } - resolution += "@" + sharedPreferences.getInt("bookmark.colors", 16); - findPreference("bookmark.screen").setSummary(resolution); - } - } - - private void initAdvancedSettings(SharedPreferences sharedPreferences) { - advancedSettingsChanged(sharedPreferences, - "bookmark.enable_gateway_settings"); - advancedSettingsChanged(sharedPreferences, - "bookmark.enable_3g_settings"); - advancedSettingsChanged(sharedPreferences, "bookmark.security"); - advancedSettingsChanged(sharedPreferences, "bookmark.resolution_3g"); - advancedSettingsChanged(sharedPreferences, "bookmark.remote_program"); - advancedSettingsChanged(sharedPreferences, "bookmark.work_dir"); - } - - private void advancedSettingsChanged(SharedPreferences sharedPreferences, - String key) { - if (key.equals("bookmark.enable_gateway_settings")) { - boolean enabled = sharedPreferences.getBoolean(key, false); - findPreference("bookmark.gateway_settings").setEnabled(enabled); - } else if (key.equals("bookmark.enable_3g_settings")) { - boolean enabled = sharedPreferences.getBoolean(key, false); - findPreference("bookmark.screen_3g").setEnabled(enabled); - findPreference("bookmark.performance_3g").setEnabled(enabled); - } else if (key.equals("bookmark.security")) { - ListPreference listPreference = (ListPreference) findPreference(key); - CharSequence security = listPreference.getEntries()[sharedPreferences - .getInt(key, 0)]; - listPreference.setSummary(security); - } else if (key.equals("bookmark.resolution_3g") - || key.equals("bookmark.colors_3g") - || key.equals("bookmark.width_3g") - || key.equals("bookmark.height_3g")) { - String resolution = sharedPreferences.getString( - "bookmark.resolution_3g", "800x600"); - if (resolution.equals("automatic")) - resolution = getResources().getString( - R.string.resolution_automatic); - else if (resolution.equals("custom")) - resolution = getResources().getString( - R.string.resolution_custom); - resolution += "@" - + sharedPreferences.getInt("bookmark.colors_3g", 16); - findPreference("bookmark.screen_3g").setSummary(resolution); - } else if (key.equals("bookmark.remote_program")) - findPreference(key) - .setSummary(sharedPreferences.getString(key, "")); - else if (key.equals("bookmark.work_dir")) - findPreference(key) - .setSummary(sharedPreferences.getString(key, "")); - } - - private void initCredentialsSettings(SharedPreferences sharedPreferences) { - credentialsSettingsChanged(sharedPreferences, "bookmark.username"); - credentialsSettingsChanged(sharedPreferences, "bookmark.password"); - credentialsSettingsChanged(sharedPreferences, "bookmark.domain"); - } - - private void credentialsSettingsChanged( - SharedPreferences sharedPreferences, String key) { - if (key.equals("bookmark.username")) - findPreference(key) - .setSummary(sharedPreferences.getString(key, "")); - else if (key.equals("bookmark.password")) { - if (sharedPreferences.getString(key, "").length() == 0) - findPreference(key).setSummary( - getResources().getString( - R.string.settings_password_empty)); - else - findPreference(key).setSummary( - getResources().getString( - R.string.settings_password_present)); - } else if (key.equals("bookmark.domain")) - findPreference(key) - .setSummary(sharedPreferences.getString(key, "")); - } - - private void initScreenSettings(SharedPreferences sharedPreferences) { - screenSettingsChanged(sharedPreferences, "bookmark.colors"); - screenSettingsChanged(sharedPreferences, "bookmark.resolution"); - screenSettingsChanged(sharedPreferences, "bookmark.width"); - screenSettingsChanged(sharedPreferences, "bookmark.height"); - } - - private void initScreenSettings3G(SharedPreferences sharedPreferences) { - screenSettingsChanged(sharedPreferences, "bookmark.colors_3g"); - screenSettingsChanged(sharedPreferences, "bookmark.resolution_3g"); - screenSettingsChanged(sharedPreferences, "bookmark.width_3g"); - screenSettingsChanged(sharedPreferences, "bookmark.height_3g"); - } - - private void screenSettingsChanged(SharedPreferences sharedPreferences, - String key) { - // could happen during initialization because 3g and non-3g settings - // share this routine - just skip - if (findPreference(key) == null) - return; - - if (key.equals("bookmark.colors") || key.equals("bookmark.colors_3g")) { - ListPreference listPreference = (ListPreference) findPreference(key); - listPreference.setSummary(listPreference.getEntry()); - } else if (key.equals("bookmark.resolution") - || key.equals("bookmark.resolution_3g")) { - ListPreference listPreference = (ListPreference) findPreference(key); - listPreference.setSummary(listPreference.getEntry()); - - String value = listPreference.getValue(); - boolean enabled = value.equalsIgnoreCase("custom"); - if (key.equals("bookmark.resolution")) { - findPreference("bookmark.width").setEnabled(enabled); - findPreference("bookmark.height").setEnabled(enabled); - } else { - findPreference("bookmark.width_3g").setEnabled(enabled); - findPreference("bookmark.height_3g").setEnabled(enabled); - } - } else if (key.equals("bookmark.width") - || key.equals("bookmark.width_3g")) - findPreference(key).setSummary( - String.valueOf(sharedPreferences.getInt(key, 800))); - else if (key.equals("bookmark.height") - || key.equals("bookmark.height_3g")) - findPreference(key).setSummary( - String.valueOf(sharedPreferences.getInt(key, 600))); - } - - private void initDebugSettings(SharedPreferences sharedPreferences) { - debugSettingsChanged(sharedPreferences, "bookmark.debug_level"); - debugSettingsChanged(sharedPreferences, "bookmark.async_channel"); - debugSettingsChanged(sharedPreferences, "bookmark.async_update"); - debugSettingsChanged(sharedPreferences, "bookmark.async_input"); - } - - private void initGatewaySettings(SharedPreferences sharedPreferences) { - gatewaySettingsChanged(sharedPreferences, "bookmark.gateway_hostname"); - gatewaySettingsChanged(sharedPreferences, "bookmark.gateway_port"); - gatewaySettingsChanged(sharedPreferences, "bookmark.gateway_username"); - gatewaySettingsChanged(sharedPreferences, "bookmark.gateway_password"); - gatewaySettingsChanged(sharedPreferences, "bookmark.gateway_domain"); - } - - private void debugSettingsChanged(SharedPreferences sharedPreferences, - String key) { - if (key.equals("bookmark.debug_level")) { - String level = sharedPreferences.getString(key, "INFO"); - Preference pref = findPreference("bookmark.debug_level"); - pref.setDefaultValue(level); - } else if (key.equals("bookmark.async_channel")) { - boolean enabled = sharedPreferences.getBoolean(key, false); - Preference pref = findPreference("bookmark.async_channel"); - pref.setDefaultValue(enabled); - } else if (key.equals("bookmark.async_update")) { - boolean enabled = sharedPreferences.getBoolean(key, false); - Preference pref = findPreference("bookmark.async_update"); - pref.setDefaultValue(enabled); - } else if (key.equals("bookmark.async_input")) { - boolean enabled = sharedPreferences.getBoolean(key, false); - Preference pref = findPreference("bookmark.async_input"); - pref.setDefaultValue(enabled); - } - } - - private void gatewaySettingsChanged(SharedPreferences sharedPreferences, - String key) { - if (key.equals("bookmark.gateway_hostname")) { - findPreference(key) - .setSummary(sharedPreferences.getString(key, "")); - } else if (key.equals("bookmark.gateway_port")) { - findPreference(key).setSummary( - String.valueOf(sharedPreferences.getInt(key, 443))); - } else if (key.equals("bookmark.gateway_username")) { - findPreference(key) - .setSummary(sharedPreferences.getString(key, "")); - } else if (key.equals("bookmark.gateway_password")) { - if (sharedPreferences.getString(key, "").length() == 0) - findPreference(key).setSummary( - getResources().getString( - R.string.settings_password_empty)); - else - findPreference(key).setSummary( - getResources().getString( - R.string.settings_password_present)); - } else if (key.equals("bookmark.gateway_domain")) - findPreference(key) - .setSummary(sharedPreferences.getString(key, "")); - } - - private boolean verifySettings(SharedPreferences sharedPreferences) { - - boolean verifyFailed = false; - // perform sanity checks on settings - // Label set - if (sharedPreferences.getString("bookmark.label", "").length() == 0) - verifyFailed = true; - - // Server and port specified - if (!verifyFailed - && sharedPreferences.getString("bookmark.hostname", "") - .length() == 0) - verifyFailed = true; - - // Server and port specified - if (!verifyFailed && sharedPreferences.getInt("bookmark.port", -1) <= 0) - verifyFailed = true; - - // if an error occurred - display toast and return false - return (!verifyFailed); - } - - private void finishAndResetBookmark() { - bookmark = null; - getPreferenceManager().getSharedPreferences() - .unregisterOnSharedPreferenceChangeListener(this); - finish(); - } - - @Override - public void onBackPressed() { - // only proceed if we are in the main preferences screen - if (current_preferences != PREFERENCES_BOOKMARK) { - super.onBackPressed(); - getPreferenceManager().getSharedPreferences() - .unregisterOnSharedPreferenceChangeListener(this); - return; - } - - SharedPreferences sharedPreferences = getPreferenceManager() - .getSharedPreferences(); - if (!verifySettings(sharedPreferences)) { - // ask the user if he wants to cancel or continue editing - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(R.string.error_bookmark_incomplete_title) - .setMessage(R.string.error_bookmark_incomplete) - .setPositiveButton(R.string.cancel, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, - int which) { - finishAndResetBookmark(); - } - }) - .setNegativeButton(R.string.cont, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, - int which) { - dialog.cancel(); - } - }).show(); - - return; - } else { - // ask the user if he wants to save or cancel editing if a setting - // has changed - if (new_bookmark || settings_changed) { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(R.string.dlg_title_save_bookmark) - .setMessage(R.string.dlg_save_bookmark) - .setPositiveButton(R.string.yes, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, - int which) { - // read shared prefs back to bookmark - bookmark.readFromSharedPreferences(getPreferenceManager() - .getSharedPreferences()); - - BookmarkBaseGateway bookmarkGateway; - if (bookmark.getType() == BookmarkBase.TYPE_MANUAL) { - bookmarkGateway = GlobalApp - .getManualBookmarkGateway(); - // remove any history entry for this - // bookmark - GlobalApp - .getQuickConnectHistoryGateway() - .removeHistoryItem( - bookmark.get() - .getHostname()); - } else { - assert false; - return; - } - - // insert or update bookmark and leave - // activity - if (bookmark.getId() > 0) - bookmarkGateway.update(bookmark); - else - bookmarkGateway.insert(bookmark); - - finishAndResetBookmark(); - } - }) - .setNegativeButton(R.string.no, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, - int which) { - finishAndResetBookmark(); - } - }).show(); - } else { - finishAndResetBookmark(); - } - } - } +public class BookmarkActivity extends PreferenceActivity implements OnSharedPreferenceChangeListener +{ + public static final String PARAM_CONNECTION_REFERENCE = "conRef"; + + private static final String TAG = "BookmarkActivity"; + private static final int PREFERENCES_BOOKMARK = 1; + private static final int PREFERENCES_CREDENTIALS = 2; + private static final int PREFERENCES_SCREEN = 3; + private static final int PREFERENCES_PERFORMANCE = 4; + private static final int PREFERENCES_ADVANCED = 5; + private static final int PREFERENCES_SCREEN3G = 6; + private static final int PREFERENCES_PERFORMANCE3G = 7; + private static final int PREFERENCES_GATEWAY = 8; + private static final int PREFERENCES_DEBUG = 9; + // bookmark needs to be static because the activity is started for each + // subview + // (we have to do this because Android has a bug where the style for + // Preferences + // is only applied to the first PreferenceScreen but not to subsequent ones) + private static BookmarkBase bookmark = null; + private static boolean settings_changed = false; + private static boolean new_bookmark = false; + private int current_preferences; + + @Override public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + + PreferenceManager mgr = getPreferenceManager(); + // init shared preferences for activity + mgr.setSharedPreferencesName("TEMP"); + mgr.setSharedPreferencesMode(MODE_PRIVATE); + + if (bookmark == null) + { + // if we have a bookmark id set in the extras we are in edit mode + Bundle bundle = getIntent().getExtras(); + if (bundle != null) + { + // See if we got a connection reference to a bookmark + if (bundle.containsKey(PARAM_CONNECTION_REFERENCE)) + { + String refStr = bundle.getString(PARAM_CONNECTION_REFERENCE); + if (ConnectionReference.isManualBookmarkReference(refStr)) + { + bookmark = GlobalApp.getManualBookmarkGateway().findById( + ConnectionReference.getManualBookmarkId(refStr)); + new_bookmark = false; + } + else if (ConnectionReference.isHostnameReference(refStr)) + { + bookmark = new ManualBookmark(); + bookmark.get().setLabel( + ConnectionReference.getHostname(refStr)); + bookmark.get().setHostname( + ConnectionReference.getHostname(refStr)); + new_bookmark = true; + } + else if (ConnectionReference.isFileReference(refStr)) + { + String file = ConnectionReference.getFile(refStr); + + bookmark = new ManualBookmark(); + bookmark.setLabel(file); + + try + { + RDPFileParser rdpFile = new RDPFileParser(file); + updateBookmarkFromFile((ManualBookmark)bookmark, rdpFile); + + bookmark.setLabel(new File(file).getName()); + new_bookmark = true; + } + catch (IOException e) + { + Log.e(TAG, "Failed reading RDP file", e); + } + } + } + } + + // last chance - ensure we really have a valid bookmark + if (bookmark == null) + bookmark = new ManualBookmark(); + + // hide gateway settings if we edit a non-manual bookmark + if (current_preferences == PREFERENCES_ADVANCED && + bookmark.getType() != ManualBookmark.TYPE_MANUAL) + { + PreferenceScreen screen = getPreferenceScreen(); + screen.removePreference(findPreference("bookmark.enable_gateway")); + screen.removePreference(findPreference("bookmark.gateway")); + } + + updateH264Preferences(); + + // update preferences from bookmark + bookmark.writeToSharedPreferences(mgr.getSharedPreferences()); + + // no settings changed yet + settings_changed = false; + } + + // load the requested settings resource + if (getIntent() == null || getIntent().getData() == null) + { + addPreferencesFromResource(R.xml.bookmark_settings); + current_preferences = PREFERENCES_BOOKMARK; + } + else if (getIntent().getData().toString().equals("preferences://screen_settings")) + { + addPreferencesFromResource(R.xml.screen_settings); + current_preferences = PREFERENCES_SCREEN; + } + else if (getIntent().getData().toString().equals("preferences://performance_flags")) + { + addPreferencesFromResource(R.xml.performance_flags); + current_preferences = PREFERENCES_PERFORMANCE; + } + else if (getIntent().getData().toString().equals("preferences://screen_settings_3g")) + { + addPreferencesFromResource(R.xml.screen_settings_3g); + current_preferences = PREFERENCES_SCREEN3G; + } + else if (getIntent().getData().toString().equals("preferences://performance_flags_3g")) + { + addPreferencesFromResource(R.xml.performance_flags_3g); + current_preferences = PREFERENCES_PERFORMANCE3G; + } + else if (getIntent().getData().toString().equals("preferences://advanced_settings")) + { + addPreferencesFromResource(R.xml.advanced_settings); + current_preferences = PREFERENCES_ADVANCED; + } + else if (getIntent().getData().toString().equals("preferences://credentials_settings")) + { + addPreferencesFromResource(R.xml.credentials_settings); + current_preferences = PREFERENCES_CREDENTIALS; + } + else if (getIntent().getData().toString().equals("preferences://gateway_settings")) + { + addPreferencesFromResource(R.xml.gateway_settings); + current_preferences = PREFERENCES_GATEWAY; + } + else if (getIntent().getData().toString().equals("preferences://debug_settings")) + { + addPreferencesFromResource(R.xml.debug_settings); + current_preferences = PREFERENCES_DEBUG; + } + else + { + addPreferencesFromResource(R.xml.bookmark_settings); + current_preferences = PREFERENCES_BOOKMARK; + } + + // update UI with bookmark data + SharedPreferences spref = mgr.getSharedPreferences(); + initSettings(spref); + + // register for preferences changed notification + mgr.getSharedPreferences().registerOnSharedPreferenceChangeListener(this); + + // set the correct component names in our preferencescreen settings + setIntentComponentNames(); + + updateH264Preferences(); + } + + private void updateH264Preferences() + { + if (!LibFreeRDP.hasH264Support()) + { + final int preferenceIdList[] = { R.string.preference_key_h264, + R.string.preference_key_h264_3g }; + + PreferenceManager mgr = getPreferenceManager(); + for (int id : preferenceIdList) + { + final String key = getString(id); + Preference preference = mgr.findPreference(key); + if (preference != null) + { + preference.setEnabled(false); + } + } + } + } + + private void updateBookmarkFromFile(ManualBookmark bookmark, RDPFileParser rdpFile) + { + String s; + Integer i; + + s = rdpFile.getString("full address"); + if (s != null) + { + // this gets complicated as it can include port + if (s.lastIndexOf(":") > s.lastIndexOf("]")) + { + try + { + String port = s.substring(s.lastIndexOf(":") + 1); + bookmark.setPort(Integer.parseInt(port)); + } + catch (NumberFormatException e) + { + Log.e(TAG, "Malformed address"); + } + + s = s.substring(0, s.lastIndexOf(":")); + } + + // or even be an ipv6 address + if (s.startsWith("[") && s.endsWith("]")) + s = s.substring(1, s.length() - 1); + + bookmark.setHostname(s); + } + + i = rdpFile.getInteger("server port"); + if (i != null) + bookmark.setPort(i); + + s = rdpFile.getString("username"); + if (s != null) + bookmark.setUsername(s); + + s = rdpFile.getString("domain"); + if (s != null) + bookmark.setDomain(s); + + i = rdpFile.getInteger("connect to console"); + if (i != null) + bookmark.getAdvancedSettings().setConsoleMode(i == 1); + } + + private void setIntentComponentNames() + { + // we set the component name for our sub-activity calls here because we + // don't know the package + // name of the main app in our library project. + ComponentName compName = + new ComponentName(getPackageName(), BookmarkActivity.class.getName()); + ArrayList prefKeys = new ArrayList(); + + prefKeys.add("bookmark.credentials"); + prefKeys.add("bookmark.screen"); + prefKeys.add("bookmark.performance"); + prefKeys.add("bookmark.advanced"); + prefKeys.add("bookmark.screen_3g"); + prefKeys.add("bookmark.performance_3g"); + prefKeys.add("bookmark.gateway_settings"); + prefKeys.add("bookmark.debug"); + + for (String p : prefKeys) + { + Preference pref = findPreference(p); + if (pref != null) + pref.getIntent().setComponent(compName); + } + } + + @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) + { + settings_changed = true; + switch (current_preferences) + { + case PREFERENCES_DEBUG: + debugSettingsChanged(sharedPreferences, key); + break; + + case PREFERENCES_BOOKMARK: + bookmarkSettingsChanged(sharedPreferences, key); + break; + + case PREFERENCES_ADVANCED: + advancedSettingsChanged(sharedPreferences, key); + break; + + case PREFERENCES_CREDENTIALS: + credentialsSettingsChanged(sharedPreferences, key); + break; + + case PREFERENCES_SCREEN: + case PREFERENCES_SCREEN3G: + screenSettingsChanged(sharedPreferences, key); + break; + + case PREFERENCES_GATEWAY: + gatewaySettingsChanged(sharedPreferences, key); + break; + + default: + break; + } + } + + private void initSettings(SharedPreferences sharedPreferences) + { + switch (current_preferences) + { + case PREFERENCES_BOOKMARK: + initBookmarkSettings(sharedPreferences); + break; + + case PREFERENCES_ADVANCED: + initAdvancedSettings(sharedPreferences); + break; + + case PREFERENCES_CREDENTIALS: + initCredentialsSettings(sharedPreferences); + break; + + case PREFERENCES_SCREEN: + initScreenSettings(sharedPreferences); + break; + + case PREFERENCES_SCREEN3G: + initScreenSettings3G(sharedPreferences); + break; + + case PREFERENCES_GATEWAY: + initGatewaySettings(sharedPreferences); + break; + + case PREFERENCES_DEBUG: + initDebugSettings(sharedPreferences); + break; + + default: + break; + } + } + + private void initBookmarkSettings(SharedPreferences sharedPreferences) + { + bookmarkSettingsChanged(sharedPreferences, "bookmark.label"); + bookmarkSettingsChanged(sharedPreferences, "bookmark.hostname"); + bookmarkSettingsChanged(sharedPreferences, "bookmark.port"); + bookmarkSettingsChanged(sharedPreferences, "bookmark.username"); + bookmarkSettingsChanged(sharedPreferences, "bookmark.resolution"); + } + + private void bookmarkSettingsChanged(SharedPreferences sharedPreferences, String key) + { + if (key.equals("bookmark.label") && findPreference(key) != null) + findPreference(key).setSummary(sharedPreferences.getString(key, "")); + else if (key.equals("bookmark.hostname") && findPreference(key) != null) + findPreference(key).setSummary(sharedPreferences.getString(key, "")); + else if (key.equals("bookmark.port") && findPreference(key) != null) + findPreference(key).setSummary(String.valueOf(sharedPreferences.getInt(key, -1))); + else if (key.equals("bookmark.username")) + { + String username = sharedPreferences.getString(key, ""); + if (username.length() == 0) + username = ""; + findPreference("bookmark.credentials").setSummary(username); + } + else if (key.equals("bookmark.resolution") || key.equals("bookmark.colors") || + key.equals("bookmark.width") || key.equals("bookmark.height")) + { + String resolution = sharedPreferences.getString("bookmark.resolution", "800x600"); + // compare english string from resolutions_values_array array, + // decode to localized + // text for display + if (resolution.equals("automatic")) + { + resolution = getResources().getString(R.string.resolution_automatic); + } + if (resolution.equals("custom")) + { + resolution = getResources().getString(R.string.resolution_custom); + } + if (resolution.equals("fitscreen")) + { + resolution = getResources().getString(R.string.resolution_fit); + } + resolution += "@" + sharedPreferences.getInt("bookmark.colors", 16); + findPreference("bookmark.screen").setSummary(resolution); + } + } + + private void initAdvancedSettings(SharedPreferences sharedPreferences) + { + advancedSettingsChanged(sharedPreferences, "bookmark.enable_gateway_settings"); + advancedSettingsChanged(sharedPreferences, "bookmark.enable_3g_settings"); + advancedSettingsChanged(sharedPreferences, "bookmark.security"); + advancedSettingsChanged(sharedPreferences, "bookmark.resolution_3g"); + advancedSettingsChanged(sharedPreferences, "bookmark.remote_program"); + advancedSettingsChanged(sharedPreferences, "bookmark.work_dir"); + } + + private void advancedSettingsChanged(SharedPreferences sharedPreferences, String key) + { + if (key.equals("bookmark.enable_gateway_settings")) + { + boolean enabled = sharedPreferences.getBoolean(key, false); + findPreference("bookmark.gateway_settings").setEnabled(enabled); + } + else if (key.equals("bookmark.enable_3g_settings")) + { + boolean enabled = sharedPreferences.getBoolean(key, false); + findPreference("bookmark.screen_3g").setEnabled(enabled); + findPreference("bookmark.performance_3g").setEnabled(enabled); + } + else if (key.equals("bookmark.security")) + { + ListPreference listPreference = (ListPreference)findPreference(key); + CharSequence security = listPreference.getEntries()[sharedPreferences.getInt(key, 0)]; + listPreference.setSummary(security); + } + else if (key.equals("bookmark.resolution_3g") || key.equals("bookmark.colors_3g") || + key.equals("bookmark.width_3g") || key.equals("bookmark.height_3g")) + { + String resolution = sharedPreferences.getString("bookmark.resolution_3g", "800x600"); + if (resolution.equals("automatic")) + resolution = getResources().getString(R.string.resolution_automatic); + else if (resolution.equals("custom")) + resolution = getResources().getString(R.string.resolution_custom); + resolution += "@" + sharedPreferences.getInt("bookmark.colors_3g", 16); + findPreference("bookmark.screen_3g").setSummary(resolution); + } + else if (key.equals("bookmark.remote_program")) + findPreference(key).setSummary(sharedPreferences.getString(key, "")); + else if (key.equals("bookmark.work_dir")) + findPreference(key).setSummary(sharedPreferences.getString(key, "")); + } + + private void initCredentialsSettings(SharedPreferences sharedPreferences) + { + credentialsSettingsChanged(sharedPreferences, "bookmark.username"); + credentialsSettingsChanged(sharedPreferences, "bookmark.password"); + credentialsSettingsChanged(sharedPreferences, "bookmark.domain"); + } + + private void credentialsSettingsChanged(SharedPreferences sharedPreferences, String key) + { + if (key.equals("bookmark.username")) + findPreference(key).setSummary(sharedPreferences.getString(key, "")); + else if (key.equals("bookmark.password")) + { + if (sharedPreferences.getString(key, "").length() == 0) + findPreference(key).setSummary( + getResources().getString(R.string.settings_password_empty)); + else + findPreference(key).setSummary( + getResources().getString(R.string.settings_password_present)); + } + else if (key.equals("bookmark.domain")) + findPreference(key).setSummary(sharedPreferences.getString(key, "")); + } + + private void initScreenSettings(SharedPreferences sharedPreferences) + { + screenSettingsChanged(sharedPreferences, "bookmark.colors"); + screenSettingsChanged(sharedPreferences, "bookmark.resolution"); + screenSettingsChanged(sharedPreferences, "bookmark.width"); + screenSettingsChanged(sharedPreferences, "bookmark.height"); + } + + private void initScreenSettings3G(SharedPreferences sharedPreferences) + { + screenSettingsChanged(sharedPreferences, "bookmark.colors_3g"); + screenSettingsChanged(sharedPreferences, "bookmark.resolution_3g"); + screenSettingsChanged(sharedPreferences, "bookmark.width_3g"); + screenSettingsChanged(sharedPreferences, "bookmark.height_3g"); + } + + private void screenSettingsChanged(SharedPreferences sharedPreferences, String key) + { + // could happen during initialization because 3g and non-3g settings + // share this routine - just skip + if (findPreference(key) == null) + return; + + if (key.equals("bookmark.colors") || key.equals("bookmark.colors_3g")) + { + ListPreference listPreference = (ListPreference)findPreference(key); + listPreference.setSummary(listPreference.getEntry()); + } + else if (key.equals("bookmark.resolution") || key.equals("bookmark.resolution_3g")) + { + ListPreference listPreference = (ListPreference)findPreference(key); + listPreference.setSummary(listPreference.getEntry()); + + String value = listPreference.getValue(); + boolean enabled = value.equalsIgnoreCase("custom"); + if (key.equals("bookmark.resolution")) + { + findPreference("bookmark.width").setEnabled(enabled); + findPreference("bookmark.height").setEnabled(enabled); + } + else + { + findPreference("bookmark.width_3g").setEnabled(enabled); + findPreference("bookmark.height_3g").setEnabled(enabled); + } + } + else if (key.equals("bookmark.width") || key.equals("bookmark.width_3g")) + findPreference(key).setSummary(String.valueOf(sharedPreferences.getInt(key, 800))); + else if (key.equals("bookmark.height") || key.equals("bookmark.height_3g")) + findPreference(key).setSummary(String.valueOf(sharedPreferences.getInt(key, 600))); + } + + private void initDebugSettings(SharedPreferences sharedPreferences) + { + debugSettingsChanged(sharedPreferences, "bookmark.debug_level"); + debugSettingsChanged(sharedPreferences, "bookmark.async_channel"); + debugSettingsChanged(sharedPreferences, "bookmark.async_update"); + debugSettingsChanged(sharedPreferences, "bookmark.async_input"); + } + + private void initGatewaySettings(SharedPreferences sharedPreferences) + { + gatewaySettingsChanged(sharedPreferences, "bookmark.gateway_hostname"); + gatewaySettingsChanged(sharedPreferences, "bookmark.gateway_port"); + gatewaySettingsChanged(sharedPreferences, "bookmark.gateway_username"); + gatewaySettingsChanged(sharedPreferences, "bookmark.gateway_password"); + gatewaySettingsChanged(sharedPreferences, "bookmark.gateway_domain"); + } + + private void debugSettingsChanged(SharedPreferences sharedPreferences, String key) + { + if (key.equals("bookmark.debug_level")) + { + String level = sharedPreferences.getString(key, "INFO"); + Preference pref = findPreference("bookmark.debug_level"); + pref.setDefaultValue(level); + } + else if (key.equals("bookmark.async_channel")) + { + boolean enabled = sharedPreferences.getBoolean(key, false); + Preference pref = findPreference("bookmark.async_channel"); + pref.setDefaultValue(enabled); + } + else if (key.equals("bookmark.async_update")) + { + boolean enabled = sharedPreferences.getBoolean(key, false); + Preference pref = findPreference("bookmark.async_update"); + pref.setDefaultValue(enabled); + } + else if (key.equals("bookmark.async_input")) + { + boolean enabled = sharedPreferences.getBoolean(key, false); + Preference pref = findPreference("bookmark.async_input"); + pref.setDefaultValue(enabled); + } + } + + private void gatewaySettingsChanged(SharedPreferences sharedPreferences, String key) + { + if (key.equals("bookmark.gateway_hostname")) + { + findPreference(key).setSummary(sharedPreferences.getString(key, "")); + } + else if (key.equals("bookmark.gateway_port")) + { + findPreference(key).setSummary(String.valueOf(sharedPreferences.getInt(key, 443))); + } + else if (key.equals("bookmark.gateway_username")) + { + findPreference(key).setSummary(sharedPreferences.getString(key, "")); + } + else if (key.equals("bookmark.gateway_password")) + { + if (sharedPreferences.getString(key, "").length() == 0) + findPreference(key).setSummary( + getResources().getString(R.string.settings_password_empty)); + else + findPreference(key).setSummary( + getResources().getString(R.string.settings_password_present)); + } + else if (key.equals("bookmark.gateway_domain")) + findPreference(key).setSummary(sharedPreferences.getString(key, "")); + } + + private boolean verifySettings(SharedPreferences sharedPreferences) + { + + boolean verifyFailed = false; + // perform sanity checks on settings + // Label set + if (sharedPreferences.getString("bookmark.label", "").length() == 0) + verifyFailed = true; + + // Server and port specified + if (!verifyFailed && sharedPreferences.getString("bookmark.hostname", "").length() == 0) + verifyFailed = true; + + // Server and port specified + if (!verifyFailed && sharedPreferences.getInt("bookmark.port", -1) <= 0) + verifyFailed = true; + + // if an error occurred - display toast and return false + return (!verifyFailed); + } + + private void finishAndResetBookmark() + { + bookmark = null; + getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener( + this); + finish(); + } + + @Override public void onBackPressed() + { + // only proceed if we are in the main preferences screen + if (current_preferences != PREFERENCES_BOOKMARK) + { + super.onBackPressed(); + getPreferenceManager() + .getSharedPreferences() + .unregisterOnSharedPreferenceChangeListener(this); + return; + } + + SharedPreferences sharedPreferences = getPreferenceManager().getSharedPreferences(); + if (!verifySettings(sharedPreferences)) + { + // ask the user if he wants to cancel or continue editing + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(R.string.error_bookmark_incomplete_title) + .setMessage(R.string.error_bookmark_incomplete) + .setPositiveButton(R.string.cancel, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) + { + finishAndResetBookmark(); + } + }) + .setNegativeButton(R.string.cont, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) + { + dialog.cancel(); + } + }) + .show(); + + return; + } + else + { + // ask the user if he wants to save or cancel editing if a setting + // has changed + if (new_bookmark || settings_changed) + { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(R.string.dlg_title_save_bookmark) + .setMessage(R.string.dlg_save_bookmark) + .setPositiveButton( + R.string.yes, + new DialogInterface.OnClickListener() { + @Override public void onClick(DialogInterface dialog, int which) + { + // read shared prefs back to bookmark + bookmark.readFromSharedPreferences( + getPreferenceManager().getSharedPreferences()); + + BookmarkBaseGateway bookmarkGateway; + if (bookmark.getType() == BookmarkBase.TYPE_MANUAL) + { + bookmarkGateway = GlobalApp.getManualBookmarkGateway(); + // remove any history entry for this + // bookmark + GlobalApp.getQuickConnectHistoryGateway().removeHistoryItem( + bookmark.get().getHostname()); + } + else + { + assert false; + return; + } + + // insert or update bookmark and leave + // activity + if (bookmark.getId() > 0) + bookmarkGateway.update(bookmark); + else + bookmarkGateway.insert(bookmark); + + finishAndResetBookmark(); + } + }) + .setNegativeButton(R.string.no, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) + { + finishAndResetBookmark(); + } + }) + .show(); + } + else + { + finishAndResetBookmark(); + } + } + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/HelpActivity.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/HelpActivity.java index 247635e..8e1e6b2 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/HelpActivity.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/HelpActivity.java @@ -3,8 +3,9 @@ Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.presentation; @@ -22,50 +23,55 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.util.Locale; -public class HelpActivity extends AppCompatActivity { +public class HelpActivity extends AppCompatActivity +{ - private static final String TAG = HelpActivity.class.toString(); + private static final String TAG = HelpActivity.class.toString(); - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + @Override public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); - WebView webview = new WebView(this); - setContentView(webview); + WebView webview = new WebView(this); + setContentView(webview); - String filename; - if ((getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE) - filename = "gestures.html"; - else - filename = "gestures_phone.html"; + String filename; + if ((getResources().getConfiguration().screenLayout & + Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE) + filename = "gestures.html"; + else + filename = "gestures_phone.html"; - WebSettings settings = webview.getSettings(); - settings.setDomStorageEnabled(true); - settings.setUseWideViewPort(true); - settings.setLoadWithOverviewMode(true); - settings.setSupportZoom(true); - settings.setJavaScriptEnabled(true); - - settings.setAllowContentAccess(true); - settings.setAllowFileAccess(true); + WebSettings settings = webview.getSettings(); + settings.setDomStorageEnabled(true); + settings.setUseWideViewPort(true); + settings.setLoadWithOverviewMode(true); + settings.setSupportZoom(true); + settings.setJavaScriptEnabled(true); - final Locale def = Locale.getDefault(); - final String prefix = def.getLanguage().toLowerCase(def); + settings.setAllowContentAccess(true); + settings.setAllowFileAccess(true); - final String base = "file:///android_asset/"; - final String baseName = "help_page"; - String dir = prefix + "_" + baseName + "/"; - String file = dir + filename; - InputStream is; - try { - is = getAssets().open(file); - is.close(); - } catch (IOException e) { - Log.e(TAG, "Missing localized asset " + file, e); - dir = baseName + "/"; - file = dir + filename; - } + final Locale def = Locale.getDefault(); + final String prefix = def.getLanguage().toLowerCase(def); - webview.loadUrl(base + file); - } + final String base = "file:///android_asset/"; + final String baseName = "help_page"; + String dir = prefix + "_" + baseName + "/"; + String file = dir + filename; + InputStream is; + try + { + is = getAssets().open(file); + is.close(); + } + catch (IOException e) + { + Log.e(TAG, "Missing localized asset " + file, e); + dir = baseName + "/"; + file = dir + filename; + } + + webview.loadUrl(base + file); + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/HomeActivity.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/HomeActivity.java index 7407373..b9f9680 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/HomeActivity.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/HomeActivity.java @@ -4,7 +4,8 @@ Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.presentation; @@ -45,303 +46,354 @@ import com.freerdp.freerdpcore.utils.SeparatedListAdapter; import java.util.ArrayList; -public class HomeActivity extends AppCompatActivity { - private final static String ADD_BOOKMARK_PLACEHOLDER = "add_bookmark"; - private static final String TAG = "HomeActivity"; - private static final String PARAM_SUPERBAR_TEXT = "superbar_text"; - private ListView listViewBookmarks; - private Button clearTextButton; - private EditText superBarEditText; - private BookmarkArrayAdapter manualBookmarkAdapter; - private SeparatedListAdapter separatedListAdapter; - private PlaceholderBookmark addBookmarkPlaceholder; - private String sectionLabelBookmarks; - - View mDecor; - - @Override - public void onCreate(Bundle savedInstanceState) { - setTitle(R.string.title_home); - super.onCreate(savedInstanceState); - setContentView(R.layout.home); - - mDecor = getWindow().getDecorView(); - mDecor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); - - long heapSize = Runtime.getRuntime().maxMemory(); - Log.i(TAG, "Max HeapSize: " + heapSize); - Log.i(TAG, "App data folder: " + getFilesDir().toString()); - - // load strings - sectionLabelBookmarks = getResources().getString(R.string.section_bookmarks); - - // create add bookmark/quick connect bookmark placeholder - addBookmarkPlaceholder = new PlaceholderBookmark(); - addBookmarkPlaceholder.setName(ADD_BOOKMARK_PLACEHOLDER); - addBookmarkPlaceholder.setLabel(getResources().getString(R.string.list_placeholder_add_bookmark)); - - // check for passed .rdp file and open it in a new bookmark - Intent caller = getIntent(); - Uri callParameter = caller.getData(); - - if (Intent.ACTION_VIEW.equals(caller.getAction()) && callParameter != null) { - String refStr = ConnectionReference.getFileReference(callParameter.getPath()); - Bundle bundle = new Bundle(); - bundle.putString(BookmarkActivity.PARAM_CONNECTION_REFERENCE, refStr); - - Intent bookmarkIntent = new Intent(this.getApplicationContext(), BookmarkActivity.class); - bookmarkIntent.putExtras(bundle); - startActivity(bookmarkIntent); - } - - // load views - clearTextButton = (Button) findViewById(R.id.clear_search_btn); - superBarEditText = (EditText) findViewById(R.id.superBarEditText); - - listViewBookmarks = (ListView) findViewById(R.id.listViewBookmarks); - - // set listeners for the list view - listViewBookmarks.setOnItemClickListener(new AdapterView.OnItemClickListener() { - public void onItemClick(AdapterView parent, View view, int position, long id) { - String curSection = separatedListAdapter.getSectionForPosition(position); - Log.v(TAG, "Clicked on item id " + separatedListAdapter.getItemId(position) + " in section " + curSection); - if (curSection == sectionLabelBookmarks) { - String refStr = view.getTag().toString(); - if (ConnectionReference.isManualBookmarkReference(refStr) || - ConnectionReference.isHostnameReference(refStr)) { - Bundle bundle = new Bundle(); - bundle.putString(SessionActivity.PARAM_CONNECTION_REFERENCE, refStr); - - Intent sessionIntent = new Intent(view.getContext(), SessionActivity.class); - sessionIntent.putExtras(bundle); - startActivity(sessionIntent); - - // clear any search text - superBarEditText.setText(""); - superBarEditText.clearFocus(); - } else if (ConnectionReference.isPlaceholderReference(refStr)) { - // is this the add bookmark placeholder? - if (ConnectionReference.getPlaceholder(refStr).equals(ADD_BOOKMARK_PLACEHOLDER)) { - Intent bookmarkIntent = new Intent(view.getContext(), BookmarkActivity.class); - startActivity(bookmarkIntent); - } - } - } - } - }); - - listViewBookmarks.setOnCreateContextMenuListener(new OnCreateContextMenuListener() { - @Override - public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { - // if the selected item is not a session item (tag == null) and not a quick connect entry - // (not a hostname connection reference) inflate the context menu - View itemView = ((AdapterContextMenuInfo) menuInfo).targetView; - String refStr = itemView.getTag() != null ? itemView.getTag().toString() : null; - if (refStr != null && !ConnectionReference.isHostnameReference(refStr) && !ConnectionReference.isPlaceholderReference(refStr)) { - getMenuInflater().inflate(R.menu.bookmark_context_menu, menu); - menu.setHeaderTitle(getResources().getString(R.string.menu_title_bookmark)); - } - } - }); - - superBarEditText.addTextChangedListener(new SuperBarTextWatcher()); - - clearTextButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - superBarEditText.setText(""); - } - }); - } - - - @Override - public void onConfigurationChanged(Configuration newConfig) { - // ignore orientation/keyboard change - super.onConfigurationChanged(newConfig); - mDecor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); - } - - @Override - public boolean onSearchRequested() { - superBarEditText.requestFocus(); - return true; - } - - @Override - public boolean onContextItemSelected(MenuItem aItem) { - - // get connection reference - AdapterContextMenuInfo menuInfo = (AdapterContextMenuInfo) aItem.getMenuInfo(); - String refStr = menuInfo.targetView.getTag().toString(); - - // refer to http://tools.android.com/tips/non-constant-fields why we can't use switch/case here .. - int itemId = aItem.getItemId(); - if (itemId == R.id.bookmark_connect) { - Bundle bundle = new Bundle(); - bundle.putString(SessionActivity.PARAM_CONNECTION_REFERENCE, refStr); - Intent sessionIntent = new Intent(this, SessionActivity.class); - sessionIntent.putExtras(bundle); - - startActivity(sessionIntent); - return true; - } else if (itemId == R.id.bookmark_edit) { - Bundle bundle = new Bundle(); - bundle.putString(BookmarkActivity.PARAM_CONNECTION_REFERENCE, refStr); - - Intent bookmarkIntent = new Intent(this.getApplicationContext(), BookmarkActivity.class); - bookmarkIntent.putExtras(bundle); - startActivity(bookmarkIntent); - return true; - } else if (itemId == R.id.bookmark_delete) { - if (ConnectionReference.isManualBookmarkReference(refStr)) { - long id = ConnectionReference.getManualBookmarkId(refStr); - GlobalApp.getManualBookmarkGateway().delete(id); - manualBookmarkAdapter.remove(id); - separatedListAdapter.notifyDataSetChanged(); - } else { - assert false; - } - - // clear super bar text - superBarEditText.setText(""); - return true; - } - - return false; - } - - @Override - protected void onResume() { - super.onResume(); - Log.v(TAG, "HomeActivity.onResume"); - - // create bookmark cursor adapter - manualBookmarkAdapter = new BookmarkArrayAdapter(this, R.layout.bookmark_list_item, GlobalApp.getManualBookmarkGateway().findAll()); - - // add add bookmark item to manual adapter - manualBookmarkAdapter.insert(addBookmarkPlaceholder, 0); - - // attach all adapters to the separatedListView adapter and assign it to the list view - separatedListAdapter = new SeparatedListAdapter(this); - separatedListAdapter.addSection(sectionLabelBookmarks, manualBookmarkAdapter); - listViewBookmarks.setAdapter(separatedListAdapter); - - // if we have a filter text entered cause an update to be caused here - String filter = superBarEditText.getText().toString(); - if (filter.length() > 0) - superBarEditText.setText(filter); - } - - @Override - protected void onPause() { - super.onPause(); - Log.v(TAG, "HomeActivity.onPause"); - - // reset adapters - listViewBookmarks.setAdapter(null); - separatedListAdapter = null; - manualBookmarkAdapter = null; - } - - @Override - public void onBackPressed() { - // if back was pressed - ask the user if he really wants to exit - if (ApplicationSettingsActivity.getAskOnExit(this)) { - final CheckBox cb = new CheckBox(this); - cb.setChecked(!ApplicationSettingsActivity.getAskOnExit(this)); - cb.setText(R.string.dlg_dont_show_again); - - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(R.string.dlg_title_exit) - .setMessage(R.string.dlg_msg_exit) - .setView(cb) - .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - finish(); - } - }) - .setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - } - }) - .create() - .show(); - } else { - super.onBackPressed(); - } - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putString(PARAM_SUPERBAR_TEXT, superBarEditText.getText().toString()); - } - - @Override - protected void onRestoreInstanceState(Bundle inState) { - super.onRestoreInstanceState(inState); - superBarEditText.setText(inState.getString(PARAM_SUPERBAR_TEXT)); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.home_menu, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - - // refer to http://tools.android.com/tips/non-constant-fields why we can't use switch/case here .. - int itemId = item.getItemId(); - if (itemId == R.id.newBookmark) { - Intent bookmarkIntent = new Intent(this, BookmarkActivity.class); - startActivity(bookmarkIntent); - } else if (itemId == R.id.appSettings) { - Intent settingsIntent = new Intent(this, ApplicationSettingsActivity.class); - startActivity(settingsIntent); - } else if (itemId == R.id.help) { - Intent helpIntent = new Intent(this, HelpActivity.class); - startActivity(helpIntent); - } else if (itemId == R.id.about) { - Intent aboutIntent = new Intent(this, AboutActivity.class); - startActivity(aboutIntent); - } - - return true; - } - - private class SuperBarTextWatcher implements TextWatcher { - @Override - public void afterTextChanged(Editable s) { - if (separatedListAdapter != null) { - String text = s.toString(); - if (text.length() > 0) { - ArrayList computers_list = GlobalApp.getQuickConnectHistoryGateway().findHistory(text); - computers_list.addAll(GlobalApp.getManualBookmarkGateway().findByLabelOrHostnameLike(text)); - manualBookmarkAdapter.replaceItems(computers_list); - QuickConnectBookmark qcBm = new QuickConnectBookmark(); - qcBm.setLabel(text); - qcBm.setHostname(text); - manualBookmarkAdapter.insert(qcBm, 0); - } else { - manualBookmarkAdapter.replaceItems(GlobalApp.getManualBookmarkGateway().findAll()); - manualBookmarkAdapter.insert(addBookmarkPlaceholder, 0); - } - - separatedListAdapter.notifyDataSetChanged(); - } - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - } - } +public class HomeActivity extends AppCompatActivity +{ + private final static String ADD_BOOKMARK_PLACEHOLDER = "add_bookmark"; + private static final String TAG = "HomeActivity"; + private static final String PARAM_SUPERBAR_TEXT = "superbar_text"; + private ListView listViewBookmarks; + private Button clearTextButton; + private EditText superBarEditText; + private BookmarkArrayAdapter manualBookmarkAdapter; + private SeparatedListAdapter separatedListAdapter; + private PlaceholderBookmark addBookmarkPlaceholder; + private String sectionLabelBookmarks; + + View mDecor; + + @Override public void onCreate(Bundle savedInstanceState) + { + setTitle(R.string.title_home); + super.onCreate(savedInstanceState); + setContentView(R.layout.home); + + mDecor = getWindow().getDecorView(); + mDecor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); + + long heapSize = Runtime.getRuntime().maxMemory(); + Log.i(TAG, "Max HeapSize: " + heapSize); + Log.i(TAG, "App data folder: " + getFilesDir().toString()); + + // load strings + sectionLabelBookmarks = getResources().getString(R.string.section_bookmarks); + + // create add bookmark/quick connect bookmark placeholder + addBookmarkPlaceholder = new PlaceholderBookmark(); + addBookmarkPlaceholder.setName(ADD_BOOKMARK_PLACEHOLDER); + addBookmarkPlaceholder.setLabel( + getResources().getString(R.string.list_placeholder_add_bookmark)); + + // check for passed .rdp file and open it in a new bookmark + Intent caller = getIntent(); + Uri callParameter = caller.getData(); + + if (Intent.ACTION_VIEW.equals(caller.getAction()) && callParameter != null) + { + String refStr = ConnectionReference.getFileReference(callParameter.getPath()); + Bundle bundle = new Bundle(); + bundle.putString(BookmarkActivity.PARAM_CONNECTION_REFERENCE, refStr); + + Intent bookmarkIntent = + new Intent(this.getApplicationContext(), BookmarkActivity.class); + bookmarkIntent.putExtras(bundle); + startActivity(bookmarkIntent); + } + + // load views + clearTextButton = (Button)findViewById(R.id.clear_search_btn); + superBarEditText = (EditText)findViewById(R.id.superBarEditText); + + listViewBookmarks = (ListView)findViewById(R.id.listViewBookmarks); + + // set listeners for the list view + listViewBookmarks.setOnItemClickListener(new AdapterView.OnItemClickListener() { + public void onItemClick(AdapterView parent, View view, int position, long id) + { + String curSection = separatedListAdapter.getSectionForPosition(position); + Log.v(TAG, "Clicked on item id " + separatedListAdapter.getItemId(position) + + " in section " + curSection); + if (curSection.equals(sectionLabelBookmarks)) + { + String refStr = view.getTag().toString(); + if (ConnectionReference.isManualBookmarkReference(refStr) || + ConnectionReference.isHostnameReference(refStr)) + { + Bundle bundle = new Bundle(); + bundle.putString(SessionActivity.PARAM_CONNECTION_REFERENCE, refStr); + + Intent sessionIntent = new Intent(view.getContext(), SessionActivity.class); + sessionIntent.putExtras(bundle); + startActivity(sessionIntent); + + // clear any search text + superBarEditText.setText(""); + superBarEditText.clearFocus(); + } + else if (ConnectionReference.isPlaceholderReference(refStr)) + { + // is this the add bookmark placeholder? + if (ConnectionReference.getPlaceholder(refStr).equals( + ADD_BOOKMARK_PLACEHOLDER)) + { + Intent bookmarkIntent = + new Intent(view.getContext(), BookmarkActivity.class); + startActivity(bookmarkIntent); + } + } + } + } + }); + + listViewBookmarks.setOnCreateContextMenuListener(new OnCreateContextMenuListener() { + @Override + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) + { + // if the selected item is not a session item (tag == null) and not a quick connect + // entry (not a hostname connection reference) inflate the context menu + View itemView = ((AdapterContextMenuInfo)menuInfo).targetView; + String refStr = itemView.getTag() != null ? itemView.getTag().toString() : null; + if (refStr != null && !ConnectionReference.isHostnameReference(refStr) && + !ConnectionReference.isPlaceholderReference(refStr)) + { + getMenuInflater().inflate(R.menu.bookmark_context_menu, menu); + menu.setHeaderTitle(getResources().getString(R.string.menu_title_bookmark)); + } + } + }); + + superBarEditText.addTextChangedListener(new SuperBarTextWatcher()); + + clearTextButton.setOnClickListener(new OnClickListener() { + @Override public void onClick(View v) + { + superBarEditText.setText(""); + } + }); + } + + @Override public void onConfigurationChanged(Configuration newConfig) + { + // ignore orientation/keyboard change + super.onConfigurationChanged(newConfig); + mDecor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); + } + + @Override public boolean onSearchRequested() + { + superBarEditText.requestFocus(); + return true; + } + + @Override public boolean onContextItemSelected(MenuItem aItem) + { + + // get connection reference + AdapterContextMenuInfo menuInfo = (AdapterContextMenuInfo)aItem.getMenuInfo(); + String refStr = menuInfo.targetView.getTag().toString(); + + // refer to http://tools.android.com/tips/non-constant-fields why we can't use switch/case + // here .. + int itemId = aItem.getItemId(); + if (itemId == R.id.bookmark_connect) + { + Bundle bundle = new Bundle(); + bundle.putString(SessionActivity.PARAM_CONNECTION_REFERENCE, refStr); + Intent sessionIntent = new Intent(this, SessionActivity.class); + sessionIntent.putExtras(bundle); + + startActivity(sessionIntent); + return true; + } + else if (itemId == R.id.bookmark_edit) + { + Bundle bundle = new Bundle(); + bundle.putString(BookmarkActivity.PARAM_CONNECTION_REFERENCE, refStr); + + Intent bookmarkIntent = + new Intent(this.getApplicationContext(), BookmarkActivity.class); + bookmarkIntent.putExtras(bundle); + startActivity(bookmarkIntent); + return true; + } + else if (itemId == R.id.bookmark_delete) + { + if (ConnectionReference.isManualBookmarkReference(refStr)) + { + long id = ConnectionReference.getManualBookmarkId(refStr); + GlobalApp.getManualBookmarkGateway().delete(id); + manualBookmarkAdapter.remove(id); + separatedListAdapter.notifyDataSetChanged(); + } + else + { + assert false; + } + + // clear super bar text + superBarEditText.setText(""); + return true; + } + + return false; + } + + @Override protected void onResume() + { + super.onResume(); + Log.v(TAG, "HomeActivity.onResume"); + + // create bookmark cursor adapter + manualBookmarkAdapter = new BookmarkArrayAdapter( + this, R.layout.bookmark_list_item, GlobalApp.getManualBookmarkGateway().findAll()); + + // add add bookmark item to manual adapter + manualBookmarkAdapter.insert(addBookmarkPlaceholder, 0); + + // attach all adapters to the separatedListView adapter and assign it to the list view + separatedListAdapter = new SeparatedListAdapter(this); + separatedListAdapter.addSection(sectionLabelBookmarks, manualBookmarkAdapter); + listViewBookmarks.setAdapter(separatedListAdapter); + + // if we have a filter text entered cause an update to be caused here + String filter = superBarEditText.getText().toString(); + if (filter.length() > 0) + superBarEditText.setText(filter); + } + + @Override protected void onPause() + { + super.onPause(); + Log.v(TAG, "HomeActivity.onPause"); + + // reset adapters + listViewBookmarks.setAdapter(null); + separatedListAdapter = null; + manualBookmarkAdapter = null; + } + + @Override public void onBackPressed() + { + // if back was pressed - ask the user if he really wants to exit + if (ApplicationSettingsActivity.getAskOnExit(this)) + { + final CheckBox cb = new CheckBox(this); + cb.setChecked(!ApplicationSettingsActivity.getAskOnExit(this)); + cb.setText(R.string.dlg_dont_show_again); + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(R.string.dlg_title_exit) + .setMessage(R.string.dlg_msg_exit) + .setView(cb) + .setPositiveButton(R.string.yes, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) + { + finish(); + } + }) + .setNegativeButton(R.string.no, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) + { + dialog.dismiss(); + } + }) + .create() + .show(); + } + else + { + super.onBackPressed(); + } + } + + @Override protected void onSaveInstanceState(Bundle outState) + { + super.onSaveInstanceState(outState); + outState.putString(PARAM_SUPERBAR_TEXT, superBarEditText.getText().toString()); + } + + @Override protected void onRestoreInstanceState(Bundle inState) + { + super.onRestoreInstanceState(inState); + superBarEditText.setText(inState.getString(PARAM_SUPERBAR_TEXT)); + } + + @Override public boolean onCreateOptionsMenu(Menu menu) + { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.home_menu, menu); + return true; + } + + @Override public boolean onOptionsItemSelected(MenuItem item) + { + + // refer to http://tools.android.com/tips/non-constant-fields why we can't use switch/case + // here .. + int itemId = item.getItemId(); + if (itemId == R.id.newBookmark) + { + Intent bookmarkIntent = new Intent(this, BookmarkActivity.class); + startActivity(bookmarkIntent); + } + else if (itemId == R.id.appSettings) + { + Intent settingsIntent = new Intent(this, ApplicationSettingsActivity.class); + startActivity(settingsIntent); + } + else if (itemId == R.id.help) + { + Intent helpIntent = new Intent(this, HelpActivity.class); + startActivity(helpIntent); + } + else if (itemId == R.id.about) + { + Intent aboutIntent = new Intent(this, AboutActivity.class); + startActivity(aboutIntent); + } + + return true; + } + + private class SuperBarTextWatcher implements TextWatcher + { + @Override public void afterTextChanged(Editable s) + { + if (separatedListAdapter != null) + { + String text = s.toString(); + if (text.length() > 0) + { + ArrayList computers_list = + GlobalApp.getQuickConnectHistoryGateway().findHistory(text); + computers_list.addAll( + GlobalApp.getManualBookmarkGateway().findByLabelOrHostnameLike(text)); + manualBookmarkAdapter.replaceItems(computers_list); + QuickConnectBookmark qcBm = new QuickConnectBookmark(); + qcBm.setLabel(text); + qcBm.setHostname(text); + manualBookmarkAdapter.insert(qcBm, 0); + } + else + { + manualBookmarkAdapter.replaceItems( + GlobalApp.getManualBookmarkGateway().findAll()); + manualBookmarkAdapter.insert(addBookmarkPlaceholder, 0); + } + + separatedListAdapter.notifyDataSetChanged(); + } + } + + @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) + { + } + + @Override public void onTextChanged(CharSequence s, int start, int before, int count) + { + } + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/ScrollView2D.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/ScrollView2D.java index a2fee7c..ad1d572 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/ScrollView2D.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/ScrollView2D.java @@ -54,1097 +54,1296 @@ import java.util.List; * using the two together is possible to achieve the effect of a text view * within a larger container. */ -public class ScrollView2D extends FrameLayout { - - static final int ANIMATED_SCROLL_GAP = 250; - static final float MAX_SCROLL_FACTOR = 0.5f; - private final Rect mTempRect = new Rect(); - private ScrollView2DListener scrollView2DListener = null; - private long mLastScroll; - private Scroller mScroller; - private boolean scrollEnabled = true; - /** - * Flag to indicate that we are moving focus ourselves. This is so the - * code that watches for focus changes initiated outside this TwoDScrollView - * knows that it does not have to do anything. - */ - private boolean mTwoDScrollViewMovedFocus; - /** - * Position of the last motion event. - */ - private float mLastMotionY; - private float mLastMotionX; - /** - * True when the layout has changed but the traversal has not come through yet. - * Ideally the view hierarchy would keep track of this for us. - */ - private boolean mIsLayoutDirty = true; - /** - * The child to give focus to in the event that a child has requested focus while the - * layout is dirty. This prevents the scroll from being wrong if the child has not been - * laid out before requesting focus. - */ - private View mChildToScrollTo = null; - /** - * True if the user is currently dragging this TwoDScrollView around. This is - * not the same as 'is being flinged', which can be checked by - * mScroller.isFinished() (flinging begins when the user lifts his finger). - */ - private boolean mIsBeingDragged = false; - /** - * Determines speed during touch scrolling - */ - private VelocityTracker mVelocityTracker; - /** - * Whether arrow scrolling is animated. - */ - private int mTouchSlop; - private int mMinimumVelocity; - private int mMaximumVelocity; - public ScrollView2D(Context context) { - super(context); - initTwoDScrollView(); - } - - public ScrollView2D(Context context, AttributeSet attrs) { - super(context, attrs); - initTwoDScrollView(); - } - - public ScrollView2D(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - initTwoDScrollView(); - } - - @Override - protected float getTopFadingEdgeStrength() { - if (getChildCount() == 0) { - return 0.0f; - } - final int length = getVerticalFadingEdgeLength(); - if (getScrollY() < length) { - return getScrollY() / (float) length; - } - return 1.0f; - } - - @Override - protected float getBottomFadingEdgeStrength() { - if (getChildCount() == 0) { - return 0.0f; - } - final int length = getVerticalFadingEdgeLength(); - final int bottomEdge = getHeight() - getPaddingBottom(); - final int span = getChildAt(0).getBottom() - getScrollY() - bottomEdge; - if (span < length) { - return span / (float) length; - } - return 1.0f; - } - - @Override - protected float getLeftFadingEdgeStrength() { - if (getChildCount() == 0) { - return 0.0f; - } - final int length = getHorizontalFadingEdgeLength(); - if (getScrollX() < length) { - return getScrollX() / (float) length; - } - return 1.0f; - } - - @Override - protected float getRightFadingEdgeStrength() { - if (getChildCount() == 0) { - return 0.0f; - } - final int length = getHorizontalFadingEdgeLength(); - final int rightEdge = getWidth() - getPaddingRight(); - final int span = getChildAt(0).getRight() - getScrollX() - rightEdge; - if (span < length) { - return span / (float) length; - } - return 1.0f; - } - - /** - * Disable/Enable scrolling - */ - public void setScrollEnabled(boolean enable) { - scrollEnabled = enable; - } - - /** - * @return The maximum amount this scroll view will scroll in response to - * an arrow event. - */ - public int getMaxScrollAmountVertical() { - return (int) (MAX_SCROLL_FACTOR * getHeight()); - } - - public int getMaxScrollAmountHorizontal() { - return (int) (MAX_SCROLL_FACTOR * getWidth()); - } - - private void initTwoDScrollView() { - mScroller = new Scroller(getContext()); - setFocusable(true); - setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); - setWillNotDraw(false); - final ViewConfiguration configuration = ViewConfiguration.get(getContext()); - mTouchSlop = configuration.getScaledTouchSlop(); - mMinimumVelocity = configuration.getScaledMinimumFlingVelocity(); - mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); - } - - @Override - public void addView(View child) { - if (getChildCount() > 0) { - throw new IllegalStateException("TwoDScrollView can host only one direct child"); - } - super.addView(child); - } - - @Override - public void addView(View child, int index) { - if (getChildCount() > 0) { - throw new IllegalStateException("TwoDScrollView can host only one direct child"); - } - super.addView(child, index); - } - - @Override - public void addView(View child, ViewGroup.LayoutParams params) { - if (getChildCount() > 0) { - throw new IllegalStateException("TwoDScrollView can host only one direct child"); - } - super.addView(child, params); - } - - @Override - public void addView(View child, int index, ViewGroup.LayoutParams params) { - if (getChildCount() > 0) { - throw new IllegalStateException("TwoDScrollView can host only one direct child"); - } - super.addView(child, index, params); - } - - /** - * @return Returns true this TwoDScrollView can be scrolled - */ - private boolean canScroll() { - if (!scrollEnabled) - return false; - View child = getChildAt(0); - if (child != null) { - int childHeight = child.getHeight(); - int childWidth = child.getWidth(); - return (getHeight() < childHeight + getPaddingTop() + getPaddingBottom()) || - (getWidth() < childWidth + getPaddingLeft() + getPaddingRight()); - } - return false; - } - - @Override - public boolean dispatchKeyEvent(KeyEvent event) { - // Let the focused view and/or our descendants get the key first - boolean handled = super.dispatchKeyEvent(event); - if (handled) { - return true; - } - return executeKeyEvent(event); - } - - /** - * You can call this function yourself to have the scroll view perform - * scrolling from a key event, just as if the event had been dispatched to - * it by the view hierarchy. - * - * @param event The key event to execute. - * @return Return true if the event was handled, else false. - */ - public boolean executeKeyEvent(KeyEvent event) { - mTempRect.setEmpty(); - if (!canScroll()) { - if (isFocused()) { - View currentFocused = findFocus(); - if (currentFocused == this) currentFocused = null; - View nextFocused = FocusFinder.getInstance().findNextFocus(this, currentFocused, View.FOCUS_DOWN); - return nextFocused != null && nextFocused != this && nextFocused.requestFocus(View.FOCUS_DOWN); - } - return false; - } - boolean handled = false; - if (event.getAction() == KeyEvent.ACTION_DOWN) { - switch (event.getKeyCode()) { - case KeyEvent.KEYCODE_DPAD_UP: - if (!event.isAltPressed()) { - handled = arrowScroll(View.FOCUS_UP, false); - } else { - handled = fullScroll(View.FOCUS_UP, false); - } - break; - case KeyEvent.KEYCODE_DPAD_DOWN: - if (!event.isAltPressed()) { - handled = arrowScroll(View.FOCUS_DOWN, false); - } else { - handled = fullScroll(View.FOCUS_DOWN, false); - } - break; - case KeyEvent.KEYCODE_DPAD_LEFT: - if (!event.isAltPressed()) { - handled = arrowScroll(View.FOCUS_LEFT, true); - } else { - handled = fullScroll(View.FOCUS_LEFT, true); - } - break; - case KeyEvent.KEYCODE_DPAD_RIGHT: - if (!event.isAltPressed()) { - handled = arrowScroll(View.FOCUS_RIGHT, true); - } else { - handled = fullScroll(View.FOCUS_RIGHT, true); - } - break; - } - } - return handled; - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - /* - * This method JUST determines whether we want to intercept the motion. - * If we return true, onMotionEvent will be called and we do the actual - * scrolling there. - * - * Shortcut the most recurring case: the user is in the dragging - * state and he is moving his finger. We want to intercept this - * motion. - */ - final int action = ev.getAction(); - if ((action == MotionEvent.ACTION_MOVE) && (mIsBeingDragged)) { - return true; - } - if (!canScroll()) { - mIsBeingDragged = false; - return false; - } - final float y = ev.getY(); - final float x = ev.getX(); - switch (action) { - case MotionEvent.ACTION_MOVE: - /* - * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check - * whether the user has moved far enough from his original down touch. - */ - /* - * Locally do absolute value. mLastMotionY is set to the y value - * of the down event. - */ - final int yDiff = (int) Math.abs(y - mLastMotionY); - final int xDiff = (int) Math.abs(x - mLastMotionX); - if (yDiff > mTouchSlop || xDiff > mTouchSlop) { - mIsBeingDragged = true; - } - break; - - case MotionEvent.ACTION_DOWN: - /* Remember location of down touch */ - mLastMotionY = y; - mLastMotionX = x; - - /* - * If being flinged and user touches the screen, initiate drag; - * otherwise don't. mScroller.isFinished should be false when - * being flinged. - */ - mIsBeingDragged = !mScroller.isFinished(); - break; - - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: - /* Release the drag */ - mIsBeingDragged = false; - break; - } - - /* - * The only time we want to intercept motion events is if we are in the - * drag mode. - */ - return mIsBeingDragged; - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - - if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) { - // Don't handle edge touches immediately -- they may actually belong to one of our - // descendants. - return false; - } - - if (!canScroll()) { - return false; - } - - if (mVelocityTracker == null) { - mVelocityTracker = VelocityTracker.obtain(); - } - mVelocityTracker.addMovement(ev); - - final int action = ev.getAction(); - final float y = ev.getY(); - final float x = ev.getX(); - - switch (action) { - case MotionEvent.ACTION_DOWN: - /* - * If being flinged and user touches, stop the fling. isFinished - * will be false if being flinged. - */ - if (!mScroller.isFinished()) { - mScroller.abortAnimation(); - } - - // Remember where the motion event started - mLastMotionY = y; - mLastMotionX = x; - break; - case MotionEvent.ACTION_MOVE: - // Scroll to follow the motion event - int deltaX = (int) (mLastMotionX - x); - int deltaY = (int) (mLastMotionY - y); - mLastMotionX = x; - mLastMotionY = y; - - if (deltaX < 0) { - if (getScrollX() < 0) { - deltaX = 0; - } - } else if (deltaX > 0) { - final int rightEdge = getWidth() - getPaddingRight(); - final int availableToScroll = getChildAt(0).getRight() - getScrollX() - rightEdge; - if (availableToScroll > 0) { - deltaX = Math.min(availableToScroll, deltaX); - } else { - deltaX = 0; - } - } - if (deltaY < 0) { - if (getScrollY() < 0) { - deltaY = 0; - } - } else if (deltaY > 0) { - final int bottomEdge = getHeight() - getPaddingBottom(); - final int availableToScroll = getChildAt(0).getBottom() - getScrollY() - bottomEdge; - if (availableToScroll > 0) { - deltaY = Math.min(availableToScroll, deltaY); - } else { - deltaY = 0; - } - } - if (deltaY != 0 || deltaX != 0) - scrollBy(deltaX, deltaY); - break; - case MotionEvent.ACTION_UP: - final VelocityTracker velocityTracker = mVelocityTracker; - velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); - int initialXVelocity = (int) velocityTracker.getXVelocity(); - int initialYVelocity = (int) velocityTracker.getYVelocity(); - if ((Math.abs(initialXVelocity) + Math.abs(initialYVelocity) > mMinimumVelocity) && getChildCount() > 0) { - fling(-initialXVelocity, -initialYVelocity); - } - if (mVelocityTracker != null) { - mVelocityTracker.recycle(); - mVelocityTracker = null; - } - } - return true; - } - - /** - * Finds the next focusable component that fits in this View's bounds - * (excluding fading edges) pretending that this View's top is located at - * the parameter top. - * - * @param topFocus look for a candidate is the one at the top of the bounds - * if topFocus is true, or at the bottom of the bounds if topFocus is - * false - * @param top the top offset of the bounds in which a focusable must be - * found (the fading edge is assumed to start at this position) - * @param preferredFocusable the View that has highest priority and will be - * returned if it is within my bounds (null is valid) - * @return the next focusable component in the bounds or null if none can be - * found - */ - private View findFocusableViewInMyBounds(final boolean topFocus, final int top, final boolean leftFocus, final int left, View preferredFocusable) { - /* - * The fading edge's transparent side should be considered for focus - * since it's mostly visible, so we divide the actual fading edge length - * by 2. - */ - final int verticalFadingEdgeLength = getVerticalFadingEdgeLength() / 2; - final int topWithoutFadingEdge = top + verticalFadingEdgeLength; - final int bottomWithoutFadingEdge = top + getHeight() - verticalFadingEdgeLength; - final int horizontalFadingEdgeLength = getHorizontalFadingEdgeLength() / 2; - final int leftWithoutFadingEdge = left + horizontalFadingEdgeLength; - final int rightWithoutFadingEdge = left + getWidth() - horizontalFadingEdgeLength; - - if ((preferredFocusable != null) - && (preferredFocusable.getTop() < bottomWithoutFadingEdge) - && (preferredFocusable.getBottom() > topWithoutFadingEdge) - && (preferredFocusable.getLeft() < rightWithoutFadingEdge) - && (preferredFocusable.getRight() > leftWithoutFadingEdge)) { - return preferredFocusable; - } - return findFocusableViewInBounds(topFocus, topWithoutFadingEdge, bottomWithoutFadingEdge, leftFocus, leftWithoutFadingEdge, rightWithoutFadingEdge); - } - - /** - * Finds the next focusable component that fits in the specified bounds. - *

- * - * @param topFocus look for a candidate is the one at the top of the bounds - * if topFocus is true, or at the bottom of the bounds if topFocus is - * false - * @param top the top offset of the bounds in which a focusable must be - * found - * @param bottom the bottom offset of the bounds in which a focusable must - * be found - * @return the next focusable component in the bounds or null if none can - * be found - */ - private View findFocusableViewInBounds(boolean topFocus, int top, int bottom, boolean leftFocus, int left, int right) { - List focusables = getFocusables(View.FOCUS_FORWARD); - View focusCandidate = null; - - /* - * A fully contained focusable is one where its top is below the bound's - * top, and its bottom is above the bound's bottom. A partially - * contained focusable is one where some part of it is within the - * bounds, but it also has some part that is not within bounds. A fully contained - * focusable is preferred to a partially contained focusable. - */ - boolean foundFullyContainedFocusable = false; - - int count = focusables.size(); - for (int i = 0; i < count; i++) { - View view = focusables.get(i); - int viewTop = view.getTop(); - int viewBottom = view.getBottom(); - int viewLeft = view.getLeft(); - int viewRight = view.getRight(); - - if (top < viewBottom && viewTop < bottom && left < viewRight && viewLeft < right) { - /* - * the focusable is in the target area, it is a candidate for - * focusing - */ - final boolean viewIsFullyContained = (top < viewTop) && (viewBottom < bottom) && (left < viewLeft) && (viewRight < right); - if (focusCandidate == null) { - /* No candidate, take this one */ - focusCandidate = view; - foundFullyContainedFocusable = viewIsFullyContained; - } else { - final boolean viewIsCloserToVerticalBoundary = - (topFocus && viewTop < focusCandidate.getTop()) || - (!topFocus && viewBottom > focusCandidate.getBottom()); - final boolean viewIsCloserToHorizontalBoundary = - (leftFocus && viewLeft < focusCandidate.getLeft()) || - (!leftFocus && viewRight > focusCandidate.getRight()); - if (foundFullyContainedFocusable) { - if (viewIsFullyContained && viewIsCloserToVerticalBoundary && viewIsCloserToHorizontalBoundary) { - /* - * We're dealing with only fully contained views, so - * it has to be closer to the boundary to beat our - * candidate - */ - focusCandidate = view; - } - } else { - if (viewIsFullyContained) { - /* Any fully contained view beats a partially contained view */ - focusCandidate = view; - foundFullyContainedFocusable = true; - } else if (viewIsCloserToVerticalBoundary && viewIsCloserToHorizontalBoundary) { - /* - * Partially contained view beats another partially - * contained view if it's closer - */ - focusCandidate = view; - } - } - } - } - } - return focusCandidate; - } - - /** - *

Handles scrolling in response to a "home/end" shortcut press. This - * method will scroll the view to the top or bottom and give the focus - * to the topmost/bottommost component in the new visible area. If no - * component is a good candidate for focus, this scrollview reclaims the - * focus.

- * - * @param direction the scroll direction: {@link android.view.View#FOCUS_UP} - * to go the top of the view or - * {@link android.view.View#FOCUS_DOWN} to go the bottom - * @return true if the key event is consumed by this method, false otherwise - */ - public boolean fullScroll(int direction, boolean horizontal) { - if (!horizontal) { - boolean down = direction == View.FOCUS_DOWN; - int height = getHeight(); - mTempRect.top = 0; - mTempRect.bottom = height; - if (down) { - int count = getChildCount(); - if (count > 0) { - View view = getChildAt(count - 1); - mTempRect.bottom = view.getBottom(); - mTempRect.top = mTempRect.bottom - height; - } - } - return scrollAndFocus(direction, mTempRect.top, mTempRect.bottom, 0, 0, 0); - } else { - boolean right = direction == View.FOCUS_DOWN; - int width = getWidth(); - mTempRect.left = 0; - mTempRect.right = width; - if (right) { - int count = getChildCount(); - if (count > 0) { - View view = getChildAt(count - 1); - mTempRect.right = view.getBottom(); - mTempRect.left = mTempRect.right - width; - } - } - return scrollAndFocus(0, 0, 0, direction, mTempRect.top, mTempRect.bottom); - } - } - - /** - *

Scrolls the view to make the area defined by top and - * bottom visible. This method attempts to give the focus - * to a component visible in this area. If no component can be focused in - * the new visible area, the focus is reclaimed by this scrollview.

- * - * @param direction the scroll direction: {@link android.view.View#FOCUS_UP} - * to go upward - * {@link android.view.View#FOCUS_DOWN} to downward - * @param top the top offset of the new area to be made visible - * @param bottom the bottom offset of the new area to be made visible - * @return true if the key event is consumed by this method, false otherwise - */ - private boolean scrollAndFocus(int directionY, int top, int bottom, int directionX, int left, int right) { - boolean handled = true; - int height = getHeight(); - int containerTop = getScrollY(); - int containerBottom = containerTop + height; - boolean up = directionY == View.FOCUS_UP; - int width = getWidth(); - int containerLeft = getScrollX(); - int containerRight = containerLeft + width; - boolean leftwards = directionX == View.FOCUS_UP; - View newFocused = findFocusableViewInBounds(up, top, bottom, leftwards, left, right); - if (newFocused == null) { - newFocused = this; - } - if ((top >= containerTop && bottom <= containerBottom) || (left >= containerLeft && right <= containerRight)) { - handled = false; - } else { - int deltaY = up ? (top - containerTop) : (bottom - containerBottom); - int deltaX = leftwards ? (left - containerLeft) : (right - containerRight); - doScroll(deltaX, deltaY); - } - if (newFocused != findFocus() && newFocused.requestFocus(directionY)) { - mTwoDScrollViewMovedFocus = true; - mTwoDScrollViewMovedFocus = false; - } - return handled; - } - - /** - * Handle scrolling in response to an up or down arrow click. - * - * @param direction The direction corresponding to the arrow key that was - * pressed - * @return True if we consumed the event, false otherwise - */ - public boolean arrowScroll(int direction, boolean horizontal) { - View currentFocused = findFocus(); - if (currentFocused == this) currentFocused = null; - View nextFocused = FocusFinder.getInstance().findNextFocus(this, currentFocused, direction); - final int maxJump = horizontal ? getMaxScrollAmountHorizontal() : getMaxScrollAmountVertical(); - - if (!horizontal) { - if (nextFocused != null) { - nextFocused.getDrawingRect(mTempRect); - offsetDescendantRectToMyCoords(nextFocused, mTempRect); - int scrollDelta = computeScrollDeltaToGetChildRectOnScreen(mTempRect); - doScroll(0, scrollDelta); - nextFocused.requestFocus(direction); - } else { - // no new focus - int scrollDelta = maxJump; - if (direction == View.FOCUS_UP && getScrollY() < scrollDelta) { - scrollDelta = getScrollY(); - } else if (direction == View.FOCUS_DOWN) { - if (getChildCount() > 0) { - int daBottom = getChildAt(0).getBottom(); - int screenBottom = getScrollY() + getHeight(); - if (daBottom - screenBottom < maxJump) { - scrollDelta = daBottom - screenBottom; - } - } - } - if (scrollDelta == 0) { - return false; - } - doScroll(0, direction == View.FOCUS_DOWN ? scrollDelta : -scrollDelta); - } - } else { - if (nextFocused != null) { - nextFocused.getDrawingRect(mTempRect); - offsetDescendantRectToMyCoords(nextFocused, mTempRect); - int scrollDelta = computeScrollDeltaToGetChildRectOnScreen(mTempRect); - doScroll(scrollDelta, 0); - nextFocused.requestFocus(direction); - } else { - // no new focus - int scrollDelta = maxJump; - if (direction == View.FOCUS_UP && getScrollY() < scrollDelta) { - scrollDelta = getScrollY(); - } else if (direction == View.FOCUS_DOWN) { - if (getChildCount() > 0) { - int daBottom = getChildAt(0).getBottom(); - int screenBottom = getScrollY() + getHeight(); - if (daBottom - screenBottom < maxJump) { - scrollDelta = daBottom - screenBottom; - } - } - } - if (scrollDelta == 0) { - return false; - } - doScroll(direction == View.FOCUS_DOWN ? scrollDelta : -scrollDelta, 0); - } - } - return true; - } - - /** - * Smooth scroll by a Y delta - * - * @param delta the number of pixels to scroll by on the Y axis - */ - private void doScroll(int deltaX, int deltaY) { - if (deltaX != 0 || deltaY != 0) { - smoothScrollBy(deltaX, deltaY); - } - } - - /** - * Like {@link View#scrollBy}, but scroll smoothly instead of immediately. - * - * @param dx the number of pixels to scroll by on the X axis - * @param dy the number of pixels to scroll by on the Y axis - */ - public final void smoothScrollBy(int dx, int dy) { - long duration = AnimationUtils.currentAnimationTimeMillis() - mLastScroll; - if (duration > ANIMATED_SCROLL_GAP) { - mScroller.startScroll(getScrollX(), getScrollY(), dx, dy); - awakenScrollBars(mScroller.getDuration()); - invalidate(); - } else { - if (!mScroller.isFinished()) { - mScroller.abortAnimation(); - } - scrollBy(dx, dy); - } - mLastScroll = AnimationUtils.currentAnimationTimeMillis(); - } - - /** - * Like {@link #scrollTo}, but scroll smoothly instead of immediately. - * - * @param x the position where to scroll on the X axis - * @param y the position where to scroll on the Y axis - */ - public final void smoothScrollTo(int x, int y) { - smoothScrollBy(x - getScrollX(), y - getScrollY()); - } - - /** - *

The scroll range of a scroll view is the overall height of all of its - * children.

- */ - @Override - protected int computeVerticalScrollRange() { - int count = getChildCount(); - return count == 0 ? getHeight() : (getChildAt(0)).getBottom(); - } - - @Override - protected int computeHorizontalScrollRange() { - int count = getChildCount(); - return count == 0 ? getWidth() : (getChildAt(0)).getRight(); - } - - @Override - protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec) { - ViewGroup.LayoutParams lp = child.getLayoutParams(); - int childWidthMeasureSpec; - int childHeightMeasureSpec; - - childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, getPaddingLeft() + getPaddingRight(), lp.width); - childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); - - child.measure(childWidthMeasureSpec, childHeightMeasureSpec); - } - - @Override - protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) { - final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); - final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.leftMargin + lp.rightMargin, MeasureSpec.UNSPECIFIED); - final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.topMargin + lp.bottomMargin, MeasureSpec.UNSPECIFIED); - - child.measure(childWidthMeasureSpec, childHeightMeasureSpec); - } - - @Override - public void computeScroll() { - if (mScroller.computeScrollOffset()) { - // This is called at drawing time by ViewGroup. We don't want to - // re-show the scrollbars at this point, which scrollTo will do, - // so we replicate most of scrollTo here. - // - // It's a little odd to call onScrollChanged from inside the drawing. - // - // It is, except when you remember that computeScroll() is used to - // animate scrolling. So unless we want to defer the onScrollChanged() - // until the end of the animated scrolling, we don't really have a - // choice here. - // - // I agree. The alternative, which I think would be worse, is to post - // something and tell the subclasses later. This is bad because there - // will be a window where mScrollX/Y is different from what the app - // thinks it is. - // - int oldX = getScrollX(); - int oldY = getScrollY(); - int x = mScroller.getCurrX(); - int y = mScroller.getCurrY(); - if (getChildCount() > 0) { - View child = getChildAt(0); - scrollTo(clamp(x, getWidth() - getPaddingRight() - getPaddingLeft(), child.getWidth()), - clamp(y, getHeight() - getPaddingBottom() - getPaddingTop(), child.getHeight())); - } else { - scrollTo(x, y); - } - if (oldX != getScrollX() || oldY != getScrollY()) { - onScrollChanged(getScrollX(), getScrollY(), oldX, oldY); - } - - // Keep on drawing until the animation has finished. - postInvalidate(); - } - } - - /** - * Scrolls the view to the given child. - * - * @param child the View to scroll to - */ - private void scrollToChild(View child) { - child.getDrawingRect(mTempRect); - /* Offset from child's local coordinates to TwoDScrollView coordinates */ - offsetDescendantRectToMyCoords(child, mTempRect); - int scrollDelta = computeScrollDeltaToGetChildRectOnScreen(mTempRect); - if (scrollDelta != 0) { - scrollBy(0, scrollDelta); - } - } - - /** - * If rect is off screen, scroll just enough to get it (or at least the - * first screen size chunk of it) on screen. - * - * @param rect The rectangle. - * @param immediate True to scroll immediately without animation - * @return true if scrolling was performed - */ - private boolean scrollToChildRect(Rect rect, boolean immediate) { - final int delta = computeScrollDeltaToGetChildRectOnScreen(rect); - final boolean scroll = delta != 0; - if (scroll) { - if (immediate) { - scrollBy(0, delta); - } else { - smoothScrollBy(0, delta); - } - } - return scroll; - } - - /** - * Compute the amount to scroll in the Y direction in order to get - * a rectangle completely on the screen (or, if taller than the screen, - * at least the first screen size chunk of it). - * - * @param rect The rect. - * @return The scroll delta. - */ - protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) { - if (getChildCount() == 0) return 0; - int height = getHeight(); - int screenTop = getScrollY(); - int screenBottom = screenTop + height; - int fadingEdge = getVerticalFadingEdgeLength(); - // leave room for top fading edge as long as rect isn't at very top - if (rect.top > 0) { - screenTop += fadingEdge; - } - - // leave room for bottom fading edge as long as rect isn't at very bottom - if (rect.bottom < getChildAt(0).getHeight()) { - screenBottom -= fadingEdge; - } - int scrollYDelta = 0; - if (rect.bottom > screenBottom && rect.top > screenTop) { - // need to move down to get it in view: move down just enough so - // that the entire rectangle is in view (or at least the first - // screen size chunk). - if (rect.height() > height) { - // just enough to get screen size chunk on - scrollYDelta += (rect.top - screenTop); - } else { - // get entire rect at bottom of screen - scrollYDelta += (rect.bottom - screenBottom); - } - - // make sure we aren't scrolling beyond the end of our content - int bottom = getChildAt(0).getBottom(); - int distanceToBottom = bottom - screenBottom; - scrollYDelta = Math.min(scrollYDelta, distanceToBottom); - - } else if (rect.top < screenTop && rect.bottom < screenBottom) { - // need to move up to get it in view: move up just enough so that - // entire rectangle is in view (or at least the first screen - // size chunk of it). - - if (rect.height() > height) { - // screen size chunk - scrollYDelta -= (screenBottom - rect.bottom); - } else { - // entire rect at top - scrollYDelta -= (screenTop - rect.top); - } - - // make sure we aren't scrolling any further than the top our content - scrollYDelta = Math.max(scrollYDelta, -getScrollY()); - } - return scrollYDelta; - } - - @Override - public void requestChildFocus(View child, View focused) { - if (!mTwoDScrollViewMovedFocus) { - if (!mIsLayoutDirty) { - scrollToChild(focused); - } else { - // The child may not be laid out yet, we can't compute the scroll yet - mChildToScrollTo = focused; - } - } - super.requestChildFocus(child, focused); - } - - /** - * When looking for focus in children of a scroll view, need to be a little - * more careful not to give focus to something that is scrolled off screen. - *

- * This is more expensive than the default {@link android.view.ViewGroup} - * implementation, otherwise this behavior might have been made the default. - */ - @Override - protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { - // convert from forward / backward notation to up / down / left / right - // (ugh). - if (direction == View.FOCUS_FORWARD) { - direction = View.FOCUS_DOWN; - } else if (direction == View.FOCUS_BACKWARD) { - direction = View.FOCUS_UP; - } - - final View nextFocus = previouslyFocusedRect == null ? - FocusFinder.getInstance().findNextFocus(this, null, direction) : - FocusFinder.getInstance().findNextFocusFromRect(this, - previouslyFocusedRect, direction); - - if (nextFocus == null) { - return false; - } - - return nextFocus.requestFocus(direction, previouslyFocusedRect); - } - - @Override - public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) { - // offset into coordinate space of this scroll view - rectangle.offset(child.getLeft() - child.getScrollX(), child.getTop() - child.getScrollY()); - return scrollToChildRect(rectangle, immediate); - } - - @Override - public void requestLayout() { - mIsLayoutDirty = true; - super.requestLayout(); - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - super.onLayout(changed, l, t, r, b); - mIsLayoutDirty = false; - // Give a child focus if it needs it - if (mChildToScrollTo != null && isViewDescendantOf(mChildToScrollTo, this)) { - scrollToChild(mChildToScrollTo); - } - mChildToScrollTo = null; - - // Calling this with the present values causes it to re-clam them - scrollTo(getScrollX(), getScrollY()); - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - - View currentFocused = findFocus(); - if (null == currentFocused || this == currentFocused) - return; - - // If the currently-focused view was visible on the screen when the - // screen was at the old height, then scroll the screen to make that - // view visible with the new screen height. - currentFocused.getDrawingRect(mTempRect); - offsetDescendantRectToMyCoords(currentFocused, mTempRect); - int scrollDeltaX = computeScrollDeltaToGetChildRectOnScreen(mTempRect); - int scrollDeltaY = computeScrollDeltaToGetChildRectOnScreen(mTempRect); - doScroll(scrollDeltaX, scrollDeltaY); - } - - /** - * Return true if child is an descendant of parent, (or equal to the parent). - */ - private boolean isViewDescendantOf(View child, View parent) { - if (child == parent) { - return true; - } - - final ViewParent theParent = child.getParent(); - return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent); - } - - /** - * Fling the scroll view - * - * @param velocityY The initial velocity in the Y direction. Positive - * numbers mean that the finger/curor is moving down the screen, - * which means we want to scroll towards the top. - */ - public void fling(int velocityX, int velocityY) { - if (getChildCount() > 0) { - int height = getHeight() - getPaddingBottom() - getPaddingTop(); - int bottom = getChildAt(0).getHeight(); - int width = getWidth() - getPaddingRight() - getPaddingLeft(); - int right = getChildAt(0).getWidth(); - - mScroller.fling(getScrollX(), getScrollY(), velocityX, velocityY, 0, right - width, 0, bottom - height); - - final boolean movingDown = velocityY > 0; - final boolean movingRight = velocityX > 0; - - View newFocused = findFocusableViewInMyBounds(movingRight, mScroller.getFinalX(), movingDown, mScroller.getFinalY(), findFocus()); - if (newFocused == null) { - newFocused = this; - } - - if (newFocused != findFocus() && newFocused.requestFocus(movingDown ? View.FOCUS_DOWN : View.FOCUS_UP)) { - mTwoDScrollViewMovedFocus = true; - mTwoDScrollViewMovedFocus = false; - } - - awakenScrollBars(mScroller.getDuration()); - invalidate(); - } - } - - /** - * {@inheritDoc} - *

- *

This version also clamps the scrolling to the bounds of our child. - */ - public void scrollTo(int x, int y) { - // we rely on the fact the View.scrollBy calls scrollTo. - if (getChildCount() > 0) { - View child = getChildAt(0); - x = clamp(x, getWidth() - getPaddingRight() - getPaddingLeft(), child.getWidth()); - y = clamp(y, getHeight() - getPaddingBottom() - getPaddingTop(), child.getHeight()); - if (x != getScrollX() || y != getScrollY()) { - super.scrollTo(x, y); - } - } - } - - private int clamp(int n, int my, int child) { - if (my >= child || n < 0) { - /* my >= child is this case: - * |--------------- me ---------------| - * |------ child ------| - * or - * |--------------- me ---------------| - * |------ child ------| - * or - * |--------------- me ---------------| - * |------ child ------| - * - * n < 0 is this case: - * |------ me ------| - * |-------- child --------| - * |-- mScrollX --| - */ - return 0; - } - if ((my + n) > child) { - /* this case: - * |------ me ------| - * |------ child ------| - * |-- mScrollX --| - */ - return child - my; - } - return n; - } - - public void setScrollViewListener(ScrollView2DListener scrollViewListener) { - this.scrollView2DListener = scrollViewListener; - } - - @Override - protected void onScrollChanged(int x, int y, int oldx, int oldy) { - super.onScrollChanged(x, y, oldx, oldy); - if (scrollView2DListener != null) { - scrollView2DListener.onScrollChanged(this, x, y, oldx, oldy); - } - } - - // interface to receive notifications when the view is scrolled - public interface ScrollView2DListener { - abstract void onScrollChanged(ScrollView2D scrollView, int x, int y, int oldx, int oldy); - } - +public class ScrollView2D extends FrameLayout +{ + + static final int ANIMATED_SCROLL_GAP = 250; + static final float MAX_SCROLL_FACTOR = 0.5f; + private final Rect mTempRect = new Rect(); + private ScrollView2DListener scrollView2DListener = null; + private long mLastScroll; + private Scroller mScroller; + private boolean scrollEnabled = true; + /** + * Flag to indicate that we are moving focus ourselves. This is so the + * code that watches for focus changes initiated outside this TwoDScrollView + * knows that it does not have to do anything. + */ + private boolean mTwoDScrollViewMovedFocus; + /** + * Position of the last motion event. + */ + private float mLastMotionY; + private float mLastMotionX; + /** + * True when the layout has changed but the traversal has not come through yet. + * Ideally the view hierarchy would keep track of this for us. + */ + private boolean mIsLayoutDirty = true; + /** + * The child to give focus to in the event that a child has requested focus while the + * layout is dirty. This prevents the scroll from being wrong if the child has not been + * laid out before requesting focus. + */ + private View mChildToScrollTo = null; + /** + * True if the user is currently dragging this TwoDScrollView around. This is + * not the same as 'is being flinged', which can be checked by + * mScroller.isFinished() (flinging begins when the user lifts his finger). + */ + private boolean mIsBeingDragged = false; + /** + * Determines speed during touch scrolling + */ + private VelocityTracker mVelocityTracker; + /** + * Whether arrow scrolling is animated. + */ + private int mTouchSlop; + private int mMinimumVelocity; + private int mMaximumVelocity; + public ScrollView2D(Context context) + { + super(context); + initTwoDScrollView(); + } + + public ScrollView2D(Context context, AttributeSet attrs) + { + super(context, attrs); + initTwoDScrollView(); + } + + public ScrollView2D(Context context, AttributeSet attrs, int defStyle) + { + super(context, attrs, defStyle); + initTwoDScrollView(); + } + + @Override protected float getTopFadingEdgeStrength() + { + if (getChildCount() == 0) + { + return 0.0f; + } + final int length = getVerticalFadingEdgeLength(); + if (getScrollY() < length) + { + return getScrollY() / (float)length; + } + return 1.0f; + } + + @Override protected float getBottomFadingEdgeStrength() + { + if (getChildCount() == 0) + { + return 0.0f; + } + final int length = getVerticalFadingEdgeLength(); + final int bottomEdge = getHeight() - getPaddingBottom(); + final int span = getChildAt(0).getBottom() - getScrollY() - bottomEdge; + if (span < length) + { + return span / (float)length; + } + return 1.0f; + } + + @Override protected float getLeftFadingEdgeStrength() + { + if (getChildCount() == 0) + { + return 0.0f; + } + final int length = getHorizontalFadingEdgeLength(); + if (getScrollX() < length) + { + return getScrollX() / (float)length; + } + return 1.0f; + } + + @Override protected float getRightFadingEdgeStrength() + { + if (getChildCount() == 0) + { + return 0.0f; + } + final int length = getHorizontalFadingEdgeLength(); + final int rightEdge = getWidth() - getPaddingRight(); + final int span = getChildAt(0).getRight() - getScrollX() - rightEdge; + if (span < length) + { + return span / (float)length; + } + return 1.0f; + } + + /** + * Disable/Enable scrolling + */ + public void setScrollEnabled(boolean enable) + { + scrollEnabled = enable; + } + + /** + * @return The maximum amount this scroll view will scroll in response to + * an arrow event. + */ + public int getMaxScrollAmountVertical() + { + return (int)(MAX_SCROLL_FACTOR * getHeight()); + } + + public int getMaxScrollAmountHorizontal() + { + return (int)(MAX_SCROLL_FACTOR * getWidth()); + } + + private void initTwoDScrollView() + { + mScroller = new Scroller(getContext()); + setFocusable(true); + setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); + setWillNotDraw(false); + final ViewConfiguration configuration = ViewConfiguration.get(getContext()); + mTouchSlop = configuration.getScaledTouchSlop(); + mMinimumVelocity = configuration.getScaledMinimumFlingVelocity(); + mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); + } + + @Override public void addView(View child) + { + if (getChildCount() > 0) + { + throw new IllegalStateException("TwoDScrollView can host only one direct child"); + } + super.addView(child); + } + + @Override public void addView(View child, int index) + { + if (getChildCount() > 0) + { + throw new IllegalStateException("TwoDScrollView can host only one direct child"); + } + super.addView(child, index); + } + + @Override public void addView(View child, ViewGroup.LayoutParams params) + { + if (getChildCount() > 0) + { + throw new IllegalStateException("TwoDScrollView can host only one direct child"); + } + super.addView(child, params); + } + + @Override public void addView(View child, int index, ViewGroup.LayoutParams params) + { + if (getChildCount() > 0) + { + throw new IllegalStateException("TwoDScrollView can host only one direct child"); + } + super.addView(child, index, params); + } + + /** + * @return Returns true this TwoDScrollView can be scrolled + */ + private boolean canScroll() + { + if (!scrollEnabled) + return false; + View child = getChildAt(0); + if (child != null) + { + int childHeight = child.getHeight(); + int childWidth = child.getWidth(); + return (getHeight() < childHeight + getPaddingTop() + getPaddingBottom()) || + (getWidth() < childWidth + getPaddingLeft() + getPaddingRight()); + } + return false; + } + + @Override public boolean dispatchKeyEvent(KeyEvent event) + { + // Let the focused view and/or our descendants get the key first + boolean handled = super.dispatchKeyEvent(event); + if (handled) + { + return true; + } + return executeKeyEvent(event); + } + + /** + * You can call this function yourself to have the scroll view perform + * scrolling from a key event, just as if the event had been dispatched to + * it by the view hierarchy. + * + * @param event The key event to execute. + * @return Return true if the event was handled, else false. + */ + public boolean executeKeyEvent(KeyEvent event) + { + mTempRect.setEmpty(); + if (!canScroll()) + { + if (isFocused()) + { + View currentFocused = findFocus(); + if (currentFocused == this) + currentFocused = null; + View nextFocused = + FocusFinder.getInstance().findNextFocus(this, currentFocused, View.FOCUS_DOWN); + return nextFocused != null && nextFocused != this && + nextFocused.requestFocus(View.FOCUS_DOWN); + } + return false; + } + boolean handled = false; + if (event.getAction() == KeyEvent.ACTION_DOWN) + { + switch (event.getKeyCode()) + { + case KeyEvent.KEYCODE_DPAD_UP: + if (!event.isAltPressed()) + { + handled = arrowScroll(View.FOCUS_UP, false); + } + else + { + handled = fullScroll(View.FOCUS_UP, false); + } + break; + case KeyEvent.KEYCODE_DPAD_DOWN: + if (!event.isAltPressed()) + { + handled = arrowScroll(View.FOCUS_DOWN, false); + } + else + { + handled = fullScroll(View.FOCUS_DOWN, false); + } + break; + case KeyEvent.KEYCODE_DPAD_LEFT: + if (!event.isAltPressed()) + { + handled = arrowScroll(View.FOCUS_LEFT, true); + } + else + { + handled = fullScroll(View.FOCUS_LEFT, true); + } + break; + case KeyEvent.KEYCODE_DPAD_RIGHT: + if (!event.isAltPressed()) + { + handled = arrowScroll(View.FOCUS_RIGHT, true); + } + else + { + handled = fullScroll(View.FOCUS_RIGHT, true); + } + break; + } + } + return handled; + } + + @Override public boolean onInterceptTouchEvent(MotionEvent ev) + { + /* + * This method JUST determines whether we want to intercept the motion. + * If we return true, onMotionEvent will be called and we do the actual + * scrolling there. + * + * Shortcut the most recurring case: the user is in the dragging + * state and he is moving his finger. We want to intercept this + * motion. + */ + final int action = ev.getAction(); + if ((action == MotionEvent.ACTION_MOVE) && (mIsBeingDragged)) + { + return true; + } + if (!canScroll()) + { + mIsBeingDragged = false; + return false; + } + final float y = ev.getY(); + final float x = ev.getX(); + switch (action) + { + case MotionEvent.ACTION_MOVE: + /* + * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check + * whether the user has moved far enough from his original down touch. + */ + /* + * Locally do absolute value. mLastMotionY is set to the y value + * of the down event. + */ + final int yDiff = (int)Math.abs(y - mLastMotionY); + final int xDiff = (int)Math.abs(x - mLastMotionX); + if (yDiff > mTouchSlop || xDiff > mTouchSlop) + { + mIsBeingDragged = true; + } + break; + + case MotionEvent.ACTION_DOWN: + /* Remember location of down touch */ + mLastMotionY = y; + mLastMotionX = x; + + /* + * If being flinged and user touches the screen, initiate drag; + * otherwise don't. mScroller.isFinished should be false when + * being flinged. + */ + mIsBeingDragged = !mScroller.isFinished(); + break; + + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + /* Release the drag */ + mIsBeingDragged = false; + break; + } + + /* + * The only time we want to intercept motion events is if we are in the + * drag mode. + */ + return mIsBeingDragged; + } + + @Override public boolean onTouchEvent(MotionEvent ev) + { + + if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) + { + // Don't handle edge touches immediately -- they may actually belong to one of our + // descendants. + return false; + } + + if (!canScroll()) + { + return false; + } + + if (mVelocityTracker == null) + { + mVelocityTracker = VelocityTracker.obtain(); + } + mVelocityTracker.addMovement(ev); + + final int action = ev.getAction(); + final float y = ev.getY(); + final float x = ev.getX(); + + switch (action) + { + case MotionEvent.ACTION_DOWN: + /* + * If being flinged and user touches, stop the fling. isFinished + * will be false if being flinged. + */ + if (!mScroller.isFinished()) + { + mScroller.abortAnimation(); + } + + // Remember where the motion event started + mLastMotionY = y; + mLastMotionX = x; + break; + case MotionEvent.ACTION_MOVE: + // Scroll to follow the motion event + int deltaX = (int)(mLastMotionX - x); + int deltaY = (int)(mLastMotionY - y); + mLastMotionX = x; + mLastMotionY = y; + + if (deltaX < 0) + { + if (getScrollX() < 0) + { + deltaX = 0; + } + } + else if (deltaX > 0) + { + final int rightEdge = getWidth() - getPaddingRight(); + final int availableToScroll = + getChildAt(0).getRight() - getScrollX() - rightEdge; + if (availableToScroll > 0) + { + deltaX = Math.min(availableToScroll, deltaX); + } + else + { + deltaX = 0; + } + } + if (deltaY < 0) + { + if (getScrollY() < 0) + { + deltaY = 0; + } + } + else if (deltaY > 0) + { + final int bottomEdge = getHeight() - getPaddingBottom(); + final int availableToScroll = + getChildAt(0).getBottom() - getScrollY() - bottomEdge; + if (availableToScroll > 0) + { + deltaY = Math.min(availableToScroll, deltaY); + } + else + { + deltaY = 0; + } + } + if (deltaY != 0 || deltaX != 0) + scrollBy(deltaX, deltaY); + break; + case MotionEvent.ACTION_UP: + final VelocityTracker velocityTracker = mVelocityTracker; + velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); + int initialXVelocity = (int)velocityTracker.getXVelocity(); + int initialYVelocity = (int)velocityTracker.getYVelocity(); + if ((Math.abs(initialXVelocity) + Math.abs(initialYVelocity) > mMinimumVelocity) && + getChildCount() > 0) + { + fling(-initialXVelocity, -initialYVelocity); + } + if (mVelocityTracker != null) + { + mVelocityTracker.recycle(); + mVelocityTracker = null; + } + } + return true; + } + + /** + * Finds the next focusable component that fits in this View's bounds + * (excluding fading edges) pretending that this View's top is located at + * the parameter top. + * + * @param topFocus look for a candidate is the one at the top of the bounds + * if topFocus is true, or at the bottom of the bounds if topFocus is + * false + * @param top the top offset of the bounds in which a focusable must be + * found (the fading edge is assumed to start at this position) + * @param preferredFocusable the View that has highest priority and will be + * returned if it is within my bounds (null is valid) + * @return the next focusable component in the bounds or null if none can be + * found + */ + private View findFocusableViewInMyBounds(final boolean topFocus, final int top, + final boolean leftFocus, final int left, + View preferredFocusable) + { + /* + * The fading edge's transparent side should be considered for focus + * since it's mostly visible, so we divide the actual fading edge length + * by 2. + */ + final int verticalFadingEdgeLength = getVerticalFadingEdgeLength() / 2; + final int topWithoutFadingEdge = top + verticalFadingEdgeLength; + final int bottomWithoutFadingEdge = top + getHeight() - verticalFadingEdgeLength; + final int horizontalFadingEdgeLength = getHorizontalFadingEdgeLength() / 2; + final int leftWithoutFadingEdge = left + horizontalFadingEdgeLength; + final int rightWithoutFadingEdge = left + getWidth() - horizontalFadingEdgeLength; + + if ((preferredFocusable != null) && + (preferredFocusable.getTop() < bottomWithoutFadingEdge) && + (preferredFocusable.getBottom() > topWithoutFadingEdge) && + (preferredFocusable.getLeft() < rightWithoutFadingEdge) && + (preferredFocusable.getRight() > leftWithoutFadingEdge)) + { + return preferredFocusable; + } + return findFocusableViewInBounds(topFocus, topWithoutFadingEdge, bottomWithoutFadingEdge, + leftFocus, leftWithoutFadingEdge, rightWithoutFadingEdge); + } + + /** + * Finds the next focusable component that fits in the specified bounds. + *

+ * + * @param topFocus look for a candidate is the one at the top of the bounds + * if topFocus is true, or at the bottom of the bounds if topFocus is + * false + * @param top the top offset of the bounds in which a focusable must be + * found + * @param bottom the bottom offset of the bounds in which a focusable must + * be found + * @return the next focusable component in the bounds or null if none can + * be found + */ + private View findFocusableViewInBounds(boolean topFocus, int top, int bottom, boolean leftFocus, + int left, int right) + { + List focusables = getFocusables(View.FOCUS_FORWARD); + View focusCandidate = null; + + /* + * A fully contained focusable is one where its top is below the bound's + * top, and its bottom is above the bound's bottom. A partially + * contained focusable is one where some part of it is within the + * bounds, but it also has some part that is not within bounds. A fully contained + * focusable is preferred to a partially contained focusable. + */ + boolean foundFullyContainedFocusable = false; + + int count = focusables.size(); + for (int i = 0; i < count; i++) + { + View view = focusables.get(i); + int viewTop = view.getTop(); + int viewBottom = view.getBottom(); + int viewLeft = view.getLeft(); + int viewRight = view.getRight(); + + if (top < viewBottom && viewTop < bottom && left < viewRight && viewLeft < right) + { + /* + * the focusable is in the target area, it is a candidate for + * focusing + */ + final boolean viewIsFullyContained = (top < viewTop) && (viewBottom < bottom) && + (left < viewLeft) && (viewRight < right); + if (focusCandidate == null) + { + /* No candidate, take this one */ + focusCandidate = view; + foundFullyContainedFocusable = viewIsFullyContained; + } + else + { + final boolean viewIsCloserToVerticalBoundary = + (topFocus && viewTop < focusCandidate.getTop()) || + (!topFocus && viewBottom > focusCandidate.getBottom()); + final boolean viewIsCloserToHorizontalBoundary = + (leftFocus && viewLeft < focusCandidate.getLeft()) || + (!leftFocus && viewRight > focusCandidate.getRight()); + if (foundFullyContainedFocusable) + { + if (viewIsFullyContained && viewIsCloserToVerticalBoundary && + viewIsCloserToHorizontalBoundary) + { + /* + * We're dealing with only fully contained views, so + * it has to be closer to the boundary to beat our + * candidate + */ + focusCandidate = view; + } + } + else + { + if (viewIsFullyContained) + { + /* Any fully contained view beats a partially contained view */ + focusCandidate = view; + foundFullyContainedFocusable = true; + } + else if (viewIsCloserToVerticalBoundary && viewIsCloserToHorizontalBoundary) + { + /* + * Partially contained view beats another partially + * contained view if it's closer + */ + focusCandidate = view; + } + } + } + } + } + return focusCandidate; + } + + /** + *

Handles scrolling in response to a "home/end" shortcut press. This + * method will scroll the view to the top or bottom and give the focus + * to the topmost/bottommost component in the new visible area. If no + * component is a good candidate for focus, this scrollview reclaims the + * focus.

+ * + * @param direction the scroll direction: {@link android.view.View#FOCUS_UP} + * to go the top of the view or + * {@link android.view.View#FOCUS_DOWN} to go the bottom + * @return true if the key event is consumed by this method, false otherwise + */ + public boolean fullScroll(int direction, boolean horizontal) + { + if (!horizontal) + { + boolean down = direction == View.FOCUS_DOWN; + int height = getHeight(); + mTempRect.top = 0; + mTempRect.bottom = height; + if (down) + { + int count = getChildCount(); + if (count > 0) + { + View view = getChildAt(count - 1); + mTempRect.bottom = view.getBottom(); + mTempRect.top = mTempRect.bottom - height; + } + } + return scrollAndFocus(direction, mTempRect.top, mTempRect.bottom, 0, 0, 0); + } + else + { + boolean right = direction == View.FOCUS_DOWN; + int width = getWidth(); + mTempRect.left = 0; + mTempRect.right = width; + if (right) + { + int count = getChildCount(); + if (count > 0) + { + View view = getChildAt(count - 1); + mTempRect.right = view.getBottom(); + mTempRect.left = mTempRect.right - width; + } + } + return scrollAndFocus(0, 0, 0, direction, mTempRect.top, mTempRect.bottom); + } + } + + /** + *

Scrolls the view to make the area defined by top and + * bottom visible. This method attempts to give the focus + * to a component visible in this area. If no component can be focused in + * the new visible area, the focus is reclaimed by this scrollview.

+ * + * @param direction the scroll direction: {@link android.view.View#FOCUS_UP} + * to go upward + * {@link android.view.View#FOCUS_DOWN} to downward + * @param top the top offset of the new area to be made visible + * @param bottom the bottom offset of the new area to be made visible + * @return true if the key event is consumed by this method, false otherwise + */ + private boolean scrollAndFocus(int directionY, int top, int bottom, int directionX, int left, + int right) + { + boolean handled = true; + int height = getHeight(); + int containerTop = getScrollY(); + int containerBottom = containerTop + height; + boolean up = directionY == View.FOCUS_UP; + int width = getWidth(); + int containerLeft = getScrollX(); + int containerRight = containerLeft + width; + boolean leftwards = directionX == View.FOCUS_UP; + View newFocused = findFocusableViewInBounds(up, top, bottom, leftwards, left, right); + if (newFocused == null) + { + newFocused = this; + } + if ((top >= containerTop && bottom <= containerBottom) || + (left >= containerLeft && right <= containerRight)) + { + handled = false; + } + else + { + int deltaY = up ? (top - containerTop) : (bottom - containerBottom); + int deltaX = leftwards ? (left - containerLeft) : (right - containerRight); + doScroll(deltaX, deltaY); + } + if (newFocused != findFocus() && newFocused.requestFocus(directionY)) + { + mTwoDScrollViewMovedFocus = true; + mTwoDScrollViewMovedFocus = false; + } + return handled; + } + + /** + * Handle scrolling in response to an up or down arrow click. + * + * @param direction The direction corresponding to the arrow key that was + * pressed + * @return True if we consumed the event, false otherwise + */ + public boolean arrowScroll(int direction, boolean horizontal) + { + View currentFocused = findFocus(); + if (currentFocused == this) + currentFocused = null; + View nextFocused = FocusFinder.getInstance().findNextFocus(this, currentFocused, direction); + final int maxJump = + horizontal ? getMaxScrollAmountHorizontal() : getMaxScrollAmountVertical(); + + if (!horizontal) + { + if (nextFocused != null) + { + nextFocused.getDrawingRect(mTempRect); + offsetDescendantRectToMyCoords(nextFocused, mTempRect); + int scrollDelta = computeScrollDeltaToGetChildRectOnScreen(mTempRect); + doScroll(0, scrollDelta); + nextFocused.requestFocus(direction); + } + else + { + // no new focus + int scrollDelta = maxJump; + if (direction == View.FOCUS_UP && getScrollY() < scrollDelta) + { + scrollDelta = getScrollY(); + } + else if (direction == View.FOCUS_DOWN) + { + if (getChildCount() > 0) + { + int daBottom = getChildAt(0).getBottom(); + int screenBottom = getScrollY() + getHeight(); + if (daBottom - screenBottom < maxJump) + { + scrollDelta = daBottom - screenBottom; + } + } + } + if (scrollDelta == 0) + { + return false; + } + doScroll(0, direction == View.FOCUS_DOWN ? scrollDelta : -scrollDelta); + } + } + else + { + if (nextFocused != null) + { + nextFocused.getDrawingRect(mTempRect); + offsetDescendantRectToMyCoords(nextFocused, mTempRect); + int scrollDelta = computeScrollDeltaToGetChildRectOnScreen(mTempRect); + doScroll(scrollDelta, 0); + nextFocused.requestFocus(direction); + } + else + { + // no new focus + int scrollDelta = maxJump; + if (direction == View.FOCUS_UP && getScrollY() < scrollDelta) + { + scrollDelta = getScrollY(); + } + else if (direction == View.FOCUS_DOWN) + { + if (getChildCount() > 0) + { + int daBottom = getChildAt(0).getBottom(); + int screenBottom = getScrollY() + getHeight(); + if (daBottom - screenBottom < maxJump) + { + scrollDelta = daBottom - screenBottom; + } + } + } + if (scrollDelta == 0) + { + return false; + } + doScroll(direction == View.FOCUS_DOWN ? scrollDelta : -scrollDelta, 0); + } + } + return true; + } + + /** + * Smooth scroll by a Y delta + * + * @param delta the number of pixels to scroll by on the Y axis + */ + private void doScroll(int deltaX, int deltaY) + { + if (deltaX != 0 || deltaY != 0) + { + smoothScrollBy(deltaX, deltaY); + } + } + + /** + * Like {@link View#scrollBy}, but scroll smoothly instead of immediately. + * + * @param dx the number of pixels to scroll by on the X axis + * @param dy the number of pixels to scroll by on the Y axis + */ + public final void smoothScrollBy(int dx, int dy) + { + long duration = AnimationUtils.currentAnimationTimeMillis() - mLastScroll; + if (duration > ANIMATED_SCROLL_GAP) + { + mScroller.startScroll(getScrollX(), getScrollY(), dx, dy); + awakenScrollBars(mScroller.getDuration()); + invalidate(); + } + else + { + if (!mScroller.isFinished()) + { + mScroller.abortAnimation(); + } + scrollBy(dx, dy); + } + mLastScroll = AnimationUtils.currentAnimationTimeMillis(); + } + + /** + * Like {@link #scrollTo}, but scroll smoothly instead of immediately. + * + * @param x the position where to scroll on the X axis + * @param y the position where to scroll on the Y axis + */ + public final void smoothScrollTo(int x, int y) + { + smoothScrollBy(x - getScrollX(), y - getScrollY()); + } + + /** + *

The scroll range of a scroll view is the overall height of all of its + * children.

+ */ + @Override protected int computeVerticalScrollRange() + { + int count = getChildCount(); + return count == 0 ? getHeight() : (getChildAt(0)).getBottom(); + } + + @Override protected int computeHorizontalScrollRange() + { + int count = getChildCount(); + return count == 0 ? getWidth() : (getChildAt(0)).getRight(); + } + + @Override + protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec) + { + ViewGroup.LayoutParams lp = child.getLayoutParams(); + int childWidthMeasureSpec; + int childHeightMeasureSpec; + + childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, + getPaddingLeft() + getPaddingRight(), lp.width); + childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + + child.measure(childWidthMeasureSpec, childHeightMeasureSpec); + } + + @Override + protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, + int parentHeightMeasureSpec, int heightUsed) + { + final MarginLayoutParams lp = (MarginLayoutParams)child.getLayoutParams(); + final int childWidthMeasureSpec = + MeasureSpec.makeMeasureSpec(lp.leftMargin + lp.rightMargin, MeasureSpec.UNSPECIFIED); + final int childHeightMeasureSpec = + MeasureSpec.makeMeasureSpec(lp.topMargin + lp.bottomMargin, MeasureSpec.UNSPECIFIED); + + child.measure(childWidthMeasureSpec, childHeightMeasureSpec); + } + + @Override public void computeScroll() + { + if (mScroller.computeScrollOffset()) + { + // This is called at drawing time by ViewGroup. We don't want to + // re-show the scrollbars at this point, which scrollTo will do, + // so we replicate most of scrollTo here. + // + // It's a little odd to call onScrollChanged from inside the drawing. + // + // It is, except when you remember that computeScroll() is used to + // animate scrolling. So unless we want to defer the onScrollChanged() + // until the end of the animated scrolling, we don't really have a + // choice here. + // + // I agree. The alternative, which I think would be worse, is to post + // something and tell the subclasses later. This is bad because there + // will be a window where mScrollX/Y is different from what the app + // thinks it is. + // + int oldX = getScrollX(); + int oldY = getScrollY(); + int x = mScroller.getCurrX(); + int y = mScroller.getCurrY(); + if (getChildCount() > 0) + { + View child = getChildAt(0); + scrollTo( + clamp(x, getWidth() - getPaddingRight() - getPaddingLeft(), child.getWidth()), + clamp(y, getHeight() - getPaddingBottom() - getPaddingTop(), + child.getHeight())); + } + else + { + scrollTo(x, y); + } + if (oldX != getScrollX() || oldY != getScrollY()) + { + onScrollChanged(getScrollX(), getScrollY(), oldX, oldY); + } + + // Keep on drawing until the animation has finished. + postInvalidate(); + } + } + + /** + * Scrolls the view to the given child. + * + * @param child the View to scroll to + */ + private void scrollToChild(View child) + { + child.getDrawingRect(mTempRect); + /* Offset from child's local coordinates to TwoDScrollView coordinates */ + offsetDescendantRectToMyCoords(child, mTempRect); + int scrollDelta = computeScrollDeltaToGetChildRectOnScreen(mTempRect); + if (scrollDelta != 0) + { + scrollBy(0, scrollDelta); + } + } + + /** + * If rect is off screen, scroll just enough to get it (or at least the + * first screen size chunk of it) on screen. + * + * @param rect The rectangle. + * @param immediate True to scroll immediately without animation + * @return true if scrolling was performed + */ + private boolean scrollToChildRect(Rect rect, boolean immediate) + { + final int delta = computeScrollDeltaToGetChildRectOnScreen(rect); + final boolean scroll = delta != 0; + if (scroll) + { + if (immediate) + { + scrollBy(0, delta); + } + else + { + smoothScrollBy(0, delta); + } + } + return scroll; + } + + /** + * Compute the amount to scroll in the Y direction in order to get + * a rectangle completely on the screen (or, if taller than the screen, + * at least the first screen size chunk of it). + * + * @param rect The rect. + * @return The scroll delta. + */ + protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) + { + if (getChildCount() == 0) + return 0; + int height = getHeight(); + int screenTop = getScrollY(); + int screenBottom = screenTop + height; + int fadingEdge = getVerticalFadingEdgeLength(); + // leave room for top fading edge as long as rect isn't at very top + if (rect.top > 0) + { + screenTop += fadingEdge; + } + + // leave room for bottom fading edge as long as rect isn't at very bottom + if (rect.bottom < getChildAt(0).getHeight()) + { + screenBottom -= fadingEdge; + } + int scrollYDelta = 0; + if (rect.bottom > screenBottom && rect.top > screenTop) + { + // need to move down to get it in view: move down just enough so + // that the entire rectangle is in view (or at least the first + // screen size chunk). + if (rect.height() > height) + { + // just enough to get screen size chunk on + scrollYDelta += (rect.top - screenTop); + } + else + { + // get entire rect at bottom of screen + scrollYDelta += (rect.bottom - screenBottom); + } + + // make sure we aren't scrolling beyond the end of our content + int bottom = getChildAt(0).getBottom(); + int distanceToBottom = bottom - screenBottom; + scrollYDelta = Math.min(scrollYDelta, distanceToBottom); + } + else if (rect.top < screenTop && rect.bottom < screenBottom) + { + // need to move up to get it in view: move up just enough so that + // entire rectangle is in view (or at least the first screen + // size chunk of it). + + if (rect.height() > height) + { + // screen size chunk + scrollYDelta -= (screenBottom - rect.bottom); + } + else + { + // entire rect at top + scrollYDelta -= (screenTop - rect.top); + } + + // make sure we aren't scrolling any further than the top our content + scrollYDelta = Math.max(scrollYDelta, -getScrollY()); + } + return scrollYDelta; + } + + @Override public void requestChildFocus(View child, View focused) + { + if (!mTwoDScrollViewMovedFocus) + { + if (!mIsLayoutDirty) + { + scrollToChild(focused); + } + else + { + // The child may not be laid out yet, we can't compute the scroll yet + mChildToScrollTo = focused; + } + } + super.requestChildFocus(child, focused); + } + + /** + * When looking for focus in children of a scroll view, need to be a little + * more careful not to give focus to something that is scrolled off screen. + *

+ * This is more expensive than the default {@link android.view.ViewGroup} + * implementation, otherwise this behavior might have been made the default. + */ + @Override + protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) + { + // convert from forward / backward notation to up / down / left / right + // (ugh). + if (direction == View.FOCUS_FORWARD) + { + direction = View.FOCUS_DOWN; + } + else if (direction == View.FOCUS_BACKWARD) + { + direction = View.FOCUS_UP; + } + + final View nextFocus = previouslyFocusedRect == null + ? FocusFinder.getInstance().findNextFocus(this, null, direction) + : FocusFinder.getInstance().findNextFocusFromRect( + this, previouslyFocusedRect, direction); + + if (nextFocus == null) + { + return false; + } + + return nextFocus.requestFocus(direction, previouslyFocusedRect); + } + + @Override + public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) + { + // offset into coordinate space of this scroll view + rectangle.offset(child.getLeft() - child.getScrollX(), child.getTop() - child.getScrollY()); + return scrollToChildRect(rectangle, immediate); + } + + @Override public void requestLayout() + { + mIsLayoutDirty = true; + super.requestLayout(); + } + + @Override protected void onLayout(boolean changed, int l, int t, int r, int b) + { + super.onLayout(changed, l, t, r, b); + mIsLayoutDirty = false; + // Give a child focus if it needs it + if (mChildToScrollTo != null && isViewDescendantOf(mChildToScrollTo, this)) + { + scrollToChild(mChildToScrollTo); + } + mChildToScrollTo = null; + + // Calling this with the present values causes it to re-clam them + scrollTo(getScrollX(), getScrollY()); + } + + @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) + { + super.onSizeChanged(w, h, oldw, oldh); + + View currentFocused = findFocus(); + if (null == currentFocused || this == currentFocused) + return; + + // If the currently-focused view was visible on the screen when the + // screen was at the old height, then scroll the screen to make that + // view visible with the new screen height. + currentFocused.getDrawingRect(mTempRect); + offsetDescendantRectToMyCoords(currentFocused, mTempRect); + int scrollDeltaX = computeScrollDeltaToGetChildRectOnScreen(mTempRect); + int scrollDeltaY = computeScrollDeltaToGetChildRectOnScreen(mTempRect); + doScroll(scrollDeltaX, scrollDeltaY); + } + + /** + * Return true if child is an descendant of parent, (or equal to the parent). + */ + private boolean isViewDescendantOf(View child, View parent) + { + if (child == parent) + { + return true; + } + + final ViewParent theParent = child.getParent(); + return (theParent instanceof ViewGroup) && isViewDescendantOf((View)theParent, parent); + } + + /** + * Fling the scroll view + * + * @param velocityY The initial velocity in the Y direction. Positive + * numbers mean that the finger/curor is moving down the screen, + * which means we want to scroll towards the top. + */ + public void fling(int velocityX, int velocityY) + { + if (getChildCount() > 0) + { + int height = getHeight() - getPaddingBottom() - getPaddingTop(); + int bottom = getChildAt(0).getHeight(); + int width = getWidth() - getPaddingRight() - getPaddingLeft(); + int right = getChildAt(0).getWidth(); + + mScroller.fling(getScrollX(), getScrollY(), velocityX, velocityY, 0, right - width, 0, + bottom - height); + + final boolean movingDown = velocityY > 0; + final boolean movingRight = velocityX > 0; + + View newFocused = findFocusableViewInMyBounds( + movingRight, mScroller.getFinalX(), movingDown, mScroller.getFinalY(), findFocus()); + if (newFocused == null) + { + newFocused = this; + } + + if (newFocused != findFocus() && + newFocused.requestFocus(movingDown ? View.FOCUS_DOWN : View.FOCUS_UP)) + { + mTwoDScrollViewMovedFocus = true; + mTwoDScrollViewMovedFocus = false; + } + + awakenScrollBars(mScroller.getDuration()); + invalidate(); + } + } + + /** + * {@inheritDoc} + *

+ *

This version also clamps the scrolling to the bounds of our child. + */ + public void scrollTo(int x, int y) + { + // we rely on the fact the View.scrollBy calls scrollTo. + if (getChildCount() > 0) + { + View child = getChildAt(0); + x = clamp(x, getWidth() - getPaddingRight() - getPaddingLeft(), child.getWidth()); + y = clamp(y, getHeight() - getPaddingBottom() - getPaddingTop(), child.getHeight()); + if (x != getScrollX() || y != getScrollY()) + { + super.scrollTo(x, y); + } + } + } + + private int clamp(int n, int my, int child) + { + if (my >= child || n < 0) + { + /* my >= child is this case: + * |--------------- me ---------------| + * |------ child ------| + * or + * |--------------- me ---------------| + * |------ child ------| + * or + * |--------------- me ---------------| + * |------ child ------| + * + * n < 0 is this case: + * |------ me ------| + * |-------- child --------| + * |-- mScrollX --| + */ + return 0; + } + if ((my + n) > child) + { + /* this case: + * |------ me ------| + * |------ child ------| + * |-- mScrollX --| + */ + return child - my; + } + return n; + } + + public void setScrollViewListener(ScrollView2DListener scrollViewListener) + { + this.scrollView2DListener = scrollViewListener; + } + + @Override protected void onScrollChanged(int x, int y, int oldx, int oldy) + { + super.onScrollChanged(x, y, oldx, oldy); + if (scrollView2DListener != null) + { + scrollView2DListener.onScrollChanged(this, x, y, oldx, oldy); + } + } + + // interface to receive notifications when the view is scrolled + public interface ScrollView2DListener { + abstract void onScrollChanged(ScrollView2D scrollView, int x, int y, int oldx, int oldy); + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/SessionActivity.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/SessionActivity.java index 81cb993..2e64f85 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/SessionActivity.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/SessionActivity.java @@ -3,8 +3,9 @@ Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.presentation; @@ -63,1304 +64,1370 @@ import java.util.Collection; import java.util.Iterator; import java.util.List; -public class SessionActivity extends AppCompatActivity implements - LibFreeRDP.UIEventListener, KeyboardView.OnKeyboardActionListener, - ScrollView2D.ScrollView2DListener, - KeyboardMapper.KeyProcessingListener, SessionView.SessionViewListener, - TouchPointerView.TouchPointerListener, - ClipboardManagerProxy.OnClipboardChangedListener { - public static final String PARAM_CONNECTION_REFERENCE = "conRef"; - public static final String PARAM_INSTANCE = "instance"; - private static final float ZOOMING_STEP = 0.5f; - private static final int ZOOMCONTROLS_AUTOHIDE_TIMEOUT = 4000; - // timeout between subsequent scrolling requests when the touch-pointer is - // at the edge of the session view - private static final int SCROLLING_TIMEOUT = 50; - private static final int SCROLLING_DISTANCE = 20; - private static final String TAG = "FreeRDP.SessionActivity"; - // variables for delayed move event sending - private static final int MAX_DISCARDED_MOVE_EVENTS = 3; - private static final int SEND_MOVE_EVENT_TIMEOUT = 150; - private Bitmap bitmap; - private SessionState session; - private SessionView sessionView; - private TouchPointerView touchPointerView; - private ProgressDialog progressDialog; - private KeyboardView keyboardView; - private KeyboardView modifiersKeyboardView; - private ZoomControls zoomControls; - private KeyboardMapper keyboardMapper; - - private Keyboard specialkeysKeyboard; - private Keyboard numpadKeyboard; - private Keyboard cursorKeyboard; - private Keyboard modifiersKeyboard; - - private AlertDialog dlgVerifyCertificate; - private AlertDialog dlgUserCredentials; - private View userCredView; - - private UIHandler uiHandler; - - private int screen_width; - private int screen_height; - - private boolean connectCancelledByUser = false; - private boolean sessionRunning = false; - private boolean toggleMouseButtons = false; - - private LibFreeRDPBroadcastReceiver libFreeRDPBroadcastReceiver; - private ScrollView2D scrollView; - // keyboard visibility flags - private boolean sysKeyboardVisible = false; - private boolean extKeyboardVisible = false; - private int discardedMoveEvents = 0; - private ClipboardManagerProxy mClipboardManager; - private boolean callbackDialogResult; - View mDecor; - - private void createDialogs() { - // build verify certificate dialog - dlgVerifyCertificate = new AlertDialog.Builder(this) - .setTitle(R.string.dlg_title_verify_certificate) - .setPositiveButton(android.R.string.yes, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, - int which) { - callbackDialogResult = true; - synchronized (dialog) { - dialog.notify(); - } - } - }) - .setNegativeButton(android.R.string.no, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, - int which) { - callbackDialogResult = false; - connectCancelledByUser = true; - synchronized (dialog) { - dialog.notify(); - } - } - }).setCancelable(false).create(); - - // build the dialog - userCredView = getLayoutInflater().inflate(R.layout.credentials, null, - true); - dlgUserCredentials = new AlertDialog.Builder(this) - .setView(userCredView) - .setTitle(R.string.dlg_title_credentials) - .setPositiveButton(android.R.string.ok, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, - int which) { - callbackDialogResult = true; - synchronized (dialog) { - dialog.notify(); - } - } - }) - .setNegativeButton(android.R.string.cancel, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, - int which) { - callbackDialogResult = false; - connectCancelledByUser = true; - synchronized (dialog) { - dialog.notify(); - } - } - }).setCancelable(false).create(); - } - - private boolean hasHardwareMenuButton() { - if (Build.VERSION.SDK_INT <= 10) - return true; - - if (Build.VERSION.SDK_INT >= 14) { - boolean rc = false; - final ViewConfiguration cfg = ViewConfiguration.get(this); - - return cfg.hasPermanentMenuKey(); - } - - return false; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - // show status bar or make fullscreen? - if (ApplicationSettingsActivity.getHideStatusBar(this)) { - getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, - WindowManager.LayoutParams.FLAG_FULLSCREEN); - } - - this.setContentView(R.layout.session); - if (hasHardwareMenuButton() || ApplicationSettingsActivity.getHideActionBar(this)) { - this.getSupportActionBar().hide(); - } else - this.getSupportActionBar().show(); - - Log.v(TAG, "Session.onCreate"); - - // ATTENTION: We use the onGlobalLayout notification to start our - // session. - // This is because only then we can know the exact size of our session - // when using fit screen - // accounting for any status bars etc. that Android might throws on us. - // A bit weird looking - // but this is the only way ... - final View activityRootView = findViewById(R.id.session_root_view); - activityRootView.getViewTreeObserver().addOnGlobalLayoutListener( - new OnGlobalLayoutListener() { - @Override - public void onGlobalLayout() { - screen_width = activityRootView.getWidth(); - screen_height = activityRootView.getHeight(); - - // start session - if (!sessionRunning && getIntent() != null) { - processIntent(getIntent()); - sessionRunning = true; - } - } - }); - - sessionView = (SessionView) findViewById(R.id.sessionView); - sessionView.setScaleGestureDetector(new ScaleGestureDetector(this, - new PinchZoomListener())); - sessionView.setSessionViewListener(this); - sessionView.requestFocus(); - - touchPointerView = (TouchPointerView) findViewById(R.id.touchPointerView); - touchPointerView.setTouchPointerListener(this); - - keyboardMapper = new KeyboardMapper(); - keyboardMapper.init(this); - keyboardMapper.reset(this); - - modifiersKeyboard = new Keyboard(getApplicationContext(), - R.xml.modifiers_keyboard); - specialkeysKeyboard = new Keyboard(getApplicationContext(), - R.xml.specialkeys_keyboard); - numpadKeyboard = new Keyboard(getApplicationContext(), - R.xml.numpad_keyboard); - cursorKeyboard = new Keyboard(getApplicationContext(), - R.xml.cursor_keyboard); - - // hide keyboard below the sessionView - keyboardView = (KeyboardView) findViewById(R.id.extended_keyboard); - keyboardView.setKeyboard(specialkeysKeyboard); - keyboardView.setOnKeyboardActionListener(this); - - modifiersKeyboardView = (KeyboardView) findViewById(R.id.extended_keyboard_header); - modifiersKeyboardView.setKeyboard(modifiersKeyboard); - modifiersKeyboardView.setOnKeyboardActionListener(this); - - scrollView = (ScrollView2D) findViewById(R.id.sessionScrollView); - scrollView.setScrollViewListener(this); - uiHandler = new UIHandler(); - libFreeRDPBroadcastReceiver = new LibFreeRDPBroadcastReceiver(); - - zoomControls = (ZoomControls) findViewById(R.id.zoomControls); - zoomControls.hide(); - zoomControls.setOnZoomInClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - resetZoomControlsAutoHideTimeout(); - zoomControls.setIsZoomInEnabled(sessionView - .zoomIn(ZOOMING_STEP)); - zoomControls.setIsZoomOutEnabled(true); - } - }); - zoomControls.setOnZoomOutClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - resetZoomControlsAutoHideTimeout(); - zoomControls.setIsZoomOutEnabled(sessionView - .zoomOut(ZOOMING_STEP)); - zoomControls.setIsZoomInEnabled(true); - } - }); - - toggleMouseButtons = false; - - createDialogs(); - - // register freerdp events broadcast receiver - IntentFilter filter = new IntentFilter(); - filter.addAction(GlobalApp.ACTION_EVENT_FREERDP); - registerReceiver(libFreeRDPBroadcastReceiver, filter); - - mClipboardManager = ClipboardManagerProxy.getClipboardManager(this); - mClipboardManager.addClipboardChangedListener(this); - - mDecor = getWindow().getDecorView(); - mDecor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); - } - - @Override - protected void onStart() { - super.onStart(); - Log.v(TAG, "Session.onStart"); - } - - @Override - protected void onRestart() { - super.onRestart(); - Log.v(TAG, "Session.onRestart"); - } - - @Override - protected void onResume() { - super.onResume(); - Log.v(TAG, "Session.onResume"); - } - - @Override - protected void onPause() { - super.onPause(); - Log.v(TAG, "Session.onPause"); - - // hide any visible keyboards - showKeyboard(false, false); - } - - @Override - protected void onStop() { - super.onStop(); - Log.v(TAG, "Session.onStop"); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - Log.v(TAG, "Session.onDestroy"); - - // Cancel running disconnect timers. - GlobalApp.cancelDisconnectTimer(); - - // Disconnect all remaining sessions. - Collection sessions = GlobalApp.getSessions(); - for (SessionState session : sessions) - LibFreeRDP.disconnect(session.getInstance()); - - // unregister freerdp events broadcast receiver - unregisterReceiver(libFreeRDPBroadcastReceiver); - - // remove clipboard listener - mClipboardManager.removeClipboardboardChangedListener(this); - - // free session - GlobalApp.freeSession(session.getInstance()); - - session = null; - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - - // reload keyboard resources (changed from landscape) - modifiersKeyboard = new Keyboard(getApplicationContext(), - R.xml.modifiers_keyboard); - specialkeysKeyboard = new Keyboard(getApplicationContext(), - R.xml.specialkeys_keyboard); - numpadKeyboard = new Keyboard(getApplicationContext(), - R.xml.numpad_keyboard); - cursorKeyboard = new Keyboard(getApplicationContext(), - R.xml.cursor_keyboard); - - // apply loaded keyboards - keyboardView.setKeyboard(specialkeysKeyboard); - modifiersKeyboardView.setKeyboard(modifiersKeyboard); - - mDecor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); - } - - private void processIntent(Intent intent) { - // get either session instance or create one from a bookmark/uri - Bundle bundle = intent.getExtras(); - Uri openUri = intent.getData(); - if (openUri != null) { - // Launched from URI, e.g: - // freerdp://user@ip:port/connect?sound=&rfx=&p=password&clipboard=%2b&themes=- - connect(openUri); - } else if (bundle.containsKey(PARAM_INSTANCE)) { - int inst = bundle.getInt(PARAM_INSTANCE); - session = GlobalApp.getSession(inst); - bitmap = session.getSurface().getBitmap(); - bindSession(); - } else if (bundle.containsKey(PARAM_CONNECTION_REFERENCE)) { - BookmarkBase bookmark = null; - String refStr = bundle.getString(PARAM_CONNECTION_REFERENCE); - if (ConnectionReference.isHostnameReference(refStr)) { - bookmark = new ManualBookmark(); - bookmark.get().setHostname( - ConnectionReference.getHostname(refStr)); - } else if (ConnectionReference.isBookmarkReference(refStr)) { - if (ConnectionReference.isManualBookmarkReference(refStr)) - bookmark = GlobalApp.getManualBookmarkGateway().findById( - ConnectionReference.getManualBookmarkId(refStr)); - else - assert false; - } - - if (bookmark != null) - connect(bookmark); - else - closeSessionActivity(RESULT_CANCELED); - } else { - // no session found - exit - closeSessionActivity(RESULT_CANCELED); - } - } - - private void connect(BookmarkBase bookmark) { - session = GlobalApp.createSession(bookmark, getApplicationContext()); - - BookmarkBase.ScreenSettings screenSettings = session.getBookmark() - .getActiveScreenSettings(); - Log.v(TAG, "Screen Resolution: " + screenSettings.getResolutionString()); - if (screenSettings.isAutomatic()) { - if ((getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE) { - // large screen device i.e. tablet: simply use screen info - screenSettings.setHeight(screen_height); - screenSettings.setWidth(screen_width); - } else { - // small screen device i.e. phone: - // Automatic uses the largest side length of the screen and - // makes a 16:10 resolution setting out of it - int screenMax = (screen_width > screen_height) ? screen_width - : screen_height; - screenSettings.setHeight(screenMax); - screenSettings.setWidth((int) ((float) screenMax * 1.6f)); - } - } - if (screenSettings.isFitScreen()) { - screenSettings.setHeight(screen_height); - screenSettings.setWidth(screen_width); - } - - connectWithTitle(bookmark.getLabel()); - } - - private void connect(Uri openUri) { - session = GlobalApp.createSession(openUri, getApplicationContext()); - - connectWithTitle(openUri.getAuthority()); - } - - private void connectWithTitle(String title) { - session.setUIEventListener(this); - - progressDialog = new ProgressDialog(this); - progressDialog.setTitle(title); - progressDialog.setMessage(getResources().getText( - R.string.dlg_msg_connecting)); - progressDialog.setButton(ProgressDialog.BUTTON_NEGATIVE, "Cancel", - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - connectCancelledByUser = true; - LibFreeRDP.cancelConnection(session.getInstance()); - } - }); - progressDialog.setCancelable(false); - progressDialog.show(); - - Thread thread = new Thread(new Runnable() { - public void run() { - session.connect(getApplicationContext()); - } - }); - thread.start(); - } - - // binds the current session to the activity by wiring it up with the - // sessionView and updating all internal objects accordingly - private void bindSession() { - Log.v(TAG, "bindSession called"); - session.setUIEventListener(this); - sessionView.onSurfaceChange(session); - scrollView.requestLayout(); - keyboardMapper.reset(this); - mDecor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); - - } - - private void hideSoftInput() { - InputMethodManager mgr = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); - - if (mgr.isActive()) { - mgr.toggleSoftInput(InputMethodManager.HIDE_NOT_ALWAYS, 0); - } else { - mgr.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS); - } - } - - // displays either the system or the extended keyboard or non of them - private void showKeyboard(final boolean showSystemKeyboard, - final boolean showExtendedKeyboard) { - // no matter what we are doing ... hide the zoom controls - // TODO: this is not working correctly as hiding the keyboard issues a - // onScrollChange notification showing the control again ... - uiHandler.removeMessages(UIHandler.HIDE_ZOOMCONTROLS); - if (zoomControls.getVisibility() == View.VISIBLE) - zoomControls.hide(); - - InputMethodManager mgr = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); - - if (showSystemKeyboard) { - // hide extended keyboard - keyboardView.setVisibility(View.GONE); - // show system keyboard - mgr.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); - - // show modifiers keyboard - modifiersKeyboardView.setVisibility(View.VISIBLE); - } else if (showExtendedKeyboard) { - // hide system keyboard - hideSoftInput(); - - // show extended keyboard - keyboardView.setKeyboard(specialkeysKeyboard); - keyboardView.setVisibility(View.VISIBLE); - modifiersKeyboardView.setVisibility(View.VISIBLE); - } else { - // hide both - hideSoftInput(); - keyboardView.setVisibility(View.GONE); - modifiersKeyboardView.setVisibility(View.GONE); - - // clear any active key modifiers) - keyboardMapper.clearlAllModifiers(); - } - - sysKeyboardVisible = showSystemKeyboard; - extKeyboardVisible = showExtendedKeyboard; - } - - private void closeSessionActivity(int resultCode) { - // Go back to home activity (and send intent data back to home) - setResult(resultCode, getIntent()); - finish(); - } - - // update the state of our modifier keys - private void updateModifierKeyStates() { - // check if any key is in the keycodes list - - List keys = modifiersKeyboard.getKeys(); - for (Iterator it = keys.iterator(); it.hasNext(); ) { - // if the key is a sticky key - just set it to off - Keyboard.Key curKey = it.next(); - if (curKey.sticky) { - switch (keyboardMapper.getModifierState(curKey.codes[0])) { - case KeyboardMapper.KEYSTATE_ON: - curKey.on = true; - curKey.pressed = false; - break; - - case KeyboardMapper.KEYSTATE_OFF: - curKey.on = false; - curKey.pressed = false; - break; - - case KeyboardMapper.KEYSTATE_LOCKED: - curKey.on = true; - curKey.pressed = true; - break; - } - } - } - - // refresh image - modifiersKeyboardView.invalidateAllKeys(); - } - - private void sendDelayedMoveEvent(int x, int y) { - if (uiHandler.hasMessages(UIHandler.SEND_MOVE_EVENT)) { - uiHandler.removeMessages(UIHandler.SEND_MOVE_EVENT); - discardedMoveEvents++; - } else - discardedMoveEvents = 0; - - if (discardedMoveEvents > MAX_DISCARDED_MOVE_EVENTS) - LibFreeRDP.sendCursorEvent(session.getInstance(), x, y, - Mouse.getMoveEvent()); - else - uiHandler.sendMessageDelayed( - Message.obtain(null, UIHandler.SEND_MOVE_EVENT, x, y), - SEND_MOVE_EVENT_TIMEOUT); - } - - private void cancelDelayedMoveEvent() { - uiHandler.removeMessages(UIHandler.SEND_MOVE_EVENT); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.session_menu, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - // refer to http://tools.android.com/tips/non-constant-fields why we - // can't use switch/case here .. - int itemId = item.getItemId(); - - if (itemId == R.id.session_touch_pointer) { - // toggle touch pointer - if (touchPointerView.getVisibility() == View.VISIBLE) { - touchPointerView.setVisibility(View.INVISIBLE); - sessionView.setTouchPointerPadding(0, 0); - } else { - touchPointerView.setVisibility(View.VISIBLE); - sessionView.setTouchPointerPadding( - touchPointerView.getPointerWidth(), - touchPointerView.getPointerHeight()); - } - } else if (itemId == R.id.session_sys_keyboard) { - showKeyboard(!sysKeyboardVisible, false); - } else if (itemId == R.id.session_ext_keyboard) { - showKeyboard(false, !extKeyboardVisible); - } else if (itemId == R.id.session_disconnect) { - showKeyboard(false, false); - LibFreeRDP.disconnect(session.getInstance()); - } - - return true; - } - - @Override - public void onBackPressed() { - // hide keyboards (if any visible) or send alt+f4 to the session - if (sysKeyboardVisible || extKeyboardVisible) - showKeyboard(false, false); - else - keyboardMapper.sendAltF4(); - } - - @Override - public boolean onKeyLongPress(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_BACK) { - LibFreeRDP.disconnect(session.getInstance()); - return true; - } - return super.onKeyLongPress(keyCode, event); - } - - // android keyboard input handling - // We always use the unicode value to process input from the android - // keyboard except if key modifiers - // (like Win, Alt, Ctrl) are activated. In this case we will send the - // virtual key code to allow key - // combinations (like Win + E to open the explorer). - @Override - public boolean onKeyDown(int keycode, KeyEvent event) { - return keyboardMapper.processAndroidKeyEvent(event); - } - - @Override - public boolean onKeyUp(int keycode, KeyEvent event) { - return keyboardMapper.processAndroidKeyEvent(event); - } - - // onKeyMultiple is called for input of some special characters like umlauts - // and some symbol characters - @Override - public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { - return keyboardMapper.processAndroidKeyEvent(event); - } - - // **************************************************************************** - // KeyboardView.KeyboardActionEventListener - @Override - public void onKey(int primaryCode, int[] keyCodes) { - keyboardMapper.processCustomKeyEvent(primaryCode); - } - - @Override - public void onText(CharSequence text) { - } - - @Override - public void swipeRight() { - } - - @Override - public void swipeLeft() { - } - - @Override - public void swipeDown() { - } - - @Override - public void swipeUp() { - } - - @Override - public void onPress(int primaryCode) { - } - - @Override - public void onRelease(int primaryCode) { - } - - // **************************************************************************** - // KeyboardMapper.KeyProcessingListener implementation - @Override - public void processVirtualKey(int virtualKeyCode, boolean down) { - LibFreeRDP.sendKeyEvent(session.getInstance(), virtualKeyCode, down); - } - - @Override - public void processUnicodeKey(int unicodeKey) { - LibFreeRDP.sendUnicodeKeyEvent(session.getInstance(), unicodeKey); - } - - @Override - public void switchKeyboard(int keyboardType) { - switch (keyboardType) { - case KeyboardMapper.KEYBOARD_TYPE_FUNCTIONKEYS: - keyboardView.setKeyboard(specialkeysKeyboard); - break; - - case KeyboardMapper.KEYBOARD_TYPE_NUMPAD: - keyboardView.setKeyboard(numpadKeyboard); - break; - - case KeyboardMapper.KEYBOARD_TYPE_CURSOR: - keyboardView.setKeyboard(cursorKeyboard); - break; - - default: - break; - } - } - - @Override - public void modifiersChanged() { - updateModifierKeyStates(); - } - - // **************************************************************************** - // LibFreeRDP UI event listener implementation - @Override - public void OnSettingsChanged(int width, int height, int bpp) { - - if (bpp > 16) - bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888); - else - bitmap = Bitmap.createBitmap(width, height, Config.RGB_565); - - session.setSurface(new BitmapDrawable(bitmap)); - - if (session.getBookmark() == null) { - // Return immediately if we launch from URI - return; - } - - // check this settings and initial settings - if they are not equal the - // server doesn't support our settings - // FIXME: the additional check (settings.getWidth() != width + 1) is for - // the RDVH bug fix to avoid accidental notifications - // (refer to android_freerdp.c for more info on this problem) - BookmarkBase.ScreenSettings settings = session.getBookmark() - .getActiveScreenSettings(); - if ((settings.getWidth() != width && settings.getWidth() != width + 1) - || settings.getHeight() != height - || settings.getColors() != bpp) - uiHandler - .sendMessage(Message.obtain( - null, - UIHandler.DISPLAY_TOAST, - getResources().getText( - R.string.info_capabilities_changed))); - } - - @Override - public void OnGraphicsUpdate(int x, int y, int width, int height) { - LibFreeRDP.updateGraphics(session.getInstance(), bitmap, x, y, width, - height); - - sessionView.addInvalidRegion(new Rect(x, y, x + width, y + height)); +public class SessionActivity extends AppCompatActivity + implements LibFreeRDP.UIEventListener, KeyboardView.OnKeyboardActionListener, + ScrollView2D.ScrollView2DListener, KeyboardMapper.KeyProcessingListener, + SessionView.SessionViewListener, TouchPointerView.TouchPointerListener, + ClipboardManagerProxy.OnClipboardChangedListener +{ + public static final String PARAM_CONNECTION_REFERENCE = "conRef"; + public static final String PARAM_INSTANCE = "instance"; + private static final float ZOOMING_STEP = 0.5f; + private static final int ZOOMCONTROLS_AUTOHIDE_TIMEOUT = 4000; + // timeout between subsequent scrolling requests when the touch-pointer is + // at the edge of the session view + private static final int SCROLLING_TIMEOUT = 50; + private static final int SCROLLING_DISTANCE = 20; + private static final String TAG = "FreeRDP.SessionActivity"; + // variables for delayed move event sending + private static final int MAX_DISCARDED_MOVE_EVENTS = 3; + private static final int SEND_MOVE_EVENT_TIMEOUT = 150; + private Bitmap bitmap; + private SessionState session; + private SessionView sessionView; + private TouchPointerView touchPointerView; + private ProgressDialog progressDialog; + private KeyboardView keyboardView; + private KeyboardView modifiersKeyboardView; + private ZoomControls zoomControls; + private KeyboardMapper keyboardMapper; + + private Keyboard specialkeysKeyboard; + private Keyboard numpadKeyboard; + private Keyboard cursorKeyboard; + private Keyboard modifiersKeyboard; + + private AlertDialog dlgVerifyCertificate; + private AlertDialog dlgUserCredentials; + private View userCredView; + + private UIHandler uiHandler; + + private int screen_width; + private int screen_height; + + private boolean connectCancelledByUser = false; + private boolean sessionRunning = false; + private boolean toggleMouseButtons = false; + + private LibFreeRDPBroadcastReceiver libFreeRDPBroadcastReceiver; + private ScrollView2D scrollView; + // keyboard visibility flags + private boolean sysKeyboardVisible = false; + private boolean extKeyboardVisible = false; + private int discardedMoveEvents = 0; + private ClipboardManagerProxy mClipboardManager; + private boolean callbackDialogResult; + View mDecor; + + private void createDialogs() + { + // build verify certificate dialog + dlgVerifyCertificate = + new AlertDialog.Builder(this) + .setTitle(R.string.dlg_title_verify_certificate) + .setPositiveButton(android.R.string.yes, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) + { + callbackDialogResult = true; + synchronized (dialog) + { + dialog.notify(); + } + } + }) + .setNegativeButton(android.R.string.no, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) + { + callbackDialogResult = false; + connectCancelledByUser = true; + synchronized (dialog) + { + dialog.notify(); + } + } + }) + .setCancelable(false) + .create(); + + // build the dialog + userCredView = getLayoutInflater().inflate(R.layout.credentials, null, true); + dlgUserCredentials = + new AlertDialog.Builder(this) + .setView(userCredView) + .setTitle(R.string.dlg_title_credentials) + .setPositiveButton(android.R.string.ok, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) + { + callbackDialogResult = true; + synchronized (dialog) + { + dialog.notify(); + } + } + }) + .setNegativeButton(android.R.string.cancel, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) + { + callbackDialogResult = false; + connectCancelledByUser = true; + synchronized (dialog) + { + dialog.notify(); + } + } + }) + .setCancelable(false) + .create(); + } + + private boolean hasHardwareMenuButton() + { + if (Build.VERSION.SDK_INT <= 10) + return true; + + if (Build.VERSION.SDK_INT >= 14) + { + boolean rc = false; + final ViewConfiguration cfg = ViewConfiguration.get(this); + + return cfg.hasPermanentMenuKey(); + } + + return false; + } + + @Override public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + + // show status bar or make fullscreen? + if (ApplicationSettingsActivity.getHideStatusBar(this)) + { + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + } + + this.setContentView(R.layout.session); + if (hasHardwareMenuButton() || ApplicationSettingsActivity.getHideActionBar(this)) + { + this.getSupportActionBar().hide(); + } + else + this.getSupportActionBar().show(); + + Log.v(TAG, "Session.onCreate"); + + // ATTENTION: We use the onGlobalLayout notification to start our + // session. + // This is because only then we can know the exact size of our session + // when using fit screen + // accounting for any status bars etc. that Android might throws on us. + // A bit weird looking + // but this is the only way ... + final View activityRootView = findViewById(R.id.session_root_view); + activityRootView.getViewTreeObserver().addOnGlobalLayoutListener( + new OnGlobalLayoutListener() { + @Override public void onGlobalLayout() + { + screen_width = activityRootView.getWidth(); + screen_height = activityRootView.getHeight(); + + // start session + if (!sessionRunning && getIntent() != null) + { + processIntent(getIntent()); + sessionRunning = true; + } + } + }); + + sessionView = (SessionView)findViewById(R.id.sessionView); + sessionView.setScaleGestureDetector( + new ScaleGestureDetector(this, new PinchZoomListener())); + sessionView.setSessionViewListener(this); + sessionView.requestFocus(); + + touchPointerView = (TouchPointerView)findViewById(R.id.touchPointerView); + touchPointerView.setTouchPointerListener(this); + + keyboardMapper = new KeyboardMapper(); + keyboardMapper.init(this); + keyboardMapper.reset(this); + + modifiersKeyboard = new Keyboard(getApplicationContext(), R.xml.modifiers_keyboard); + specialkeysKeyboard = new Keyboard(getApplicationContext(), R.xml.specialkeys_keyboard); + numpadKeyboard = new Keyboard(getApplicationContext(), R.xml.numpad_keyboard); + cursorKeyboard = new Keyboard(getApplicationContext(), R.xml.cursor_keyboard); + + // hide keyboard below the sessionView + keyboardView = (KeyboardView)findViewById(R.id.extended_keyboard); + keyboardView.setKeyboard(specialkeysKeyboard); + keyboardView.setOnKeyboardActionListener(this); + + modifiersKeyboardView = (KeyboardView)findViewById(R.id.extended_keyboard_header); + modifiersKeyboardView.setKeyboard(modifiersKeyboard); + modifiersKeyboardView.setOnKeyboardActionListener(this); + + scrollView = (ScrollView2D)findViewById(R.id.sessionScrollView); + scrollView.setScrollViewListener(this); + uiHandler = new UIHandler(); + libFreeRDPBroadcastReceiver = new LibFreeRDPBroadcastReceiver(); + + zoomControls = (ZoomControls)findViewById(R.id.zoomControls); + zoomControls.hide(); + zoomControls.setOnZoomInClickListener(new View.OnClickListener() { + @Override public void onClick(View v) + { + resetZoomControlsAutoHideTimeout(); + zoomControls.setIsZoomInEnabled(sessionView.zoomIn(ZOOMING_STEP)); + zoomControls.setIsZoomOutEnabled(true); + } + }); + zoomControls.setOnZoomOutClickListener(new View.OnClickListener() { + @Override public void onClick(View v) + { + resetZoomControlsAutoHideTimeout(); + zoomControls.setIsZoomOutEnabled(sessionView.zoomOut(ZOOMING_STEP)); + zoomControls.setIsZoomInEnabled(true); + } + }); + + toggleMouseButtons = false; + + createDialogs(); + + // register freerdp events broadcast receiver + IntentFilter filter = new IntentFilter(); + filter.addAction(GlobalApp.ACTION_EVENT_FREERDP); + registerReceiver(libFreeRDPBroadcastReceiver, filter); + + mClipboardManager = ClipboardManagerProxy.getClipboardManager(this); + mClipboardManager.addClipboardChangedListener(this); + + mDecor = getWindow().getDecorView(); + mDecor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); + } + + @Override protected void onStart() + { + super.onStart(); + Log.v(TAG, "Session.onStart"); + } + + @Override protected void onRestart() + { + super.onRestart(); + Log.v(TAG, "Session.onRestart"); + } + + @Override protected void onResume() + { + super.onResume(); + Log.v(TAG, "Session.onResume"); + } + + @Override protected void onPause() + { + super.onPause(); + Log.v(TAG, "Session.onPause"); + + // hide any visible keyboards + showKeyboard(false, false); + } + + @Override protected void onStop() + { + super.onStop(); + Log.v(TAG, "Session.onStop"); + } + + @Override protected void onDestroy() + { + super.onDestroy(); + Log.v(TAG, "Session.onDestroy"); + + // Cancel running disconnect timers. + GlobalApp.cancelDisconnectTimer(); + + // Disconnect all remaining sessions. + Collection sessions = GlobalApp.getSessions(); + for (SessionState session : sessions) + LibFreeRDP.disconnect(session.getInstance()); + + // unregister freerdp events broadcast receiver + unregisterReceiver(libFreeRDPBroadcastReceiver); + + // remove clipboard listener + mClipboardManager.removeClipboardboardChangedListener(this); + + // free session + GlobalApp.freeSession(session.getInstance()); + + session = null; + } + + @Override public void onConfigurationChanged(Configuration newConfig) + { + super.onConfigurationChanged(newConfig); + + // reload keyboard resources (changed from landscape) + modifiersKeyboard = new Keyboard(getApplicationContext(), R.xml.modifiers_keyboard); + specialkeysKeyboard = new Keyboard(getApplicationContext(), R.xml.specialkeys_keyboard); + numpadKeyboard = new Keyboard(getApplicationContext(), R.xml.numpad_keyboard); + cursorKeyboard = new Keyboard(getApplicationContext(), R.xml.cursor_keyboard); + + // apply loaded keyboards + keyboardView.setKeyboard(specialkeysKeyboard); + modifiersKeyboardView.setKeyboard(modifiersKeyboard); + + mDecor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); + } + + private void processIntent(Intent intent) + { + // get either session instance or create one from a bookmark/uri + Bundle bundle = intent.getExtras(); + Uri openUri = intent.getData(); + if (openUri != null) + { + // Launched from URI, e.g: + // freerdp://user@ip:port/connect?sound=&rfx=&p=password&clipboard=%2b&themes=- + connect(openUri); + } + else if (bundle.containsKey(PARAM_INSTANCE)) + { + int inst = bundle.getInt(PARAM_INSTANCE); + session = GlobalApp.getSession(inst); + bitmap = session.getSurface().getBitmap(); + bindSession(); + } + else if (bundle.containsKey(PARAM_CONNECTION_REFERENCE)) + { + BookmarkBase bookmark = null; + String refStr = bundle.getString(PARAM_CONNECTION_REFERENCE); + if (ConnectionReference.isHostnameReference(refStr)) + { + bookmark = new ManualBookmark(); + bookmark.get().setHostname(ConnectionReference.getHostname(refStr)); + } + else if (ConnectionReference.isBookmarkReference(refStr)) + { + if (ConnectionReference.isManualBookmarkReference(refStr)) + bookmark = GlobalApp.getManualBookmarkGateway().findById( + ConnectionReference.getManualBookmarkId(refStr)); + else + assert false; + } + + if (bookmark != null) + connect(bookmark); + else + closeSessionActivity(RESULT_CANCELED); + } + else + { + // no session found - exit + closeSessionActivity(RESULT_CANCELED); + } + } + + private void connect(BookmarkBase bookmark) + { + session = GlobalApp.createSession(bookmark, getApplicationContext()); + + BookmarkBase.ScreenSettings screenSettings = + session.getBookmark().getActiveScreenSettings(); + Log.v(TAG, "Screen Resolution: " + screenSettings.getResolutionString()); + if (screenSettings.isAutomatic()) + { + if ((getResources().getConfiguration().screenLayout & + Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE) + { + // large screen device i.e. tablet: simply use screen info + screenSettings.setHeight(screen_height); + screenSettings.setWidth(screen_width); + } + else + { + // small screen device i.e. phone: + // Automatic uses the largest side length of the screen and + // makes a 16:10 resolution setting out of it + int screenMax = (screen_width > screen_height) ? screen_width : screen_height; + screenSettings.setHeight(screenMax); + screenSettings.setWidth((int)((float)screenMax * 1.6f)); + } + } + if (screenSettings.isFitScreen()) + { + screenSettings.setHeight(screen_height); + screenSettings.setWidth(screen_width); + } + + connectWithTitle(bookmark.getLabel()); + } + + private void connect(Uri openUri) + { + session = GlobalApp.createSession(openUri, getApplicationContext()); + + connectWithTitle(openUri.getAuthority()); + } + + private void connectWithTitle(String title) + { + session.setUIEventListener(this); + + progressDialog = new ProgressDialog(this); + progressDialog.setTitle(title); + progressDialog.setMessage(getResources().getText(R.string.dlg_msg_connecting)); + progressDialog.setButton( + ProgressDialog.BUTTON_NEGATIVE, "Cancel", new DialogInterface.OnClickListener() { + @Override public void onClick(DialogInterface dialog, int which) + { + connectCancelledByUser = true; + LibFreeRDP.cancelConnection(session.getInstance()); + } + }); + progressDialog.setCancelable(false); + progressDialog.show(); + + Thread thread = new Thread(new Runnable() { + public void run() + { + session.connect(getApplicationContext()); + } + }); + thread.start(); + } + + // binds the current session to the activity by wiring it up with the + // sessionView and updating all internal objects accordingly + private void bindSession() + { + Log.v(TAG, "bindSession called"); + session.setUIEventListener(this); + sessionView.onSurfaceChange(session); + scrollView.requestLayout(); + keyboardMapper.reset(this); + mDecor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); + } + + private void hideSoftInput() + { + InputMethodManager mgr = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); + + if (mgr.isActive()) + { + mgr.toggleSoftInput(InputMethodManager.HIDE_NOT_ALWAYS, 0); + } + else + { + mgr.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS); + } + } + + // displays either the system or the extended keyboard or non of them + private void showKeyboard(final boolean showSystemKeyboard, final boolean showExtendedKeyboard) + { + // no matter what we are doing ... hide the zoom controls + // TODO: this is not working correctly as hiding the keyboard issues a + // onScrollChange notification showing the control again ... + uiHandler.removeMessages(UIHandler.HIDE_ZOOMCONTROLS); + if (zoomControls.getVisibility() == View.VISIBLE) + zoomControls.hide(); + + InputMethodManager mgr = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); + + if (showSystemKeyboard) + { + // hide extended keyboard + keyboardView.setVisibility(View.GONE); + // show system keyboard + mgr.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); + + // show modifiers keyboard + modifiersKeyboardView.setVisibility(View.VISIBLE); + } + else if (showExtendedKeyboard) + { + // hide system keyboard + hideSoftInput(); + + // show extended keyboard + keyboardView.setKeyboard(specialkeysKeyboard); + keyboardView.setVisibility(View.VISIBLE); + modifiersKeyboardView.setVisibility(View.VISIBLE); + } + else + { + // hide both + hideSoftInput(); + keyboardView.setVisibility(View.GONE); + modifiersKeyboardView.setVisibility(View.GONE); + + // clear any active key modifiers) + keyboardMapper.clearlAllModifiers(); + } + + sysKeyboardVisible = showSystemKeyboard; + extKeyboardVisible = showExtendedKeyboard; + } + + private void closeSessionActivity(int resultCode) + { + // Go back to home activity (and send intent data back to home) + setResult(resultCode, getIntent()); + finish(); + } + + // update the state of our modifier keys + private void updateModifierKeyStates() + { + // check if any key is in the keycodes list + + List keys = modifiersKeyboard.getKeys(); + for (Iterator it = keys.iterator(); it.hasNext();) + { + // if the key is a sticky key - just set it to off + Keyboard.Key curKey = it.next(); + if (curKey.sticky) + { + switch (keyboardMapper.getModifierState(curKey.codes[0])) + { + case KeyboardMapper.KEYSTATE_ON: + curKey.on = true; + curKey.pressed = false; + break; + + case KeyboardMapper.KEYSTATE_OFF: + curKey.on = false; + curKey.pressed = false; + break; + + case KeyboardMapper.KEYSTATE_LOCKED: + curKey.on = true; + curKey.pressed = true; + break; + } + } + } + + // refresh image + modifiersKeyboardView.invalidateAllKeys(); + } + + private void sendDelayedMoveEvent(int x, int y) + { + if (uiHandler.hasMessages(UIHandler.SEND_MOVE_EVENT)) + { + uiHandler.removeMessages(UIHandler.SEND_MOVE_EVENT); + discardedMoveEvents++; + } + else + discardedMoveEvents = 0; + + if (discardedMoveEvents > MAX_DISCARDED_MOVE_EVENTS) + LibFreeRDP.sendCursorEvent(session.getInstance(), x, y, Mouse.getMoveEvent()); + else + uiHandler.sendMessageDelayed(Message.obtain(null, UIHandler.SEND_MOVE_EVENT, x, y), + SEND_MOVE_EVENT_TIMEOUT); + } + + private void cancelDelayedMoveEvent() + { + uiHandler.removeMessages(UIHandler.SEND_MOVE_EVENT); + } + + @Override public boolean onCreateOptionsMenu(Menu menu) + { + getMenuInflater().inflate(R.menu.session_menu, menu); + return true; + } + + @Override public boolean onOptionsItemSelected(MenuItem item) + { + // refer to http://tools.android.com/tips/non-constant-fields why we + // can't use switch/case here .. + int itemId = item.getItemId(); + + if (itemId == R.id.session_touch_pointer) + { + // toggle touch pointer + if (touchPointerView.getVisibility() == View.VISIBLE) + { + touchPointerView.setVisibility(View.INVISIBLE); + sessionView.setTouchPointerPadding(0, 0); + } + else + { + touchPointerView.setVisibility(View.VISIBLE); + sessionView.setTouchPointerPadding(touchPointerView.getPointerWidth(), + touchPointerView.getPointerHeight()); + } + } + else if (itemId == R.id.session_sys_keyboard) + { + showKeyboard(!sysKeyboardVisible, false); + } + else if (itemId == R.id.session_ext_keyboard) + { + showKeyboard(false, !extKeyboardVisible); + } + else if (itemId == R.id.session_disconnect) + { + showKeyboard(false, false); + LibFreeRDP.disconnect(session.getInstance()); + } + + return true; + } + + @Override public void onBackPressed() + { + // hide keyboards (if any visible) or send alt+f4 to the session + if (sysKeyboardVisible || extKeyboardVisible) + showKeyboard(false, false); + else + keyboardMapper.sendAltF4(); + } + + @Override public boolean onKeyLongPress(int keyCode, KeyEvent event) + { + if (keyCode == KeyEvent.KEYCODE_BACK) + { + LibFreeRDP.disconnect(session.getInstance()); + return true; + } + return super.onKeyLongPress(keyCode, event); + } + + // android keyboard input handling + // We always use the unicode value to process input from the android + // keyboard except if key modifiers + // (like Win, Alt, Ctrl) are activated. In this case we will send the + // virtual key code to allow key + // combinations (like Win + E to open the explorer). + @Override public boolean onKeyDown(int keycode, KeyEvent event) + { + return keyboardMapper.processAndroidKeyEvent(event); + } + + @Override public boolean onKeyUp(int keycode, KeyEvent event) + { + return keyboardMapper.processAndroidKeyEvent(event); + } + + // onKeyMultiple is called for input of some special characters like umlauts + // and some symbol characters + @Override public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) + { + return keyboardMapper.processAndroidKeyEvent(event); + } + + // **************************************************************************** + // KeyboardView.KeyboardActionEventListener + @Override public void onKey(int primaryCode, int[] keyCodes) + { + keyboardMapper.processCustomKeyEvent(primaryCode); + } + + @Override public void onText(CharSequence text) + { + } + + @Override public void swipeRight() + { + } + + @Override public void swipeLeft() + { + } + + @Override public void swipeDown() + { + } + + @Override public void swipeUp() + { + } + + @Override public void onPress(int primaryCode) + { + } + + @Override public void onRelease(int primaryCode) + { + } + + // **************************************************************************** + // KeyboardMapper.KeyProcessingListener implementation + @Override public void processVirtualKey(int virtualKeyCode, boolean down) + { + LibFreeRDP.sendKeyEvent(session.getInstance(), virtualKeyCode, down); + } + + @Override public void processUnicodeKey(int unicodeKey) + { + LibFreeRDP.sendUnicodeKeyEvent(session.getInstance(), unicodeKey, true); + LibFreeRDP.sendUnicodeKeyEvent(session.getInstance(), unicodeKey, false); + } + + @Override public void switchKeyboard(int keyboardType) + { + switch (keyboardType) + { + case KeyboardMapper.KEYBOARD_TYPE_FUNCTIONKEYS: + keyboardView.setKeyboard(specialkeysKeyboard); + break; + + case KeyboardMapper.KEYBOARD_TYPE_NUMPAD: + keyboardView.setKeyboard(numpadKeyboard); + break; + + case KeyboardMapper.KEYBOARD_TYPE_CURSOR: + keyboardView.setKeyboard(cursorKeyboard); + break; + + default: + break; + } + } + + @Override public void modifiersChanged() + { + updateModifierKeyStates(); + } + + // **************************************************************************** + // LibFreeRDP UI event listener implementation + @Override public void OnSettingsChanged(int width, int height, int bpp) + { + + if (bpp > 16) + bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888); + else + bitmap = Bitmap.createBitmap(width, height, Config.RGB_565); + + session.setSurface(new BitmapDrawable(bitmap)); + + if (session.getBookmark() == null) + { + // Return immediately if we launch from URI + return; + } + + // check this settings and initial settings - if they are not equal the + // server doesn't support our settings + // FIXME: the additional check (settings.getWidth() != width + 1) is for + // the RDVH bug fix to avoid accidental notifications + // (refer to android_freerdp.c for more info on this problem) + BookmarkBase.ScreenSettings settings = session.getBookmark().getActiveScreenSettings(); + if ((settings.getWidth() != width && settings.getWidth() != width + 1) || + settings.getHeight() != height || settings.getColors() != bpp) + uiHandler.sendMessage( + Message.obtain(null, UIHandler.DISPLAY_TOAST, + getResources().getText(R.string.info_capabilities_changed))); + } + + @Override public void OnGraphicsUpdate(int x, int y, int width, int height) + { + LibFreeRDP.updateGraphics(session.getInstance(), bitmap, x, y, width, height); + + sessionView.addInvalidRegion(new Rect(x, y, x + width, y + height)); /* - * since sessionView can only be modified from the UI thread any + * since sessionView can only be modified from the UI thread any * modifications to it need to be scheduled */ - uiHandler.sendEmptyMessage(UIHandler.REFRESH_SESSIONVIEW); - } + uiHandler.sendEmptyMessage(UIHandler.REFRESH_SESSIONVIEW); + } - @Override - public void OnGraphicsResize(int width, int height, int bpp) { - // replace bitmap - if (bpp > 16) - bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888); - else - bitmap = Bitmap.createBitmap(width, height, Config.RGB_565); - session.setSurface(new BitmapDrawable(bitmap)); + @Override public void OnGraphicsResize(int width, int height, int bpp) + { + // replace bitmap + if (bpp > 16) + bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888); + else + bitmap = Bitmap.createBitmap(width, height, Config.RGB_565); + session.setSurface(new BitmapDrawable(bitmap)); /* - * since sessionView can only be modified from the UI thread any + * since sessionView can only be modified from the UI thread any * modifications to it need to be scheduled */ - uiHandler.sendEmptyMessage(UIHandler.GRAPHICS_CHANGED); - } - - @Override - public boolean OnAuthenticate(StringBuilder username, StringBuilder domain, - StringBuilder password) { - // this is where the return code of our dialog will be stored - callbackDialogResult = false; - - // set text fields - ((EditText) userCredView.findViewById(R.id.editTextUsername)) - .setText(username); - ((EditText) userCredView.findViewById(R.id.editTextDomain)) - .setText(domain); - ((EditText) userCredView.findViewById(R.id.editTextPassword)) - .setText(password); - - // start dialog in UI thread - uiHandler.sendMessage(Message.obtain(null, UIHandler.SHOW_DIALOG, - dlgUserCredentials)); - - // wait for result - try { - synchronized (dlgUserCredentials) { - dlgUserCredentials.wait(); - } - } catch (InterruptedException e) { - } - - // clear buffers - username.setLength(0); - domain.setLength(0); - password.setLength(0); - - // read back user credentials - username.append(((EditText) userCredView - .findViewById(R.id.editTextUsername)).getText().toString()); - domain.append(((EditText) userCredView - .findViewById(R.id.editTextDomain)).getText().toString()); - password.append(((EditText) userCredView - .findViewById(R.id.editTextPassword)).getText().toString()); - - return callbackDialogResult; - } - - @Override - public boolean OnGatewayAuthenticate(StringBuilder username, StringBuilder domain, StringBuilder password) { - // this is where the return code of our dialog will be stored - callbackDialogResult = false; - - // set text fields - ((EditText) userCredView.findViewById(R.id.editTextUsername)) - .setText(username); - ((EditText) userCredView.findViewById(R.id.editTextDomain)) - .setText(domain); - ((EditText) userCredView.findViewById(R.id.editTextPassword)) - .setText(password); - - // start dialog in UI thread - uiHandler.sendMessage(Message.obtain(null, UIHandler.SHOW_DIALOG, - dlgUserCredentials)); - - // wait for result - try { - synchronized (dlgUserCredentials) { - dlgUserCredentials.wait(); - } - } catch (InterruptedException e) { - } - - // clear buffers - username.setLength(0); - domain.setLength(0); - password.setLength(0); - - // read back user credentials - username.append(((EditText) userCredView - .findViewById(R.id.editTextUsername)).getText().toString()); - domain.append(((EditText) userCredView - .findViewById(R.id.editTextDomain)).getText().toString()); - password.append(((EditText) userCredView - .findViewById(R.id.editTextPassword)).getText().toString()); - - return callbackDialogResult; - } - - @Override - public int OnVerifiyCertificate(String commonName, String subject, String issuer, String fingerprint, boolean mismatch) { - // see if global settings says accept all - if (ApplicationSettingsActivity.getAcceptAllCertificates(this)) - return 0; - - // this is where the return code of our dialog will be stored - callbackDialogResult = false; - - // set message - String msg = getResources().getString( - R.string.dlg_msg_verify_certificate); - msg = msg + "\n\nSubject: " + subject + "\nIssuer: " + issuer - + "\nFingerprint: " + fingerprint; - dlgVerifyCertificate.setMessage(msg); - - // start dialog in UI thread - uiHandler.sendMessage(Message.obtain(null, UIHandler.SHOW_DIALOG, - dlgVerifyCertificate)); - - // wait for result - try { - synchronized (dlgVerifyCertificate) { - dlgVerifyCertificate.wait(); - } - } catch (InterruptedException e) { - } - - return callbackDialogResult ? 1 : 0; - } - - @Override - public int OnVerifyChangedCertificate(String commonName, String subject, String issuer, String fingerprint, String oldSubject, String oldIssuer, String oldFingerprint) { - // see if global settings says accept all - if (ApplicationSettingsActivity.getAcceptAllCertificates(this)) - return 0; - - // this is where the return code of our dialog will be stored - callbackDialogResult = false; - - // set message - String msg = getResources().getString( - R.string.dlg_msg_verify_certificate); - msg = msg + "\n\nSubject: " + subject + "\nIssuer: " + issuer - + "\nFingerprint: " + fingerprint; - dlgVerifyCertificate.setMessage(msg); - - // start dialog in UI thread - uiHandler.sendMessage(Message.obtain(null, UIHandler.SHOW_DIALOG, - dlgVerifyCertificate)); - - // wait for result - try { - synchronized (dlgVerifyCertificate) { - dlgVerifyCertificate.wait(); - } - } catch (InterruptedException e) { - } - - return callbackDialogResult ? 1 : 0; - } - - @Override - public void OnRemoteClipboardChanged(String data) { - Log.v(TAG, "OnRemoteClipboardChanged: " + data); - mClipboardManager.setClipboardData(data); - } - - // **************************************************************************** - // ScrollView2DListener implementation - private void resetZoomControlsAutoHideTimeout() { - uiHandler.removeMessages(UIHandler.HIDE_ZOOMCONTROLS); - uiHandler.sendEmptyMessageDelayed(UIHandler.HIDE_ZOOMCONTROLS, - ZOOMCONTROLS_AUTOHIDE_TIMEOUT); - } - - @Override - public void onScrollChanged(ScrollView2D scrollView, int x, int y, - int oldx, int oldy) { - zoomControls.setIsZoomInEnabled(!sessionView.isAtMaxZoom()); - zoomControls.setIsZoomOutEnabled(!sessionView.isAtMinZoom()); - if (!ApplicationSettingsActivity.getHideZoomControls(this) - && zoomControls.getVisibility() != View.VISIBLE) - zoomControls.show(); - resetZoomControlsAutoHideTimeout(); - } - - // **************************************************************************** - // SessionView.SessionViewListener - @Override - public void onSessionViewBeginTouch() { - scrollView.setScrollEnabled(false); - } - - @Override - public void onSessionViewEndTouch() { - scrollView.setScrollEnabled(true); - } - - @Override - public void onSessionViewLeftTouch(int x, int y, boolean down) { - if (!down) - cancelDelayedMoveEvent(); - - LibFreeRDP.sendCursorEvent( - session.getInstance(), - x, - y, - toggleMouseButtons ? Mouse.getRightButtonEvent(this, down) : Mouse - .getLeftButtonEvent(this, down)); - - if (!down) - toggleMouseButtons = false; - } - - public void onSessionViewRightTouch(int x, int y, boolean down) { - if (!down) - toggleMouseButtons = !toggleMouseButtons; - } - - @Override - public void onSessionViewMove(int x, int y) { - sendDelayedMoveEvent(x, y); - } - - @Override - public void onSessionViewScroll(boolean down) { - LibFreeRDP.sendCursorEvent(session.getInstance(), 0, 0, - Mouse.getScrollEvent(this, down)); - } - - // **************************************************************************** - // TouchPointerView.TouchPointerListener - @Override - public void onTouchPointerClose() { - touchPointerView.setVisibility(View.INVISIBLE); - sessionView.setTouchPointerPadding(0, 0); - } - - private Point mapScreenCoordToSessionCoord(int x, int y) { - int mappedX = (int) ((float) (x + scrollView.getScrollX()) / sessionView - .getZoom()); - int mappedY = (int) ((float) (y + scrollView.getScrollY()) / sessionView - .getZoom()); - if (mappedX > bitmap.getWidth()) - mappedX = bitmap.getWidth(); - if (mappedY > bitmap.getHeight()) - mappedY = bitmap.getHeight(); - return new Point(mappedX, mappedY); - } - - @Override - public void onTouchPointerLeftClick(int x, int y, boolean down) { - Point p = mapScreenCoordToSessionCoord(x, y); - LibFreeRDP.sendCursorEvent(session.getInstance(), p.x, p.y, - Mouse.getLeftButtonEvent(this, down)); - } - - @Override - public void onTouchPointerRightClick(int x, int y, boolean down) { - Point p = mapScreenCoordToSessionCoord(x, y); - LibFreeRDP.sendCursorEvent(session.getInstance(), p.x, p.y, - Mouse.getRightButtonEvent(this, down)); - } - - @Override - public void onTouchPointerMove(int x, int y) { - Point p = mapScreenCoordToSessionCoord(x, y); - LibFreeRDP.sendCursorEvent(session.getInstance(), p.x, p.y, - Mouse.getMoveEvent()); - - if (ApplicationSettingsActivity.getAutoScrollTouchPointer(this) - && !uiHandler.hasMessages(UIHandler.SCROLLING_REQUESTED)) { - Log.v(TAG, "Starting auto-scroll"); - uiHandler.sendEmptyMessageDelayed(UIHandler.SCROLLING_REQUESTED, - SCROLLING_TIMEOUT); - } - } - - @Override - public void onTouchPointerScroll(boolean down) { - LibFreeRDP.sendCursorEvent(session.getInstance(), 0, 0, - Mouse.getScrollEvent(this, down)); - } - - @Override - public void onTouchPointerToggleKeyboard() { - showKeyboard(!sysKeyboardVisible, false); - } - - @Override - public void onTouchPointerToggleExtKeyboard() { - showKeyboard(false, !extKeyboardVisible); - } - - @Override - public void onTouchPointerResetScrollZoom() { - sessionView.setZoom(1.0f); - scrollView.scrollTo(0, 0); - } - - @Override - public boolean onGenericMotionEvent(MotionEvent e) { - super.onGenericMotionEvent(e); - switch (e.getAction()) { - case MotionEvent.ACTION_SCROLL: - final float vScroll = e.getAxisValue(MotionEvent.AXIS_VSCROLL); - if (vScroll < 0) { - LibFreeRDP.sendCursorEvent(session.getInstance(), 0, 0, Mouse.getScrollEvent(this, false)); - } - if (vScroll > 0) { - LibFreeRDP.sendCursorEvent(session.getInstance(), 0, 0, Mouse.getScrollEvent(this, true)); - } - break; - } - return true; - } - - // **************************************************************************** - // ClipboardManagerProxy.OnClipboardChangedListener - @Override - public void onClipboardChanged(String data) { - Log.v(TAG, "onClipboardChanged: " + data); - LibFreeRDP.sendClipboardData(session.getInstance(), data); - } - - private class UIHandler extends Handler { - - public static final int REFRESH_SESSIONVIEW = 1; - public static final int DISPLAY_TOAST = 2; - public static final int HIDE_ZOOMCONTROLS = 3; - public static final int SEND_MOVE_EVENT = 4; - public static final int SHOW_DIALOG = 5; - public static final int GRAPHICS_CHANGED = 6; - public static final int SCROLLING_REQUESTED = 7; - - UIHandler() { - super(); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case GRAPHICS_CHANGED: { - sessionView.onSurfaceChange(session); - scrollView.requestLayout(); - break; - } - case REFRESH_SESSIONVIEW: { - sessionView.invalidateRegion(); - break; - } - case DISPLAY_TOAST: { - Toast errorToast = Toast.makeText(getApplicationContext(), - msg.obj.toString(), Toast.LENGTH_LONG); - errorToast.show(); - break; - } - case HIDE_ZOOMCONTROLS: { - zoomControls.hide(); - break; - } - case SEND_MOVE_EVENT: { - LibFreeRDP.sendCursorEvent(session.getInstance(), msg.arg1, - msg.arg2, Mouse.getMoveEvent()); - break; - } - case SHOW_DIALOG: { - // create and show the dialog - ((Dialog) msg.obj).show(); - break; - } - case SCROLLING_REQUESTED: { - int scrollX = 0; - int scrollY = 0; - float[] pointerPos = touchPointerView.getPointerPosition(); - - if (pointerPos[0] > (screen_width - touchPointerView - .getPointerWidth())) - scrollX = SCROLLING_DISTANCE; - else if (pointerPos[0] < 0) - scrollX = -SCROLLING_DISTANCE; - - if (pointerPos[1] > (screen_height - touchPointerView - .getPointerHeight())) - scrollY = SCROLLING_DISTANCE; - else if (pointerPos[1] < 0) - scrollY = -SCROLLING_DISTANCE; - - scrollView.scrollBy(scrollX, scrollY); - - // see if we reached the min/max scroll positions - if (scrollView.getScrollX() == 0 - || scrollView.getScrollX() == (sessionView.getWidth() - scrollView - .getWidth())) - scrollX = 0; - if (scrollView.getScrollY() == 0 - || scrollView.getScrollY() == (sessionView.getHeight() - scrollView - .getHeight())) - scrollY = 0; - - if (scrollX != 0 || scrollY != 0) - uiHandler.sendEmptyMessageDelayed(SCROLLING_REQUESTED, - SCROLLING_TIMEOUT); - else - Log.v(TAG, "Stopping auto-scroll"); - break; - } - } - } - } - - private class PinchZoomListener extends - ScaleGestureDetector.SimpleOnScaleGestureListener { - private float scaleFactor = 1.0f; - - @Override - public boolean onScaleBegin(ScaleGestureDetector detector) { - scrollView.setScrollEnabled(false); - return true; - } - - @Override - public boolean onScale(ScaleGestureDetector detector) { - - // calc scale factor - scaleFactor *= detector.getScaleFactor(); - scaleFactor = Math.max(SessionView.MIN_SCALE_FACTOR, - Math.min(scaleFactor, SessionView.MAX_SCALE_FACTOR)); - sessionView.setZoom(scaleFactor); - - if (!sessionView.isAtMinZoom() && !sessionView.isAtMaxZoom()) { - // transform scroll origin to the new zoom space - float transOriginX = scrollView.getScrollX() - * detector.getScaleFactor(); - float transOriginY = scrollView.getScrollY() - * detector.getScaleFactor(); - - // transform center point to the zoomed space - float transCenterX = (scrollView.getScrollX() + detector - .getFocusX()) * detector.getScaleFactor(); - float transCenterY = (scrollView.getScrollY() + detector - .getFocusY()) * detector.getScaleFactor(); - - // scroll by the difference between the distance of the - // transformed center/origin point and their old distance - // (focusX/Y) - scrollView.scrollBy( - (int) ((transCenterX - transOriginX) - detector - .getFocusX()), - (int) ((transCenterY - transOriginY) - detector - .getFocusY())); - } - - return true; - } - - @Override - public void onScaleEnd(ScaleGestureDetector de) { - scrollView.setScrollEnabled(true); - } - } - - private class LibFreeRDPBroadcastReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - // still got a valid session? - if (session == null) - return; - - // is this event for the current session? - if (session.getInstance() != intent.getExtras().getLong( - GlobalApp.EVENT_PARAM, -1)) - return; - - switch (intent.getExtras().getInt(GlobalApp.EVENT_TYPE, -1)) { - case GlobalApp.FREERDP_EVENT_CONNECTION_SUCCESS: - OnConnectionSuccess(context); - break; - - case GlobalApp.FREERDP_EVENT_CONNECTION_FAILURE: - OnConnectionFailure(context); - break; - case GlobalApp.FREERDP_EVENT_DISCONNECTED: - OnDisconnected(context); - break; - } - } - - private void OnConnectionSuccess(Context context) { - Log.v(TAG, "OnConnectionSuccess"); - - // bind session - bindSession(); - - if (progressDialog != null) { - progressDialog.dismiss(); - progressDialog = null; - } - - if (session.getBookmark() == null) { - // Return immediately if we launch from URI - return; - } - - // add hostname to history if quick connect was used - Bundle bundle = getIntent().getExtras(); - if (bundle != null - && bundle.containsKey(PARAM_CONNECTION_REFERENCE)) { - if (ConnectionReference.isHostnameReference(bundle - .getString(PARAM_CONNECTION_REFERENCE))) { - assert session.getBookmark().getType() == BookmarkBase.TYPE_MANUAL; - String item = session.getBookmark().get() - .getHostname(); - if (!GlobalApp.getQuickConnectHistoryGateway() - .historyItemExists(item)) - GlobalApp.getQuickConnectHistoryGateway() - .addHistoryItem(item); - } - } - } - - private void OnConnectionFailure(Context context) { - Log.v(TAG, "OnConnectionFailure"); - - // remove pending move events - uiHandler.removeMessages(UIHandler.SEND_MOVE_EVENT); - - if (progressDialog != null) { - progressDialog.dismiss(); - progressDialog = null; - } - - // post error message on UI thread - if (!connectCancelledByUser) - uiHandler.sendMessage(Message.obtain( - null, - UIHandler.DISPLAY_TOAST, - getResources().getText( - R.string.error_connection_failure))); - - closeSessionActivity(RESULT_CANCELED); - } - - private void OnDisconnected(Context context) { - Log.v(TAG, "OnDisconnected"); - - // remove pending move events - uiHandler.removeMessages(UIHandler.SEND_MOVE_EVENT); - - if (progressDialog != null) { - progressDialog.dismiss(); - progressDialog = null; - } - - session.setUIEventListener(null); - closeSessionActivity(RESULT_OK); - } - } - + uiHandler.sendEmptyMessage(UIHandler.GRAPHICS_CHANGED); + } + + @Override + public boolean OnAuthenticate(StringBuilder username, StringBuilder domain, + StringBuilder password) + { + // this is where the return code of our dialog will be stored + callbackDialogResult = false; + + // set text fields + ((EditText)userCredView.findViewById(R.id.editTextUsername)).setText(username); + ((EditText)userCredView.findViewById(R.id.editTextDomain)).setText(domain); + ((EditText)userCredView.findViewById(R.id.editTextPassword)).setText(password); + + // start dialog in UI thread + uiHandler.sendMessage(Message.obtain(null, UIHandler.SHOW_DIALOG, dlgUserCredentials)); + + // wait for result + try + { + synchronized (dlgUserCredentials) + { + dlgUserCredentials.wait(); + } + } + catch (InterruptedException e) + { + } + + // clear buffers + username.setLength(0); + domain.setLength(0); + password.setLength(0); + + // read back user credentials + username.append( + ((EditText)userCredView.findViewById(R.id.editTextUsername)).getText().toString()); + domain.append( + ((EditText)userCredView.findViewById(R.id.editTextDomain)).getText().toString()); + password.append( + ((EditText)userCredView.findViewById(R.id.editTextPassword)).getText().toString()); + + return callbackDialogResult; + } + + @Override + public boolean OnGatewayAuthenticate(StringBuilder username, StringBuilder domain, + StringBuilder password) + { + // this is where the return code of our dialog will be stored + callbackDialogResult = false; + + // set text fields + ((EditText)userCredView.findViewById(R.id.editTextUsername)).setText(username); + ((EditText)userCredView.findViewById(R.id.editTextDomain)).setText(domain); + ((EditText)userCredView.findViewById(R.id.editTextPassword)).setText(password); + + // start dialog in UI thread + uiHandler.sendMessage(Message.obtain(null, UIHandler.SHOW_DIALOG, dlgUserCredentials)); + + // wait for result + try + { + synchronized (dlgUserCredentials) + { + dlgUserCredentials.wait(); + } + } + catch (InterruptedException e) + { + } + + // clear buffers + username.setLength(0); + domain.setLength(0); + password.setLength(0); + + // read back user credentials + username.append( + ((EditText)userCredView.findViewById(R.id.editTextUsername)).getText().toString()); + domain.append( + ((EditText)userCredView.findViewById(R.id.editTextDomain)).getText().toString()); + password.append( + ((EditText)userCredView.findViewById(R.id.editTextPassword)).getText().toString()); + + return callbackDialogResult; + } + + @Override + public int OnVerifiyCertificate(String commonName, String subject, String issuer, + String fingerprint, boolean mismatch) + { + // see if global settings says accept all + if (ApplicationSettingsActivity.getAcceptAllCertificates(this)) + return 0; + + // this is where the return code of our dialog will be stored + callbackDialogResult = false; + + // set message + String msg = getResources().getString(R.string.dlg_msg_verify_certificate); + msg = msg + "\n\nSubject: " + subject + "\nIssuer: " + issuer + + "\nFingerprint: " + fingerprint; + dlgVerifyCertificate.setMessage(msg); + + // start dialog in UI thread + uiHandler.sendMessage(Message.obtain(null, UIHandler.SHOW_DIALOG, dlgVerifyCertificate)); + + // wait for result + try + { + synchronized (dlgVerifyCertificate) + { + dlgVerifyCertificate.wait(); + } + } + catch (InterruptedException e) + { + } + + return callbackDialogResult ? 1 : 0; + } + + @Override + public int OnVerifyChangedCertificate(String commonName, String subject, String issuer, + String fingerprint, String oldSubject, String oldIssuer, + String oldFingerprint) + { + // see if global settings says accept all + if (ApplicationSettingsActivity.getAcceptAllCertificates(this)) + return 0; + + // this is where the return code of our dialog will be stored + callbackDialogResult = false; + + // set message + String msg = getResources().getString(R.string.dlg_msg_verify_certificate); + msg = msg + "\n\nSubject: " + subject + "\nIssuer: " + issuer + + "\nFingerprint: " + fingerprint; + dlgVerifyCertificate.setMessage(msg); + + // start dialog in UI thread + uiHandler.sendMessage(Message.obtain(null, UIHandler.SHOW_DIALOG, dlgVerifyCertificate)); + + // wait for result + try + { + synchronized (dlgVerifyCertificate) + { + dlgVerifyCertificate.wait(); + } + } + catch (InterruptedException e) + { + } + + return callbackDialogResult ? 1 : 0; + } + + @Override public void OnRemoteClipboardChanged(String data) + { + Log.v(TAG, "OnRemoteClipboardChanged: " + data); + mClipboardManager.setClipboardData(data); + } + + // **************************************************************************** + // ScrollView2DListener implementation + private void resetZoomControlsAutoHideTimeout() + { + uiHandler.removeMessages(UIHandler.HIDE_ZOOMCONTROLS); + uiHandler.sendEmptyMessageDelayed(UIHandler.HIDE_ZOOMCONTROLS, + ZOOMCONTROLS_AUTOHIDE_TIMEOUT); + } + + @Override public void onScrollChanged(ScrollView2D scrollView, int x, int y, int oldx, int oldy) + { + zoomControls.setIsZoomInEnabled(!sessionView.isAtMaxZoom()); + zoomControls.setIsZoomOutEnabled(!sessionView.isAtMinZoom()); + if (!ApplicationSettingsActivity.getHideZoomControls(this) && + zoomControls.getVisibility() != View.VISIBLE) + zoomControls.show(); + resetZoomControlsAutoHideTimeout(); + } + + // **************************************************************************** + // SessionView.SessionViewListener + @Override public void onSessionViewBeginTouch() + { + scrollView.setScrollEnabled(false); + } + + @Override public void onSessionViewEndTouch() + { + scrollView.setScrollEnabled(true); + } + + @Override public void onSessionViewLeftTouch(int x, int y, boolean down) + { + if (!down) + cancelDelayedMoveEvent(); + + LibFreeRDP.sendCursorEvent(session.getInstance(), x, y, + toggleMouseButtons ? Mouse.getRightButtonEvent(this, down) + : Mouse.getLeftButtonEvent(this, down)); + + if (!down) + toggleMouseButtons = false; + } + + public void onSessionViewRightTouch(int x, int y, boolean down) + { + if (!down) + toggleMouseButtons = !toggleMouseButtons; + } + + @Override public void onSessionViewMove(int x, int y) + { + sendDelayedMoveEvent(x, y); + } + + @Override public void onSessionViewScroll(boolean down) + { + LibFreeRDP.sendCursorEvent(session.getInstance(), 0, 0, Mouse.getScrollEvent(this, down)); + } + + // **************************************************************************** + // TouchPointerView.TouchPointerListener + @Override public void onTouchPointerClose() + { + touchPointerView.setVisibility(View.INVISIBLE); + sessionView.setTouchPointerPadding(0, 0); + } + + private Point mapScreenCoordToSessionCoord(int x, int y) + { + int mappedX = (int)((float)(x + scrollView.getScrollX()) / sessionView.getZoom()); + int mappedY = (int)((float)(y + scrollView.getScrollY()) / sessionView.getZoom()); + if (mappedX > bitmap.getWidth()) + mappedX = bitmap.getWidth(); + if (mappedY > bitmap.getHeight()) + mappedY = bitmap.getHeight(); + return new Point(mappedX, mappedY); + } + + @Override public void onTouchPointerLeftClick(int x, int y, boolean down) + { + Point p = mapScreenCoordToSessionCoord(x, y); + LibFreeRDP.sendCursorEvent(session.getInstance(), p.x, p.y, + Mouse.getLeftButtonEvent(this, down)); + } + + @Override public void onTouchPointerRightClick(int x, int y, boolean down) + { + Point p = mapScreenCoordToSessionCoord(x, y); + LibFreeRDP.sendCursorEvent(session.getInstance(), p.x, p.y, + Mouse.getRightButtonEvent(this, down)); + } + + @Override public void onTouchPointerMove(int x, int y) + { + Point p = mapScreenCoordToSessionCoord(x, y); + LibFreeRDP.sendCursorEvent(session.getInstance(), p.x, p.y, Mouse.getMoveEvent()); + + if (ApplicationSettingsActivity.getAutoScrollTouchPointer(this) && + !uiHandler.hasMessages(UIHandler.SCROLLING_REQUESTED)) + { + Log.v(TAG, "Starting auto-scroll"); + uiHandler.sendEmptyMessageDelayed(UIHandler.SCROLLING_REQUESTED, SCROLLING_TIMEOUT); + } + } + + @Override public void onTouchPointerScroll(boolean down) + { + LibFreeRDP.sendCursorEvent(session.getInstance(), 0, 0, Mouse.getScrollEvent(this, down)); + } + + @Override public void onTouchPointerToggleKeyboard() + { + showKeyboard(!sysKeyboardVisible, false); + } + + @Override public void onTouchPointerToggleExtKeyboard() + { + showKeyboard(false, !extKeyboardVisible); + } + + @Override public void onTouchPointerResetScrollZoom() + { + sessionView.setZoom(1.0f); + scrollView.scrollTo(0, 0); + } + + @Override public boolean onGenericMotionEvent(MotionEvent e) + { + super.onGenericMotionEvent(e); + switch (e.getAction()) + { + case MotionEvent.ACTION_SCROLL: + final float vScroll = e.getAxisValue(MotionEvent.AXIS_VSCROLL); + if (vScroll < 0) + { + LibFreeRDP.sendCursorEvent(session.getInstance(), 0, 0, + Mouse.getScrollEvent(this, false)); + } + if (vScroll > 0) + { + LibFreeRDP.sendCursorEvent(session.getInstance(), 0, 0, + Mouse.getScrollEvent(this, true)); + } + break; + } + return true; + } + + // **************************************************************************** + // ClipboardManagerProxy.OnClipboardChangedListener + @Override public void onClipboardChanged(String data) + { + Log.v(TAG, "onClipboardChanged: " + data); + LibFreeRDP.sendClipboardData(session.getInstance(), data); + } + + private class UIHandler extends Handler + { + + public static final int REFRESH_SESSIONVIEW = 1; + public static final int DISPLAY_TOAST = 2; + public static final int HIDE_ZOOMCONTROLS = 3; + public static final int SEND_MOVE_EVENT = 4; + public static final int SHOW_DIALOG = 5; + public static final int GRAPHICS_CHANGED = 6; + public static final int SCROLLING_REQUESTED = 7; + + UIHandler() + { + super(); + } + + @Override public void handleMessage(Message msg) + { + switch (msg.what) + { + case GRAPHICS_CHANGED: + { + sessionView.onSurfaceChange(session); + scrollView.requestLayout(); + break; + } + case REFRESH_SESSIONVIEW: + { + sessionView.invalidateRegion(); + break; + } + case DISPLAY_TOAST: + { + Toast errorToast = Toast.makeText(getApplicationContext(), msg.obj.toString(), + Toast.LENGTH_LONG); + errorToast.show(); + break; + } + case HIDE_ZOOMCONTROLS: + { + zoomControls.hide(); + break; + } + case SEND_MOVE_EVENT: + { + LibFreeRDP.sendCursorEvent(session.getInstance(), msg.arg1, msg.arg2, + Mouse.getMoveEvent()); + break; + } + case SHOW_DIALOG: + { + // create and show the dialog + ((Dialog)msg.obj).show(); + break; + } + case SCROLLING_REQUESTED: + { + int scrollX = 0; + int scrollY = 0; + float[] pointerPos = touchPointerView.getPointerPosition(); + + if (pointerPos[0] > (screen_width - touchPointerView.getPointerWidth())) + scrollX = SCROLLING_DISTANCE; + else if (pointerPos[0] < 0) + scrollX = -SCROLLING_DISTANCE; + + if (pointerPos[1] > (screen_height - touchPointerView.getPointerHeight())) + scrollY = SCROLLING_DISTANCE; + else if (pointerPos[1] < 0) + scrollY = -SCROLLING_DISTANCE; + + scrollView.scrollBy(scrollX, scrollY); + + // see if we reached the min/max scroll positions + if (scrollView.getScrollX() == 0 || + scrollView.getScrollX() == (sessionView.getWidth() - scrollView.getWidth())) + scrollX = 0; + if (scrollView.getScrollY() == 0 || + scrollView.getScrollY() == + (sessionView.getHeight() - scrollView.getHeight())) + scrollY = 0; + + if (scrollX != 0 || scrollY != 0) + uiHandler.sendEmptyMessageDelayed(SCROLLING_REQUESTED, SCROLLING_TIMEOUT); + else + Log.v(TAG, "Stopping auto-scroll"); + break; + } + } + } + } + + private class PinchZoomListener extends ScaleGestureDetector.SimpleOnScaleGestureListener + { + private float scaleFactor = 1.0f; + + @Override public boolean onScaleBegin(ScaleGestureDetector detector) + { + scrollView.setScrollEnabled(false); + return true; + } + + @Override public boolean onScale(ScaleGestureDetector detector) + { + + // calc scale factor + scaleFactor *= detector.getScaleFactor(); + scaleFactor = Math.max(SessionView.MIN_SCALE_FACTOR, + Math.min(scaleFactor, SessionView.MAX_SCALE_FACTOR)); + sessionView.setZoom(scaleFactor); + + if (!sessionView.isAtMinZoom() && !sessionView.isAtMaxZoom()) + { + // transform scroll origin to the new zoom space + float transOriginX = scrollView.getScrollX() * detector.getScaleFactor(); + float transOriginY = scrollView.getScrollY() * detector.getScaleFactor(); + + // transform center point to the zoomed space + float transCenterX = + (scrollView.getScrollX() + detector.getFocusX()) * detector.getScaleFactor(); + float transCenterY = + (scrollView.getScrollY() + detector.getFocusY()) * detector.getScaleFactor(); + + // scroll by the difference between the distance of the + // transformed center/origin point and their old distance + // (focusX/Y) + scrollView.scrollBy((int)((transCenterX - transOriginX) - detector.getFocusX()), + (int)((transCenterY - transOriginY) - detector.getFocusY())); + } + + return true; + } + + @Override public void onScaleEnd(ScaleGestureDetector de) + { + scrollView.setScrollEnabled(true); + } + } + + private class LibFreeRDPBroadcastReceiver extends BroadcastReceiver + { + @Override public void onReceive(Context context, Intent intent) + { + // still got a valid session? + if (session == null) + return; + + // is this event for the current session? + if (session.getInstance() != intent.getExtras().getLong(GlobalApp.EVENT_PARAM, -1)) + return; + + switch (intent.getExtras().getInt(GlobalApp.EVENT_TYPE, -1)) + { + case GlobalApp.FREERDP_EVENT_CONNECTION_SUCCESS: + OnConnectionSuccess(context); + break; + + case GlobalApp.FREERDP_EVENT_CONNECTION_FAILURE: + OnConnectionFailure(context); + break; + case GlobalApp.FREERDP_EVENT_DISCONNECTED: + OnDisconnected(context); + break; + } + } + + private void OnConnectionSuccess(Context context) + { + Log.v(TAG, "OnConnectionSuccess"); + + // bind session + bindSession(); + + if (progressDialog != null) + { + progressDialog.dismiss(); + progressDialog = null; + } + + if (session.getBookmark() == null) + { + // Return immediately if we launch from URI + return; + } + + // add hostname to history if quick connect was used + Bundle bundle = getIntent().getExtras(); + if (bundle != null && bundle.containsKey(PARAM_CONNECTION_REFERENCE)) + { + if (ConnectionReference.isHostnameReference( + bundle.getString(PARAM_CONNECTION_REFERENCE))) + { + assert session.getBookmark().getType() == BookmarkBase.TYPE_MANUAL; + String item = session.getBookmark().get().getHostname(); + if (!GlobalApp.getQuickConnectHistoryGateway().historyItemExists(item)) + GlobalApp.getQuickConnectHistoryGateway().addHistoryItem(item); + } + } + } + + private void OnConnectionFailure(Context context) + { + Log.v(TAG, "OnConnectionFailure"); + + // remove pending move events + uiHandler.removeMessages(UIHandler.SEND_MOVE_EVENT); + + if (progressDialog != null) + { + progressDialog.dismiss(); + progressDialog = null; + } + + // post error message on UI thread + if (!connectCancelledByUser) + uiHandler.sendMessage( + Message.obtain(null, UIHandler.DISPLAY_TOAST, + getResources().getText(R.string.error_connection_failure))); + + closeSessionActivity(RESULT_CANCELED); + } + + private void OnDisconnected(Context context) + { + Log.v(TAG, "OnDisconnected"); + + // remove pending move events + uiHandler.removeMessages(UIHandler.SEND_MOVE_EVENT); + + if (progressDialog != null) + { + progressDialog.dismiss(); + progressDialog = null; + } + + session.setUIEventListener(null); + closeSessionActivity(RESULT_OK); + } + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/SessionView.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/SessionView.java index 5ecbcb7..008b153 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/SessionView.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/SessionView.java @@ -3,8 +3,9 @@ Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.presentation; @@ -32,319 +33,380 @@ import com.freerdp.freerdpcore.utils.Mouse; import java.util.Stack; - -public class SessionView extends View { - public static final float MAX_SCALE_FACTOR = 3.0f; - public static final float MIN_SCALE_FACTOR = 1.0f; - private static final String TAG = "SessionView"; - private static final float SCALE_FACTOR_DELTA = 0.0001f; - private static final float TOUCH_SCROLL_DELTA = 10.0f; - private int width; - private int height; - private BitmapDrawable surface; - private Stack invalidRegions; - private int touchPointerPaddingWidth = 0; - private int touchPointerPaddingHeight = 0; - private SessionViewListener sessionViewListener = null; - // helpers for scaling gesture handling - private float scaleFactor = 1.0f; - private Matrix scaleMatrix; - private Matrix invScaleMatrix; - private RectF invalidRegionF; - private GestureDetector gestureDetector; - private SessionState currentSession; - - //private static final String TAG = "FreeRDP.SessionView"; - private DoubleGestureDetector doubleGestureDetector; - public SessionView(Context context) { - super(context); - initSessionView(context); - } - - public SessionView(Context context, AttributeSet attrs) { - super(context, attrs); - initSessionView(context); - } - - public SessionView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - initSessionView(context); - } - - private void initSessionView(Context context) { - invalidRegions = new Stack(); - gestureDetector = new GestureDetector(context, new SessionGestureListener(), null, true); - doubleGestureDetector = new DoubleGestureDetector(context, null, new SessionDoubleGestureListener()); - - scaleFactor = 1.0f; - scaleMatrix = new Matrix(); - invScaleMatrix = new Matrix(); - invalidRegionF = new RectF(); - - setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); - } - - public void setScaleGestureDetector(ScaleGestureDetector scaleGestureDetector) { - doubleGestureDetector.setScaleGestureDetector(scaleGestureDetector); - } - - public void setSessionViewListener(SessionViewListener sessionViewListener) { - this.sessionViewListener = sessionViewListener; - } - - public void addInvalidRegion(Rect invalidRegion) { - // correctly transform invalid region depending on current scaling - invalidRegionF.set(invalidRegion); - scaleMatrix.mapRect(invalidRegionF); - invalidRegionF.roundOut(invalidRegion); - - invalidRegions.add(invalidRegion); - } - - public void invalidateRegion() { - invalidate(invalidRegions.pop()); - } - - public void onSurfaceChange(SessionState session) { - surface = session.getSurface(); - Bitmap bitmap = surface.getBitmap(); - width = bitmap.getWidth(); - height = bitmap.getHeight(); - surface.setBounds(0, 0, width, height); - - setMinimumWidth(width); - setMinimumHeight(height); - - requestLayout(); - currentSession = session; - } - - public float getZoom() { - return scaleFactor; - } - - public void setZoom(float factor) { - // calc scale matrix and inverse scale matrix (to correctly transform the view and moues coordinates) - scaleFactor = factor; - scaleMatrix.setScale(scaleFactor, scaleFactor); - invScaleMatrix.setScale(1.0f / scaleFactor, 1.0f / scaleFactor); - - // update layout - requestLayout(); - } - - public boolean isAtMaxZoom() { - return (scaleFactor > (MAX_SCALE_FACTOR - SCALE_FACTOR_DELTA)); - } - - public boolean isAtMinZoom() { - return (scaleFactor < (MIN_SCALE_FACTOR + SCALE_FACTOR_DELTA)); - } - - public boolean zoomIn(float factor) { - boolean res = true; - scaleFactor += factor; - if (scaleFactor > (MAX_SCALE_FACTOR - SCALE_FACTOR_DELTA)) { - scaleFactor = MAX_SCALE_FACTOR; - res = false; - } - setZoom(scaleFactor); - return res; - } - - public boolean zoomOut(float factor) { - boolean res = true; - scaleFactor -= factor; - if (scaleFactor < (MIN_SCALE_FACTOR + SCALE_FACTOR_DELTA)) { - scaleFactor = MIN_SCALE_FACTOR; - res = false; - } - setZoom(scaleFactor); - return res; - } - - public void setTouchPointerPadding(int widht, int height) { - touchPointerPaddingWidth = widht; - touchPointerPaddingHeight = height; - requestLayout(); - } - - public int getTouchPointerPaddingWidth() { - return touchPointerPaddingWidth; - } - - public int getTouchPointerPaddingHeight() { - return touchPointerPaddingHeight; - } - - @Override - public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - Log.v(TAG, width + "x" + height); - this.setMeasuredDimension((int) (width * scaleFactor) + touchPointerPaddingWidth, (int) (height * scaleFactor) + touchPointerPaddingHeight); - } - - @Override - public void onDraw(Canvas canvas) { - super.onDraw(canvas); - - canvas.save(); - canvas.concat(scaleMatrix); - surface.draw(canvas); - canvas.restore(); - } - - // dirty hack: we call back to our activity and call onBackPressed as this doesn't reach us when the soft keyboard is shown ... - @Override - public boolean dispatchKeyEventPreIme(KeyEvent event) { - if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) - ((SessionActivity) this.getContext()).onBackPressed(); - return super.dispatchKeyEventPreIme(event); - } - - // perform mapping on the touch event's coordinates according to the current scaling - private MotionEvent mapTouchEvent(MotionEvent event) { - MotionEvent mappedEvent = MotionEvent.obtain(event); - float[] coordinates = {mappedEvent.getX(), mappedEvent.getY()}; - invScaleMatrix.mapPoints(coordinates); - mappedEvent.setLocation(coordinates[0], coordinates[1]); - return mappedEvent; - } - - // perform mapping on the double touch event's coordinates according to the current scaling - private MotionEvent mapDoubleTouchEvent(MotionEvent event) { - MotionEvent mappedEvent = MotionEvent.obtain(event); - float[] coordinates = {(mappedEvent.getX(0) + mappedEvent.getX(1)) / 2, (mappedEvent.getY(0) + mappedEvent.getY(1)) / 2}; - invScaleMatrix.mapPoints(coordinates); - mappedEvent.setLocation(coordinates[0], coordinates[1]); - return mappedEvent; - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - boolean res = gestureDetector.onTouchEvent(event); - res |= doubleGestureDetector.onTouchEvent(event); - return res; - } - - public interface SessionViewListener { - abstract void onSessionViewBeginTouch(); - - abstract void onSessionViewEndTouch(); - - abstract void onSessionViewLeftTouch(int x, int y, boolean down); - - abstract void onSessionViewRightTouch(int x, int y, boolean down); - - abstract void onSessionViewMove(int x, int y); - - abstract void onSessionViewScroll(boolean down); - } - - private class SessionGestureListener extends GestureDetector.SimpleOnGestureListener { - boolean longPressInProgress = false; - - public boolean onDown(MotionEvent e) { - return true; - } - - public boolean onUp(MotionEvent e) { - sessionViewListener.onSessionViewEndTouch(); - return true; - } - - public void onLongPress(MotionEvent e) { - MotionEvent mappedEvent = mapTouchEvent(e); - sessionViewListener.onSessionViewBeginTouch(); - sessionViewListener.onSessionViewLeftTouch((int) mappedEvent.getX(), (int) mappedEvent.getY(), true); - longPressInProgress = true; - } - - public void onLongPressUp(MotionEvent e) { - MotionEvent mappedEvent = mapTouchEvent(e); - sessionViewListener.onSessionViewLeftTouch((int) mappedEvent.getX(), (int) mappedEvent.getY(), false); - longPressInProgress = false; - sessionViewListener.onSessionViewEndTouch(); - } - - public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { - if (longPressInProgress) { - MotionEvent mappedEvent = mapTouchEvent(e2); - sessionViewListener.onSessionViewMove((int) mappedEvent.getX(), (int) mappedEvent.getY()); - return true; - } - - return false; - } - - public boolean onDoubleTap(MotionEvent e) { - // send 2nd click for double click - MotionEvent mappedEvent = mapTouchEvent(e); - sessionViewListener.onSessionViewLeftTouch((int) mappedEvent.getX(), (int) mappedEvent.getY(), true); - sessionViewListener.onSessionViewLeftTouch((int) mappedEvent.getX(), (int) mappedEvent.getY(), false); - return true; - } - - public boolean onSingleTapUp(MotionEvent e) { - // send single click - MotionEvent mappedEvent = mapTouchEvent(e); - sessionViewListener.onSessionViewBeginTouch(); - switch (e.getButtonState()) { - case MotionEvent.BUTTON_PRIMARY: - sessionViewListener.onSessionViewLeftTouch((int) mappedEvent.getX(), (int) mappedEvent.getY(), true); - sessionViewListener.onSessionViewLeftTouch((int) mappedEvent.getX(), (int) mappedEvent.getY(), false); - break; - case MotionEvent.BUTTON_SECONDARY: - sessionViewListener.onSessionViewRightTouch((int) mappedEvent.getX(), (int) mappedEvent.getY(), true); - sessionViewListener.onSessionViewRightTouch((int) mappedEvent.getX(), (int) mappedEvent.getY(), false); - sessionViewListener.onSessionViewLeftTouch((int) mappedEvent.getX(), (int) mappedEvent.getY(), true); - sessionViewListener.onSessionViewLeftTouch((int) mappedEvent.getX(), (int) mappedEvent.getY(), false); - break; - } - sessionViewListener.onSessionViewEndTouch(); - return true; - } - } - - private class SessionDoubleGestureListener implements DoubleGestureDetector.OnDoubleGestureListener { - private MotionEvent prevEvent = null; - - public boolean onDoubleTouchDown(MotionEvent e) { - sessionViewListener.onSessionViewBeginTouch(); - prevEvent = MotionEvent.obtain(e); - return true; - } - - public boolean onDoubleTouchUp(MotionEvent e) { - if (prevEvent != null) { - prevEvent.recycle(); - prevEvent = null; - } - sessionViewListener.onSessionViewEndTouch(); - return true; - } - - public boolean onDoubleTouchScroll(MotionEvent e1, MotionEvent e2) { - // calc if user scrolled up or down (or if any scrolling happened at all) - float deltaY = e2.getY() - prevEvent.getY(); - if (deltaY > TOUCH_SCROLL_DELTA) { - sessionViewListener.onSessionViewScroll(true); - prevEvent.recycle(); - prevEvent = MotionEvent.obtain(e2); - } else if (deltaY < -TOUCH_SCROLL_DELTA) { - sessionViewListener.onSessionViewScroll(false); - prevEvent.recycle(); - prevEvent = MotionEvent.obtain(e2); - } - return true; - } - - public boolean onDoubleTouchSingleTap(MotionEvent e) { - // send single click - MotionEvent mappedEvent = mapDoubleTouchEvent(e); - sessionViewListener.onSessionViewRightTouch((int) mappedEvent.getX(), (int) mappedEvent.getY(), true); - sessionViewListener.onSessionViewRightTouch((int) mappedEvent.getX(), (int) mappedEvent.getY(), false); - return true; - } - } - +public class SessionView extends View +{ + public static final float MAX_SCALE_FACTOR = 3.0f; + public static final float MIN_SCALE_FACTOR = 1.0f; + private static final String TAG = "SessionView"; + private static final float SCALE_FACTOR_DELTA = 0.0001f; + private static final float TOUCH_SCROLL_DELTA = 10.0f; + private int width; + private int height; + private BitmapDrawable surface; + private Stack invalidRegions; + private int touchPointerPaddingWidth = 0; + private int touchPointerPaddingHeight = 0; + private SessionViewListener sessionViewListener = null; + // helpers for scaling gesture handling + private float scaleFactor = 1.0f; + private Matrix scaleMatrix; + private Matrix invScaleMatrix; + private RectF invalidRegionF; + private GestureDetector gestureDetector; + private SessionState currentSession; + + // private static final String TAG = "FreeRDP.SessionView"; + private DoubleGestureDetector doubleGestureDetector; + public SessionView(Context context) + { + super(context); + initSessionView(context); + } + + public SessionView(Context context, AttributeSet attrs) + { + super(context, attrs); + initSessionView(context); + } + + public SessionView(Context context, AttributeSet attrs, int defStyle) + { + super(context, attrs, defStyle); + initSessionView(context); + } + + private void initSessionView(Context context) + { + invalidRegions = new Stack(); + gestureDetector = new GestureDetector(context, new SessionGestureListener(), null, true); + doubleGestureDetector = + new DoubleGestureDetector(context, null, new SessionDoubleGestureListener()); + + scaleFactor = 1.0f; + scaleMatrix = new Matrix(); + invScaleMatrix = new Matrix(); + invalidRegionF = new RectF(); + + setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); + } + + public void setScaleGestureDetector(ScaleGestureDetector scaleGestureDetector) + { + doubleGestureDetector.setScaleGestureDetector(scaleGestureDetector); + } + + public void setSessionViewListener(SessionViewListener sessionViewListener) + { + this.sessionViewListener = sessionViewListener; + } + + public void addInvalidRegion(Rect invalidRegion) + { + // correctly transform invalid region depending on current scaling + invalidRegionF.set(invalidRegion); + scaleMatrix.mapRect(invalidRegionF); + invalidRegionF.roundOut(invalidRegion); + + invalidRegions.add(invalidRegion); + } + + public void invalidateRegion() + { + invalidate(invalidRegions.pop()); + } + + public void onSurfaceChange(SessionState session) + { + surface = session.getSurface(); + Bitmap bitmap = surface.getBitmap(); + width = bitmap.getWidth(); + height = bitmap.getHeight(); + surface.setBounds(0, 0, width, height); + + setMinimumWidth(width); + setMinimumHeight(height); + + requestLayout(); + currentSession = session; + } + + public float getZoom() + { + return scaleFactor; + } + + public void setZoom(float factor) + { + // calc scale matrix and inverse scale matrix (to correctly transform the view and moues + // coordinates) + scaleFactor = factor; + scaleMatrix.setScale(scaleFactor, scaleFactor); + invScaleMatrix.setScale(1.0f / scaleFactor, 1.0f / scaleFactor); + + // update layout + requestLayout(); + } + + public boolean isAtMaxZoom() + { + return (scaleFactor > (MAX_SCALE_FACTOR - SCALE_FACTOR_DELTA)); + } + + public boolean isAtMinZoom() + { + return (scaleFactor < (MIN_SCALE_FACTOR + SCALE_FACTOR_DELTA)); + } + + public boolean zoomIn(float factor) + { + boolean res = true; + scaleFactor += factor; + if (scaleFactor > (MAX_SCALE_FACTOR - SCALE_FACTOR_DELTA)) + { + scaleFactor = MAX_SCALE_FACTOR; + res = false; + } + setZoom(scaleFactor); + return res; + } + + public boolean zoomOut(float factor) + { + boolean res = true; + scaleFactor -= factor; + if (scaleFactor < (MIN_SCALE_FACTOR + SCALE_FACTOR_DELTA)) + { + scaleFactor = MIN_SCALE_FACTOR; + res = false; + } + setZoom(scaleFactor); + return res; + } + + public void setTouchPointerPadding(int widht, int height) + { + touchPointerPaddingWidth = widht; + touchPointerPaddingHeight = height; + requestLayout(); + } + + public int getTouchPointerPaddingWidth() + { + return touchPointerPaddingWidth; + } + + public int getTouchPointerPaddingHeight() + { + return touchPointerPaddingHeight; + } + + @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) + { + Log.v(TAG, width + "x" + height); + this.setMeasuredDimension((int)(width * scaleFactor) + touchPointerPaddingWidth, + (int)(height * scaleFactor) + touchPointerPaddingHeight); + } + + @Override public void onDraw(Canvas canvas) + { + super.onDraw(canvas); + + canvas.save(); + canvas.concat(scaleMatrix); + surface.draw(canvas); + canvas.restore(); + } + + // dirty hack: we call back to our activity and call onBackPressed as this doesn't reach us when + // the soft keyboard is shown ... + @Override public boolean dispatchKeyEventPreIme(KeyEvent event) + { + if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && + event.getAction() == KeyEvent.ACTION_DOWN) + ((SessionActivity)this.getContext()).onBackPressed(); + return super.dispatchKeyEventPreIme(event); + } + + // perform mapping on the touch event's coordinates according to the current scaling + private MotionEvent mapTouchEvent(MotionEvent event) + { + MotionEvent mappedEvent = MotionEvent.obtain(event); + float[] coordinates = { mappedEvent.getX(), mappedEvent.getY() }; + invScaleMatrix.mapPoints(coordinates); + mappedEvent.setLocation(coordinates[0], coordinates[1]); + return mappedEvent; + } + + // perform mapping on the double touch event's coordinates according to the current scaling + private MotionEvent mapDoubleTouchEvent(MotionEvent event) + { + MotionEvent mappedEvent = MotionEvent.obtain(event); + float[] coordinates = { (mappedEvent.getX(0) + mappedEvent.getX(1)) / 2, + (mappedEvent.getY(0) + mappedEvent.getY(1)) / 2 }; + invScaleMatrix.mapPoints(coordinates); + mappedEvent.setLocation(coordinates[0], coordinates[1]); + return mappedEvent; + } + + @Override public boolean onTouchEvent(MotionEvent event) + { + boolean res = gestureDetector.onTouchEvent(event); + res |= doubleGestureDetector.onTouchEvent(event); + return res; + } + + public interface SessionViewListener { + abstract void onSessionViewBeginTouch(); + + abstract void onSessionViewEndTouch(); + + abstract void onSessionViewLeftTouch(int x, int y, boolean down); + + abstract void onSessionViewRightTouch(int x, int y, boolean down); + + abstract void onSessionViewMove(int x, int y); + + abstract void onSessionViewScroll(boolean down); + } + + private class SessionGestureListener extends GestureDetector.SimpleOnGestureListener + { + boolean longPressInProgress = false; + + public boolean onDown(MotionEvent e) + { + return true; + } + + public boolean onUp(MotionEvent e) + { + sessionViewListener.onSessionViewEndTouch(); + return true; + } + + public void onLongPress(MotionEvent e) + { + MotionEvent mappedEvent = mapTouchEvent(e); + sessionViewListener.onSessionViewBeginTouch(); + sessionViewListener.onSessionViewLeftTouch((int)mappedEvent.getX(), + (int)mappedEvent.getY(), true); + longPressInProgress = true; + } + + public void onLongPressUp(MotionEvent e) + { + MotionEvent mappedEvent = mapTouchEvent(e); + sessionViewListener.onSessionViewLeftTouch((int)mappedEvent.getX(), + (int)mappedEvent.getY(), false); + longPressInProgress = false; + sessionViewListener.onSessionViewEndTouch(); + } + + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) + { + if (longPressInProgress) + { + MotionEvent mappedEvent = mapTouchEvent(e2); + sessionViewListener.onSessionViewMove((int)mappedEvent.getX(), + (int)mappedEvent.getY()); + return true; + } + + return false; + } + + public boolean onDoubleTap(MotionEvent e) + { + // send 2nd click for double click + MotionEvent mappedEvent = mapTouchEvent(e); + sessionViewListener.onSessionViewLeftTouch((int)mappedEvent.getX(), + (int)mappedEvent.getY(), true); + sessionViewListener.onSessionViewLeftTouch((int)mappedEvent.getX(), + (int)mappedEvent.getY(), false); + return true; + } + + public boolean onSingleTapUp(MotionEvent e) + { + // send single click + MotionEvent mappedEvent = mapTouchEvent(e); + sessionViewListener.onSessionViewBeginTouch(); + switch (e.getButtonState()) + { + case MotionEvent.BUTTON_PRIMARY: + sessionViewListener.onSessionViewLeftTouch((int)mappedEvent.getX(), + (int)mappedEvent.getY(), true); + sessionViewListener.onSessionViewLeftTouch((int)mappedEvent.getX(), + (int)mappedEvent.getY(), false); + break; + case MotionEvent.BUTTON_SECONDARY: + sessionViewListener.onSessionViewRightTouch((int)mappedEvent.getX(), + (int)mappedEvent.getY(), true); + sessionViewListener.onSessionViewRightTouch((int)mappedEvent.getX(), + (int)mappedEvent.getY(), false); + sessionViewListener.onSessionViewLeftTouch((int)mappedEvent.getX(), + (int)mappedEvent.getY(), true); + sessionViewListener.onSessionViewLeftTouch((int)mappedEvent.getX(), + (int)mappedEvent.getY(), false); + break; + } + sessionViewListener.onSessionViewEndTouch(); + return true; + } + } + + private class SessionDoubleGestureListener + implements DoubleGestureDetector.OnDoubleGestureListener + { + private MotionEvent prevEvent = null; + + public boolean onDoubleTouchDown(MotionEvent e) + { + sessionViewListener.onSessionViewBeginTouch(); + prevEvent = MotionEvent.obtain(e); + return true; + } + + public boolean onDoubleTouchUp(MotionEvent e) + { + if (prevEvent != null) + { + prevEvent.recycle(); + prevEvent = null; + } + sessionViewListener.onSessionViewEndTouch(); + return true; + } + + public boolean onDoubleTouchScroll(MotionEvent e1, MotionEvent e2) + { + // calc if user scrolled up or down (or if any scrolling happened at all) + float deltaY = e2.getY() - prevEvent.getY(); + if (deltaY > TOUCH_SCROLL_DELTA) + { + sessionViewListener.onSessionViewScroll(true); + prevEvent.recycle(); + prevEvent = MotionEvent.obtain(e2); + } + else if (deltaY < -TOUCH_SCROLL_DELTA) + { + sessionViewListener.onSessionViewScroll(false); + prevEvent.recycle(); + prevEvent = MotionEvent.obtain(e2); + } + return true; + } + + public boolean onDoubleTouchSingleTap(MotionEvent e) + { + // send single click + MotionEvent mappedEvent = mapDoubleTouchEvent(e); + sessionViewListener.onSessionViewRightTouch((int)mappedEvent.getX(), + (int)mappedEvent.getY(), true); + sessionViewListener.onSessionViewRightTouch((int)mappedEvent.getX(), + (int)mappedEvent.getY(), false); + return true; + } + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/ShortcutsActivity.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/ShortcutsActivity.java index 7101fb4..2121c6e 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/ShortcutsActivity.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/ShortcutsActivity.java @@ -3,8 +3,9 @@ Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.presentation; @@ -30,118 +31,130 @@ import com.freerdp.freerdpcore.utils.BookmarkArrayAdapter; import java.util.ArrayList; -public class ShortcutsActivity extends ListActivity { - - public static final String TAG = "ShortcutsActivity"; - - - @Override - public void onCreate(Bundle savedInstanceState) { - - super.onCreate(savedInstanceState); - - Intent intent = getIntent(); - if (Intent.ACTION_CREATE_SHORTCUT.equals(intent.getAction())) { - // set listeners for the list view - getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() { - public void onItemClick(AdapterView parent, View view, int position, long id) { - String refStr = view.getTag().toString(); - String defLabel = ((TextView) (view.findViewById(R.id.bookmark_text1))).getText().toString(); - setupShortcut(refStr, defLabel); - } - }); - } else { - // just exit - finish(); - } - } - - @Override - public void onResume() { - super.onResume(); - // create bookmark cursor adapter - ArrayList bookmarks = GlobalApp.getManualBookmarkGateway().findAll(); - BookmarkArrayAdapter bookmarkAdapter = new BookmarkArrayAdapter(this, android.R.layout.simple_list_item_2, bookmarks); - getListView().setAdapter(bookmarkAdapter); - } - - public void onPause() { - super.onPause(); - getListView().setAdapter(null); - } - - /** - * This function creates a shortcut and returns it to the caller. There are actually two - * intents that you will send back. - *

- * The first intent serves as a container for the shortcut and is returned to the launcher by - * setResult(). This intent must contain three fields: - *

- *

    - *
  • {@link android.content.Intent#EXTRA_SHORTCUT_INTENT} The shortcut intent.
  • - *
  • {@link android.content.Intent#EXTRA_SHORTCUT_NAME} The text that will be displayed with - * the shortcut.
  • - *
  • {@link android.content.Intent#EXTRA_SHORTCUT_ICON} The shortcut's icon, if provided as a - * bitmap, or {@link android.content.Intent#EXTRA_SHORTCUT_ICON_RESOURCE} if provided as - * a drawable resource.
  • - *
- *

- * If you use a simple drawable resource, note that you must wrapper it using - * {@link android.content.Intent.ShortcutIconResource}, as shown below. This is required so - * that the launcher can access resources that are stored in your application's .apk file. If - * you return a bitmap, such as a thumbnail, you can simply put the bitmap into the extras - * bundle using {@link android.content.Intent#EXTRA_SHORTCUT_ICON}. - *

- * The shortcut intent can be any intent that you wish the launcher to send, when the user - * clicks on the shortcut. Typically this will be {@link android.content.Intent#ACTION_VIEW} - * with an appropriate Uri for your content, but any Intent will work here as long as it - * triggers the desired action within your Activity. - */ - - private void setupShortcut(String strRef, String defaultLabel) { - final String paramStrRef = strRef; - final String paramDefaultLabel = defaultLabel; - final Context paramContext = this; - - // display edit dialog to the user so he can specify the shortcut name - final EditText input = new EditText(this); - input.setText(defaultLabel); - - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(R.string.dlg_title_create_shortcut) - .setMessage(R.string.dlg_msg_create_shortcut) - .setView(input) - .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - String label = input.getText().toString(); - if (label.length() == 0) - label = paramDefaultLabel; - - Intent shortcutIntent = new Intent(Intent.ACTION_VIEW); - shortcutIntent.setClassName(paramContext, SessionRequestHandlerActivity.class.getName()); - shortcutIntent.setData(Uri.parse(paramStrRef)); - - // Then, set up the container intent (the response to the caller) - Intent intent = new Intent(); - intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); - intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, label); - Parcelable iconResource = Intent.ShortcutIconResource.fromContext(paramContext, R.drawable.icon_launcher_freerdp); - intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, iconResource); - - // Now, return the result to the launcher - setResult(RESULT_OK, intent); - finish(); - } - }) - .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - } - }) - .create().show(); - - } - +public class ShortcutsActivity extends ListActivity +{ + + public static final String TAG = "ShortcutsActivity"; + + @Override public void onCreate(Bundle savedInstanceState) + { + + super.onCreate(savedInstanceState); + + Intent intent = getIntent(); + if (Intent.ACTION_CREATE_SHORTCUT.equals(intent.getAction())) + { + // set listeners for the list view + getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() { + public void onItemClick(AdapterView parent, View view, int position, long id) + { + String refStr = view.getTag().toString(); + String defLabel = + ((TextView)(view.findViewById(R.id.bookmark_text1))).getText().toString(); + setupShortcut(refStr, defLabel); + } + }); + } + else + { + // just exit + finish(); + } + } + + @Override public void onResume() + { + super.onResume(); + // create bookmark cursor adapter + ArrayList bookmarks = GlobalApp.getManualBookmarkGateway().findAll(); + BookmarkArrayAdapter bookmarkAdapter = + new BookmarkArrayAdapter(this, android.R.layout.simple_list_item_2, bookmarks); + getListView().setAdapter(bookmarkAdapter); + } + + public void onPause() + { + super.onPause(); + getListView().setAdapter(null); + } + + /** + * This function creates a shortcut and returns it to the caller. There are actually two + * intents that you will send back. + *

+ * The first intent serves as a container for the shortcut and is returned to the launcher by + * setResult(). This intent must contain three fields: + *

+ *

    + *
  • {@link android.content.Intent#EXTRA_SHORTCUT_INTENT} The shortcut intent.
  • + *
  • {@link android.content.Intent#EXTRA_SHORTCUT_NAME} The text that will be displayed with + * the shortcut.
  • + *
  • {@link android.content.Intent#EXTRA_SHORTCUT_ICON} The shortcut's icon, if provided as a + * bitmap, or {@link android.content.Intent#EXTRA_SHORTCUT_ICON_RESOURCE} if provided as + * a drawable resource.
  • + *
+ *

+ * If you use a simple drawable resource, note that you must wrapper it using + * {@link android.content.Intent.ShortcutIconResource}, as shown below. This is required so + * that the launcher can access resources that are stored in your application's .apk file. If + * you return a bitmap, such as a thumbnail, you can simply put the bitmap into the extras + * bundle using {@link android.content.Intent#EXTRA_SHORTCUT_ICON}. + *

+ * The shortcut intent can be any intent that you wish the launcher to send, when the user + * clicks on the shortcut. Typically this will be {@link android.content.Intent#ACTION_VIEW} + * with an appropriate Uri for your content, but any Intent will work here as long as it + * triggers the desired action within your Activity. + */ + + private void setupShortcut(String strRef, String defaultLabel) + { + final String paramStrRef = strRef; + final String paramDefaultLabel = defaultLabel; + final Context paramContext = this; + + // display edit dialog to the user so he can specify the shortcut name + final EditText input = new EditText(this); + input.setText(defaultLabel); + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(R.string.dlg_title_create_shortcut) + .setMessage(R.string.dlg_msg_create_shortcut) + .setView(input) + .setPositiveButton( + android.R.string.ok, + new DialogInterface.OnClickListener() { + @Override public void onClick(DialogInterface dialog, int which) + { + String label = input.getText().toString(); + if (label.length() == 0) + label = paramDefaultLabel; + + Intent shortcutIntent = new Intent(Intent.ACTION_VIEW); + shortcutIntent.setClassName(paramContext, + SessionRequestHandlerActivity.class.getName()); + shortcutIntent.setData(Uri.parse(paramStrRef)); + + // Then, set up the container intent (the response to the caller) + Intent intent = new Intent(); + intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); + intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, label); + Parcelable iconResource = Intent.ShortcutIconResource.fromContext( + paramContext, R.drawable.icon_launcher_freerdp); + intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, iconResource); + + // Now, return the result to the launcher + setResult(RESULT_OK, intent); + finish(); + } + }) + .setNegativeButton(android.R.string.cancel, + new DialogInterface.OnClickListener() { + @Override public void onClick(DialogInterface dialog, int which) + { + dialog.dismiss(); + } + }) + .create() + .show(); + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/TouchPointerView.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/TouchPointerView.java index d58159d..6b8b96c 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/TouchPointerView.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/TouchPointerView.java @@ -3,8 +3,9 @@ Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.presentation; @@ -21,312 +22,364 @@ import android.widget.ImageView; import com.freerdp.freerdpcore.R; import com.freerdp.freerdpcore.utils.GestureDetector; -public class TouchPointerView extends ImageView { - - private static final int POINTER_ACTION_CURSOR = 0; - private static final int POINTER_ACTION_CLOSE = 3; - - - // the touch pointer consists of 9 quadrants with the following functionality: - // - // ------------- - // | 0 | 1 | 2 | - // ------------- - // | 3 | 4 | 5 | - // ------------- - // | 6 | 7 | 8 | - // ------------- - // - // 0 ... contains the actual pointer (the tip must be centered in the quadrant) - // 1 ... is left empty - // 2, 3, 5, 6, 7, 8 ... function quadrants that issue a callback - // 4 ... pointer center used for left clicks and to drag the pointer - private static final int POINTER_ACTION_RCLICK = 2; - private static final int POINTER_ACTION_LCLICK = 4; - private static final int POINTER_ACTION_MOVE = 4; - private static final int POINTER_ACTION_SCROLL = 5; - private static final int POINTER_ACTION_RESET = 6; - private static final int POINTER_ACTION_KEYBOARD = 7; - private static final int POINTER_ACTION_EXTKEYBOARD = 8; - private static final float SCROLL_DELTA = 10.0f; - private static final int DEFAULT_TOUCH_POINTER_RESTORE_DELAY = 150; - private RectF pointerRect; - private RectF pointerAreaRects[] = new RectF[9]; - private Matrix translationMatrix; - private boolean pointerMoving = false; - private boolean pointerScrolling = false; - private TouchPointerListener listener = null; - private UIHandler uiHandler = new UIHandler(); - // gesture detection - private GestureDetector gestureDetector; - public TouchPointerView(Context context) { - super(context); - initTouchPointer(context); - } - - public TouchPointerView(Context context, AttributeSet attrs) { - super(context, attrs); - initTouchPointer(context); - } - - public TouchPointerView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - initTouchPointer(context); - } - - private void initTouchPointer(Context context) { - gestureDetector = new GestureDetector(context, new TouchPointerGestureListener(), null, true); - gestureDetector.setLongPressTimeout(500); - translationMatrix = new Matrix(); - setScaleType(ScaleType.MATRIX); - setImageMatrix(translationMatrix); - - // init rects - final float rectSizeWidth = (float) getDrawable().getIntrinsicWidth() / 3.0f; - final float rectSizeHeight = (float) getDrawable().getIntrinsicWidth() / 3.0f; - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - int left = (int) (j * rectSizeWidth); - int top = (int) (i * rectSizeHeight); - int right = left + (int) rectSizeWidth; - int bottom = top + (int) rectSizeHeight; - pointerAreaRects[i * 3 + j] = new RectF(left, top, right, bottom); - } - } - pointerRect = new RectF(0, 0, getDrawable().getIntrinsicWidth(), getDrawable().getIntrinsicHeight()); - } - - public void setTouchPointerListener(TouchPointerListener listener) { - this.listener = listener; - } - - public int getPointerWidth() { - return getDrawable().getIntrinsicWidth(); - } - - public int getPointerHeight() { - return getDrawable().getIntrinsicHeight(); - } - - public float[] getPointerPosition() { - float[] curPos = new float[2]; - translationMatrix.mapPoints(curPos); - return curPos; - } - - private void movePointer(float deltaX, float deltaY) { - translationMatrix.postTranslate(deltaX, deltaY); - setImageMatrix(translationMatrix); - } - - private void ensureVisibility(int screen_width, int screen_height) { - float[] curPos = new float[2]; - translationMatrix.mapPoints(curPos); - - if (curPos[0] > (screen_width - pointerRect.width())) - curPos[0] = screen_width - pointerRect.width(); - if (curPos[0] < 0) - curPos[0] = 0; - if (curPos[1] > (screen_height - pointerRect.height())) - curPos[1] = screen_height - pointerRect.height(); - if (curPos[1] < 0) - curPos[1] = 0; - - translationMatrix.setTranslate(curPos[0], curPos[1]); - setImageMatrix(translationMatrix); - } - - private void displayPointerImageAction(int resId) { - setPointerImage(resId); - uiHandler.sendEmptyMessageDelayed(0, DEFAULT_TOUCH_POINTER_RESTORE_DELAY); - } - - private void setPointerImage(int resId) { - setImageResource(resId); - } - - // returns the pointer area with the current translation matrix applied - private RectF getCurrentPointerArea(int area) { - RectF transRect = new RectF(pointerAreaRects[area]); - translationMatrix.mapRect(transRect); - return transRect; - } - - private boolean pointerAreaTouched(MotionEvent event, int area) { - RectF transRect = new RectF(pointerAreaRects[area]); - translationMatrix.mapRect(transRect); - if (transRect.contains(event.getX(), event.getY())) - return true; - return false; - } - - private boolean pointerTouched(MotionEvent event) { - RectF transRect = new RectF(pointerRect); - translationMatrix.mapRect(transRect); - if (transRect.contains(event.getX(), event.getY())) - return true; - return false; - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - // check if pointer is being moved or if we are in scroll mode or if the pointer is touched - if (!pointerMoving && !pointerScrolling && !pointerTouched(event)) - return false; - return gestureDetector.onTouchEvent(event); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - // ensure touch pointer is visible - if (changed) - ensureVisibility(right - left, bottom - top); - } - - // touch pointer listener - is triggered if an action field is - public interface TouchPointerListener { - abstract void onTouchPointerClose(); - - abstract void onTouchPointerLeftClick(int x, int y, boolean down); - - abstract void onTouchPointerRightClick(int x, int y, boolean down); - - abstract void onTouchPointerMove(int x, int y); - - abstract void onTouchPointerScroll(boolean down); - - abstract void onTouchPointerToggleKeyboard(); - - abstract void onTouchPointerToggleExtKeyboard(); - - abstract void onTouchPointerResetScrollZoom(); - } - - private class UIHandler extends Handler { - - UIHandler() { - super(); - } - - @Override - public void handleMessage(Message msg) { - setPointerImage(R.drawable.touch_pointer_default); - } - } - - private class TouchPointerGestureListener extends GestureDetector.SimpleOnGestureListener { - - private MotionEvent prevEvent = null; - - public boolean onDown(MotionEvent e) { - if (pointerAreaTouched(e, POINTER_ACTION_MOVE)) { - prevEvent = MotionEvent.obtain(e); - pointerMoving = true; - } else if (pointerAreaTouched(e, POINTER_ACTION_SCROLL)) { - prevEvent = MotionEvent.obtain(e); - pointerScrolling = true; - setPointerImage(R.drawable.touch_pointer_scroll); - } - - return true; - } - - public boolean onUp(MotionEvent e) { - if (prevEvent != null) { - prevEvent.recycle(); - prevEvent = null; - } - - if (pointerScrolling) - setPointerImage(R.drawable.touch_pointer_default); - - pointerMoving = false; - pointerScrolling = false; - return true; - } - - public void onLongPress(MotionEvent e) { - if (pointerAreaTouched(e, POINTER_ACTION_LCLICK)) { - setPointerImage(R.drawable.touch_pointer_active); - pointerMoving = true; - RectF rect = getCurrentPointerArea(POINTER_ACTION_CURSOR); - listener.onTouchPointerLeftClick((int) rect.centerX(), (int) rect.centerY(), true); - } - } - - public void onLongPressUp(MotionEvent e) { - if (pointerMoving) { - setPointerImage(R.drawable.touch_pointer_default); - pointerMoving = false; - RectF rect = getCurrentPointerArea(POINTER_ACTION_CURSOR); - listener.onTouchPointerLeftClick((int) rect.centerX(), (int) rect.centerY(), false); - } - } - - public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { - if (pointerMoving) { - // move pointer graphics - movePointer((int) (e2.getX() - prevEvent.getX()), (int) (e2.getY() - prevEvent.getY())); - prevEvent.recycle(); - prevEvent = MotionEvent.obtain(e2); - - // send move notification - RectF rect = getCurrentPointerArea(POINTER_ACTION_CURSOR); - listener.onTouchPointerMove((int) rect.centerX(), (int) rect.centerY()); - return true; - } else if (pointerScrolling) { - // calc if user scrolled up or down (or if any scrolling happened at all) - float deltaY = e2.getY() - prevEvent.getY(); - if (deltaY > SCROLL_DELTA) { - listener.onTouchPointerScroll(true); - prevEvent.recycle(); - prevEvent = MotionEvent.obtain(e2); - } else if (deltaY < -SCROLL_DELTA) { - listener.onTouchPointerScroll(false); - prevEvent.recycle(); - prevEvent = MotionEvent.obtain(e2); - } - return true; - } - return false; - } - - public boolean onSingleTapUp(MotionEvent e) { - // look what area got touched and fire actions accordingly - if (pointerAreaTouched(e, POINTER_ACTION_CLOSE)) - listener.onTouchPointerClose(); - else if (pointerAreaTouched(e, POINTER_ACTION_LCLICK)) { - displayPointerImageAction(R.drawable.touch_pointer_lclick); - RectF rect = getCurrentPointerArea(POINTER_ACTION_CURSOR); - listener.onTouchPointerLeftClick((int) rect.centerX(), (int) rect.centerY(), true); - listener.onTouchPointerLeftClick((int) rect.centerX(), (int) rect.centerY(), false); - } else if (pointerAreaTouched(e, POINTER_ACTION_RCLICK)) { - displayPointerImageAction(R.drawable.touch_pointer_rclick); - RectF rect = getCurrentPointerArea(POINTER_ACTION_CURSOR); - listener.onTouchPointerRightClick((int) rect.centerX(), (int) rect.centerY(), true); - listener.onTouchPointerRightClick((int) rect.centerX(), (int) rect.centerY(), false); - } else if (pointerAreaTouched(e, POINTER_ACTION_KEYBOARD)) { - displayPointerImageAction(R.drawable.touch_pointer_keyboard); - listener.onTouchPointerToggleKeyboard(); - } else if (pointerAreaTouched(e, POINTER_ACTION_EXTKEYBOARD)) { - displayPointerImageAction(R.drawable.touch_pointer_extkeyboard); - listener.onTouchPointerToggleExtKeyboard(); - } else if (pointerAreaTouched(e, POINTER_ACTION_RESET)) { - displayPointerImageAction(R.drawable.touch_pointer_reset); - listener.onTouchPointerResetScrollZoom(); - } - - return true; - } - - public boolean onDoubleTap(MotionEvent e) { - // issue a double click notification if performed in center quadrant - if (pointerAreaTouched(e, POINTER_ACTION_LCLICK)) { - RectF rect = getCurrentPointerArea(POINTER_ACTION_CURSOR); - listener.onTouchPointerLeftClick((int) rect.centerX(), (int) rect.centerY(), true); - listener.onTouchPointerLeftClick((int) rect.centerX(), (int) rect.centerY(), false); - } - return true; - } - } +public class TouchPointerView extends ImageView +{ + + private static final int POINTER_ACTION_CURSOR = 0; + private static final int POINTER_ACTION_CLOSE = 3; + + // the touch pointer consists of 9 quadrants with the following functionality: + // + // ------------- + // | 0 | 1 | 2 | + // ------------- + // | 3 | 4 | 5 | + // ------------- + // | 6 | 7 | 8 | + // ------------- + // + // 0 ... contains the actual pointer (the tip must be centered in the quadrant) + // 1 ... is left empty + // 2, 3, 5, 6, 7, 8 ... function quadrants that issue a callback + // 4 ... pointer center used for left clicks and to drag the pointer + private static final int POINTER_ACTION_RCLICK = 2; + private static final int POINTER_ACTION_LCLICK = 4; + private static final int POINTER_ACTION_MOVE = 4; + private static final int POINTER_ACTION_SCROLL = 5; + private static final int POINTER_ACTION_RESET = 6; + private static final int POINTER_ACTION_KEYBOARD = 7; + private static final int POINTER_ACTION_EXTKEYBOARD = 8; + private static final float SCROLL_DELTA = 10.0f; + private static final int DEFAULT_TOUCH_POINTER_RESTORE_DELAY = 150; + private RectF pointerRect; + private RectF pointerAreaRects[] = new RectF[9]; + private Matrix translationMatrix; + private boolean pointerMoving = false; + private boolean pointerScrolling = false; + private TouchPointerListener listener = null; + private UIHandler uiHandler = new UIHandler(); + // gesture detection + private GestureDetector gestureDetector; + public TouchPointerView(Context context) + { + super(context); + initTouchPointer(context); + } + + public TouchPointerView(Context context, AttributeSet attrs) + { + super(context, attrs); + initTouchPointer(context); + } + + public TouchPointerView(Context context, AttributeSet attrs, int defStyle) + { + super(context, attrs, defStyle); + initTouchPointer(context); + } + + private void initTouchPointer(Context context) + { + gestureDetector = + new GestureDetector(context, new TouchPointerGestureListener(), null, true); + gestureDetector.setLongPressTimeout(500); + translationMatrix = new Matrix(); + setScaleType(ScaleType.MATRIX); + setImageMatrix(translationMatrix); + + // init rects + final float rectSizeWidth = (float)getDrawable().getIntrinsicWidth() / 3.0f; + final float rectSizeHeight = (float)getDrawable().getIntrinsicWidth() / 3.0f; + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + { + int left = (int)(j * rectSizeWidth); + int top = (int)(i * rectSizeHeight); + int right = left + (int)rectSizeWidth; + int bottom = top + (int)rectSizeHeight; + pointerAreaRects[i * 3 + j] = new RectF(left, top, right, bottom); + } + } + pointerRect = + new RectF(0, 0, getDrawable().getIntrinsicWidth(), getDrawable().getIntrinsicHeight()); + } + + public void setTouchPointerListener(TouchPointerListener listener) + { + this.listener = listener; + } + + public int getPointerWidth() + { + return getDrawable().getIntrinsicWidth(); + } + + public int getPointerHeight() + { + return getDrawable().getIntrinsicHeight(); + } + + public float[] getPointerPosition() + { + float[] curPos = new float[2]; + translationMatrix.mapPoints(curPos); + return curPos; + } + + private void movePointer(float deltaX, float deltaY) + { + translationMatrix.postTranslate(deltaX, deltaY); + setImageMatrix(translationMatrix); + } + + private void ensureVisibility(int screen_width, int screen_height) + { + float[] curPos = new float[2]; + translationMatrix.mapPoints(curPos); + + if (curPos[0] > (screen_width - pointerRect.width())) + curPos[0] = screen_width - pointerRect.width(); + if (curPos[0] < 0) + curPos[0] = 0; + if (curPos[1] > (screen_height - pointerRect.height())) + curPos[1] = screen_height - pointerRect.height(); + if (curPos[1] < 0) + curPos[1] = 0; + + translationMatrix.setTranslate(curPos[0], curPos[1]); + setImageMatrix(translationMatrix); + } + + private void displayPointerImageAction(int resId) + { + setPointerImage(resId); + uiHandler.sendEmptyMessageDelayed(0, DEFAULT_TOUCH_POINTER_RESTORE_DELAY); + } + + private void setPointerImage(int resId) + { + setImageResource(resId); + } + + // returns the pointer area with the current translation matrix applied + private RectF getCurrentPointerArea(int area) + { + RectF transRect = new RectF(pointerAreaRects[area]); + translationMatrix.mapRect(transRect); + return transRect; + } + + private boolean pointerAreaTouched(MotionEvent event, int area) + { + RectF transRect = new RectF(pointerAreaRects[area]); + translationMatrix.mapRect(transRect); + if (transRect.contains(event.getX(), event.getY())) + return true; + return false; + } + + private boolean pointerTouched(MotionEvent event) + { + RectF transRect = new RectF(pointerRect); + translationMatrix.mapRect(transRect); + if (transRect.contains(event.getX(), event.getY())) + return true; + return false; + } + + @Override public boolean onTouchEvent(MotionEvent event) + { + // check if pointer is being moved or if we are in scroll mode or if the pointer is touched + if (!pointerMoving && !pointerScrolling && !pointerTouched(event)) + return false; + return gestureDetector.onTouchEvent(event); + } + + @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) + { + // ensure touch pointer is visible + if (changed) + ensureVisibility(right - left, bottom - top); + } + + // touch pointer listener - is triggered if an action field is + public interface TouchPointerListener { + abstract void onTouchPointerClose(); + + abstract void onTouchPointerLeftClick(int x, int y, boolean down); + + abstract void onTouchPointerRightClick(int x, int y, boolean down); + + abstract void onTouchPointerMove(int x, int y); + + abstract void onTouchPointerScroll(boolean down); + + abstract void onTouchPointerToggleKeyboard(); + + abstract void onTouchPointerToggleExtKeyboard(); + + abstract void onTouchPointerResetScrollZoom(); + } + + private class UIHandler extends Handler + { + + UIHandler() + { + super(); + } + + @Override public void handleMessage(Message msg) + { + setPointerImage(R.drawable.touch_pointer_default); + } + } + + private class TouchPointerGestureListener extends GestureDetector.SimpleOnGestureListener + { + + private MotionEvent prevEvent = null; + + public boolean onDown(MotionEvent e) + { + if (pointerAreaTouched(e, POINTER_ACTION_MOVE)) + { + prevEvent = MotionEvent.obtain(e); + pointerMoving = true; + } + else if (pointerAreaTouched(e, POINTER_ACTION_SCROLL)) + { + prevEvent = MotionEvent.obtain(e); + pointerScrolling = true; + setPointerImage(R.drawable.touch_pointer_scroll); + } + + return true; + } + + public boolean onUp(MotionEvent e) + { + if (prevEvent != null) + { + prevEvent.recycle(); + prevEvent = null; + } + + if (pointerScrolling) + setPointerImage(R.drawable.touch_pointer_default); + + pointerMoving = false; + pointerScrolling = false; + return true; + } + + public void onLongPress(MotionEvent e) + { + if (pointerAreaTouched(e, POINTER_ACTION_LCLICK)) + { + setPointerImage(R.drawable.touch_pointer_active); + pointerMoving = true; + RectF rect = getCurrentPointerArea(POINTER_ACTION_CURSOR); + listener.onTouchPointerLeftClick((int)rect.centerX(), (int)rect.centerY(), true); + } + } + + public void onLongPressUp(MotionEvent e) + { + if (pointerMoving) + { + setPointerImage(R.drawable.touch_pointer_default); + pointerMoving = false; + RectF rect = getCurrentPointerArea(POINTER_ACTION_CURSOR); + listener.onTouchPointerLeftClick((int)rect.centerX(), (int)rect.centerY(), false); + } + } + + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) + { + if (pointerMoving) + { + // move pointer graphics + movePointer((int)(e2.getX() - prevEvent.getX()), + (int)(e2.getY() - prevEvent.getY())); + prevEvent.recycle(); + prevEvent = MotionEvent.obtain(e2); + + // send move notification + RectF rect = getCurrentPointerArea(POINTER_ACTION_CURSOR); + listener.onTouchPointerMove((int)rect.centerX(), (int)rect.centerY()); + return true; + } + else if (pointerScrolling) + { + // calc if user scrolled up or down (or if any scrolling happened at all) + float deltaY = e2.getY() - prevEvent.getY(); + if (deltaY > SCROLL_DELTA) + { + listener.onTouchPointerScroll(true); + prevEvent.recycle(); + prevEvent = MotionEvent.obtain(e2); + } + else if (deltaY < -SCROLL_DELTA) + { + listener.onTouchPointerScroll(false); + prevEvent.recycle(); + prevEvent = MotionEvent.obtain(e2); + } + return true; + } + return false; + } + + public boolean onSingleTapUp(MotionEvent e) + { + // look what area got touched and fire actions accordingly + if (pointerAreaTouched(e, POINTER_ACTION_CLOSE)) + listener.onTouchPointerClose(); + else if (pointerAreaTouched(e, POINTER_ACTION_LCLICK)) + { + displayPointerImageAction(R.drawable.touch_pointer_lclick); + RectF rect = getCurrentPointerArea(POINTER_ACTION_CURSOR); + listener.onTouchPointerLeftClick((int)rect.centerX(), (int)rect.centerY(), true); + listener.onTouchPointerLeftClick((int)rect.centerX(), (int)rect.centerY(), false); + } + else if (pointerAreaTouched(e, POINTER_ACTION_RCLICK)) + { + displayPointerImageAction(R.drawable.touch_pointer_rclick); + RectF rect = getCurrentPointerArea(POINTER_ACTION_CURSOR); + listener.onTouchPointerRightClick((int)rect.centerX(), (int)rect.centerY(), true); + listener.onTouchPointerRightClick((int)rect.centerX(), (int)rect.centerY(), false); + } + else if (pointerAreaTouched(e, POINTER_ACTION_KEYBOARD)) + { + displayPointerImageAction(R.drawable.touch_pointer_keyboard); + listener.onTouchPointerToggleKeyboard(); + } + else if (pointerAreaTouched(e, POINTER_ACTION_EXTKEYBOARD)) + { + displayPointerImageAction(R.drawable.touch_pointer_extkeyboard); + listener.onTouchPointerToggleExtKeyboard(); + } + else if (pointerAreaTouched(e, POINTER_ACTION_RESET)) + { + displayPointerImageAction(R.drawable.touch_pointer_reset); + listener.onTouchPointerResetScrollZoom(); + } + + return true; + } + + public boolean onDoubleTap(MotionEvent e) + { + // issue a double click notification if performed in center quadrant + if (pointerAreaTouched(e, POINTER_ACTION_LCLICK)) + { + RectF rect = getCurrentPointerArea(POINTER_ACTION_CURSOR); + listener.onTouchPointerLeftClick((int)rect.centerX(), (int)rect.centerY(), true); + listener.onTouchPointerLeftClick((int)rect.centerX(), (int)rect.centerY(), false); + } + return true; + } + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/BookmarkBaseGateway.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/BookmarkBaseGateway.java index 5335ff5..d3ed7fe 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/BookmarkBaseGateway.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/BookmarkBaseGateway.java @@ -3,13 +3,13 @@ Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.services; - import android.content.ContentValues; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; @@ -22,453 +22,596 @@ import com.freerdp.freerdpcore.domain.BookmarkBase; import java.util.ArrayList; -public abstract class BookmarkBaseGateway { - private final static String TAG = "BookmarkBaseGateway"; - private SQLiteOpenHelper bookmarkDB; - - private static final String JOIN_PREFIX = "join_"; - private static final String KEY_BOOKMARK_ID = "bookmarkId"; - private static final String KEY_SCREEN_COLORS = "screenColors"; - private static final String KEY_SCREEN_COLORS_3G = "screenColors3G"; - private static final String KEY_SCREEN_RESOLUTION = "screenResolution"; - private static final String KEY_SCREEN_RESOLUTION_3G = "screenResolution3G"; - private static final String KEY_SCREEN_WIDTH = "screenWidth"; - private static final String KEY_SCREEN_WIDTH_3G = "screenWidth3G"; - private static final String KEY_SCREEN_HEIGHT = "screenHeight"; - private static final String KEY_SCREEN_HEIGHT_3G = "screenHeight3G"; - - private static final String KEY_PERFORMANCE_RFX = "performanceRemoteFX"; - private static final String KEY_PERFORMANCE_RFX_3G = "performanceRemoteFX3G"; - private static final String KEY_PERFORMANCE_GFX = "performanceGfx"; - private static final String KEY_PERFORMANCE_GFX_3G = "performanceGfx3G"; - private static final String KEY_PERFORMANCE_H264 = "performanceGfxH264"; - private static final String KEY_PERFORMANCE_H264_3G = "performanceGfxH2643G"; - private static final String KEY_PERFORMANCE_WALLPAPER = "performanceWallpaper"; - private static final String KEY_PERFORMANCE_WALLPAPER_3G = "performanceWallpaper3G"; - private static final String KEY_PERFORMANCE_THEME = "performanceTheming"; - private static final String KEY_PERFORMANCE_THEME_3G = "performanceTheming3G"; - - private static final String KEY_PERFORMANCE_DRAG = "performanceFullWindowDrag"; - private static final String KEY_PERFORMANCE_DRAG_3G = "performanceFullWindowDrag3G"; - private static final String KEY_PERFORMANCE_MENU_ANIMATIONS = "performanceMenuAnimations"; - private static final String KEY_PERFORMANCE_MENU_ANIMATIONS_3G = "performanceMenuAnimations3G"; - private static final String KEY_PERFORMANCE_FONTS = "performanceFontSmoothing"; - private static final String KEY_PERFORMANCE_FONTS_3G = "performanceFontSmoothing3G"; - private static final String KEY_PERFORMANCE_COMPOSITION = "performanceDesktopComposition"; - private static final String KEY_PERFORMANCE_COMPOSITION_3G = "performanceDesktopComposition3G"; - - public BookmarkBaseGateway(SQLiteOpenHelper bookmarkDB) { - this.bookmarkDB = bookmarkDB; - } - - protected abstract BookmarkBase createBookmark(); - - protected abstract String getBookmarkTableName(); - - protected abstract void addBookmarkSpecificColumns(ArrayList columns); - - protected abstract void addBookmarkSpecificColumns(BookmarkBase bookmark, ContentValues columns); - - protected abstract void readBookmarkSpecificColumns(BookmarkBase bookmark, Cursor cursor); - - public void insert(BookmarkBase bookmark) { - // begin transaction - SQLiteDatabase db = getWritableDatabase(); - db.beginTransaction(); - - long rowid; - ContentValues values = new ContentValues(); - values.put(BookmarkDB.DB_KEY_BOOKMARK_LABEL, bookmark.getLabel()); - values.put(BookmarkDB.DB_KEY_BOOKMARK_USERNAME, bookmark.getUsername()); - values.put(BookmarkDB.DB_KEY_BOOKMARK_PASSWORD, bookmark.getPassword()); - values.put(BookmarkDB.DB_KEY_BOOKMARK_DOMAIN, bookmark.getDomain()); - // insert screen and performance settings - rowid = insertScreenSettings(db, bookmark.getScreenSettings()); - values.put(BookmarkDB.DB_KEY_SCREEN_SETTINGS, rowid); - rowid = insertPerformanceFlags(db, bookmark.getPerformanceFlags()); - values.put(BookmarkDB.DB_KEY_PERFORMANCE_FLAGS, rowid); - - // advanced settings - values.put(BookmarkDB.DB_KEY_BOOKMARK_3G_ENABLE, bookmark.getAdvancedSettings().getEnable3GSettings()); - // insert 3G screen and 3G performance settings - rowid = insertScreenSettings(db, bookmark.getAdvancedSettings().getScreen3G()); - values.put(BookmarkDB.DB_KEY_SCREEN_SETTINGS_3G, rowid); - rowid = insertPerformanceFlags(db, bookmark.getAdvancedSettings().getPerformance3G()); - values.put(BookmarkDB.DB_KEY_PERFORMANCE_FLAGS_3G, rowid); - values.put(BookmarkDB.DB_KEY_BOOKMARK_REDIRECT_SDCARD, bookmark.getAdvancedSettings().getRedirectSDCard()); - values.put(BookmarkDB.DB_KEY_BOOKMARK_REDIRECT_SOUND, bookmark.getAdvancedSettings().getRedirectSound()); - values.put(BookmarkDB.DB_KEY_BOOKMARK_REDIRECT_MICROPHONE, bookmark.getAdvancedSettings().getRedirectMicrophone()); - values.put(BookmarkDB.DB_KEY_BOOKMARK_SECURITY, bookmark.getAdvancedSettings().getSecurity()); - values.put(BookmarkDB.DB_KEY_BOOKMARK_CONSOLE_MODE, bookmark.getAdvancedSettings().getConsoleMode()); - values.put(BookmarkDB.DB_KEY_BOOKMARK_REMOTE_PROGRAM, bookmark.getAdvancedSettings().getRemoteProgram()); - values.put(BookmarkDB.DB_KEY_BOOKMARK_WORK_DIR, bookmark.getAdvancedSettings().getWorkDir()); - - values.put(BookmarkDB.DB_KEY_BOOKMARK_ASYNC_CHANNEL, bookmark.getDebugSettings().getAsyncChannel()); - values.put(BookmarkDB.DB_KEY_BOOKMARK_ASYNC_INPUT, bookmark.getDebugSettings().getAsyncInput()); - values.put(BookmarkDB.DB_KEY_BOOKMARK_ASYNC_UPDATE, bookmark.getDebugSettings().getAsyncUpdate()); - values.put(BookmarkDB.DB_KEY_BOOKMARK_DEBUG_LEVEL, bookmark.getDebugSettings().getDebugLevel()); - - // add any special columns - addBookmarkSpecificColumns(bookmark, values); - - // insert bookmark and end transaction - db.insertOrThrow(getBookmarkTableName(), null, values); - db.setTransactionSuccessful(); - db.endTransaction(); - } - - public boolean update(BookmarkBase bookmark) { - // start a transaction - SQLiteDatabase db = getWritableDatabase(); - db.beginTransaction(); - - // bookmark settings - ContentValues values = new ContentValues(); - values.put(BookmarkDB.DB_KEY_BOOKMARK_LABEL, bookmark.getLabel()); - values.put(BookmarkDB.DB_KEY_BOOKMARK_USERNAME, bookmark.getUsername()); - values.put(BookmarkDB.DB_KEY_BOOKMARK_PASSWORD, bookmark.getPassword()); - values.put(BookmarkDB.DB_KEY_BOOKMARK_DOMAIN, bookmark.getDomain()); - // update screen and performance settings settings - updateScreenSettings(db, bookmark); - updatePerformanceFlags(db, bookmark); - - // advanced settings - values.put(BookmarkDB.DB_KEY_BOOKMARK_3G_ENABLE, bookmark.getAdvancedSettings().getEnable3GSettings()); - // update 3G screen and 3G performance settings settings - updateScreenSettings3G(db, bookmark); - updatePerformanceFlags3G(db, bookmark); - values.put(BookmarkDB.DB_KEY_BOOKMARK_REDIRECT_SDCARD, bookmark.getAdvancedSettings().getRedirectSDCard()); - values.put(BookmarkDB.DB_KEY_BOOKMARK_REDIRECT_SOUND, bookmark.getAdvancedSettings().getRedirectSound()); - values.put(BookmarkDB.DB_KEY_BOOKMARK_REDIRECT_MICROPHONE, bookmark.getAdvancedSettings().getRedirectMicrophone()); - values.put(BookmarkDB.DB_KEY_BOOKMARK_SECURITY, bookmark.getAdvancedSettings().getSecurity()); - values.put(BookmarkDB.DB_KEY_BOOKMARK_CONSOLE_MODE, bookmark.getAdvancedSettings().getConsoleMode()); - values.put(BookmarkDB.DB_KEY_BOOKMARK_REMOTE_PROGRAM, bookmark.getAdvancedSettings().getRemoteProgram()); - values.put(BookmarkDB.DB_KEY_BOOKMARK_WORK_DIR, bookmark.getAdvancedSettings().getWorkDir()); - - values.put(BookmarkDB.DB_KEY_BOOKMARK_ASYNC_CHANNEL, bookmark.getDebugSettings().getAsyncChannel()); - values.put(BookmarkDB.DB_KEY_BOOKMARK_ASYNC_INPUT, bookmark.getDebugSettings().getAsyncInput()); - values.put(BookmarkDB.DB_KEY_BOOKMARK_ASYNC_UPDATE, bookmark.getDebugSettings().getAsyncUpdate()); - values.put(BookmarkDB.DB_KEY_BOOKMARK_DEBUG_LEVEL, bookmark.getDebugSettings().getDebugLevel()); - - addBookmarkSpecificColumns(bookmark, values); - - // update bookmark - boolean res = (db.update(getBookmarkTableName(), values, BookmarkDB.ID + " = " + bookmark.getId(), null) == 1); - - // commit - db.setTransactionSuccessful(); - db.endTransaction(); - - return res; - } - - public void delete(long id) { - SQLiteDatabase db = getWritableDatabase(); - db.delete(getBookmarkTableName(), BookmarkDB.ID + " = " + id, null); - } - - public BookmarkBase findById(long id) { - Cursor cursor = queryBookmarks(getBookmarkTableName() + "." + BookmarkDB.ID + " = " + id, null); - if (cursor.getCount() == 0) { - cursor.close(); - return null; - } - - cursor.moveToFirst(); - BookmarkBase bookmark = getBookmarkFromCursor(cursor); - cursor.close(); - return bookmark; - } - - public BookmarkBase findByLabel(String label) { - Cursor cursor = queryBookmarks(BookmarkDB.DB_KEY_BOOKMARK_LABEL + " = '" + label + "'", BookmarkDB.DB_KEY_BOOKMARK_LABEL); - if (cursor.getCount() > 1) - Log.e(TAG, "More than one bookmark with the same label found!"); - - BookmarkBase bookmark = null; - if (cursor.moveToFirst() && (cursor.getCount() > 0)) - bookmark = getBookmarkFromCursor(cursor); - - cursor.close(); - return bookmark; - } - - public ArrayList findByLabelLike(String pattern) { - Cursor cursor = queryBookmarks(BookmarkDB.DB_KEY_BOOKMARK_LABEL + " LIKE '%" + pattern + "%'", BookmarkDB.DB_KEY_BOOKMARK_LABEL); - ArrayList bookmarks = new ArrayList(cursor.getCount()); - - if (cursor.moveToFirst() && (cursor.getCount() > 0)) { - do { - bookmarks.add(getBookmarkFromCursor(cursor)); - } while (cursor.moveToNext()); - } - - cursor.close(); - return bookmarks; - } - - public ArrayList findAll() { - Cursor cursor = queryBookmarks(null, BookmarkDB.DB_KEY_BOOKMARK_LABEL); - final int count = cursor.getCount(); - ArrayList bookmarks = new ArrayList<>(count); - - if (cursor.moveToFirst() && (count > 0)) { - do { - bookmarks.add(getBookmarkFromCursor(cursor)); - } while (cursor.moveToNext()); - } - - cursor.close(); - return bookmarks; - } - - protected Cursor queryBookmarks(String whereClause, String orderBy) { - // create tables string - final String ID = BookmarkDB.ID; - final String tables = BookmarkDB.DB_TABLE_BOOKMARK + " INNER JOIN " + - BookmarkDB.DB_TABLE_SCREEN + " AS " + JOIN_PREFIX + BookmarkDB.DB_KEY_SCREEN_SETTINGS + " ON " + JOIN_PREFIX + BookmarkDB.DB_KEY_SCREEN_SETTINGS + "." + - ID + " = " + BookmarkDB.DB_TABLE_BOOKMARK + "." + BookmarkDB.DB_KEY_SCREEN_SETTINGS + - " INNER JOIN " + BookmarkDB.DB_TABLE_PERFORMANCE + - " AS " + JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS + " ON " + JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS + "." + ID + " = " + - BookmarkDB.DB_TABLE_BOOKMARK + "." + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS + - " INNER JOIN " + BookmarkDB.DB_TABLE_SCREEN + - " AS " + JOIN_PREFIX + BookmarkDB.DB_KEY_SCREEN_SETTINGS_3G + " ON " + JOIN_PREFIX + BookmarkDB.DB_KEY_SCREEN_SETTINGS_3G + "." + ID + " = " + - BookmarkDB.DB_TABLE_BOOKMARK + "." + BookmarkDB.DB_KEY_SCREEN_SETTINGS_3G + - " INNER JOIN " + BookmarkDB.DB_TABLE_PERFORMANCE + - " AS " + JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS_3G + " ON " + JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS_3G + "." + ID + " = " + - BookmarkDB.DB_TABLE_BOOKMARK + "." + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS_3G; - - // create columns list - ArrayList columns = new ArrayList<>(); - addBookmarkColumns(columns); - addScreenSettingsColumns(columns); - addPerformanceFlagsColumns(columns); - addScreenSettings3GColumns(columns); - addPerformanceFlags3GColumns(columns); - - String[] cols = new String[columns.size()]; - columns.toArray(cols); - - SQLiteDatabase db = getReadableDatabase(); - final String query = SQLiteQueryBuilder.buildQueryString(false, tables, cols, whereClause, null, null, orderBy, null); - return db.rawQuery(query, null); - } - - private void addBookmarkColumns(ArrayList columns) { - columns.add(getBookmarkTableName() + "." + BookmarkDB.ID + " " + KEY_BOOKMARK_ID); - columns.add(BookmarkDB.DB_KEY_BOOKMARK_LABEL); - columns.add(BookmarkDB.DB_KEY_BOOKMARK_USERNAME); - columns.add(BookmarkDB.DB_KEY_BOOKMARK_PASSWORD); - columns.add(BookmarkDB.DB_KEY_BOOKMARK_DOMAIN); - - // advanced settings - columns.add(BookmarkDB.DB_KEY_BOOKMARK_3G_ENABLE); - columns.add(BookmarkDB.DB_KEY_BOOKMARK_REDIRECT_SDCARD); - columns.add(BookmarkDB.DB_KEY_BOOKMARK_REDIRECT_SOUND); - columns.add(BookmarkDB.DB_KEY_BOOKMARK_REDIRECT_MICROPHONE); - columns.add(BookmarkDB.DB_KEY_BOOKMARK_SECURITY); - columns.add(BookmarkDB.DB_KEY_BOOKMARK_CONSOLE_MODE); - columns.add(BookmarkDB.DB_KEY_BOOKMARK_REMOTE_PROGRAM); - columns.add(BookmarkDB.DB_KEY_BOOKMARK_WORK_DIR); - - // debug settings - columns.add(BookmarkDB.DB_KEY_BOOKMARK_DEBUG_LEVEL); - columns.add(BookmarkDB.DB_KEY_BOOKMARK_ASYNC_CHANNEL); - columns.add(BookmarkDB.DB_KEY_BOOKMARK_ASYNC_UPDATE); - columns.add(BookmarkDB.DB_KEY_BOOKMARK_ASYNC_INPUT); - - addBookmarkSpecificColumns(columns); - } - - private void addScreenSettingsColumns(ArrayList columns) { - columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_SCREEN_SETTINGS + "." + BookmarkDB.DB_KEY_SCREEN_COLORS + " as " + KEY_SCREEN_COLORS); - columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_SCREEN_SETTINGS + "." + BookmarkDB.DB_KEY_SCREEN_RESOLUTION + " as " + KEY_SCREEN_RESOLUTION); - columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_SCREEN_SETTINGS + "." + BookmarkDB.DB_KEY_SCREEN_WIDTH + " as " + KEY_SCREEN_WIDTH); - columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_SCREEN_SETTINGS + "." + BookmarkDB.DB_KEY_SCREEN_HEIGHT + " as " + KEY_SCREEN_HEIGHT); - } - - private void addPerformanceFlagsColumns(ArrayList columns) { - columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS + "." + BookmarkDB.DB_KEY_PERFORMANCE_RFX + " as " + KEY_PERFORMANCE_RFX); - columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS + "." + BookmarkDB.DB_KEY_PERFORMANCE_GFX + " as " + KEY_PERFORMANCE_GFX); - columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS + "." + BookmarkDB.DB_KEY_PERFORMANCE_H264 + " as " + KEY_PERFORMANCE_H264); - columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS + "." + BookmarkDB.DB_KEY_PERFORMANCE_WALLPAPER + " as " + KEY_PERFORMANCE_WALLPAPER); - columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS + "." + BookmarkDB.DB_KEY_PERFORMANCE_THEME + " as " + KEY_PERFORMANCE_THEME); - columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS + "." + BookmarkDB.DB_KEY_PERFORMANCE_DRAG + " as " + KEY_PERFORMANCE_DRAG); - columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS + "." + BookmarkDB.DB_KEY_PERFORMANCE_MENU_ANIMATIONS + " as " + KEY_PERFORMANCE_MENU_ANIMATIONS); - columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS + "." + BookmarkDB.DB_KEY_PERFORMANCE_FONTS + " as " + KEY_PERFORMANCE_FONTS); - columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS + "." + BookmarkDB.DB_KEY_PERFORMANCE_COMPOSITION + " " + KEY_PERFORMANCE_COMPOSITION); - } - - private void addScreenSettings3GColumns(ArrayList columns) { - columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_SCREEN_SETTINGS_3G + "." + BookmarkDB.DB_KEY_SCREEN_COLORS + " as " + KEY_SCREEN_COLORS_3G); - columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_SCREEN_SETTINGS_3G + "." + BookmarkDB.DB_KEY_SCREEN_RESOLUTION + " as " + KEY_SCREEN_RESOLUTION_3G); - columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_SCREEN_SETTINGS_3G + "." + BookmarkDB.DB_KEY_SCREEN_WIDTH + " as " + KEY_SCREEN_WIDTH_3G); - columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_SCREEN_SETTINGS_3G + "." + BookmarkDB.DB_KEY_SCREEN_HEIGHT + " as " + KEY_SCREEN_HEIGHT_3G); - } - - private void addPerformanceFlags3GColumns(ArrayList columns) { - columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS_3G + "." + BookmarkDB.DB_KEY_PERFORMANCE_RFX + " as " + KEY_PERFORMANCE_RFX_3G); - columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS_3G + "." + BookmarkDB.DB_KEY_PERFORMANCE_GFX + " as " + KEY_PERFORMANCE_GFX_3G); - columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS_3G + "." + BookmarkDB.DB_KEY_PERFORMANCE_H264 + " as " + KEY_PERFORMANCE_H264_3G); - columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS_3G + "." + BookmarkDB.DB_KEY_PERFORMANCE_WALLPAPER + " as " + KEY_PERFORMANCE_WALLPAPER_3G); - columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS_3G + "." + BookmarkDB.DB_KEY_PERFORMANCE_THEME + " as " + KEY_PERFORMANCE_THEME_3G); - columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS_3G + "." + BookmarkDB.DB_KEY_PERFORMANCE_DRAG + " as " + KEY_PERFORMANCE_DRAG_3G); - columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS_3G + "." + BookmarkDB.DB_KEY_PERFORMANCE_MENU_ANIMATIONS + " as " + KEY_PERFORMANCE_MENU_ANIMATIONS_3G); - columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS_3G + "." + BookmarkDB.DB_KEY_PERFORMANCE_FONTS + " as " + KEY_PERFORMANCE_FONTS_3G); - columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS_3G + "." + BookmarkDB.DB_KEY_PERFORMANCE_COMPOSITION + " " + KEY_PERFORMANCE_COMPOSITION_3G); - } - - protected BookmarkBase getBookmarkFromCursor(Cursor cursor) { - BookmarkBase bookmark = createBookmark(); - bookmark.setId(cursor.getLong(cursor.getColumnIndex(KEY_BOOKMARK_ID))); - bookmark.setLabel(cursor.getString(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_LABEL))); - bookmark.setUsername(cursor.getString(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_USERNAME))); - bookmark.setPassword(cursor.getString(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_PASSWORD))); - bookmark.setDomain(cursor.getString(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_DOMAIN))); - readScreenSettings(bookmark, cursor); - readPerformanceFlags(bookmark, cursor); - - // advanced settings - bookmark.getAdvancedSettings().setEnable3GSettings(cursor.getInt(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_3G_ENABLE)) != 0); - readScreenSettings3G(bookmark, cursor); - readPerformanceFlags3G(bookmark, cursor); - bookmark.getAdvancedSettings().setRedirectSDCard(cursor.getInt(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_REDIRECT_SDCARD)) != 0); - bookmark.getAdvancedSettings().setRedirectSound(cursor.getInt(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_REDIRECT_SOUND))); - bookmark.getAdvancedSettings().setRedirectMicrophone(cursor.getInt(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_REDIRECT_MICROPHONE)) != 0); - bookmark.getAdvancedSettings().setSecurity(cursor.getInt(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_SECURITY))); - bookmark.getAdvancedSettings().setConsoleMode(cursor.getInt(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_CONSOLE_MODE)) != 0); - bookmark.getAdvancedSettings().setRemoteProgram(cursor.getString(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_REMOTE_PROGRAM))); - bookmark.getAdvancedSettings().setWorkDir(cursor.getString(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_WORK_DIR))); - - bookmark.getDebugSettings().setAsyncChannel( - cursor.getInt(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_ASYNC_CHANNEL)) == 1); - bookmark.getDebugSettings().setAsyncInput( - cursor.getInt(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_ASYNC_INPUT)) == 1); - bookmark.getDebugSettings().setAsyncUpdate( - cursor.getInt(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_ASYNC_UPDATE)) == 1); - bookmark.getDebugSettings().setDebugLevel(cursor.getString(cursor.getColumnIndex - (BookmarkDB.DB_KEY_BOOKMARK_DEBUG_LEVEL))); - - readBookmarkSpecificColumns(bookmark, cursor); - - return bookmark; - } - - private void readScreenSettings(BookmarkBase bookmark, Cursor cursor) { - BookmarkBase.ScreenSettings screenSettings = bookmark.getScreenSettings(); - screenSettings.setColors(cursor.getInt(cursor.getColumnIndex(KEY_SCREEN_COLORS))); - screenSettings.setResolution(cursor.getInt(cursor.getColumnIndex(KEY_SCREEN_RESOLUTION))); - screenSettings.setWidth(cursor.getInt(cursor.getColumnIndex(KEY_SCREEN_WIDTH))); - screenSettings.setHeight(cursor.getInt(cursor.getColumnIndex(KEY_SCREEN_HEIGHT))); - } - - private void readPerformanceFlags(BookmarkBase bookmark, Cursor cursor) { - BookmarkBase.PerformanceFlags perfFlags = bookmark.getPerformanceFlags(); - perfFlags.setRemoteFX(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_RFX)) != 0); - perfFlags.setGfx(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_GFX)) != 0); - perfFlags.setH264(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_H264)) != 0); - perfFlags.setWallpaper(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_WALLPAPER)) != 0); - perfFlags.setTheming(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_THEME)) != 0); - perfFlags.setFullWindowDrag(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_DRAG)) != 0); - perfFlags.setMenuAnimations(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_MENU_ANIMATIONS)) != 0); - perfFlags.setFontSmoothing(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_FONTS)) != 0); - perfFlags.setDesktopComposition(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_COMPOSITION)) != 0); - } - - private void readScreenSettings3G(BookmarkBase bookmark, Cursor cursor) { - BookmarkBase.ScreenSettings screenSettings = bookmark.getAdvancedSettings().getScreen3G(); - screenSettings.setColors(cursor.getInt(cursor.getColumnIndex(KEY_SCREEN_COLORS_3G))); - screenSettings.setResolution(cursor.getInt(cursor.getColumnIndex(KEY_SCREEN_RESOLUTION_3G))); - screenSettings.setWidth(cursor.getInt(cursor.getColumnIndex(KEY_SCREEN_WIDTH_3G))); - screenSettings.setHeight(cursor.getInt(cursor.getColumnIndex(KEY_SCREEN_HEIGHT_3G))); - } - - private void readPerformanceFlags3G(BookmarkBase bookmark, Cursor cursor) { - BookmarkBase.PerformanceFlags perfFlags = bookmark.getAdvancedSettings().getPerformance3G(); - perfFlags.setRemoteFX(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_RFX_3G)) != 0); - perfFlags.setGfx(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_GFX_3G)) != 0); - perfFlags.setH264(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_H264_3G)) != 0); - perfFlags.setWallpaper(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_WALLPAPER_3G)) != 0); - perfFlags.setTheming(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_THEME_3G)) != 0); - perfFlags.setFullWindowDrag(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_DRAG_3G)) != 0); - perfFlags.setMenuAnimations(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_MENU_ANIMATIONS_3G)) != 0); - perfFlags.setFontSmoothing(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_FONTS_3G)) != 0); - perfFlags.setDesktopComposition(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_COMPOSITION_3G)) != 0); - } - - private void fillScreenSettingsContentValues(BookmarkBase.ScreenSettings settings, ContentValues values) { - values.put(BookmarkDB.DB_KEY_SCREEN_COLORS, settings.getColors()); - values.put(BookmarkDB.DB_KEY_SCREEN_RESOLUTION, settings.getResolution()); - values.put(BookmarkDB.DB_KEY_SCREEN_WIDTH, settings.getWidth()); - values.put(BookmarkDB.DB_KEY_SCREEN_HEIGHT, settings.getHeight()); - } - - private void fillPerformanceFlagsContentValues(BookmarkBase.PerformanceFlags perfFlags, ContentValues values) { - values.put(BookmarkDB.DB_KEY_PERFORMANCE_RFX, perfFlags.getRemoteFX()); - values.put(BookmarkDB.DB_KEY_PERFORMANCE_GFX, perfFlags.getGfx()); - values.put(BookmarkDB.DB_KEY_PERFORMANCE_H264, perfFlags.getH264()); - values.put(BookmarkDB.DB_KEY_PERFORMANCE_WALLPAPER, perfFlags.getWallpaper()); - values.put(BookmarkDB.DB_KEY_PERFORMANCE_THEME, perfFlags.getTheming()); - values.put(BookmarkDB.DB_KEY_PERFORMANCE_DRAG, perfFlags.getFullWindowDrag()); - values.put(BookmarkDB.DB_KEY_PERFORMANCE_MENU_ANIMATIONS, perfFlags.getMenuAnimations()); - values.put(BookmarkDB.DB_KEY_PERFORMANCE_FONTS, perfFlags.getFontSmoothing()); - values.put(BookmarkDB.DB_KEY_PERFORMANCE_COMPOSITION, perfFlags.getDesktopComposition()); - } - - private long insertScreenSettings(SQLiteDatabase db, BookmarkBase.ScreenSettings settings) { - ContentValues values = new ContentValues(); - fillScreenSettingsContentValues(settings, values); - return db.insertOrThrow(BookmarkDB.DB_TABLE_SCREEN, null, values); - } - - private boolean updateScreenSettings(SQLiteDatabase db, BookmarkBase bookmark) { - ContentValues values = new ContentValues(); - fillScreenSettingsContentValues(bookmark.getScreenSettings(), values); - String whereClause = BookmarkDB.ID + " IN " + "(SELECT " + BookmarkDB.DB_KEY_SCREEN_SETTINGS + " FROM " + getBookmarkTableName() + " WHERE " + BookmarkDB.ID + " = " + bookmark.getId() + ");"; - return (db.update(BookmarkDB.DB_TABLE_SCREEN, values, whereClause, null) == 1); - } - - private boolean updateScreenSettings3G(SQLiteDatabase db, BookmarkBase bookmark) { - ContentValues values = new ContentValues(); - fillScreenSettingsContentValues(bookmark.getAdvancedSettings().getScreen3G(), values); - String whereClause = BookmarkDB.ID + " IN " + "(SELECT " + BookmarkDB.DB_KEY_SCREEN_SETTINGS_3G + " FROM " + getBookmarkTableName() + " WHERE " + BookmarkDB.ID + " = " + bookmark.getId() + ");"; - return (db.update(BookmarkDB.DB_TABLE_SCREEN, values, whereClause, null) == 1); - } - - private long insertPerformanceFlags(SQLiteDatabase db, BookmarkBase.PerformanceFlags perfFlags) { - ContentValues values = new ContentValues(); - fillPerformanceFlagsContentValues(perfFlags, values); - return db.insertOrThrow(BookmarkDB.DB_TABLE_PERFORMANCE, null, values); - } - - private boolean updatePerformanceFlags(SQLiteDatabase db, BookmarkBase bookmark) { - ContentValues values = new ContentValues(); - fillPerformanceFlagsContentValues(bookmark.getPerformanceFlags(), values); - String whereClause = BookmarkDB.ID + " IN " + "(SELECT " + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS + " FROM " + getBookmarkTableName() + " WHERE " + BookmarkDB.ID + " = " + bookmark.getId() + ");"; - return (db.update(BookmarkDB.DB_TABLE_PERFORMANCE, values, whereClause, null) == 1); - } - - private boolean updatePerformanceFlags3G(SQLiteDatabase db, BookmarkBase bookmark) { - ContentValues values = new ContentValues(); - fillPerformanceFlagsContentValues(bookmark.getAdvancedSettings().getPerformance3G(), values); - String whereClause = BookmarkDB.ID + " IN " + "(SELECT " + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS_3G + " FROM " + getBookmarkTableName() + " WHERE " + BookmarkDB.ID + " = " + bookmark.getId() + ");"; - return (db.update(BookmarkDB.DB_TABLE_PERFORMANCE, values, whereClause, null) == 1); - } - - // safety wrappers - // in case of getReadableDatabase it could happen that upgradeDB gets called which is - // a problem if the DB is only readable - private SQLiteDatabase getWritableDatabase() { - return bookmarkDB.getWritableDatabase(); - } - - private SQLiteDatabase getReadableDatabase() { - SQLiteDatabase db; - try { - db = bookmarkDB.getReadableDatabase(); - } catch (SQLiteException e) { - db = bookmarkDB.getWritableDatabase(); - } - return db; - } +public abstract class BookmarkBaseGateway +{ + private final static String TAG = "BookmarkBaseGateway"; + private SQLiteOpenHelper bookmarkDB; + + private static final String JOIN_PREFIX = "join_"; + private static final String KEY_BOOKMARK_ID = "bookmarkId"; + private static final String KEY_SCREEN_COLORS = "screenColors"; + private static final String KEY_SCREEN_COLORS_3G = "screenColors3G"; + private static final String KEY_SCREEN_RESOLUTION = "screenResolution"; + private static final String KEY_SCREEN_RESOLUTION_3G = "screenResolution3G"; + private static final String KEY_SCREEN_WIDTH = "screenWidth"; + private static final String KEY_SCREEN_WIDTH_3G = "screenWidth3G"; + private static final String KEY_SCREEN_HEIGHT = "screenHeight"; + private static final String KEY_SCREEN_HEIGHT_3G = "screenHeight3G"; + + private static final String KEY_PERFORMANCE_RFX = "performanceRemoteFX"; + private static final String KEY_PERFORMANCE_RFX_3G = "performanceRemoteFX3G"; + private static final String KEY_PERFORMANCE_GFX = "performanceGfx"; + private static final String KEY_PERFORMANCE_GFX_3G = "performanceGfx3G"; + private static final String KEY_PERFORMANCE_H264 = "performanceGfxH264"; + private static final String KEY_PERFORMANCE_H264_3G = "performanceGfxH2643G"; + private static final String KEY_PERFORMANCE_WALLPAPER = "performanceWallpaper"; + private static final String KEY_PERFORMANCE_WALLPAPER_3G = "performanceWallpaper3G"; + private static final String KEY_PERFORMANCE_THEME = "performanceTheming"; + private static final String KEY_PERFORMANCE_THEME_3G = "performanceTheming3G"; + + private static final String KEY_PERFORMANCE_DRAG = "performanceFullWindowDrag"; + private static final String KEY_PERFORMANCE_DRAG_3G = "performanceFullWindowDrag3G"; + private static final String KEY_PERFORMANCE_MENU_ANIMATIONS = "performanceMenuAnimations"; + private static final String KEY_PERFORMANCE_MENU_ANIMATIONS_3G = "performanceMenuAnimations3G"; + private static final String KEY_PERFORMANCE_FONTS = "performanceFontSmoothing"; + private static final String KEY_PERFORMANCE_FONTS_3G = "performanceFontSmoothing3G"; + private static final String KEY_PERFORMANCE_COMPOSITION = "performanceDesktopComposition"; + private static final String KEY_PERFORMANCE_COMPOSITION_3G = "performanceDesktopComposition3G"; + + public BookmarkBaseGateway(SQLiteOpenHelper bookmarkDB) + { + this.bookmarkDB = bookmarkDB; + } + + protected abstract BookmarkBase createBookmark(); + + protected abstract String getBookmarkTableName(); + + protected abstract void addBookmarkSpecificColumns(ArrayList columns); + + protected abstract void addBookmarkSpecificColumns(BookmarkBase bookmark, + ContentValues columns); + + protected abstract void readBookmarkSpecificColumns(BookmarkBase bookmark, Cursor cursor); + + public void insert(BookmarkBase bookmark) + { + // begin transaction + SQLiteDatabase db = getWritableDatabase(); + db.beginTransaction(); + + long rowid; + ContentValues values = new ContentValues(); + values.put(BookmarkDB.DB_KEY_BOOKMARK_LABEL, bookmark.getLabel()); + values.put(BookmarkDB.DB_KEY_BOOKMARK_USERNAME, bookmark.getUsername()); + values.put(BookmarkDB.DB_KEY_BOOKMARK_PASSWORD, bookmark.getPassword()); + values.put(BookmarkDB.DB_KEY_BOOKMARK_DOMAIN, bookmark.getDomain()); + // insert screen and performance settings + rowid = insertScreenSettings(db, bookmark.getScreenSettings()); + values.put(BookmarkDB.DB_KEY_SCREEN_SETTINGS, rowid); + rowid = insertPerformanceFlags(db, bookmark.getPerformanceFlags()); + values.put(BookmarkDB.DB_KEY_PERFORMANCE_FLAGS, rowid); + + // advanced settings + values.put(BookmarkDB.DB_KEY_BOOKMARK_3G_ENABLE, + bookmark.getAdvancedSettings().getEnable3GSettings()); + // insert 3G screen and 3G performance settings + rowid = insertScreenSettings(db, bookmark.getAdvancedSettings().getScreen3G()); + values.put(BookmarkDB.DB_KEY_SCREEN_SETTINGS_3G, rowid); + rowid = insertPerformanceFlags(db, bookmark.getAdvancedSettings().getPerformance3G()); + values.put(BookmarkDB.DB_KEY_PERFORMANCE_FLAGS_3G, rowid); + values.put(BookmarkDB.DB_KEY_BOOKMARK_REDIRECT_SDCARD, + bookmark.getAdvancedSettings().getRedirectSDCard()); + values.put(BookmarkDB.DB_KEY_BOOKMARK_REDIRECT_SOUND, + bookmark.getAdvancedSettings().getRedirectSound()); + values.put(BookmarkDB.DB_KEY_BOOKMARK_REDIRECT_MICROPHONE, + bookmark.getAdvancedSettings().getRedirectMicrophone()); + values.put(BookmarkDB.DB_KEY_BOOKMARK_SECURITY, + bookmark.getAdvancedSettings().getSecurity()); + values.put(BookmarkDB.DB_KEY_BOOKMARK_CONSOLE_MODE, + bookmark.getAdvancedSettings().getConsoleMode()); + values.put(BookmarkDB.DB_KEY_BOOKMARK_REMOTE_PROGRAM, + bookmark.getAdvancedSettings().getRemoteProgram()); + values.put(BookmarkDB.DB_KEY_BOOKMARK_WORK_DIR, + bookmark.getAdvancedSettings().getWorkDir()); + + values.put(BookmarkDB.DB_KEY_BOOKMARK_ASYNC_CHANNEL, + bookmark.getDebugSettings().getAsyncChannel()); + values.put(BookmarkDB.DB_KEY_BOOKMARK_ASYNC_INPUT, + bookmark.getDebugSettings().getAsyncInput()); + values.put(BookmarkDB.DB_KEY_BOOKMARK_ASYNC_UPDATE, + bookmark.getDebugSettings().getAsyncUpdate()); + values.put(BookmarkDB.DB_KEY_BOOKMARK_DEBUG_LEVEL, + bookmark.getDebugSettings().getDebugLevel()); + + // add any special columns + addBookmarkSpecificColumns(bookmark, values); + + // insert bookmark and end transaction + db.insertOrThrow(getBookmarkTableName(), null, values); + db.setTransactionSuccessful(); + db.endTransaction(); + } + + public boolean update(BookmarkBase bookmark) + { + // start a transaction + SQLiteDatabase db = getWritableDatabase(); + db.beginTransaction(); + + // bookmark settings + ContentValues values = new ContentValues(); + values.put(BookmarkDB.DB_KEY_BOOKMARK_LABEL, bookmark.getLabel()); + values.put(BookmarkDB.DB_KEY_BOOKMARK_USERNAME, bookmark.getUsername()); + values.put(BookmarkDB.DB_KEY_BOOKMARK_PASSWORD, bookmark.getPassword()); + values.put(BookmarkDB.DB_KEY_BOOKMARK_DOMAIN, bookmark.getDomain()); + // update screen and performance settings settings + updateScreenSettings(db, bookmark); + updatePerformanceFlags(db, bookmark); + + // advanced settings + values.put(BookmarkDB.DB_KEY_BOOKMARK_3G_ENABLE, + bookmark.getAdvancedSettings().getEnable3GSettings()); + // update 3G screen and 3G performance settings settings + updateScreenSettings3G(db, bookmark); + updatePerformanceFlags3G(db, bookmark); + values.put(BookmarkDB.DB_KEY_BOOKMARK_REDIRECT_SDCARD, + bookmark.getAdvancedSettings().getRedirectSDCard()); + values.put(BookmarkDB.DB_KEY_BOOKMARK_REDIRECT_SOUND, + bookmark.getAdvancedSettings().getRedirectSound()); + values.put(BookmarkDB.DB_KEY_BOOKMARK_REDIRECT_MICROPHONE, + bookmark.getAdvancedSettings().getRedirectMicrophone()); + values.put(BookmarkDB.DB_KEY_BOOKMARK_SECURITY, + bookmark.getAdvancedSettings().getSecurity()); + values.put(BookmarkDB.DB_KEY_BOOKMARK_CONSOLE_MODE, + bookmark.getAdvancedSettings().getConsoleMode()); + values.put(BookmarkDB.DB_KEY_BOOKMARK_REMOTE_PROGRAM, + bookmark.getAdvancedSettings().getRemoteProgram()); + values.put(BookmarkDB.DB_KEY_BOOKMARK_WORK_DIR, + bookmark.getAdvancedSettings().getWorkDir()); + + values.put(BookmarkDB.DB_KEY_BOOKMARK_ASYNC_CHANNEL, + bookmark.getDebugSettings().getAsyncChannel()); + values.put(BookmarkDB.DB_KEY_BOOKMARK_ASYNC_INPUT, + bookmark.getDebugSettings().getAsyncInput()); + values.put(BookmarkDB.DB_KEY_BOOKMARK_ASYNC_UPDATE, + bookmark.getDebugSettings().getAsyncUpdate()); + values.put(BookmarkDB.DB_KEY_BOOKMARK_DEBUG_LEVEL, + bookmark.getDebugSettings().getDebugLevel()); + + addBookmarkSpecificColumns(bookmark, values); + + // update bookmark + boolean res = (db.update(getBookmarkTableName(), values, + BookmarkDB.ID + " = " + bookmark.getId(), null) == 1); + + // commit + db.setTransactionSuccessful(); + db.endTransaction(); + + return res; + } + + public void delete(long id) + { + SQLiteDatabase db = getWritableDatabase(); + db.delete(getBookmarkTableName(), BookmarkDB.ID + " = " + id, null); + } + + public BookmarkBase findById(long id) + { + Cursor cursor = + queryBookmarks(getBookmarkTableName() + "." + BookmarkDB.ID + " = " + id, null); + if (cursor.getCount() == 0) + { + cursor.close(); + return null; + } + + cursor.moveToFirst(); + BookmarkBase bookmark = getBookmarkFromCursor(cursor); + cursor.close(); + return bookmark; + } + + public BookmarkBase findByLabel(String label) + { + Cursor cursor = queryBookmarks(BookmarkDB.DB_KEY_BOOKMARK_LABEL + " = '" + label + "'", + BookmarkDB.DB_KEY_BOOKMARK_LABEL); + if (cursor.getCount() > 1) + Log.e(TAG, "More than one bookmark with the same label found!"); + + BookmarkBase bookmark = null; + if (cursor.moveToFirst() && (cursor.getCount() > 0)) + bookmark = getBookmarkFromCursor(cursor); + + cursor.close(); + return bookmark; + } + + public ArrayList findByLabelLike(String pattern) + { + Cursor cursor = + queryBookmarks(BookmarkDB.DB_KEY_BOOKMARK_LABEL + " LIKE '%" + pattern + "%'", + BookmarkDB.DB_KEY_BOOKMARK_LABEL); + ArrayList bookmarks = new ArrayList(cursor.getCount()); + + if (cursor.moveToFirst() && (cursor.getCount() > 0)) + { + do + { + bookmarks.add(getBookmarkFromCursor(cursor)); + } while (cursor.moveToNext()); + } + + cursor.close(); + return bookmarks; + } + + public ArrayList findAll() + { + Cursor cursor = queryBookmarks(null, BookmarkDB.DB_KEY_BOOKMARK_LABEL); + final int count = cursor.getCount(); + ArrayList bookmarks = new ArrayList<>(count); + + if (cursor.moveToFirst() && (count > 0)) + { + do + { + bookmarks.add(getBookmarkFromCursor(cursor)); + } while (cursor.moveToNext()); + } + + cursor.close(); + return bookmarks; + } + + protected Cursor queryBookmarks(String whereClause, String orderBy) + { + // create tables string + final String ID = BookmarkDB.ID; + final String tables = + BookmarkDB.DB_TABLE_BOOKMARK + " INNER JOIN " + BookmarkDB.DB_TABLE_SCREEN + " AS " + + JOIN_PREFIX + BookmarkDB.DB_KEY_SCREEN_SETTINGS + " ON " + JOIN_PREFIX + + BookmarkDB.DB_KEY_SCREEN_SETTINGS + "." + ID + " = " + BookmarkDB.DB_TABLE_BOOKMARK + + "." + BookmarkDB.DB_KEY_SCREEN_SETTINGS + " INNER JOIN " + + BookmarkDB.DB_TABLE_PERFORMANCE + " AS " + JOIN_PREFIX + + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS + " ON " + JOIN_PREFIX + + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS + "." + ID + " = " + BookmarkDB.DB_TABLE_BOOKMARK + + "." + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS + " INNER JOIN " + + BookmarkDB.DB_TABLE_SCREEN + " AS " + JOIN_PREFIX + + BookmarkDB.DB_KEY_SCREEN_SETTINGS_3G + " ON " + JOIN_PREFIX + + BookmarkDB.DB_KEY_SCREEN_SETTINGS_3G + "." + ID + " = " + BookmarkDB.DB_TABLE_BOOKMARK + + "." + BookmarkDB.DB_KEY_SCREEN_SETTINGS_3G + " INNER JOIN " + + BookmarkDB.DB_TABLE_PERFORMANCE + " AS " + JOIN_PREFIX + + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS_3G + " ON " + JOIN_PREFIX + + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS_3G + "." + ID + " = " + + BookmarkDB.DB_TABLE_BOOKMARK + "." + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS_3G; + + // create columns list + ArrayList columns = new ArrayList<>(); + addBookmarkColumns(columns); + addScreenSettingsColumns(columns); + addPerformanceFlagsColumns(columns); + addScreenSettings3GColumns(columns); + addPerformanceFlags3GColumns(columns); + + String[] cols = new String[columns.size()]; + columns.toArray(cols); + + SQLiteDatabase db = getReadableDatabase(); + final String query = SQLiteQueryBuilder.buildQueryString(false, tables, cols, whereClause, + null, null, orderBy, null); + return db.rawQuery(query, null); + } + + private void addBookmarkColumns(ArrayList columns) + { + columns.add(getBookmarkTableName() + "." + BookmarkDB.ID + " " + KEY_BOOKMARK_ID); + columns.add(BookmarkDB.DB_KEY_BOOKMARK_LABEL); + columns.add(BookmarkDB.DB_KEY_BOOKMARK_USERNAME); + columns.add(BookmarkDB.DB_KEY_BOOKMARK_PASSWORD); + columns.add(BookmarkDB.DB_KEY_BOOKMARK_DOMAIN); + + // advanced settings + columns.add(BookmarkDB.DB_KEY_BOOKMARK_3G_ENABLE); + columns.add(BookmarkDB.DB_KEY_BOOKMARK_REDIRECT_SDCARD); + columns.add(BookmarkDB.DB_KEY_BOOKMARK_REDIRECT_SOUND); + columns.add(BookmarkDB.DB_KEY_BOOKMARK_REDIRECT_MICROPHONE); + columns.add(BookmarkDB.DB_KEY_BOOKMARK_SECURITY); + columns.add(BookmarkDB.DB_KEY_BOOKMARK_CONSOLE_MODE); + columns.add(BookmarkDB.DB_KEY_BOOKMARK_REMOTE_PROGRAM); + columns.add(BookmarkDB.DB_KEY_BOOKMARK_WORK_DIR); + + // debug settings + columns.add(BookmarkDB.DB_KEY_BOOKMARK_DEBUG_LEVEL); + columns.add(BookmarkDB.DB_KEY_BOOKMARK_ASYNC_CHANNEL); + columns.add(BookmarkDB.DB_KEY_BOOKMARK_ASYNC_UPDATE); + columns.add(BookmarkDB.DB_KEY_BOOKMARK_ASYNC_INPUT); + + addBookmarkSpecificColumns(columns); + } + + private void addScreenSettingsColumns(ArrayList columns) + { + columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_SCREEN_SETTINGS + "." + + BookmarkDB.DB_KEY_SCREEN_COLORS + " as " + KEY_SCREEN_COLORS); + columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_SCREEN_SETTINGS + "." + + BookmarkDB.DB_KEY_SCREEN_RESOLUTION + " as " + KEY_SCREEN_RESOLUTION); + columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_SCREEN_SETTINGS + "." + + BookmarkDB.DB_KEY_SCREEN_WIDTH + " as " + KEY_SCREEN_WIDTH); + columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_SCREEN_SETTINGS + "." + + BookmarkDB.DB_KEY_SCREEN_HEIGHT + " as " + KEY_SCREEN_HEIGHT); + } + + private void addPerformanceFlagsColumns(ArrayList columns) + { + columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS + "." + + BookmarkDB.DB_KEY_PERFORMANCE_RFX + " as " + KEY_PERFORMANCE_RFX); + columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS + "." + + BookmarkDB.DB_KEY_PERFORMANCE_GFX + " as " + KEY_PERFORMANCE_GFX); + columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS + "." + + BookmarkDB.DB_KEY_PERFORMANCE_H264 + " as " + KEY_PERFORMANCE_H264); + columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS + "." + + BookmarkDB.DB_KEY_PERFORMANCE_WALLPAPER + " as " + KEY_PERFORMANCE_WALLPAPER); + columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS + "." + + BookmarkDB.DB_KEY_PERFORMANCE_THEME + " as " + KEY_PERFORMANCE_THEME); + columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS + "." + + BookmarkDB.DB_KEY_PERFORMANCE_DRAG + " as " + KEY_PERFORMANCE_DRAG); + columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS + "." + + BookmarkDB.DB_KEY_PERFORMANCE_MENU_ANIMATIONS + " as " + + KEY_PERFORMANCE_MENU_ANIMATIONS); + columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS + "." + + BookmarkDB.DB_KEY_PERFORMANCE_FONTS + " as " + KEY_PERFORMANCE_FONTS); + columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS + "." + + BookmarkDB.DB_KEY_PERFORMANCE_COMPOSITION + " " + KEY_PERFORMANCE_COMPOSITION); + } + + private void addScreenSettings3GColumns(ArrayList columns) + { + columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_SCREEN_SETTINGS_3G + "." + + BookmarkDB.DB_KEY_SCREEN_COLORS + " as " + KEY_SCREEN_COLORS_3G); + columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_SCREEN_SETTINGS_3G + "." + + BookmarkDB.DB_KEY_SCREEN_RESOLUTION + " as " + KEY_SCREEN_RESOLUTION_3G); + columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_SCREEN_SETTINGS_3G + "." + + BookmarkDB.DB_KEY_SCREEN_WIDTH + " as " + KEY_SCREEN_WIDTH_3G); + columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_SCREEN_SETTINGS_3G + "." + + BookmarkDB.DB_KEY_SCREEN_HEIGHT + " as " + KEY_SCREEN_HEIGHT_3G); + } + + private void addPerformanceFlags3GColumns(ArrayList columns) + { + columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS_3G + "." + + BookmarkDB.DB_KEY_PERFORMANCE_RFX + " as " + KEY_PERFORMANCE_RFX_3G); + columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS_3G + "." + + BookmarkDB.DB_KEY_PERFORMANCE_GFX + " as " + KEY_PERFORMANCE_GFX_3G); + columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS_3G + "." + + BookmarkDB.DB_KEY_PERFORMANCE_H264 + " as " + KEY_PERFORMANCE_H264_3G); + columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS_3G + "." + + BookmarkDB.DB_KEY_PERFORMANCE_WALLPAPER + " as " + + KEY_PERFORMANCE_WALLPAPER_3G); + columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS_3G + "." + + BookmarkDB.DB_KEY_PERFORMANCE_THEME + " as " + KEY_PERFORMANCE_THEME_3G); + columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS_3G + "." + + BookmarkDB.DB_KEY_PERFORMANCE_DRAG + " as " + KEY_PERFORMANCE_DRAG_3G); + columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS_3G + "." + + BookmarkDB.DB_KEY_PERFORMANCE_MENU_ANIMATIONS + " as " + + KEY_PERFORMANCE_MENU_ANIMATIONS_3G); + columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS_3G + "." + + BookmarkDB.DB_KEY_PERFORMANCE_FONTS + " as " + KEY_PERFORMANCE_FONTS_3G); + columns.add(JOIN_PREFIX + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS_3G + "." + + BookmarkDB.DB_KEY_PERFORMANCE_COMPOSITION + " " + + KEY_PERFORMANCE_COMPOSITION_3G); + } + + protected BookmarkBase getBookmarkFromCursor(Cursor cursor) + { + BookmarkBase bookmark = createBookmark(); + bookmark.setId(cursor.getLong(cursor.getColumnIndex(KEY_BOOKMARK_ID))); + bookmark.setLabel( + cursor.getString(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_LABEL))); + bookmark.setUsername( + cursor.getString(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_USERNAME))); + bookmark.setPassword( + cursor.getString(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_PASSWORD))); + bookmark.setDomain( + cursor.getString(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_DOMAIN))); + readScreenSettings(bookmark, cursor); + readPerformanceFlags(bookmark, cursor); + + // advanced settings + bookmark.getAdvancedSettings().setEnable3GSettings( + cursor.getInt(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_3G_ENABLE)) != 0); + readScreenSettings3G(bookmark, cursor); + readPerformanceFlags3G(bookmark, cursor); + bookmark.getAdvancedSettings().setRedirectSDCard( + cursor.getInt(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_REDIRECT_SDCARD)) != 0); + bookmark.getAdvancedSettings().setRedirectSound( + cursor.getInt(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_REDIRECT_SOUND))); + bookmark.getAdvancedSettings().setRedirectMicrophone( + cursor.getInt(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_REDIRECT_MICROPHONE)) != + 0); + bookmark.getAdvancedSettings().setSecurity( + cursor.getInt(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_SECURITY))); + bookmark.getAdvancedSettings().setConsoleMode( + cursor.getInt(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_CONSOLE_MODE)) != 0); + bookmark.getAdvancedSettings().setRemoteProgram( + cursor.getString(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_REMOTE_PROGRAM))); + bookmark.getAdvancedSettings().setWorkDir( + cursor.getString(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_WORK_DIR))); + + bookmark.getDebugSettings().setAsyncChannel( + cursor.getInt(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_ASYNC_CHANNEL)) == 1); + bookmark.getDebugSettings().setAsyncInput( + cursor.getInt(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_ASYNC_INPUT)) == 1); + bookmark.getDebugSettings().setAsyncUpdate( + cursor.getInt(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_ASYNC_UPDATE)) == 1); + bookmark.getDebugSettings().setDebugLevel( + cursor.getString(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_DEBUG_LEVEL))); + + readBookmarkSpecificColumns(bookmark, cursor); + + return bookmark; + } + + private void readScreenSettings(BookmarkBase bookmark, Cursor cursor) + { + BookmarkBase.ScreenSettings screenSettings = bookmark.getScreenSettings(); + screenSettings.setColors(cursor.getInt(cursor.getColumnIndex(KEY_SCREEN_COLORS))); + screenSettings.setResolution(cursor.getInt(cursor.getColumnIndex(KEY_SCREEN_RESOLUTION))); + screenSettings.setWidth(cursor.getInt(cursor.getColumnIndex(KEY_SCREEN_WIDTH))); + screenSettings.setHeight(cursor.getInt(cursor.getColumnIndex(KEY_SCREEN_HEIGHT))); + } + + private void readPerformanceFlags(BookmarkBase bookmark, Cursor cursor) + { + BookmarkBase.PerformanceFlags perfFlags = bookmark.getPerformanceFlags(); + perfFlags.setRemoteFX(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_RFX)) != 0); + perfFlags.setGfx(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_GFX)) != 0); + perfFlags.setH264(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_H264)) != 0); + perfFlags.setWallpaper(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_WALLPAPER)) != + 0); + perfFlags.setTheming(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_THEME)) != 0); + perfFlags.setFullWindowDrag(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_DRAG)) != + 0); + perfFlags.setMenuAnimations( + cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_MENU_ANIMATIONS)) != 0); + perfFlags.setFontSmoothing(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_FONTS)) != + 0); + perfFlags.setDesktopComposition( + cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_COMPOSITION)) != 0); + } + + private void readScreenSettings3G(BookmarkBase bookmark, Cursor cursor) + { + BookmarkBase.ScreenSettings screenSettings = bookmark.getAdvancedSettings().getScreen3G(); + screenSettings.setColors(cursor.getInt(cursor.getColumnIndex(KEY_SCREEN_COLORS_3G))); + screenSettings.setResolution( + cursor.getInt(cursor.getColumnIndex(KEY_SCREEN_RESOLUTION_3G))); + screenSettings.setWidth(cursor.getInt(cursor.getColumnIndex(KEY_SCREEN_WIDTH_3G))); + screenSettings.setHeight(cursor.getInt(cursor.getColumnIndex(KEY_SCREEN_HEIGHT_3G))); + } + + private void readPerformanceFlags3G(BookmarkBase bookmark, Cursor cursor) + { + BookmarkBase.PerformanceFlags perfFlags = bookmark.getAdvancedSettings().getPerformance3G(); + perfFlags.setRemoteFX(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_RFX_3G)) != 0); + perfFlags.setGfx(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_GFX_3G)) != 0); + perfFlags.setH264(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_H264_3G)) != 0); + perfFlags.setWallpaper(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_WALLPAPER_3G)) != + 0); + perfFlags.setTheming(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_THEME_3G)) != 0); + perfFlags.setFullWindowDrag(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_DRAG_3G)) != + 0); + perfFlags.setMenuAnimations( + cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_MENU_ANIMATIONS_3G)) != 0); + perfFlags.setFontSmoothing(cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_FONTS_3G)) != + 0); + perfFlags.setDesktopComposition( + cursor.getInt(cursor.getColumnIndex(KEY_PERFORMANCE_COMPOSITION_3G)) != 0); + } + + private void fillScreenSettingsContentValues(BookmarkBase.ScreenSettings settings, + ContentValues values) + { + values.put(BookmarkDB.DB_KEY_SCREEN_COLORS, settings.getColors()); + values.put(BookmarkDB.DB_KEY_SCREEN_RESOLUTION, settings.getResolution()); + values.put(BookmarkDB.DB_KEY_SCREEN_WIDTH, settings.getWidth()); + values.put(BookmarkDB.DB_KEY_SCREEN_HEIGHT, settings.getHeight()); + } + + private void fillPerformanceFlagsContentValues(BookmarkBase.PerformanceFlags perfFlags, + ContentValues values) + { + values.put(BookmarkDB.DB_KEY_PERFORMANCE_RFX, perfFlags.getRemoteFX()); + values.put(BookmarkDB.DB_KEY_PERFORMANCE_GFX, perfFlags.getGfx()); + values.put(BookmarkDB.DB_KEY_PERFORMANCE_H264, perfFlags.getH264()); + values.put(BookmarkDB.DB_KEY_PERFORMANCE_WALLPAPER, perfFlags.getWallpaper()); + values.put(BookmarkDB.DB_KEY_PERFORMANCE_THEME, perfFlags.getTheming()); + values.put(BookmarkDB.DB_KEY_PERFORMANCE_DRAG, perfFlags.getFullWindowDrag()); + values.put(BookmarkDB.DB_KEY_PERFORMANCE_MENU_ANIMATIONS, perfFlags.getMenuAnimations()); + values.put(BookmarkDB.DB_KEY_PERFORMANCE_FONTS, perfFlags.getFontSmoothing()); + values.put(BookmarkDB.DB_KEY_PERFORMANCE_COMPOSITION, perfFlags.getDesktopComposition()); + } + + private long insertScreenSettings(SQLiteDatabase db, BookmarkBase.ScreenSettings settings) + { + ContentValues values = new ContentValues(); + fillScreenSettingsContentValues(settings, values); + return db.insertOrThrow(BookmarkDB.DB_TABLE_SCREEN, null, values); + } + + private boolean updateScreenSettings(SQLiteDatabase db, BookmarkBase bookmark) + { + ContentValues values = new ContentValues(); + fillScreenSettingsContentValues(bookmark.getScreenSettings(), values); + String whereClause = BookmarkDB.ID + " IN " + + "(SELECT " + BookmarkDB.DB_KEY_SCREEN_SETTINGS + " FROM " + + getBookmarkTableName() + " WHERE " + BookmarkDB.ID + " = " + + bookmark.getId() + ");"; + return (db.update(BookmarkDB.DB_TABLE_SCREEN, values, whereClause, null) == 1); + } + + private boolean updateScreenSettings3G(SQLiteDatabase db, BookmarkBase bookmark) + { + ContentValues values = new ContentValues(); + fillScreenSettingsContentValues(bookmark.getAdvancedSettings().getScreen3G(), values); + String whereClause = BookmarkDB.ID + " IN " + + "(SELECT " + BookmarkDB.DB_KEY_SCREEN_SETTINGS_3G + " FROM " + + getBookmarkTableName() + " WHERE " + BookmarkDB.ID + " = " + + bookmark.getId() + ");"; + return (db.update(BookmarkDB.DB_TABLE_SCREEN, values, whereClause, null) == 1); + } + + private long insertPerformanceFlags(SQLiteDatabase db, BookmarkBase.PerformanceFlags perfFlags) + { + ContentValues values = new ContentValues(); + fillPerformanceFlagsContentValues(perfFlags, values); + return db.insertOrThrow(BookmarkDB.DB_TABLE_PERFORMANCE, null, values); + } + + private boolean updatePerformanceFlags(SQLiteDatabase db, BookmarkBase bookmark) + { + ContentValues values = new ContentValues(); + fillPerformanceFlagsContentValues(bookmark.getPerformanceFlags(), values); + String whereClause = BookmarkDB.ID + " IN " + + "(SELECT " + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS + " FROM " + + getBookmarkTableName() + " WHERE " + BookmarkDB.ID + " = " + + bookmark.getId() + ");"; + return (db.update(BookmarkDB.DB_TABLE_PERFORMANCE, values, whereClause, null) == 1); + } + + private boolean updatePerformanceFlags3G(SQLiteDatabase db, BookmarkBase bookmark) + { + ContentValues values = new ContentValues(); + fillPerformanceFlagsContentValues(bookmark.getAdvancedSettings().getPerformance3G(), + values); + String whereClause = BookmarkDB.ID + " IN " + + "(SELECT " + BookmarkDB.DB_KEY_PERFORMANCE_FLAGS_3G + " FROM " + + getBookmarkTableName() + " WHERE " + BookmarkDB.ID + " = " + + bookmark.getId() + ");"; + return (db.update(BookmarkDB.DB_TABLE_PERFORMANCE, values, whereClause, null) == 1); + } + + // safety wrappers + // in case of getReadableDatabase it could happen that upgradeDB gets called which is + // a problem if the DB is only readable + private SQLiteDatabase getWritableDatabase() + { + return bookmarkDB.getWritableDatabase(); + } + + private SQLiteDatabase getReadableDatabase() + { + SQLiteDatabase db; + try + { + db = bookmarkDB.getReadableDatabase(); + } + catch (SQLiteException e) + { + db = bookmarkDB.getWritableDatabase(); + } + return db; + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/BookmarkDB.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/BookmarkDB.java index e2537d5..420e540 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/BookmarkDB.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/BookmarkDB.java @@ -3,8 +3,9 @@ Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.services; @@ -21,371 +22,401 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -public class BookmarkDB extends SQLiteOpenHelper { - public static final String ID = BaseColumns._ID; - private static final int DB_VERSION = 9; - private static final String DB_BACKUP_PREFIX = "temp_"; - private static final String DB_NAME = "bookmarks.db"; - static final String DB_TABLE_BOOKMARK = "tbl_manual_bookmarks"; - static final String DB_TABLE_SCREEN = "tbl_screen_settings"; - static final String DB_TABLE_PERFORMANCE = "tbl_performance_flags"; - private static final String[] DB_TABLES = { - DB_TABLE_BOOKMARK, - DB_TABLE_SCREEN, - DB_TABLE_PERFORMANCE - }; - - static final String DB_KEY_SCREEN_COLORS = "colors"; - static final String DB_KEY_SCREEN_RESOLUTION = "resolution"; - static final String DB_KEY_SCREEN_WIDTH = "width"; - static final String DB_KEY_SCREEN_HEIGHT = "height"; - - static final String DB_KEY_SCREEN_SETTINGS = "screen_settings"; - static final String DB_KEY_SCREEN_SETTINGS_3G = "screen_3g"; - static final String DB_KEY_PERFORMANCE_FLAGS = "performance_flags"; - static final String DB_KEY_PERFORMANCE_FLAGS_3G = "performance_3g"; - - static final String DB_KEY_PERFORMANCE_RFX = "perf_remotefx"; - static final String DB_KEY_PERFORMANCE_GFX = "perf_gfx"; - static final String DB_KEY_PERFORMANCE_H264 = "perf_gfx_h264"; - static final String DB_KEY_PERFORMANCE_WALLPAPER = "perf_wallpaper"; - static final String DB_KEY_PERFORMANCE_THEME = "perf_theming"; - static final String DB_KEY_PERFORMANCE_DRAG = "perf_full_window_drag"; - static final String DB_KEY_PERFORMANCE_MENU_ANIMATIONS = "perf_menu_animations"; - static final String DB_KEY_PERFORMANCE_FONTS = "perf_font_smoothing"; - static final String DB_KEY_PERFORMANCE_COMPOSITION = "perf_desktop_composition"; - - static final String DB_KEY_BOOKMARK_LABEL = "label"; - static final String DB_KEY_BOOKMARK_HOSTNAME = "hostname"; - static final String DB_KEY_BOOKMARK_USERNAME = "username"; - static final String DB_KEY_BOOKMARK_PASSWORD = "password"; - static final String DB_KEY_BOOKMARK_DOMAIN = "domain"; - static final String DB_KEY_BOOKMARK_PORT = "port"; - - static final String DB_KEY_BOOKMARK_REDIRECT_SDCARD = "redirect_sdcard"; - static final String DB_KEY_BOOKMARK_REDIRECT_SOUND = "redirect_sound"; - static final String DB_KEY_BOOKMARK_REDIRECT_MICROPHONE = "redirect_microphone"; - static final String DB_KEY_BOOKMARK_SECURITY = "security"; - static final String DB_KEY_BOOKMARK_REMOTE_PROGRAM = "remote_program"; - static final String DB_KEY_BOOKMARK_WORK_DIR = "work_dir"; - static final String DB_KEY_BOOKMARK_ASYNC_CHANNEL = "async_channel"; - static final String DB_KEY_BOOKMARK_ASYNC_INPUT = "async_input"; - static final String DB_KEY_BOOKMARK_ASYNC_UPDATE = "async_update"; - static final String DB_KEY_BOOKMARK_CONSOLE_MODE = "console_mode"; - static final String DB_KEY_BOOKMARK_DEBUG_LEVEL = "debug_level"; - - static final String DB_KEY_BOOKMARK_GW_ENABLE = "enable_gateway_settings"; - static final String DB_KEY_BOOKMARK_GW_HOSTNAME = "gateway_hostname"; - static final String DB_KEY_BOOKMARK_GW_PORT = "gateway_port"; - static final String DB_KEY_BOOKMARK_GW_USERNAME = "gateway_username"; - static final String DB_KEY_BOOKMARK_GW_PASSWORD = "gateway_password"; - static final String DB_KEY_BOOKMARK_GW_DOMAIN = "gateway_domain"; - static final String DB_KEY_BOOKMARK_3G_ENABLE = "enable_3g_settings"; - - public BookmarkDB(Context context) { - super(context, DB_NAME, null, DB_VERSION); - } - - private static List GetColumns(SQLiteDatabase db, String tableName) { - List ar = null; - Cursor c = null; - try { - c = db.rawQuery("SELECT * FROM " + tableName + " LIMIT 1", null); - if (c != null) { - ar = new ArrayList<>(Arrays.asList(c.getColumnNames())); - } - } catch (Exception e) { - Log.v(tableName, e.getMessage(), e); - e.printStackTrace(); - } finally { - if (c != null) - c.close(); - } - return ar; - } - - private static String joinStrings(List list, String delim) { - StringBuilder buf = new StringBuilder(); - int num = list.size(); - for (int i = 0; i < num; i++) { - if (i != 0) - buf.append(delim); - buf.append((String) list.get(i)); - } - return buf.toString(); - } - - private void backupTables(SQLiteDatabase db) { - for (String table : DB_TABLES) { - final String tmpTable = DB_BACKUP_PREFIX + table; - final String query = "ALTER TABLE '" + table + "' RENAME TO '" + tmpTable + "'"; - try { - db.execSQL(query); - } catch (Exception e) { - /* Ignore errors if table does not exist. */ - } - } - } - - private void dropOldTables(SQLiteDatabase db) { - for (String table : DB_TABLES) { - final String tmpTable = DB_BACKUP_PREFIX + table; - final String query = "DROP TABLE IF EXISTS '" + tmpTable + "'"; - db.execSQL(query); - } - } - - private void createDB(SQLiteDatabase db) { - final String sqlScreenSettings = - "CREATE TABLE IF NOT EXISTS " + DB_TABLE_SCREEN + " (" - + ID + " INTEGER PRIMARY KEY, " - + DB_KEY_SCREEN_COLORS + " INTEGER DEFAULT 16, " - + DB_KEY_SCREEN_RESOLUTION + " INTEGER DEFAULT 0, " - + DB_KEY_SCREEN_WIDTH + ", " - + DB_KEY_SCREEN_HEIGHT + ");"; - - db.execSQL(sqlScreenSettings); - - final String sqlPerformanceFlags = - "CREATE TABLE IF NOT EXISTS " + DB_TABLE_PERFORMANCE + " (" - + ID + " INTEGER PRIMARY KEY, " - + DB_KEY_PERFORMANCE_RFX + " INTEGER, " - + DB_KEY_PERFORMANCE_GFX + " INTEGER, " - + DB_KEY_PERFORMANCE_H264 + " INTEGER, " - + DB_KEY_PERFORMANCE_WALLPAPER + " INTEGER, " - + DB_KEY_PERFORMANCE_THEME + " INTEGER, " - + DB_KEY_PERFORMANCE_DRAG + " INTEGER, " - + DB_KEY_PERFORMANCE_MENU_ANIMATIONS + " INTEGER, " - + DB_KEY_PERFORMANCE_FONTS + " INTEGER, " - + DB_KEY_PERFORMANCE_COMPOSITION + " INTEGER);"; - - db.execSQL(sqlPerformanceFlags); - - final String sqlManualBookmarks = getManualBookmarksCreationString(); - db.execSQL(sqlManualBookmarks); - } - - private void upgradeTables(SQLiteDatabase db) { - for (String table : DB_TABLES) { - final String tmpTable = DB_BACKUP_PREFIX + table; - - final List newColumns = GetColumns(db, table); - List columns = GetColumns(db, tmpTable); - - if (columns != null) { - columns.retainAll(newColumns); - - // restore data - final String cols = joinStrings(columns, ","); - final String query = String.format("INSERT INTO %s (%s) SELECT %s from '%s'", table, cols, cols, tmpTable); - db.execSQL(query); - } - } - } - - private void downgradeTables(SQLiteDatabase db) { - for (String table : DB_TABLES) { - final String tmpTable = DB_BACKUP_PREFIX + table; - - List oldColumns = GetColumns(db, table); - final List columns = GetColumns(db, tmpTable); - - if (oldColumns != null) { - oldColumns.retainAll(columns); - - // restore data - final String cols = joinStrings(oldColumns, ","); - final String query = String.format("INSERT INTO %s (%s) SELECT %s from '%s'", table, cols, cols, tmpTable); - db.execSQL(query); - } - } - } - - private List getTableNames(SQLiteDatabase db) { - final String query = "SELECT name FROM sqlite_master WHERE type='table'"; - Cursor cursor = db.rawQuery(query, null); - List list = new ArrayList<>(); - try { - if (cursor.moveToFirst() && (cursor.getCount() > 0)) { - while (!cursor.isAfterLast()) { - final String name = cursor.getString(cursor.getColumnIndex("name")); - list.add(name); - cursor.moveToNext(); - } - } - } finally { - cursor.close(); - } - - return list; - } - - private void insertDefault(SQLiteDatabase db) { - ContentValues screenValues = new ContentValues(); - screenValues.put(DB_KEY_SCREEN_COLORS, 32); - screenValues.put(DB_KEY_SCREEN_RESOLUTION, 1); - screenValues.put(DB_KEY_SCREEN_WIDTH, 1024); - screenValues.put(DB_KEY_SCREEN_HEIGHT, 768); - - final long idScreen = db.insert(DB_TABLE_SCREEN, null, screenValues); - final long idScreen3g = db.insert(DB_TABLE_SCREEN, null, screenValues); - - ContentValues performanceValues = new ContentValues(); - performanceValues.put(DB_KEY_PERFORMANCE_RFX, 1); - performanceValues.put(DB_KEY_PERFORMANCE_GFX, 1); - performanceValues.put(DB_KEY_PERFORMANCE_H264, 0); - performanceValues.put(DB_KEY_PERFORMANCE_WALLPAPER, 0); - performanceValues.put(DB_KEY_PERFORMANCE_THEME, 0); - performanceValues.put(DB_KEY_PERFORMANCE_DRAG, 0); - performanceValues.put(DB_KEY_PERFORMANCE_MENU_ANIMATIONS, 0); - performanceValues.put(DB_KEY_PERFORMANCE_FONTS, 0); - performanceValues.put(DB_KEY_PERFORMANCE_COMPOSITION, 0); - - final long idPerformance = db.insert(DB_TABLE_PERFORMANCE, null, performanceValues); - final long idPerformance3g = db.insert(DB_TABLE_PERFORMANCE, null, performanceValues); - - ContentValues bookmarkValues = new ContentValues(); - bookmarkValues.put(DB_KEY_BOOKMARK_LABEL, "Test Server"); - bookmarkValues.put(DB_KEY_BOOKMARK_HOSTNAME, "testservice.afreerdp.com"); - bookmarkValues.put(DB_KEY_BOOKMARK_USERNAME, ""); - bookmarkValues.put(DB_KEY_BOOKMARK_PASSWORD, ""); - bookmarkValues.put(DB_KEY_BOOKMARK_DOMAIN, ""); - bookmarkValues.put(DB_KEY_BOOKMARK_PORT, "3389"); - - bookmarkValues.put(DB_KEY_SCREEN_SETTINGS, idScreen); - bookmarkValues.put(DB_KEY_SCREEN_SETTINGS_3G, idScreen3g); - bookmarkValues.put(DB_KEY_PERFORMANCE_FLAGS, idPerformance); - bookmarkValues.put(DB_KEY_PERFORMANCE_FLAGS_3G, idPerformance3g); - - bookmarkValues.put(DB_KEY_BOOKMARK_REDIRECT_SDCARD, 0); - bookmarkValues.put(DB_KEY_BOOKMARK_REDIRECT_SOUND, 0); - bookmarkValues.put(DB_KEY_BOOKMARK_REDIRECT_MICROPHONE, 0); - bookmarkValues.put(DB_KEY_BOOKMARK_SECURITY, 0); - bookmarkValues.put(DB_KEY_BOOKMARK_REMOTE_PROGRAM, ""); - bookmarkValues.put(DB_KEY_BOOKMARK_WORK_DIR, ""); - bookmarkValues.put(DB_KEY_BOOKMARK_ASYNC_CHANNEL, 1); - bookmarkValues.put(DB_KEY_BOOKMARK_ASYNC_INPUT, 1); - bookmarkValues.put(DB_KEY_BOOKMARK_ASYNC_UPDATE, 1); - bookmarkValues.put(DB_KEY_BOOKMARK_CONSOLE_MODE, 0); - bookmarkValues.put(DB_KEY_BOOKMARK_DEBUG_LEVEL, "INFO"); - - db.insert(DB_TABLE_BOOKMARK, null, bookmarkValues); - } - - @Override - public void onCreate(SQLiteDatabase db) { - createDB(db); - insertDefault(db); - } - - private String getManualBookmarksCreationString() { - return ( - "CREATE TABLE IF NOT EXISTS " + DB_TABLE_BOOKMARK + " (" - + ID + " INTEGER PRIMARY KEY, " - + DB_KEY_BOOKMARK_LABEL + " TEXT NOT NULL, " - + DB_KEY_BOOKMARK_HOSTNAME + " TEXT NOT NULL, " - + DB_KEY_BOOKMARK_USERNAME + " TEXT NOT NULL, " - + DB_KEY_BOOKMARK_PASSWORD + " TEXT, " - + DB_KEY_BOOKMARK_DOMAIN + " TEXT, " - + DB_KEY_BOOKMARK_PORT + " TEXT, " - + DB_KEY_SCREEN_SETTINGS + " INTEGER NOT NULL, " - + DB_KEY_PERFORMANCE_FLAGS + " INTEGER NOT NULL, " - - + DB_KEY_BOOKMARK_GW_ENABLE + " INTEGER DEFAULT 0, " - + DB_KEY_BOOKMARK_GW_HOSTNAME + " TEXT, " - + DB_KEY_BOOKMARK_GW_PORT + " INTEGER DEFAULT 443, " - + DB_KEY_BOOKMARK_GW_USERNAME + " TEXT, " - + DB_KEY_BOOKMARK_GW_PASSWORD + " TEXT, " - + DB_KEY_BOOKMARK_GW_DOMAIN + " TEXT, " - - + DB_KEY_BOOKMARK_3G_ENABLE + " INTEGER DEFAULT 0, " - + DB_KEY_SCREEN_SETTINGS_3G + " INTEGER NOT NULL, " - + DB_KEY_PERFORMANCE_FLAGS_3G + " INTEGER NOT NULL, " - + DB_KEY_BOOKMARK_REDIRECT_SDCARD + " INTEGER DEFAULT 0, " - + DB_KEY_BOOKMARK_REDIRECT_SOUND + " INTEGER DEFAULT 0, " - + DB_KEY_BOOKMARK_REDIRECT_MICROPHONE + " INTEGER DEFAULT 0, " - + DB_KEY_BOOKMARK_SECURITY + " INTEGER, " - + DB_KEY_BOOKMARK_REMOTE_PROGRAM + " TEXT, " - + DB_KEY_BOOKMARK_WORK_DIR + " TEXT, " - + DB_KEY_BOOKMARK_ASYNC_CHANNEL + " INTEGER DEFAULT 0, " - + DB_KEY_BOOKMARK_ASYNC_INPUT + " INTEGER DEFAULT 0, " - + DB_KEY_BOOKMARK_ASYNC_UPDATE + " INTEGER DEFAULT 0, " - + DB_KEY_BOOKMARK_CONSOLE_MODE + " INTEGER, " - + DB_KEY_BOOKMARK_DEBUG_LEVEL + " TEXT DEFAULT 'INFO', " - - + "FOREIGN KEY(" + DB_KEY_SCREEN_SETTINGS + ") REFERENCES " + DB_TABLE_SCREEN + "(" + ID + "), " - + "FOREIGN KEY(" + DB_KEY_PERFORMANCE_FLAGS + ") REFERENCES " + DB_TABLE_PERFORMANCE + "(" + ID + "), " - + "FOREIGN KEY(" + DB_KEY_SCREEN_SETTINGS_3G + ") REFERENCES " + DB_TABLE_SCREEN + "(" + ID + "), " - + "FOREIGN KEY(" + DB_KEY_PERFORMANCE_FLAGS_3G + ") REFERENCES " + DB_TABLE_PERFORMANCE + "(" + ID + ") " - - + ");"); - } - - private void recreateDB(SQLiteDatabase db) { - for (String table : DB_TABLES) { - final String query = "DROP TABLE IF EXISTS '" + table + "'"; - db.execSQL(query); - } - onCreate(db); - } - - private void upgradeDB(SQLiteDatabase db) { - db.beginTransaction(); - try { - /* Back up old tables. */ - dropOldTables(db); - backupTables(db); - createDB(db); - upgradeTables(db); - - db.setTransactionSuccessful(); - } finally { - db.endTransaction(); - dropOldTables(db); - } - } - - private void downgradeDB(SQLiteDatabase db) { - db.beginTransaction(); - try { - /* Back up old tables. */ - dropOldTables(db); - backupTables(db); - createDB(db); - downgradeTables(db); - - db.setTransactionSuccessful(); - } finally { - db.endTransaction(); - dropOldTables(db); - } - } - - // from http://stackoverflow.com/questions/3424156/upgrade-sqlite-database-from-one-version-to-another - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - switch (oldVersion) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - case 9: - upgradeDB(db); - break; - default: - recreateDB(db); - break; - } - } - - @Override - public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { - downgradeDB(db); - } - +public class BookmarkDB extends SQLiteOpenHelper +{ + public static final String ID = BaseColumns._ID; + private static final int DB_VERSION = 9; + private static final String DB_BACKUP_PREFIX = "temp_"; + private static final String DB_NAME = "bookmarks.db"; + static final String DB_TABLE_BOOKMARK = "tbl_manual_bookmarks"; + static final String DB_TABLE_SCREEN = "tbl_screen_settings"; + static final String DB_TABLE_PERFORMANCE = "tbl_performance_flags"; + private static final String[] DB_TABLES = { DB_TABLE_BOOKMARK, DB_TABLE_SCREEN, + DB_TABLE_PERFORMANCE }; + + static final String DB_KEY_SCREEN_COLORS = "colors"; + static final String DB_KEY_SCREEN_RESOLUTION = "resolution"; + static final String DB_KEY_SCREEN_WIDTH = "width"; + static final String DB_KEY_SCREEN_HEIGHT = "height"; + + static final String DB_KEY_SCREEN_SETTINGS = "screen_settings"; + static final String DB_KEY_SCREEN_SETTINGS_3G = "screen_3g"; + static final String DB_KEY_PERFORMANCE_FLAGS = "performance_flags"; + static final String DB_KEY_PERFORMANCE_FLAGS_3G = "performance_3g"; + + static final String DB_KEY_PERFORMANCE_RFX = "perf_remotefx"; + static final String DB_KEY_PERFORMANCE_GFX = "perf_gfx"; + static final String DB_KEY_PERFORMANCE_H264 = "perf_gfx_h264"; + static final String DB_KEY_PERFORMANCE_WALLPAPER = "perf_wallpaper"; + static final String DB_KEY_PERFORMANCE_THEME = "perf_theming"; + static final String DB_KEY_PERFORMANCE_DRAG = "perf_full_window_drag"; + static final String DB_KEY_PERFORMANCE_MENU_ANIMATIONS = "perf_menu_animations"; + static final String DB_KEY_PERFORMANCE_FONTS = "perf_font_smoothing"; + static final String DB_KEY_PERFORMANCE_COMPOSITION = "perf_desktop_composition"; + + static final String DB_KEY_BOOKMARK_LABEL = "label"; + static final String DB_KEY_BOOKMARK_HOSTNAME = "hostname"; + static final String DB_KEY_BOOKMARK_USERNAME = "username"; + static final String DB_KEY_BOOKMARK_PASSWORD = "password"; + static final String DB_KEY_BOOKMARK_DOMAIN = "domain"; + static final String DB_KEY_BOOKMARK_PORT = "port"; + + static final String DB_KEY_BOOKMARK_REDIRECT_SDCARD = "redirect_sdcard"; + static final String DB_KEY_BOOKMARK_REDIRECT_SOUND = "redirect_sound"; + static final String DB_KEY_BOOKMARK_REDIRECT_MICROPHONE = "redirect_microphone"; + static final String DB_KEY_BOOKMARK_SECURITY = "security"; + static final String DB_KEY_BOOKMARK_REMOTE_PROGRAM = "remote_program"; + static final String DB_KEY_BOOKMARK_WORK_DIR = "work_dir"; + static final String DB_KEY_BOOKMARK_ASYNC_CHANNEL = "async_channel"; + static final String DB_KEY_BOOKMARK_ASYNC_INPUT = "async_input"; + static final String DB_KEY_BOOKMARK_ASYNC_UPDATE = "async_update"; + static final String DB_KEY_BOOKMARK_CONSOLE_MODE = "console_mode"; + static final String DB_KEY_BOOKMARK_DEBUG_LEVEL = "debug_level"; + + static final String DB_KEY_BOOKMARK_GW_ENABLE = "enable_gateway_settings"; + static final String DB_KEY_BOOKMARK_GW_HOSTNAME = "gateway_hostname"; + static final String DB_KEY_BOOKMARK_GW_PORT = "gateway_port"; + static final String DB_KEY_BOOKMARK_GW_USERNAME = "gateway_username"; + static final String DB_KEY_BOOKMARK_GW_PASSWORD = "gateway_password"; + static final String DB_KEY_BOOKMARK_GW_DOMAIN = "gateway_domain"; + static final String DB_KEY_BOOKMARK_3G_ENABLE = "enable_3g_settings"; + + public BookmarkDB(Context context) + { + super(context, DB_NAME, null, DB_VERSION); + } + + private static List GetColumns(SQLiteDatabase db, String tableName) + { + List ar = null; + Cursor c = null; + try + { + c = db.rawQuery("SELECT * FROM " + tableName + " LIMIT 1", null); + if (c != null) + { + ar = new ArrayList<>(Arrays.asList(c.getColumnNames())); + } + } + catch (Exception e) + { + Log.v(tableName, e.getMessage(), e); + e.printStackTrace(); + } + finally + { + if (c != null) + c.close(); + } + return ar; + } + + private static String joinStrings(List list, String delim) + { + StringBuilder buf = new StringBuilder(); + int num = list.size(); + for (int i = 0; i < num; i++) + { + if (i != 0) + buf.append(delim); + buf.append((String)list.get(i)); + } + return buf.toString(); + } + + private void backupTables(SQLiteDatabase db) + { + for (String table : DB_TABLES) + { + final String tmpTable = DB_BACKUP_PREFIX + table; + final String query = "ALTER TABLE '" + table + "' RENAME TO '" + tmpTable + "'"; + try + { + db.execSQL(query); + } + catch (Exception e) + { + /* Ignore errors if table does not exist. */ + } + } + } + + private void dropOldTables(SQLiteDatabase db) + { + for (String table : DB_TABLES) + { + final String tmpTable = DB_BACKUP_PREFIX + table; + final String query = "DROP TABLE IF EXISTS '" + tmpTable + "'"; + db.execSQL(query); + } + } + + private void createDB(SQLiteDatabase db) + { + final String sqlScreenSettings = + "CREATE TABLE IF NOT EXISTS " + DB_TABLE_SCREEN + " (" + ID + " INTEGER PRIMARY KEY, " + + DB_KEY_SCREEN_COLORS + " INTEGER DEFAULT 16, " + DB_KEY_SCREEN_RESOLUTION + + " INTEGER DEFAULT 0, " + DB_KEY_SCREEN_WIDTH + ", " + DB_KEY_SCREEN_HEIGHT + ");"; + + db.execSQL(sqlScreenSettings); + + final String sqlPerformanceFlags = + "CREATE TABLE IF NOT EXISTS " + DB_TABLE_PERFORMANCE + " (" + ID + + " INTEGER PRIMARY KEY, " + DB_KEY_PERFORMANCE_RFX + " INTEGER, " + + DB_KEY_PERFORMANCE_GFX + " INTEGER, " + DB_KEY_PERFORMANCE_H264 + " INTEGER, " + + DB_KEY_PERFORMANCE_WALLPAPER + " INTEGER, " + DB_KEY_PERFORMANCE_THEME + " INTEGER, " + + DB_KEY_PERFORMANCE_DRAG + " INTEGER, " + DB_KEY_PERFORMANCE_MENU_ANIMATIONS + + " INTEGER, " + DB_KEY_PERFORMANCE_FONTS + " INTEGER, " + + DB_KEY_PERFORMANCE_COMPOSITION + " INTEGER);"; + + db.execSQL(sqlPerformanceFlags); + + final String sqlManualBookmarks = getManualBookmarksCreationString(); + db.execSQL(sqlManualBookmarks); + } + + private void upgradeTables(SQLiteDatabase db) + { + for (String table : DB_TABLES) + { + final String tmpTable = DB_BACKUP_PREFIX + table; + + final List newColumns = GetColumns(db, table); + List columns = GetColumns(db, tmpTable); + + if (columns != null) + { + columns.retainAll(newColumns); + + // restore data + final String cols = joinStrings(columns, ","); + final String query = String.format("INSERT INTO %s (%s) SELECT %s from '%s'", table, + cols, cols, tmpTable); + db.execSQL(query); + } + } + } + + private void downgradeTables(SQLiteDatabase db) + { + for (String table : DB_TABLES) + { + final String tmpTable = DB_BACKUP_PREFIX + table; + + List oldColumns = GetColumns(db, table); + final List columns = GetColumns(db, tmpTable); + + if (oldColumns != null) + { + oldColumns.retainAll(columns); + + // restore data + final String cols = joinStrings(oldColumns, ","); + final String query = String.format("INSERT INTO %s (%s) SELECT %s from '%s'", table, + cols, cols, tmpTable); + db.execSQL(query); + } + } + } + + private List getTableNames(SQLiteDatabase db) + { + final String query = "SELECT name FROM sqlite_master WHERE type='table'"; + Cursor cursor = db.rawQuery(query, null); + List list = new ArrayList<>(); + try + { + if (cursor.moveToFirst() && (cursor.getCount() > 0)) + { + while (!cursor.isAfterLast()) + { + final String name = cursor.getString(cursor.getColumnIndex("name")); + list.add(name); + cursor.moveToNext(); + } + } + } + finally + { + cursor.close(); + } + + return list; + } + + private void insertDefault(SQLiteDatabase db) + { + ContentValues screenValues = new ContentValues(); + screenValues.put(DB_KEY_SCREEN_COLORS, 32); + screenValues.put(DB_KEY_SCREEN_RESOLUTION, 1); + screenValues.put(DB_KEY_SCREEN_WIDTH, 1024); + screenValues.put(DB_KEY_SCREEN_HEIGHT, 768); + + final long idScreen = db.insert(DB_TABLE_SCREEN, null, screenValues); + final long idScreen3g = db.insert(DB_TABLE_SCREEN, null, screenValues); + + ContentValues performanceValues = new ContentValues(); + performanceValues.put(DB_KEY_PERFORMANCE_RFX, 1); + performanceValues.put(DB_KEY_PERFORMANCE_GFX, 1); + performanceValues.put(DB_KEY_PERFORMANCE_H264, 0); + performanceValues.put(DB_KEY_PERFORMANCE_WALLPAPER, 0); + performanceValues.put(DB_KEY_PERFORMANCE_THEME, 0); + performanceValues.put(DB_KEY_PERFORMANCE_DRAG, 0); + performanceValues.put(DB_KEY_PERFORMANCE_MENU_ANIMATIONS, 0); + performanceValues.put(DB_KEY_PERFORMANCE_FONTS, 0); + performanceValues.put(DB_KEY_PERFORMANCE_COMPOSITION, 0); + + final long idPerformance = db.insert(DB_TABLE_PERFORMANCE, null, performanceValues); + final long idPerformance3g = db.insert(DB_TABLE_PERFORMANCE, null, performanceValues); + + ContentValues bookmarkValues = new ContentValues(); + bookmarkValues.put(DB_KEY_BOOKMARK_LABEL, "Test Server"); + bookmarkValues.put(DB_KEY_BOOKMARK_HOSTNAME, "testservice.afreerdp.com"); + bookmarkValues.put(DB_KEY_BOOKMARK_USERNAME, ""); + bookmarkValues.put(DB_KEY_BOOKMARK_PASSWORD, ""); + bookmarkValues.put(DB_KEY_BOOKMARK_DOMAIN, ""); + bookmarkValues.put(DB_KEY_BOOKMARK_PORT, "3389"); + + bookmarkValues.put(DB_KEY_SCREEN_SETTINGS, idScreen); + bookmarkValues.put(DB_KEY_SCREEN_SETTINGS_3G, idScreen3g); + bookmarkValues.put(DB_KEY_PERFORMANCE_FLAGS, idPerformance); + bookmarkValues.put(DB_KEY_PERFORMANCE_FLAGS_3G, idPerformance3g); + + bookmarkValues.put(DB_KEY_BOOKMARK_REDIRECT_SDCARD, 0); + bookmarkValues.put(DB_KEY_BOOKMARK_REDIRECT_SOUND, 0); + bookmarkValues.put(DB_KEY_BOOKMARK_REDIRECT_MICROPHONE, 0); + bookmarkValues.put(DB_KEY_BOOKMARK_SECURITY, 0); + bookmarkValues.put(DB_KEY_BOOKMARK_REMOTE_PROGRAM, ""); + bookmarkValues.put(DB_KEY_BOOKMARK_WORK_DIR, ""); + bookmarkValues.put(DB_KEY_BOOKMARK_ASYNC_CHANNEL, 1); + bookmarkValues.put(DB_KEY_BOOKMARK_ASYNC_INPUT, 1); + bookmarkValues.put(DB_KEY_BOOKMARK_ASYNC_UPDATE, 1); + bookmarkValues.put(DB_KEY_BOOKMARK_CONSOLE_MODE, 0); + bookmarkValues.put(DB_KEY_BOOKMARK_DEBUG_LEVEL, "INFO"); + + db.insert(DB_TABLE_BOOKMARK, null, bookmarkValues); + } + + @Override public void onCreate(SQLiteDatabase db) + { + createDB(db); + insertDefault(db); + } + + private String getManualBookmarksCreationString() + { + return ("CREATE TABLE IF NOT EXISTS " + DB_TABLE_BOOKMARK + " (" + ID + + " INTEGER PRIMARY KEY, " + DB_KEY_BOOKMARK_LABEL + " TEXT NOT NULL, " + + DB_KEY_BOOKMARK_HOSTNAME + " TEXT NOT NULL, " + DB_KEY_BOOKMARK_USERNAME + + " TEXT NOT NULL, " + DB_KEY_BOOKMARK_PASSWORD + " TEXT, " + DB_KEY_BOOKMARK_DOMAIN + + " TEXT, " + DB_KEY_BOOKMARK_PORT + " TEXT, " + DB_KEY_SCREEN_SETTINGS + + " INTEGER NOT NULL, " + DB_KEY_PERFORMANCE_FLAGS + " INTEGER NOT NULL, " + + + DB_KEY_BOOKMARK_GW_ENABLE + " INTEGER DEFAULT 0, " + DB_KEY_BOOKMARK_GW_HOSTNAME + + " TEXT, " + DB_KEY_BOOKMARK_GW_PORT + " INTEGER DEFAULT 443, " + + DB_KEY_BOOKMARK_GW_USERNAME + " TEXT, " + DB_KEY_BOOKMARK_GW_PASSWORD + " TEXT, " + + DB_KEY_BOOKMARK_GW_DOMAIN + " TEXT, " + + + DB_KEY_BOOKMARK_3G_ENABLE + " INTEGER DEFAULT 0, " + DB_KEY_SCREEN_SETTINGS_3G + + " INTEGER NOT NULL, " + DB_KEY_PERFORMANCE_FLAGS_3G + " INTEGER NOT NULL, " + + DB_KEY_BOOKMARK_REDIRECT_SDCARD + " INTEGER DEFAULT 0, " + + DB_KEY_BOOKMARK_REDIRECT_SOUND + " INTEGER DEFAULT 0, " + + DB_KEY_BOOKMARK_REDIRECT_MICROPHONE + " INTEGER DEFAULT 0, " + + DB_KEY_BOOKMARK_SECURITY + " INTEGER, " + DB_KEY_BOOKMARK_REMOTE_PROGRAM + + " TEXT, " + DB_KEY_BOOKMARK_WORK_DIR + " TEXT, " + DB_KEY_BOOKMARK_ASYNC_CHANNEL + + " INTEGER DEFAULT 0, " + DB_KEY_BOOKMARK_ASYNC_INPUT + " INTEGER DEFAULT 0, " + + DB_KEY_BOOKMARK_ASYNC_UPDATE + " INTEGER DEFAULT 0, " + + DB_KEY_BOOKMARK_CONSOLE_MODE + " INTEGER, " + DB_KEY_BOOKMARK_DEBUG_LEVEL + + " TEXT DEFAULT 'INFO', " + + + "FOREIGN KEY(" + DB_KEY_SCREEN_SETTINGS + ") REFERENCES " + DB_TABLE_SCREEN + + "(" + ID + "), " + + "FOREIGN KEY(" + DB_KEY_PERFORMANCE_FLAGS + ") REFERENCES " + + DB_TABLE_PERFORMANCE + "(" + ID + "), " + + "FOREIGN KEY(" + DB_KEY_SCREEN_SETTINGS_3G + ") REFERENCES " + DB_TABLE_SCREEN + + "(" + ID + "), " + + "FOREIGN KEY(" + DB_KEY_PERFORMANCE_FLAGS_3G + ") REFERENCES " + + DB_TABLE_PERFORMANCE + "(" + ID + ") " + + + ");"); + } + + private void recreateDB(SQLiteDatabase db) + { + for (String table : DB_TABLES) + { + final String query = "DROP TABLE IF EXISTS '" + table + "'"; + db.execSQL(query); + } + onCreate(db); + } + + private void upgradeDB(SQLiteDatabase db) + { + db.beginTransaction(); + try + { + /* Back up old tables. */ + dropOldTables(db); + backupTables(db); + createDB(db); + upgradeTables(db); + + db.setTransactionSuccessful(); + } + finally + { + db.endTransaction(); + dropOldTables(db); + } + } + + private void downgradeDB(SQLiteDatabase db) + { + db.beginTransaction(); + try + { + /* Back up old tables. */ + dropOldTables(db); + backupTables(db); + createDB(db); + downgradeTables(db); + + db.setTransactionSuccessful(); + } + finally + { + db.endTransaction(); + dropOldTables(db); + } + } + + // from + // http://stackoverflow.com/questions/3424156/upgrade-sqlite-database-from-one-version-to-another + @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) + { + switch (oldVersion) + { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + upgradeDB(db); + break; + default: + recreateDB(db); + break; + } + } + + @Override public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) + { + downgradeDB(db); + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/FreeRDPSuggestionProvider.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/FreeRDPSuggestionProvider.java index 5d0035b..d5f657c 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/FreeRDPSuggestionProvider.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/FreeRDPSuggestionProvider.java @@ -1,10 +1,11 @@ /* - Suggestion Provider for RDP bookmarks + Suggestion Provider for RDP bookmarks Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.services; @@ -24,97 +25,110 @@ import com.freerdp.freerdpcore.domain.ManualBookmark; import java.util.ArrayList; -public class FreeRDPSuggestionProvider extends ContentProvider { - - public static final Uri CONTENT_URI = Uri.parse("content://com.freerdp.afreerdp.services.freerdpsuggestionprovider"); - - @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - // TODO Auto-generated method stub - return 0; - } - - @Override - public String getType(Uri uri) { - return "vnd.android.cursor.item/vnd.freerdp.remote"; - } - - @Override - public Uri insert(Uri uri, ContentValues values) { - // TODO Auto-generated method stub - return null; - } - - @Override - public boolean onCreate() { - return true; - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, - String[] selectionArgs, String sortOrder) { - - String query = (selectionArgs != null && selectionArgs.length > 0) ? selectionArgs[0] : ""; - - // search history - ArrayList history = GlobalApp.getQuickConnectHistoryGateway().findHistory(query); - - // search bookmarks - ArrayList manualBookmarks; - if (query.length() > 0) - manualBookmarks = GlobalApp.getManualBookmarkGateway().findByLabelOrHostnameLike(query); - else - manualBookmarks = GlobalApp.getManualBookmarkGateway().findAll(); - - return createResultCursor(history, manualBookmarks); - } - - @Override - public int update(Uri uri, ContentValues values, String selection, - String[] selectionArgs) { - // TODO Auto-generated method stub - return 0; - } - - private void addBookmarksToCursor(ArrayList bookmarks, MatrixCursor resultCursor) { - Object[] row = new Object[5]; - for (BookmarkBase bookmark : bookmarks) { - row[0] = new Long(bookmark.getId()); - row[1] = bookmark.getLabel(); - row[2] = bookmark.get().getHostname(); - row[3] = ConnectionReference.getManualBookmarkReference(bookmark.getId()); - row[4] = "android.resource://" + getContext().getPackageName() + "/" + R.drawable.icon_star_on; - resultCursor.addRow(row); - } - } - - private void addHistoryToCursor(ArrayList history, MatrixCursor resultCursor) { - Object[] row = new Object[5]; - for (BookmarkBase bookmark : history) { - row[0] = new Integer(1); - row[1] = bookmark.getLabel(); - row[2] = bookmark.getLabel(); - row[3] = ConnectionReference.getHostnameReference(bookmark.getLabel()); - row[4] = "android.resource://" + getContext().getPackageName() + "/" + R.drawable.icon_star_off; - resultCursor.addRow(row); - } - } - - private Cursor createResultCursor(ArrayList history, ArrayList manualBookmarks) { - - // create result matrix cursor - int totalCount = history.size() + manualBookmarks.size(); - String[] columns = {android.provider.BaseColumns._ID, SearchManager.SUGGEST_COLUMN_TEXT_1, - SearchManager.SUGGEST_COLUMN_TEXT_2, SearchManager.SUGGEST_COLUMN_INTENT_DATA, - SearchManager.SUGGEST_COLUMN_ICON_2}; - MatrixCursor matrixCursor = new MatrixCursor(columns, totalCount); - - // populate result matrix - if (totalCount > 0) { - addHistoryToCursor(history, matrixCursor); - addBookmarksToCursor(manualBookmarks, matrixCursor); - } - return matrixCursor; - } - +public class FreeRDPSuggestionProvider extends ContentProvider +{ + + public static final Uri CONTENT_URI = + Uri.parse("content://com.freerdp.afreerdp.services.freerdpsuggestionprovider"); + + @Override public int delete(Uri uri, String selection, String[] selectionArgs) + { + // TODO Auto-generated method stub + return 0; + } + + @Override public String getType(Uri uri) + { + return "vnd.android.cursor.item/vnd.freerdp.remote"; + } + + @Override public Uri insert(Uri uri, ContentValues values) + { + // TODO Auto-generated method stub + return null; + } + + @Override public boolean onCreate() + { + return true; + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, + String sortOrder) + { + + String query = (selectionArgs != null && selectionArgs.length > 0) ? selectionArgs[0] : ""; + + // search history + ArrayList history = + GlobalApp.getQuickConnectHistoryGateway().findHistory(query); + + // search bookmarks + ArrayList manualBookmarks; + if (query.length() > 0) + manualBookmarks = GlobalApp.getManualBookmarkGateway().findByLabelOrHostnameLike(query); + else + manualBookmarks = GlobalApp.getManualBookmarkGateway().findAll(); + + return createResultCursor(history, manualBookmarks); + } + + @Override + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) + { + // TODO Auto-generated method stub + return 0; + } + + private void addBookmarksToCursor(ArrayList bookmarks, MatrixCursor resultCursor) + { + Object[] row = new Object[5]; + for (BookmarkBase bookmark : bookmarks) + { + row[0] = new Long(bookmark.getId()); + row[1] = bookmark.getLabel(); + row[2] = bookmark.get().getHostname(); + row[3] = ConnectionReference.getManualBookmarkReference(bookmark.getId()); + row[4] = "android.resource://" + getContext().getPackageName() + "/" + + R.drawable.icon_star_on; + resultCursor.addRow(row); + } + } + + private void addHistoryToCursor(ArrayList history, MatrixCursor resultCursor) + { + Object[] row = new Object[5]; + for (BookmarkBase bookmark : history) + { + row[0] = new Integer(1); + row[1] = bookmark.getLabel(); + row[2] = bookmark.getLabel(); + row[3] = ConnectionReference.getHostnameReference(bookmark.getLabel()); + row[4] = "android.resource://" + getContext().getPackageName() + "/" + + R.drawable.icon_star_off; + resultCursor.addRow(row); + } + } + + private Cursor createResultCursor(ArrayList history, + ArrayList manualBookmarks) + { + + // create result matrix cursor + int totalCount = history.size() + manualBookmarks.size(); + String[] columns = { android.provider.BaseColumns._ID, SearchManager.SUGGEST_COLUMN_TEXT_1, + SearchManager.SUGGEST_COLUMN_TEXT_2, + SearchManager.SUGGEST_COLUMN_INTENT_DATA, + SearchManager.SUGGEST_COLUMN_ICON_2 }; + MatrixCursor matrixCursor = new MatrixCursor(columns, totalCount); + + // populate result matrix + if (totalCount > 0) + { + addHistoryToCursor(history, matrixCursor); + addBookmarksToCursor(manualBookmarks, matrixCursor); + } + return matrixCursor; + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/HistoryDB.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/HistoryDB.java index 91bd8b7..b483aac 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/HistoryDB.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/HistoryDB.java @@ -3,8 +3,9 @@ Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.services; @@ -13,34 +14,33 @@ import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; -public class HistoryDB extends SQLiteOpenHelper { +public class HistoryDB extends SQLiteOpenHelper +{ - public static final String QUICK_CONNECT_TABLE_NAME = "quick_connect_history"; - public static final String QUICK_CONNECT_TABLE_COL_ITEM = "item"; - public static final String QUICK_CONNECT_TABLE_COL_TIMESTAMP = "timestamp"; - private static final int DB_VERSION = 1; - private static final String DB_NAME = "history.db"; + public static final String QUICK_CONNECT_TABLE_NAME = "quick_connect_history"; + public static final String QUICK_CONNECT_TABLE_COL_ITEM = "item"; + public static final String QUICK_CONNECT_TABLE_COL_TIMESTAMP = "timestamp"; + private static final int DB_VERSION = 1; + private static final String DB_NAME = "history.db"; - public HistoryDB(Context context) { - super(context, DB_NAME, null, DB_VERSION); - } + public HistoryDB(Context context) + { + super(context, DB_NAME, null, DB_VERSION); + } - @Override - public void onCreate(SQLiteDatabase db) { + @Override public void onCreate(SQLiteDatabase db) + { - String sqlQuickConnectHistory = - "CREATE TABLE " + QUICK_CONNECT_TABLE_NAME + " (" - + QUICK_CONNECT_TABLE_COL_ITEM + " TEXT PRIMARY KEY, " - + QUICK_CONNECT_TABLE_COL_TIMESTAMP + " INTEGER" - + ");"; + String sqlQuickConnectHistory = "CREATE TABLE " + QUICK_CONNECT_TABLE_NAME + " (" + + QUICK_CONNECT_TABLE_COL_ITEM + " TEXT PRIMARY KEY, " + + QUICK_CONNECT_TABLE_COL_TIMESTAMP + " INTEGER" + + ");"; - db.execSQL(sqlQuickConnectHistory); - } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - // TODO Auto-generated method stub - - } + db.execSQL(sqlQuickConnectHistory); + } + @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) + { + // TODO Auto-generated method stub + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/LibFreeRDP.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/LibFreeRDP.java index 0d2bd2e..bab6345 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/LibFreeRDP.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/LibFreeRDP.java @@ -3,13 +3,13 @@ Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.services; - import android.content.Context; import android.graphics.Bitmap; import android.net.Uri; @@ -24,500 +24,596 @@ import com.freerdp.freerdpcore.presentation.ApplicationSettingsActivity; import java.util.ArrayList; -public class LibFreeRDP { - private static final String TAG = "LibFreeRDP"; - private static EventListener listener; - private static boolean mHasH264 = true; - - private static final LongSparseArray mInstanceState = new LongSparseArray<>(); - - static { - final String h264 = "openh264"; - final String[] libraries = { - h264, "freerdp-openssl", "jpeg", "winpr2", - "freerdp2", "freerdp-client2", "freerdp-android2"}; - final String LD_PATH = System.getProperty("java.library.path"); - - for (String lib : libraries) { - try { - Log.v(TAG, "Trying to load library " + lib + " from LD_PATH: " + LD_PATH); - System.loadLibrary(lib); - } catch (UnsatisfiedLinkError e) { - Log.e(TAG, "Failed to load library " + lib + ": " + e.toString()); - if (lib.equals(h264)) { - mHasH264 = false; - } - } - } - } - - public static boolean hasH264Support() { - return mHasH264; - } - - private static native String freerdp_get_jni_version(); - - private static native String freerdp_get_version(); - - private static native String freerdp_get_build_date(); - - private static native String freerdp_get_build_revision(); - - private static native String freerdp_get_build_config(); - - private static native long freerdp_new(Context context); - - private static native void freerdp_free(long inst); - - private static native boolean freerdp_parse_arguments(long inst, String[] args); - - private static native boolean freerdp_connect(long inst); - - private static native boolean freerdp_disconnect(long inst); - - private static native boolean freerdp_update_graphics(long inst, - Bitmap bitmap, int x, int y, int width, int height); - - private static native boolean freerdp_send_cursor_event(long inst, int x, int y, int flags); - - private static native boolean freerdp_send_key_event(long inst, int keycode, boolean down); - - private static native boolean freerdp_send_unicodekey_event(long inst, int keycode); - - private static native boolean freerdp_send_clipboard_data(long inst, String data); - - public static void setEventListener(EventListener l) { - listener = l; - } - - public static long newInstance(Context context) { - return freerdp_new(context); - } - - public static void freeInstance(long inst) { - synchronized (mInstanceState) { - if (mInstanceState.get(inst, false)) { - freerdp_disconnect(inst); - } - while(mInstanceState.get(inst, false)) { - try { - mInstanceState.wait(); - } catch (InterruptedException e) { - throw new RuntimeException(); - } - } - } - freerdp_free(inst); - } - - public static boolean connect(long inst) { - synchronized (mInstanceState) { - if (mInstanceState.get(inst, false)) { - throw new RuntimeException("instance already connected"); - } - } - return freerdp_connect(inst); - } - - public static boolean disconnect(long inst) { - synchronized (mInstanceState) { - if (mInstanceState.get(inst, false)) { - return freerdp_disconnect(inst); - } - return true; - } - } - - public static boolean cancelConnection(long inst) { - synchronized (mInstanceState) { - if (mInstanceState.get(inst, false)) { - return freerdp_disconnect(inst); - } - return true; - } - } - - private static String addFlag(String name, boolean enabled) { - if (enabled) { - return "+" + name; - } - return "-" + name; - } - - public static boolean setConnectionInfo(Context context, long inst, BookmarkBase bookmark) { - BookmarkBase.ScreenSettings screenSettings = bookmark.getActiveScreenSettings(); - BookmarkBase.AdvancedSettings advanced = bookmark.getAdvancedSettings(); - BookmarkBase.DebugSettings debug = bookmark.getDebugSettings(); - - String arg; - ArrayList args = new ArrayList(); - - args.add(TAG); - args.add("/gdi:sw"); - - final String clientName = ApplicationSettingsActivity.getClientName(context); - if (!clientName.isEmpty()) { - args.add("/client-hostname:" + clientName); - } - String certName = ""; - if (bookmark.getType() != BookmarkBase.TYPE_MANUAL) { - return false; - } - - int port = bookmark.get().getPort(); - String hostname = bookmark.get().getHostname(); - - args.add("/v:" + hostname); - args.add("/port:" + String.valueOf(port)); - - arg = bookmark.getUsername(); - if (!arg.isEmpty()) { - args.add("/u:" + arg); - } - arg = bookmark.getDomain(); - if (!arg.isEmpty()) { - args.add("/d:" + arg); - } - arg = bookmark.getPassword(); - if (!arg.isEmpty()) { - args.add("/p:" + arg); - } - - args.add(String.format("/size:%dx%d", screenSettings.getWidth(), - screenSettings.getHeight())); - args.add("/bpp:" + String.valueOf(screenSettings.getColors())); - - if (advanced.getConsoleMode()) { - args.add("/admin"); - } - - switch (advanced.getSecurity()) { - case 3: // NLA - args.add("/sec-nla"); - break; - case 2: // TLS - args.add("/sec-tls"); - break; - case 1: // RDP - args.add("/sec-rdp"); - break; - default: - break; - } - - if (!certName.isEmpty()) { - args.add("/cert-name:" + certName); - } - - BookmarkBase.PerformanceFlags flags = bookmark.getActivePerformanceFlags(); - if (flags.getRemoteFX()) { - args.add("/rfx"); - } - - if (flags.getGfx()) { - args.add("/gfx"); - } - - if (flags.getH264() && mHasH264) { - args.add("/gfx:AVC444"); - } - - args.add(addFlag("wallpaper", flags.getWallpaper())); - args.add(addFlag("window-drag", flags.getFullWindowDrag())); - args.add(addFlag("menu-anims", flags.getMenuAnimations())); - args.add(addFlag("themes", flags.getTheming())); - args.add(addFlag("fonts", flags.getFontSmoothing())); - args.add(addFlag("aero", flags.getDesktopComposition())); - args.add(addFlag("glyph-cache", false)); - - if (!advanced.getRemoteProgram().isEmpty()) { - args.add("/shell:" + advanced.getRemoteProgram()); - } - - if (!advanced.getWorkDir().isEmpty()) { - args.add("/shell-dir:" + advanced.getWorkDir()); - } - - args.add(addFlag("async-channels", debug.getAsyncChannel())); - args.add(addFlag("async-input", debug.getAsyncInput())); - args.add(addFlag("async-update", debug.getAsyncUpdate())); - - if (advanced.getRedirectSDCard()) { - String path = android.os.Environment.getExternalStorageDirectory().getPath(); - args.add("/drive:sdcard," + path); - } - - args.add("/clipboard"); - - // Gateway enabled? - if (bookmark.getType() == BookmarkBase.TYPE_MANUAL && bookmark.get().getEnableGatewaySettings()) { - ManualBookmark.GatewaySettings gateway = bookmark.get().getGatewaySettings(); - - args.add(String.format("/g:%s:%d", gateway.getHostname(), gateway.getPort())); - - arg = gateway.getUsername(); - if (!arg.isEmpty()) { - args.add("/gu:" + arg); - } - arg = gateway.getDomain(); - if (!arg.isEmpty()) { - args.add("/gd:" + arg); - } - arg = gateway.getPassword(); - if (!arg.isEmpty()) { - args.add("/gp:" + arg); - } - } - - /* 0 ... local - 1 ... remote - 2 ... disable */ - args.add("/audio-mode:" + String.valueOf(advanced.getRedirectSound())); - if (advanced.getRedirectSound() == 0) { - args.add("/sound"); - } - - if (advanced.getRedirectMicrophone()) { - args.add("/microphone"); - } - - args.add("/cert-ignore"); - args.add("/log-level:" + debug.getDebugLevel()); - String[] arrayArgs = args.toArray(new String[args.size()]); - return freerdp_parse_arguments(inst, arrayArgs); - } - - public static boolean setConnectionInfo(Context context, long inst, Uri openUri) { - ArrayList args = new ArrayList<>(); - - // Parse URI from query string. Same key overwrite previous one - // freerdp://user@ip:port/connect?sound=&rfx=&p=password&clipboard=%2b&themes=- - - // Now we only support Software GDI - args.add(TAG); - args.add("/gdi:sw"); - - final String clientName = ApplicationSettingsActivity.getClientName(context); - if (!clientName.isEmpty()) { - args.add("/client-hostname:" + clientName); - } - - // Parse hostname and port. Set to 'v' argument - String hostname = openUri.getHost(); - int port = openUri.getPort(); - if (hostname != null) { - hostname = hostname + ((port == -1) ? "" : (":" + String.valueOf(port))); - args.add("/v:" + hostname); - } - - String user = openUri.getUserInfo(); - if (user != null) { - args.add("/u:" + user); - } - - for (String key : openUri.getQueryParameterNames()) { - String value = openUri.getQueryParameter(key); - - if (value.isEmpty()) { - // Query: key= - // To freerdp argument: /key - args.add("/" + key); - } else if (value.equals("-") || value.equals("+")) { - // Query: key=- or key=+ - // To freerdp argument: -key or +key - args.add(value + key); - } else { - // Query: key=value - // To freerdp argument: /key:value - if (key.equals("drive") && value.equals("sdcard")) { - // Special for sdcard redirect - String path = android.os.Environment.getExternalStorageDirectory().getPath(); - value = "sdcard," + path; - } - - args.add("/" + key + ":" + value); - } - } - - String[] arrayArgs = args.toArray(new String[args.size()]); - return freerdp_parse_arguments(inst, arrayArgs); - } - - public static boolean updateGraphics(long inst, Bitmap bitmap, int x, int y, int width, int height) { - return freerdp_update_graphics(inst, bitmap, x, y, width, height); - } - - public static boolean sendCursorEvent(long inst, int x, int y, int flags) { - return freerdp_send_cursor_event(inst, x, y, flags); - } - - public static boolean sendKeyEvent(long inst, int keycode, boolean down) { - return freerdp_send_key_event(inst, keycode, down); - } - - public static boolean sendUnicodeKeyEvent(long inst, int keycode) { - return freerdp_send_unicodekey_event(inst, keycode); - } - - public static boolean sendClipboardData(long inst, String data) { - return freerdp_send_clipboard_data(inst, data); - } - - private static void OnConnectionSuccess(long inst) { - if (listener != null) - listener.OnConnectionSuccess(inst); - synchronized (mInstanceState) { - mInstanceState.append(inst, true); - mInstanceState.notifyAll(); - } - } - - private static void OnConnectionFailure(long inst) { - if (listener != null) - listener.OnConnectionFailure(inst); - synchronized (mInstanceState) { - mInstanceState.remove(inst); - mInstanceState.notifyAll(); - } - } - - private static void OnPreConnect(long inst) { - if (listener != null) - listener.OnPreConnect(inst); - } - - private static void OnDisconnecting(long inst) { - if (listener != null) - listener.OnDisconnecting(inst); - } - - private static void OnDisconnected(long inst) { - if (listener != null) - listener.OnDisconnected(inst); - synchronized (mInstanceState) { - mInstanceState.remove(inst); - mInstanceState.notifyAll(); - } - } - - private static void OnSettingsChanged(long inst, int width, int height, int bpp) { - SessionState s = GlobalApp.getSession(inst); - if (s == null) - return; - UIEventListener uiEventListener = s.getUIEventListener(); - if (uiEventListener != null) - uiEventListener.OnSettingsChanged(width, height, bpp); - } - - private static boolean OnAuthenticate(long inst, StringBuilder username, StringBuilder domain, StringBuilder password) { - SessionState s = GlobalApp.getSession(inst); - if (s == null) - return false; - UIEventListener uiEventListener = s.getUIEventListener(); - if (uiEventListener != null) - return uiEventListener.OnAuthenticate(username, domain, password); - return false; - } - - private static boolean OnGatewayAuthenticate(long inst, StringBuilder username, StringBuilder - domain, StringBuilder password) { - SessionState s = GlobalApp.getSession(inst); - if (s == null) - return false; - UIEventListener uiEventListener = s.getUIEventListener(); - if (uiEventListener != null) - return uiEventListener.OnGatewayAuthenticate(username, domain, password); - return false; - } - - private static int OnVerifyCertificate(long inst, String commonName, String subject, - String issuer, String fingerprint, boolean - hostMismatch) { - SessionState s = GlobalApp.getSession(inst); - if (s == null) - return 0; - UIEventListener uiEventListener = s.getUIEventListener(); - if (uiEventListener != null) - return uiEventListener.OnVerifiyCertificate(commonName, subject, issuer, fingerprint, - hostMismatch); - return 0; - } - - private static int OnVerifyChangedCertificate(long inst, String commonName, String subject, - String issuer, String fingerprint, String oldSubject, - String oldIssuer, String oldFingerprint) { - SessionState s = GlobalApp.getSession(inst); - if (s == null) - return 0; - UIEventListener uiEventListener = s.getUIEventListener(); - if (uiEventListener != null) - return uiEventListener.OnVerifyChangedCertificate(commonName, subject, issuer, - fingerprint, oldSubject, oldIssuer, oldFingerprint); - return 0; - } - - private static void OnGraphicsUpdate(long inst, int x, int y, int width, int height) { - SessionState s = GlobalApp.getSession(inst); - if (s == null) - return; - UIEventListener uiEventListener = s.getUIEventListener(); - if (uiEventListener != null) - uiEventListener.OnGraphicsUpdate(x, y, width, height); - } - - private static void OnGraphicsResize(long inst, int width, int height, int bpp) { - SessionState s = GlobalApp.getSession(inst); - if (s == null) - return; - UIEventListener uiEventListener = s.getUIEventListener(); - if (uiEventListener != null) - uiEventListener.OnGraphicsResize(width, height, bpp); - } - - private static void OnRemoteClipboardChanged(long inst, String data) { - SessionState s = GlobalApp.getSession(inst); - if (s == null) - return; - UIEventListener uiEventListener = s.getUIEventListener(); - if (uiEventListener != null) - uiEventListener.OnRemoteClipboardChanged(data); - } - - public static String getVersion() { - return freerdp_get_version(); - } - - public static interface EventListener { - void OnPreConnect(long instance); - - void OnConnectionSuccess(long instance); - - void OnConnectionFailure(long instance); - - void OnDisconnecting(long instance); - - void OnDisconnected(long instance); - } - - public static interface UIEventListener { - void OnSettingsChanged(int width, int height, int bpp); - - boolean OnAuthenticate(StringBuilder username, StringBuilder domain, StringBuilder password); - - boolean OnGatewayAuthenticate(StringBuilder username, StringBuilder domain, StringBuilder - password); - - int OnVerifiyCertificate(String commonName, String subject, - String issuer, String fingerprint, boolean mismatch); - - int OnVerifyChangedCertificate(String commonName, String subject, - String issuer, String fingerprint, String oldSubject, - String oldIssuer, String oldFingerprint); - - void OnGraphicsUpdate(int x, int y, int width, int height); - - void OnGraphicsResize(int width, int height, int bpp); - - void OnRemoteClipboardChanged(String data); - } +public class LibFreeRDP +{ + private static final String TAG = "LibFreeRDP"; + private static EventListener listener; + private static boolean mHasH264 = true; + + private static final LongSparseArray mInstanceState = new LongSparseArray<>(); + + static + { + final String h264 = "openh264"; + final String[] libraries = { h264, + "freerdp-openssl", + "ssl", + "crypto", + "jpeg", + "winpr2", + "freerdp2", + "freerdp-client2", + "freerdp-android2" }; + final String LD_PATH = System.getProperty("java.library.path"); + + for (String lib : libraries) + { + try + { + Log.v(TAG, "Trying to load library " + lib + " from LD_PATH: " + LD_PATH); + System.loadLibrary(lib); + } + catch (UnsatisfiedLinkError e) + { + Log.e(TAG, "Failed to load library " + lib + ": " + e.toString()); + if (lib.equals(h264)) + { + mHasH264 = false; + } + } + } + } + + public static boolean hasH264Support() + { + return mHasH264; + } + + private static native String freerdp_get_jni_version(); + + private static native String freerdp_get_version(); + + private static native String freerdp_get_build_date(); + + private static native String freerdp_get_build_revision(); + + private static native String freerdp_get_build_config(); + + private static native long freerdp_new(Context context); + + private static native void freerdp_free(long inst); + + private static native boolean freerdp_parse_arguments(long inst, String[] args); + + private static native boolean freerdp_connect(long inst); + + private static native boolean freerdp_disconnect(long inst); + + private static native boolean freerdp_update_graphics(long inst, Bitmap bitmap, int x, int y, + int width, int height); + + private static native boolean freerdp_send_cursor_event(long inst, int x, int y, int flags); + + private static native boolean freerdp_send_key_event(long inst, int keycode, boolean down); + + private static native boolean freerdp_send_unicodekey_event(long inst, int keycode, + boolean down); + + private static native boolean freerdp_send_clipboard_data(long inst, String data); + + private static native String freerdp_get_last_error_string(long inst); + + public static void setEventListener(EventListener l) + { + listener = l; + } + + public static long newInstance(Context context) + { + return freerdp_new(context); + } + + public static void freeInstance(long inst) + { + synchronized (mInstanceState) + { + if (mInstanceState.get(inst, false)) + { + freerdp_disconnect(inst); + } + while (mInstanceState.get(inst, false)) + { + try + { + mInstanceState.wait(); + } + catch (InterruptedException e) + { + throw new RuntimeException(); + } + } + } + freerdp_free(inst); + } + + public static boolean connect(long inst) + { + synchronized (mInstanceState) + { + if (mInstanceState.get(inst, false)) + { + throw new RuntimeException("instance already connected"); + } + } + return freerdp_connect(inst); + } + + public static boolean disconnect(long inst) + { + synchronized (mInstanceState) + { + if (mInstanceState.get(inst, false)) + { + return freerdp_disconnect(inst); + } + return true; + } + } + + public static boolean cancelConnection(long inst) + { + synchronized (mInstanceState) + { + if (mInstanceState.get(inst, false)) + { + return freerdp_disconnect(inst); + } + return true; + } + } + + private static String addFlag(String name, boolean enabled) + { + if (enabled) + { + return "+" + name; + } + return "-" + name; + } + + public static boolean setConnectionInfo(Context context, long inst, BookmarkBase bookmark) + { + BookmarkBase.ScreenSettings screenSettings = bookmark.getActiveScreenSettings(); + BookmarkBase.AdvancedSettings advanced = bookmark.getAdvancedSettings(); + BookmarkBase.DebugSettings debug = bookmark.getDebugSettings(); + + String arg; + ArrayList args = new ArrayList(); + + args.add(TAG); + args.add("/gdi:sw"); + + final String clientName = ApplicationSettingsActivity.getClientName(context); + if (!clientName.isEmpty()) + { + args.add("/client-hostname:" + clientName); + } + String certName = ""; + if (bookmark.getType() != BookmarkBase.TYPE_MANUAL) + { + return false; + } + + int port = bookmark.get().getPort(); + String hostname = bookmark.get().getHostname(); + + args.add("/v:" + hostname); + args.add("/port:" + String.valueOf(port)); + + arg = bookmark.getUsername(); + if (!arg.isEmpty()) + { + args.add("/u:" + arg); + } + arg = bookmark.getDomain(); + if (!arg.isEmpty()) + { + args.add("/d:" + arg); + } + arg = bookmark.getPassword(); + if (!arg.isEmpty()) + { + args.add("/p:" + arg); + } + + args.add( + String.format("/size:%dx%d", screenSettings.getWidth(), screenSettings.getHeight())); + args.add("/bpp:" + String.valueOf(screenSettings.getColors())); + + if (advanced.getConsoleMode()) + { + args.add("/admin"); + } + + switch (advanced.getSecurity()) + { + case 3: // NLA + args.add("/sec-nla"); + break; + case 2: // TLS + args.add("/sec-tls"); + break; + case 1: // RDP + args.add("/sec-rdp"); + break; + default: + break; + } + + if (!certName.isEmpty()) + { + args.add("/cert-name:" + certName); + } + + BookmarkBase.PerformanceFlags flags = bookmark.getActivePerformanceFlags(); + if (flags.getRemoteFX()) + { + args.add("/rfx"); + } + + if (flags.getGfx()) + { + args.add("/gfx"); + } + + if (flags.getH264() && mHasH264) + { + args.add("/gfx:AVC444"); + } + + args.add(addFlag("wallpaper", flags.getWallpaper())); + args.add(addFlag("window-drag", flags.getFullWindowDrag())); + args.add(addFlag("menu-anims", flags.getMenuAnimations())); + args.add(addFlag("themes", flags.getTheming())); + args.add(addFlag("fonts", flags.getFontSmoothing())); + args.add(addFlag("aero", flags.getDesktopComposition())); + args.add(addFlag("glyph-cache", false)); + + if (!advanced.getRemoteProgram().isEmpty()) + { + args.add("/shell:" + advanced.getRemoteProgram()); + } + + if (!advanced.getWorkDir().isEmpty()) + { + args.add("/shell-dir:" + advanced.getWorkDir()); + } + + args.add(addFlag("async-channels", debug.getAsyncChannel())); + args.add(addFlag("async-input", debug.getAsyncInput())); + args.add(addFlag("async-update", debug.getAsyncUpdate())); + + if (advanced.getRedirectSDCard()) + { + String path = android.os.Environment.getExternalStorageDirectory().getPath(); + args.add("/drive:sdcard," + path); + } + + args.add("/clipboard"); + + // Gateway enabled? + if (bookmark.getType() == BookmarkBase.TYPE_MANUAL && + bookmark.get().getEnableGatewaySettings()) + { + ManualBookmark.GatewaySettings gateway = + bookmark.get().getGatewaySettings(); + + args.add(String.format("/g:%s:%d", gateway.getHostname(), gateway.getPort())); + + arg = gateway.getUsername(); + if (!arg.isEmpty()) + { + args.add("/gu:" + arg); + } + arg = gateway.getDomain(); + if (!arg.isEmpty()) + { + args.add("/gd:" + arg); + } + arg = gateway.getPassword(); + if (!arg.isEmpty()) + { + args.add("/gp:" + arg); + } + } + + /* 0 ... local + 1 ... remote + 2 ... disable */ + args.add("/audio-mode:" + String.valueOf(advanced.getRedirectSound())); + if (advanced.getRedirectSound() == 0) + { + args.add("/sound"); + } + + if (advanced.getRedirectMicrophone()) + { + args.add("/microphone"); + } + + args.add("/cert-ignore"); + args.add("/log-level:" + debug.getDebugLevel()); + String[] arrayArgs = args.toArray(new String[args.size()]); + return freerdp_parse_arguments(inst, arrayArgs); + } + + public static boolean setConnectionInfo(Context context, long inst, Uri openUri) + { + ArrayList args = new ArrayList<>(); + + // Parse URI from query string. Same key overwrite previous one + // freerdp://user@ip:port/connect?sound=&rfx=&p=password&clipboard=%2b&themes=- + + // Now we only support Software GDI + args.add(TAG); + args.add("/gdi:sw"); + + final String clientName = ApplicationSettingsActivity.getClientName(context); + if (!clientName.isEmpty()) + { + args.add("/client-hostname:" + clientName); + } + + // Parse hostname and port. Set to 'v' argument + String hostname = openUri.getHost(); + int port = openUri.getPort(); + if (hostname != null) + { + hostname = hostname + ((port == -1) ? "" : (":" + String.valueOf(port))); + args.add("/v:" + hostname); + } + + String user = openUri.getUserInfo(); + if (user != null) + { + args.add("/u:" + user); + } + + for (String key : openUri.getQueryParameterNames()) + { + String value = openUri.getQueryParameter(key); + + if (value.isEmpty()) + { + // Query: key= + // To freerdp argument: /key + args.add("/" + key); + } + else if (value.equals("-") || value.equals("+")) + { + // Query: key=- or key=+ + // To freerdp argument: -key or +key + args.add(value + key); + } + else + { + // Query: key=value + // To freerdp argument: /key:value + if (key.equals("drive") && value.equals("sdcard")) + { + // Special for sdcard redirect + String path = android.os.Environment.getExternalStorageDirectory().getPath(); + value = "sdcard," + path; + } + + args.add("/" + key + ":" + value); + } + } + + String[] arrayArgs = args.toArray(new String[args.size()]); + return freerdp_parse_arguments(inst, arrayArgs); + } + + public static boolean updateGraphics(long inst, Bitmap bitmap, int x, int y, int width, + int height) + { + return freerdp_update_graphics(inst, bitmap, x, y, width, height); + } + + public static boolean sendCursorEvent(long inst, int x, int y, int flags) + { + return freerdp_send_cursor_event(inst, x, y, flags); + } + + public static boolean sendKeyEvent(long inst, int keycode, boolean down) + { + return freerdp_send_key_event(inst, keycode, down); + } + + public static boolean sendUnicodeKeyEvent(long inst, int keycode, boolean down) + { + return freerdp_send_unicodekey_event(inst, keycode, down); + } + + public static boolean sendClipboardData(long inst, String data) + { + return freerdp_send_clipboard_data(inst, data); + } + + private static void OnConnectionSuccess(long inst) + { + if (listener != null) + listener.OnConnectionSuccess(inst); + synchronized (mInstanceState) + { + mInstanceState.append(inst, true); + mInstanceState.notifyAll(); + } + } + + private static void OnConnectionFailure(long inst) + { + if (listener != null) + listener.OnConnectionFailure(inst); + synchronized (mInstanceState) + { + mInstanceState.remove(inst); + mInstanceState.notifyAll(); + } + } + + private static void OnPreConnect(long inst) + { + if (listener != null) + listener.OnPreConnect(inst); + } + + private static void OnDisconnecting(long inst) + { + if (listener != null) + listener.OnDisconnecting(inst); + } + + private static void OnDisconnected(long inst) + { + if (listener != null) + listener.OnDisconnected(inst); + synchronized (mInstanceState) + { + mInstanceState.remove(inst); + mInstanceState.notifyAll(); + } + } + + private static void OnSettingsChanged(long inst, int width, int height, int bpp) + { + SessionState s = GlobalApp.getSession(inst); + if (s == null) + return; + UIEventListener uiEventListener = s.getUIEventListener(); + if (uiEventListener != null) + uiEventListener.OnSettingsChanged(width, height, bpp); + } + + private static boolean OnAuthenticate(long inst, StringBuilder username, StringBuilder domain, + StringBuilder password) + { + SessionState s = GlobalApp.getSession(inst); + if (s == null) + return false; + UIEventListener uiEventListener = s.getUIEventListener(); + if (uiEventListener != null) + return uiEventListener.OnAuthenticate(username, domain, password); + return false; + } + + private static boolean OnGatewayAuthenticate(long inst, StringBuilder username, + StringBuilder domain, StringBuilder password) + { + SessionState s = GlobalApp.getSession(inst); + if (s == null) + return false; + UIEventListener uiEventListener = s.getUIEventListener(); + if (uiEventListener != null) + return uiEventListener.OnGatewayAuthenticate(username, domain, password); + return false; + } + + private static int OnVerifyCertificate(long inst, String commonName, String subject, + String issuer, String fingerprint, boolean hostMismatch) + { + SessionState s = GlobalApp.getSession(inst); + if (s == null) + return 0; + UIEventListener uiEventListener = s.getUIEventListener(); + if (uiEventListener != null) + return uiEventListener.OnVerifiyCertificate(commonName, subject, issuer, fingerprint, + hostMismatch); + return 0; + } + + private static int OnVerifyChangedCertificate(long inst, String commonName, String subject, + String issuer, String fingerprint, + String oldSubject, String oldIssuer, + String oldFingerprint) + { + SessionState s = GlobalApp.getSession(inst); + if (s == null) + return 0; + UIEventListener uiEventListener = s.getUIEventListener(); + if (uiEventListener != null) + return uiEventListener.OnVerifyChangedCertificate( + commonName, subject, issuer, fingerprint, oldSubject, oldIssuer, oldFingerprint); + return 0; + } + + private static void OnGraphicsUpdate(long inst, int x, int y, int width, int height) + { + SessionState s = GlobalApp.getSession(inst); + if (s == null) + return; + UIEventListener uiEventListener = s.getUIEventListener(); + if (uiEventListener != null) + uiEventListener.OnGraphicsUpdate(x, y, width, height); + } + + private static void OnGraphicsResize(long inst, int width, int height, int bpp) + { + SessionState s = GlobalApp.getSession(inst); + if (s == null) + return; + UIEventListener uiEventListener = s.getUIEventListener(); + if (uiEventListener != null) + uiEventListener.OnGraphicsResize(width, height, bpp); + } + + private static void OnRemoteClipboardChanged(long inst, String data) + { + SessionState s = GlobalApp.getSession(inst); + if (s == null) + return; + UIEventListener uiEventListener = s.getUIEventListener(); + if (uiEventListener != null) + uiEventListener.OnRemoteClipboardChanged(data); + } + + public static String getVersion() + { + return freerdp_get_version(); + } + + public static interface EventListener { + void OnPreConnect(long instance); + + void OnConnectionSuccess(long instance); + + void OnConnectionFailure(long instance); + + void OnDisconnecting(long instance); + + void OnDisconnected(long instance); + } + + public static interface UIEventListener { + void OnSettingsChanged(int width, int height, int bpp); + + boolean OnAuthenticate(StringBuilder username, StringBuilder domain, + StringBuilder password); + + boolean OnGatewayAuthenticate(StringBuilder username, StringBuilder domain, + StringBuilder password); + + int OnVerifiyCertificate(String commonName, String subject, String issuer, + String fingerprint, boolean mismatch); + + int OnVerifyChangedCertificate(String commonName, String subject, String issuer, + String fingerprint, String oldSubject, String oldIssuer, + String oldFingerprint); + + void OnGraphicsUpdate(int x, int y, int width, int height); + + void OnGraphicsResize(int width, int height, int bpp); + + void OnRemoteClipboardChanged(String data); + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/ManualBookmarkGateway.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/ManualBookmarkGateway.java index 64df814..2cd2751 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/ManualBookmarkGateway.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/ManualBookmarkGateway.java @@ -3,8 +3,9 @@ Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.services; @@ -18,96 +19,113 @@ import com.freerdp.freerdpcore.domain.ManualBookmark; import java.util.ArrayList; -public class ManualBookmarkGateway extends BookmarkBaseGateway { - - public ManualBookmarkGateway(SQLiteOpenHelper bookmarkDB) { - super(bookmarkDB); - } - - @Override - protected BookmarkBase createBookmark() { - return new ManualBookmark(); - } - - @Override - protected String getBookmarkTableName() { - return BookmarkDB.DB_TABLE_BOOKMARK; - } - - @Override - protected void addBookmarkSpecificColumns(BookmarkBase bookmark, ContentValues columns) { - ManualBookmark bm = (ManualBookmark) bookmark; - columns.put(BookmarkDB.DB_KEY_BOOKMARK_HOSTNAME, bm.getHostname()); - columns.put(BookmarkDB.DB_KEY_BOOKMARK_PORT, bm.getPort()); - - // gateway settings - columns.put(BookmarkDB.DB_KEY_BOOKMARK_GW_ENABLE, bm.getEnableGatewaySettings()); - columns.put(BookmarkDB.DB_KEY_BOOKMARK_GW_HOSTNAME, bm.getGatewaySettings().getHostname()); - columns.put(BookmarkDB.DB_KEY_BOOKMARK_GW_PORT, bm.getGatewaySettings().getPort()); - columns.put(BookmarkDB.DB_KEY_BOOKMARK_GW_USERNAME, bm.getGatewaySettings().getUsername()); - columns.put(BookmarkDB.DB_KEY_BOOKMARK_GW_PASSWORD, bm.getGatewaySettings().getPassword()); - columns.put(BookmarkDB.DB_KEY_BOOKMARK_GW_DOMAIN, bm.getGatewaySettings().getDomain()); - } - - @Override - protected void addBookmarkSpecificColumns(ArrayList columns) { - columns.add(BookmarkDB.DB_KEY_BOOKMARK_HOSTNAME); - columns.add(BookmarkDB.DB_KEY_BOOKMARK_PORT); - columns.add(BookmarkDB.DB_KEY_BOOKMARK_GW_ENABLE); - columns.add(BookmarkDB.DB_KEY_BOOKMARK_GW_HOSTNAME); - columns.add(BookmarkDB.DB_KEY_BOOKMARK_GW_PORT); - columns.add(BookmarkDB.DB_KEY_BOOKMARK_GW_USERNAME); - columns.add(BookmarkDB.DB_KEY_BOOKMARK_GW_PASSWORD); - columns.add(BookmarkDB.DB_KEY_BOOKMARK_GW_DOMAIN); - } - - @Override - protected void readBookmarkSpecificColumns(BookmarkBase bookmark, Cursor cursor) { - ManualBookmark bm = (ManualBookmark) bookmark; - bm.setHostname(cursor.getString(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_HOSTNAME))); - bm.setPort(cursor.getInt(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_PORT))); - - bm.setEnableGatewaySettings(cursor.getInt(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_GW_ENABLE)) != 0); - readGatewaySettings(bm, cursor); - } - - public BookmarkBase findByLabelOrHostname(String pattern) { - if (pattern.length() == 0) - return null; - - Cursor cursor = queryBookmarks(BookmarkDB.DB_KEY_BOOKMARK_LABEL + " = '" + pattern + - "' OR " + BookmarkDB.DB_KEY_BOOKMARK_HOSTNAME + " = '" + pattern + "'", - BookmarkDB.DB_KEY_BOOKMARK_LABEL); - BookmarkBase bookmark = null; - if (cursor.moveToFirst() && (cursor.getCount() > 0)) - bookmark = getBookmarkFromCursor(cursor); - - cursor.close(); - return bookmark; - } - - public ArrayList findByLabelOrHostnameLike(String pattern) { - Cursor cursor = queryBookmarks(BookmarkDB.DB_KEY_BOOKMARK_LABEL + " LIKE '%" + - pattern + "%' OR " + BookmarkDB.DB_KEY_BOOKMARK_HOSTNAME + " LIKE '%" + - pattern + "%'", BookmarkDB.DB_KEY_BOOKMARK_LABEL); - ArrayList bookmarks = new ArrayList(cursor.getCount()); - - if (cursor.moveToFirst() && (cursor.getCount() > 0)) { - do { - bookmarks.add(getBookmarkFromCursor(cursor)); - } while (cursor.moveToNext()); - } - - cursor.close(); - return bookmarks; - } - - private void readGatewaySettings(ManualBookmark bookmark, Cursor cursor) { - ManualBookmark.GatewaySettings gatewaySettings = bookmark.getGatewaySettings(); - gatewaySettings.setHostname(cursor.getString(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_GW_HOSTNAME))); - gatewaySettings.setPort(cursor.getInt(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_GW_PORT))); - gatewaySettings.setUsername(cursor.getString(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_GW_USERNAME))); - gatewaySettings.setPassword(cursor.getString(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_GW_PASSWORD))); - gatewaySettings.setDomain(cursor.getString(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_GW_DOMAIN))); - } +public class ManualBookmarkGateway extends BookmarkBaseGateway +{ + + public ManualBookmarkGateway(SQLiteOpenHelper bookmarkDB) + { + super(bookmarkDB); + } + + @Override protected BookmarkBase createBookmark() + { + return new ManualBookmark(); + } + + @Override protected String getBookmarkTableName() + { + return BookmarkDB.DB_TABLE_BOOKMARK; + } + + @Override + protected void addBookmarkSpecificColumns(BookmarkBase bookmark, ContentValues columns) + { + ManualBookmark bm = (ManualBookmark)bookmark; + columns.put(BookmarkDB.DB_KEY_BOOKMARK_HOSTNAME, bm.getHostname()); + columns.put(BookmarkDB.DB_KEY_BOOKMARK_PORT, bm.getPort()); + + // gateway settings + columns.put(BookmarkDB.DB_KEY_BOOKMARK_GW_ENABLE, bm.getEnableGatewaySettings()); + columns.put(BookmarkDB.DB_KEY_BOOKMARK_GW_HOSTNAME, bm.getGatewaySettings().getHostname()); + columns.put(BookmarkDB.DB_KEY_BOOKMARK_GW_PORT, bm.getGatewaySettings().getPort()); + columns.put(BookmarkDB.DB_KEY_BOOKMARK_GW_USERNAME, bm.getGatewaySettings().getUsername()); + columns.put(BookmarkDB.DB_KEY_BOOKMARK_GW_PASSWORD, bm.getGatewaySettings().getPassword()); + columns.put(BookmarkDB.DB_KEY_BOOKMARK_GW_DOMAIN, bm.getGatewaySettings().getDomain()); + } + + @Override protected void addBookmarkSpecificColumns(ArrayList columns) + { + columns.add(BookmarkDB.DB_KEY_BOOKMARK_HOSTNAME); + columns.add(BookmarkDB.DB_KEY_BOOKMARK_PORT); + columns.add(BookmarkDB.DB_KEY_BOOKMARK_GW_ENABLE); + columns.add(BookmarkDB.DB_KEY_BOOKMARK_GW_HOSTNAME); + columns.add(BookmarkDB.DB_KEY_BOOKMARK_GW_PORT); + columns.add(BookmarkDB.DB_KEY_BOOKMARK_GW_USERNAME); + columns.add(BookmarkDB.DB_KEY_BOOKMARK_GW_PASSWORD); + columns.add(BookmarkDB.DB_KEY_BOOKMARK_GW_DOMAIN); + } + + @Override protected void readBookmarkSpecificColumns(BookmarkBase bookmark, Cursor cursor) + { + ManualBookmark bm = (ManualBookmark)bookmark; + bm.setHostname( + cursor.getString(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_HOSTNAME))); + bm.setPort(cursor.getInt(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_PORT))); + + bm.setEnableGatewaySettings( + cursor.getInt(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_GW_ENABLE)) != 0); + readGatewaySettings(bm, cursor); + } + + public BookmarkBase findByLabelOrHostname(String pattern) + { + if (pattern.length() == 0) + return null; + + Cursor cursor = + queryBookmarks(BookmarkDB.DB_KEY_BOOKMARK_LABEL + " = '" + pattern + "' OR " + + BookmarkDB.DB_KEY_BOOKMARK_HOSTNAME + " = '" + pattern + "'", + BookmarkDB.DB_KEY_BOOKMARK_LABEL); + BookmarkBase bookmark = null; + if (cursor.moveToFirst() && (cursor.getCount() > 0)) + bookmark = getBookmarkFromCursor(cursor); + + cursor.close(); + return bookmark; + } + + public ArrayList findByLabelOrHostnameLike(String pattern) + { + Cursor cursor = + queryBookmarks(BookmarkDB.DB_KEY_BOOKMARK_LABEL + " LIKE '%" + pattern + "%' OR " + + BookmarkDB.DB_KEY_BOOKMARK_HOSTNAME + " LIKE '%" + pattern + "%'", + BookmarkDB.DB_KEY_BOOKMARK_LABEL); + ArrayList bookmarks = new ArrayList(cursor.getCount()); + + if (cursor.moveToFirst() && (cursor.getCount() > 0)) + { + do + { + bookmarks.add(getBookmarkFromCursor(cursor)); + } while (cursor.moveToNext()); + } + + cursor.close(); + return bookmarks; + } + + private void readGatewaySettings(ManualBookmark bookmark, Cursor cursor) + { + ManualBookmark.GatewaySettings gatewaySettings = bookmark.getGatewaySettings(); + gatewaySettings.setHostname( + cursor.getString(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_GW_HOSTNAME))); + gatewaySettings.setPort( + cursor.getInt(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_GW_PORT))); + gatewaySettings.setUsername( + cursor.getString(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_GW_USERNAME))); + gatewaySettings.setPassword( + cursor.getString(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_GW_PASSWORD))); + gatewaySettings.setDomain( + cursor.getString(cursor.getColumnIndex(BookmarkDB.DB_KEY_BOOKMARK_GW_DOMAIN))); + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/QuickConnectHistoryGateway.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/QuickConnectHistoryGateway.java index 7d97243..4dd5139 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/QuickConnectHistoryGateway.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/QuickConnectHistoryGateway.java @@ -3,8 +3,9 @@ Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.services; @@ -21,76 +22,100 @@ import com.freerdp.freerdpcore.domain.QuickConnectBookmark; import java.util.ArrayList; - -public class QuickConnectHistoryGateway { - private final static String TAG = "QuickConnectHistoryGateway"; - private SQLiteOpenHelper historyDB; - - - public QuickConnectHistoryGateway(SQLiteOpenHelper historyDB) { - this.historyDB = historyDB; - } - - public ArrayList findHistory(String filter) { - String[] column = {HistoryDB.QUICK_CONNECT_TABLE_COL_ITEM}; - - SQLiteDatabase db = getReadableDatabase(); - String selection = (filter.length() > 0) ? (HistoryDB.QUICK_CONNECT_TABLE_COL_ITEM + " LIKE '%" + filter + "%'") : null; - Cursor cursor = db.query(HistoryDB.QUICK_CONNECT_TABLE_NAME, column, selection, null, null, null, HistoryDB.QUICK_CONNECT_TABLE_COL_TIMESTAMP); - - ArrayList result = new ArrayList(cursor.getCount()); - if (cursor.moveToFirst()) { - do { - String hostname = cursor.getString(cursor.getColumnIndex(HistoryDB.QUICK_CONNECT_TABLE_COL_ITEM)); - QuickConnectBookmark bookmark = new QuickConnectBookmark(); - bookmark.setLabel(hostname); - bookmark.setHostname(hostname); - result.add(bookmark); - } while (cursor.moveToNext()); - } - cursor.close(); - return result; - } - - public void addHistoryItem(String item) { - String insertHistoryItem = "INSERT OR REPLACE INTO " + HistoryDB.QUICK_CONNECT_TABLE_NAME + " (" + - HistoryDB.QUICK_CONNECT_TABLE_COL_ITEM + ", " + HistoryDB.QUICK_CONNECT_TABLE_COL_TIMESTAMP + ") VALUES('" + item + "', datetime('now'))"; - SQLiteDatabase db = getWritableDatabase(); - try { - db.execSQL(insertHistoryItem); - } catch (SQLException e) { - Log.v(TAG, e.toString()); - } - } - - public boolean historyItemExists(String item) { - String[] column = {HistoryDB.QUICK_CONNECT_TABLE_COL_ITEM}; - SQLiteDatabase db = getReadableDatabase(); - Cursor cursor = db.query(HistoryDB.QUICK_CONNECT_TABLE_NAME, column, HistoryDB.QUICK_CONNECT_TABLE_COL_ITEM + " = '" + item + "'", null, null, null, null); - boolean exists = (cursor.getCount() == 1); - cursor.close(); - return exists; - } - - public void removeHistoryItem(String hostname) { - SQLiteDatabase db = getWritableDatabase(); - db.delete(HistoryDB.QUICK_CONNECT_TABLE_NAME, HistoryDB.QUICK_CONNECT_TABLE_COL_ITEM + " = '" + hostname + "'", null); - } - - // safety wrappers - // in case of getReadableDatabase it could happen that upgradeDB gets called which is - // a problem if the DB is only readable - private SQLiteDatabase getWritableDatabase() { - return historyDB.getWritableDatabase(); - } - - private SQLiteDatabase getReadableDatabase() { - SQLiteDatabase db; - try { - db = historyDB.getReadableDatabase(); - } catch (SQLiteException e) { - db = historyDB.getWritableDatabase(); - } - return db; - } +public class QuickConnectHistoryGateway +{ + private final static String TAG = "QuickConnectHistoryGateway"; + private SQLiteOpenHelper historyDB; + + public QuickConnectHistoryGateway(SQLiteOpenHelper historyDB) + { + this.historyDB = historyDB; + } + + public ArrayList findHistory(String filter) + { + String[] column = { HistoryDB.QUICK_CONNECT_TABLE_COL_ITEM }; + + SQLiteDatabase db = getReadableDatabase(); + String selection = + (filter.length() > 0) + ? (HistoryDB.QUICK_CONNECT_TABLE_COL_ITEM + " LIKE '%" + filter + "%'") + : null; + Cursor cursor = db.query(HistoryDB.QUICK_CONNECT_TABLE_NAME, column, selection, null, null, + null, HistoryDB.QUICK_CONNECT_TABLE_COL_TIMESTAMP); + + ArrayList result = new ArrayList(cursor.getCount()); + if (cursor.moveToFirst()) + { + do + { + String hostname = + cursor.getString(cursor.getColumnIndex(HistoryDB.QUICK_CONNECT_TABLE_COL_ITEM)); + QuickConnectBookmark bookmark = new QuickConnectBookmark(); + bookmark.setLabel(hostname); + bookmark.setHostname(hostname); + result.add(bookmark); + } while (cursor.moveToNext()); + } + cursor.close(); + return result; + } + + public void addHistoryItem(String item) + { + String insertHistoryItem = "INSERT OR REPLACE INTO " + HistoryDB.QUICK_CONNECT_TABLE_NAME + + " (" + HistoryDB.QUICK_CONNECT_TABLE_COL_ITEM + ", " + + HistoryDB.QUICK_CONNECT_TABLE_COL_TIMESTAMP + ") VALUES('" + + item + "', datetime('now'))"; + SQLiteDatabase db = getWritableDatabase(); + try + { + db.execSQL(insertHistoryItem); + } + catch (SQLException e) + { + Log.v(TAG, e.toString()); + } + } + + public boolean historyItemExists(String item) + { + String[] column = { HistoryDB.QUICK_CONNECT_TABLE_COL_ITEM }; + SQLiteDatabase db = getReadableDatabase(); + Cursor cursor = db.query(HistoryDB.QUICK_CONNECT_TABLE_NAME, column, + HistoryDB.QUICK_CONNECT_TABLE_COL_ITEM + " = '" + item + "'", null, + null, null, null); + boolean exists = (cursor.getCount() == 1); + cursor.close(); + return exists; + } + + public void removeHistoryItem(String hostname) + { + SQLiteDatabase db = getWritableDatabase(); + db.delete(HistoryDB.QUICK_CONNECT_TABLE_NAME, + HistoryDB.QUICK_CONNECT_TABLE_COL_ITEM + " = '" + hostname + "'", null); + } + + // safety wrappers + // in case of getReadableDatabase it could happen that upgradeDB gets called which is + // a problem if the DB is only readable + private SQLiteDatabase getWritableDatabase() + { + return historyDB.getWritableDatabase(); + } + + private SQLiteDatabase getReadableDatabase() + { + SQLiteDatabase db; + try + { + db = historyDB.getReadableDatabase(); + } + catch (SQLiteException e) + { + db = historyDB.getWritableDatabase(); + } + return db; + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/SessionRequestHandlerActivity.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/SessionRequestHandlerActivity.java index 6239aca..772b3a3 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/SessionRequestHandlerActivity.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/SessionRequestHandlerActivity.java @@ -3,8 +3,9 @@ Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.services; @@ -19,54 +20,58 @@ import com.freerdp.freerdpcore.domain.ConnectionReference; import com.freerdp.freerdpcore.presentation.BookmarkActivity; import com.freerdp.freerdpcore.presentation.SessionActivity; - -public class SessionRequestHandlerActivity extends AppCompatActivity { - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - handleIntent(getIntent()); - } - - @Override - protected void onNewIntent(Intent intent) { - setIntent(intent); - handleIntent(intent); - } - - private void startSessionWithConnectionReference(String refStr) { - - Bundle bundle = new Bundle(); - bundle.putString(SessionActivity.PARAM_CONNECTION_REFERENCE, refStr); - Intent sessionIntent = new Intent(this, SessionActivity.class); - sessionIntent.putExtras(bundle); - - startActivityForResult(sessionIntent, 0); - } - - private void editBookmarkWithConnectionReference(String refStr) { - Bundle bundle = new Bundle(); - bundle.putString(BookmarkActivity.PARAM_CONNECTION_REFERENCE, refStr); - Intent bookmarkIntent = new Intent(this.getApplicationContext(), BookmarkActivity.class); - bookmarkIntent.putExtras(bundle); - startActivityForResult(bookmarkIntent, 0); - } - - private void handleIntent(Intent intent) { - - String action = intent.getAction(); - if (Intent.ACTION_SEARCH.equals(action)) - startSessionWithConnectionReference(ConnectionReference.getHostnameReference(intent.getStringExtra(SearchManager.QUERY))); - else if (Intent.ACTION_VIEW.equals(action)) - startSessionWithConnectionReference(intent.getDataString()); - else if (Intent.ACTION_EDIT.equals(action)) - editBookmarkWithConnectionReference(intent.getDataString()); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - this.setResult(resultCode); - this.finish(); - } +public class SessionRequestHandlerActivity extends AppCompatActivity +{ + + @Override public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + handleIntent(getIntent()); + } + + @Override protected void onNewIntent(Intent intent) + { + setIntent(intent); + handleIntent(intent); + } + + private void startSessionWithConnectionReference(String refStr) + { + + Bundle bundle = new Bundle(); + bundle.putString(SessionActivity.PARAM_CONNECTION_REFERENCE, refStr); + Intent sessionIntent = new Intent(this, SessionActivity.class); + sessionIntent.putExtras(bundle); + + startActivityForResult(sessionIntent, 0); + } + + private void editBookmarkWithConnectionReference(String refStr) + { + Bundle bundle = new Bundle(); + bundle.putString(BookmarkActivity.PARAM_CONNECTION_REFERENCE, refStr); + Intent bookmarkIntent = new Intent(this.getApplicationContext(), BookmarkActivity.class); + bookmarkIntent.putExtras(bundle); + startActivityForResult(bookmarkIntent, 0); + } + + private void handleIntent(Intent intent) + { + + String action = intent.getAction(); + if (Intent.ACTION_SEARCH.equals(action)) + startSessionWithConnectionReference(ConnectionReference.getHostnameReference( + intent.getStringExtra(SearchManager.QUERY))); + else if (Intent.ACTION_VIEW.equals(action)) + startSessionWithConnectionReference(intent.getDataString()); + else if (Intent.ACTION_EDIT.equals(action)) + editBookmarkWithConnectionReference(intent.getDataString()); + } + + @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) + { + super.onActivityResult(requestCode, resultCode, data); + this.setResult(resultCode); + this.finish(); + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/AppCompatPreferenceActivity.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/AppCompatPreferenceActivity.java index 3e7aaa3..73377fa 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/AppCompatPreferenceActivity.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/AppCompatPreferenceActivity.java @@ -13,95 +13,100 @@ import android.view.MenuInflater; import android.view.View; import android.view.ViewGroup; -public abstract class AppCompatPreferenceActivity extends PreferenceActivity { - - private AppCompatDelegate mDelegate; - - @Override - protected void onCreate(Bundle savedInstanceState) { - getDelegate().installViewFactory(); - getDelegate().onCreate(savedInstanceState); - super.onCreate(savedInstanceState); - } - - @Override - protected void onPostCreate(Bundle savedInstanceState) { - super.onPostCreate(savedInstanceState); - getDelegate().onPostCreate(savedInstanceState); - } - - public ActionBar getSupportActionBar() { - return getDelegate().getSupportActionBar(); - } - - public void setSupportActionBar(@Nullable Toolbar toolbar) { - getDelegate().setSupportActionBar(toolbar); - } - - @Override - @NonNull - public MenuInflater getMenuInflater() { - return getDelegate().getMenuInflater(); - } - - @Override - public void setContentView(@LayoutRes int layoutResID) { - getDelegate().setContentView(layoutResID); - } - - @Override - public void setContentView(View view) { - getDelegate().setContentView(view); - } - - @Override - public void setContentView(View view, ViewGroup.LayoutParams params) { - getDelegate().setContentView(view, params); - } - - @Override - public void addContentView(View view, ViewGroup.LayoutParams params) { - getDelegate().addContentView(view, params); - } - - @Override - protected void onPostResume() { - super.onPostResume(); - getDelegate().onPostResume(); - } - - @Override - protected void onTitleChanged(CharSequence title, int color) { - super.onTitleChanged(title, color); - getDelegate().setTitle(title); - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - getDelegate().onConfigurationChanged(newConfig); - } - - @Override - protected void onStop() { - super.onStop(); - getDelegate().onStop(); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - getDelegate().onDestroy(); - } - - public void invalidateOptionsMenu() { - getDelegate().invalidateOptionsMenu(); - } - - private AppCompatDelegate getDelegate() { - if (mDelegate == null) { - mDelegate = AppCompatDelegate.create(this, null); - } - return mDelegate; - } +public abstract class AppCompatPreferenceActivity extends PreferenceActivity +{ + + private AppCompatDelegate mDelegate; + + @Override protected void onCreate(Bundle savedInstanceState) + { + getDelegate().installViewFactory(); + getDelegate().onCreate(savedInstanceState); + super.onCreate(savedInstanceState); + } + + @Override protected void onPostCreate(Bundle savedInstanceState) + { + super.onPostCreate(savedInstanceState); + getDelegate().onPostCreate(savedInstanceState); + } + + public ActionBar getSupportActionBar() + { + return getDelegate().getSupportActionBar(); + } + + public void setSupportActionBar(@Nullable Toolbar toolbar) + { + getDelegate().setSupportActionBar(toolbar); + } + + @Override @NonNull public MenuInflater getMenuInflater() + { + return getDelegate().getMenuInflater(); + } + + @Override public void setContentView(@LayoutRes int layoutResID) + { + getDelegate().setContentView(layoutResID); + } + + @Override public void setContentView(View view) + { + getDelegate().setContentView(view); + } + + @Override public void setContentView(View view, ViewGroup.LayoutParams params) + { + getDelegate().setContentView(view, params); + } + + @Override public void addContentView(View view, ViewGroup.LayoutParams params) + { + getDelegate().addContentView(view, params); + } + + @Override protected void onPostResume() + { + super.onPostResume(); + getDelegate().onPostResume(); + } + + @Override protected void onTitleChanged(CharSequence title, int color) + { + super.onTitleChanged(title, color); + getDelegate().setTitle(title); + } + + @Override public void onConfigurationChanged(Configuration newConfig) + { + super.onConfigurationChanged(newConfig); + getDelegate().onConfigurationChanged(newConfig); + } + + @Override protected void onStop() + { + super.onStop(); + getDelegate().onStop(); + } + + @Override protected void onDestroy() + { + super.onDestroy(); + getDelegate().onDestroy(); + } + + public void invalidateOptionsMenu() + { + getDelegate().invalidateOptionsMenu(); + } + + private AppCompatDelegate getDelegate() + { + if (mDelegate == null) + { + mDelegate = AppCompatDelegate.create(this, null); + } + return mDelegate; + } } \ No newline at end of file diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/BookmarkArrayAdapter.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/BookmarkArrayAdapter.java index 4968c57..6c6de6a 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/BookmarkArrayAdapter.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/BookmarkArrayAdapter.java @@ -3,8 +3,9 @@ Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.utils; @@ -29,89 +30,106 @@ import com.freerdp.freerdpcore.presentation.BookmarkActivity; import java.util.List; -public class BookmarkArrayAdapter extends ArrayAdapter { - - public BookmarkArrayAdapter(Context context, int textViewResourceId, List objects) { - super(context, textViewResourceId, objects); - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - View curView = convertView; - if (curView == null) { - LayoutInflater vi = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); - curView = vi.inflate(R.layout.bookmark_list_item, null); - } - - BookmarkBase bookmark = getItem(position); - TextView label = (TextView) curView.findViewById(R.id.bookmark_text1); - TextView hostname = (TextView) curView.findViewById(R.id.bookmark_text2); - ImageView star_icon = (ImageView) curView.findViewById(R.id.bookmark_icon2); - assert label != null; - assert hostname != null; - - label.setText(bookmark.getLabel()); - star_icon.setVisibility(View.VISIBLE); - - String refStr; - if (bookmark.getType() == BookmarkBase.TYPE_MANUAL) { - hostname.setText(bookmark.get().getHostname()); - refStr = ConnectionReference.getManualBookmarkReference(bookmark.getId()); - star_icon.setImageResource(R.drawable.icon_star_on); - } else if (bookmark.getType() == BookmarkBase.TYPE_QUICKCONNECT) { - // just set an empty hostname (with a blank) - the hostname is already displayed in the label - // and in case we just set it to "" the textview will shrunk - hostname.setText(" "); - refStr = ConnectionReference.getHostnameReference(bookmark.getLabel()); - star_icon.setImageResource(R.drawable.icon_star_off); - } else if (bookmark.getType() == BookmarkBase.TYPE_PLACEHOLDER) { - hostname.setText(" "); - refStr = ConnectionReference.getPlaceholderReference(bookmark.get().getName()); - star_icon.setVisibility(View.GONE); - } else { - // unknown bookmark type... - refStr = ""; - assert false; - } - - star_icon.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - // start bookmark editor - Bundle bundle = new Bundle(); - String refStr = v.getTag().toString(); - bundle.putString(BookmarkActivity.PARAM_CONNECTION_REFERENCE, refStr); - - Intent bookmarkIntent = new Intent(getContext(), BookmarkActivity.class); - bookmarkIntent.putExtras(bundle); - getContext().startActivity(bookmarkIntent); - } - }); - - curView.setTag(refStr); - star_icon.setTag(refStr); - - return curView; - } - - public void addItems(List newItems) { - for (BookmarkBase item : newItems) - add(item); - } - - public void replaceItems(List newItems) { - clear(); - for (BookmarkBase item : newItems) - add(item); - } - - public void remove(long bookmarkId) { - for (int i = 0; i < getCount(); i++) { - BookmarkBase bm = getItem(i); - if (bm.getId() == bookmarkId) { - remove(bm); - return; - } - } - } +public class BookmarkArrayAdapter extends ArrayAdapter +{ + + public BookmarkArrayAdapter(Context context, int textViewResourceId, List objects) + { + super(context, textViewResourceId, objects); + } + + @Override public View getView(int position, View convertView, ViewGroup parent) + { + View curView = convertView; + if (curView == null) + { + LayoutInflater vi = + (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + curView = vi.inflate(R.layout.bookmark_list_item, null); + } + + BookmarkBase bookmark = getItem(position); + TextView label = (TextView)curView.findViewById(R.id.bookmark_text1); + TextView hostname = (TextView)curView.findViewById(R.id.bookmark_text2); + ImageView star_icon = (ImageView)curView.findViewById(R.id.bookmark_icon2); + assert label != null; + assert hostname != null; + + label.setText(bookmark.getLabel()); + star_icon.setVisibility(View.VISIBLE); + + String refStr; + if (bookmark.getType() == BookmarkBase.TYPE_MANUAL) + { + hostname.setText(bookmark.get().getHostname()); + refStr = ConnectionReference.getManualBookmarkReference(bookmark.getId()); + star_icon.setImageResource(R.drawable.icon_star_on); + } + else if (bookmark.getType() == BookmarkBase.TYPE_QUICKCONNECT) + { + // just set an empty hostname (with a blank) - the hostname is already displayed in the + // label and in case we just set it to "" the textview will shrunk + hostname.setText(" "); + refStr = ConnectionReference.getHostnameReference(bookmark.getLabel()); + star_icon.setImageResource(R.drawable.icon_star_off); + } + else if (bookmark.getType() == BookmarkBase.TYPE_PLACEHOLDER) + { + hostname.setText(" "); + refStr = ConnectionReference.getPlaceholderReference( + bookmark.get().getName()); + star_icon.setVisibility(View.GONE); + } + else + { + // unknown bookmark type... + refStr = ""; + assert false; + } + + star_icon.setOnClickListener(new OnClickListener() { + @Override public void onClick(View v) + { + // start bookmark editor + Bundle bundle = new Bundle(); + String refStr = v.getTag().toString(); + bundle.putString(BookmarkActivity.PARAM_CONNECTION_REFERENCE, refStr); + + Intent bookmarkIntent = new Intent(getContext(), BookmarkActivity.class); + bookmarkIntent.putExtras(bundle); + getContext().startActivity(bookmarkIntent); + } + }); + + curView.setTag(refStr); + star_icon.setTag(refStr); + + return curView; + } + + public void addItems(List newItems) + { + for (BookmarkBase item : newItems) + add(item); + } + + public void replaceItems(List newItems) + { + clear(); + for (BookmarkBase item : newItems) + add(item); + } + + public void remove(long bookmarkId) + { + for (int i = 0; i < getCount(); i++) + { + BookmarkBase bm = getItem(i); + if (bm.getId() == bookmarkId) + { + remove(bm); + return; + } + } + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/ButtonPreference.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/ButtonPreference.java index 7248932..72c8cf0 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/ButtonPreference.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/ButtonPreference.java @@ -3,8 +3,9 @@ Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.utils; @@ -20,67 +21,76 @@ import android.widget.LinearLayout; import com.freerdp.freerdpcore.R; -public class ButtonPreference extends Preference { - - private OnClickListener buttonOnClickListener; - private String buttonText; - private Button button; - - public ButtonPreference(Context context) { - super(context); - init(); - } - - public ButtonPreference(Context context, AttributeSet attrs) { - super(context, attrs); - init(); - } - - public ButtonPreference(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - init(); - } - - private void init() { - setLayoutResource(R.layout.button_preference); - button = null; - buttonText = null; - buttonOnClickListener = null; - } - - @Override - public View getView(View convertView, ViewGroup parent) { - View v = super.getView(convertView, parent); - button = (Button) v.findViewById(R.id.preference_button); - if (buttonText != null) - button.setText(buttonText); - if (buttonOnClickListener != null) - button.setOnClickListener(buttonOnClickListener); - - // additional init for ICS - make widget frame visible - // refer to http://stackoverflow.com/questions/8762984/custom-preference-broken-in-honeycomb-ics - LinearLayout widgetFrameView = ((LinearLayout) v.findViewById(android.R.id.widget_frame)); - widgetFrameView.setVisibility(View.VISIBLE); - - return v; - } - - public void setButtonText(int resId) { - buttonText = getContext().getResources().getString(resId); - if (button != null) - button.setText(buttonText); - } - - public void setButtonText(String text) { - buttonText = text; - if (button != null) - button.setText(text); - } - - public void setButtonOnClickListener(OnClickListener listener) { - if (button != null) - button.setOnClickListener(listener); - else - buttonOnClickListener = listener; - } +public class ButtonPreference extends Preference +{ + + private OnClickListener buttonOnClickListener; + private String buttonText; + private Button button; + + public ButtonPreference(Context context) + { + super(context); + init(); + } + + public ButtonPreference(Context context, AttributeSet attrs) + { + super(context, attrs); + init(); + } + + public ButtonPreference(Context context, AttributeSet attrs, int defStyle) + { + super(context, attrs, defStyle); + init(); + } + + private void init() + { + setLayoutResource(R.layout.button_preference); + button = null; + buttonText = null; + buttonOnClickListener = null; + } + + @Override public View getView(View convertView, ViewGroup parent) + { + View v = super.getView(convertView, parent); + button = (Button)v.findViewById(R.id.preference_button); + if (buttonText != null) + button.setText(buttonText); + if (buttonOnClickListener != null) + button.setOnClickListener(buttonOnClickListener); + + // additional init for ICS - make widget frame visible + // refer to + // http://stackoverflow.com/questions/8762984/custom-preference-broken-in-honeycomb-ics + LinearLayout widgetFrameView = ((LinearLayout)v.findViewById(android.R.id.widget_frame)); + widgetFrameView.setVisibility(View.VISIBLE); + + return v; + } + + public void setButtonText(int resId) + { + buttonText = getContext().getResources().getString(resId); + if (button != null) + button.setText(buttonText); + } + + public void setButtonText(String text) + { + buttonText = text; + if (button != null) + button.setText(text); + } + + public void setButtonOnClickListener(OnClickListener listener) + { + if (button != null) + button.setOnClickListener(listener); + else + buttonOnClickListener = listener; + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/ClipboardManagerProxy.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/ClipboardManagerProxy.java index dce3b1b..cb26ddb 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/ClipboardManagerProxy.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/ClipboardManagerProxy.java @@ -7,87 +7,94 @@ import android.content.Context; import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; -public abstract class ClipboardManagerProxy { - - public static ClipboardManagerProxy getClipboardManager(Context ctx) { - if (VERSION.SDK_INT < VERSION_CODES.HONEYCOMB) - return new PreHCClipboardManager(ctx); - else - return new HCClipboardManager(ctx); - } - - public abstract void setClipboardData(String data); - - public abstract void addClipboardChangedListener(OnClipboardChangedListener listener); - - public abstract void removeClipboardboardChangedListener(OnClipboardChangedListener listener); - - public static interface OnClipboardChangedListener { - void onClipboardChanged(String data); - } - - private static class PreHCClipboardManager extends ClipboardManagerProxy { - - public PreHCClipboardManager(Context ctx) { - - } - - @Override - public void setClipboardData(String data) { - } - - @Override - public void addClipboardChangedListener( - OnClipboardChangedListener listener) { - } - - @Override - public void removeClipboardboardChangedListener( - OnClipboardChangedListener listener) { - } - } - - @TargetApi(11) - private static class HCClipboardManager extends ClipboardManagerProxy implements ClipboardManager.OnPrimaryClipChangedListener { - private ClipboardManager mClipboardManager; - private OnClipboardChangedListener mListener; - - public HCClipboardManager(Context ctx) { - mClipboardManager = (ClipboardManager) ctx.getSystemService(Context.CLIPBOARD_SERVICE); - } - - @Override - public void setClipboardData(String data) { - mClipboardManager.setPrimaryClip(ClipData.newPlainText("rdp-clipboard", data == null ? "" : data)); - } - - @Override - public void onPrimaryClipChanged() { - ClipData clip = mClipboardManager.getPrimaryClip(); - String data = null; - - if (clip != null && clip.getItemCount() > 0) { - CharSequence cs = clip.getItemAt(0).getText(); - if (cs != null) - data = cs.toString(); - } - if (mListener != null) { - mListener.onClipboardChanged(data); - } - } - - @Override - public void addClipboardChangedListener( - OnClipboardChangedListener listener) { - mListener = listener; - mClipboardManager.addPrimaryClipChangedListener(this); - } - - @Override - public void removeClipboardboardChangedListener( - OnClipboardChangedListener listener) { - mListener = null; - mClipboardManager.removePrimaryClipChangedListener(this); - } - } +public abstract class ClipboardManagerProxy +{ + + public static ClipboardManagerProxy getClipboardManager(Context ctx) + { + if (VERSION.SDK_INT < VERSION_CODES.HONEYCOMB) + return new PreHCClipboardManager(ctx); + else + return new HCClipboardManager(ctx); + } + + public abstract void setClipboardData(String data); + + public abstract void addClipboardChangedListener(OnClipboardChangedListener listener); + + public abstract void removeClipboardboardChangedListener(OnClipboardChangedListener listener); + + public static interface OnClipboardChangedListener { + void onClipboardChanged(String data); + } + + private static class PreHCClipboardManager extends ClipboardManagerProxy + { + + public PreHCClipboardManager(Context ctx) + { + } + + @Override public void setClipboardData(String data) + { + } + + @Override public void addClipboardChangedListener(OnClipboardChangedListener listener) + { + } + + @Override + public void removeClipboardboardChangedListener(OnClipboardChangedListener listener) + { + } + } + + @TargetApi(11) + private static class HCClipboardManager + extends ClipboardManagerProxy implements ClipboardManager.OnPrimaryClipChangedListener + { + private ClipboardManager mClipboardManager; + private OnClipboardChangedListener mListener; + + public HCClipboardManager(Context ctx) + { + mClipboardManager = (ClipboardManager)ctx.getSystemService(Context.CLIPBOARD_SERVICE); + } + + @Override public void setClipboardData(String data) + { + mClipboardManager.setPrimaryClip( + ClipData.newPlainText("rdp-clipboard", data == null ? "" : data)); + } + + @Override public void onPrimaryClipChanged() + { + ClipData clip = mClipboardManager.getPrimaryClip(); + String data = null; + + if (clip != null && clip.getItemCount() > 0) + { + CharSequence cs = clip.getItemAt(0).getText(); + if (cs != null) + data = cs.toString(); + } + if (mListener != null) + { + mListener.onClipboardChanged(data); + } + } + + @Override public void addClipboardChangedListener(OnClipboardChangedListener listener) + { + mListener = listener; + mClipboardManager.addPrimaryClipChangedListener(this); + } + + @Override + public void removeClipboardboardChangedListener(OnClipboardChangedListener listener) + { + mListener = null; + mClipboardManager.removePrimaryClipChangedListener(this); + } + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/DoubleGestureDetector.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/DoubleGestureDetector.java index 563bc61..2e8dfc8 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/DoubleGestureDetector.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/DoubleGestureDetector.java @@ -3,8 +3,9 @@ Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.utils; @@ -16,312 +17,333 @@ import android.view.ScaleGestureDetector; import com.freerdp.freerdpcore.utils.GestureDetector.OnGestureListener; -public class DoubleGestureDetector { - // timeout during that the second finger has to touch the screen before the double finger detection is cancelled - private static final long DOUBLE_TOUCH_TIMEOUT = 100; - // timeout during that an UP event will trigger a single double touch event - private static final long SINGLE_DOUBLE_TOUCH_TIMEOUT = 1000; - // constants for Message.what used by GestureHandler below - private static final int TAP = 1; - // different detection modes - private static final int MODE_UNKNOWN = 0; - private static final int MODE_PINCH_ZOOM = 1; - private static final int MODE_SCROLL = 2; - private static final int SCROLL_SCORE_TO_REACH = 20; - private final OnDoubleGestureListener mListener; - private int mPointerDistanceSquare; - private int mCurrentMode; - private int mScrollDetectionScore; - private ScaleGestureDetector scaleGestureDetector; - private boolean mCancelDetection; - private boolean mDoubleInProgress; - private GestureHandler mHandler; - private MotionEvent mCurrentDownEvent; - private MotionEvent mCurrentDoubleDownEvent; - private MotionEvent mPreviousUpEvent; - private MotionEvent mPreviousPointerUpEvent; - /** - * Creates a GestureDetector with the supplied listener. - * You may only use this constructor from a UI thread (this is the usual situation). - * - * @param context the application's context - * @param listener the listener invoked for all the callbacks, this must - * not be null. - * @throws NullPointerException if {@code listener} is null. - * @see android.os.Handler#Handler() - */ - public DoubleGestureDetector(Context context, Handler handler, OnDoubleGestureListener listener) { - mListener = listener; - init(context, handler); - } - - private void init(Context context, Handler handler) { - if (mListener == null) { - throw new NullPointerException("OnGestureListener must not be null"); - } - - if (handler != null) - mHandler = new GestureHandler(handler); - else - mHandler = new GestureHandler(); - - // we use 1cm distance to decide between scroll and pinch zoom - // - first convert cm to inches - // - then multiply inches by dots per inch - float distInches = 0.5f / 2.54f; - float distPixelsX = distInches * context.getResources().getDisplayMetrics().xdpi; - float distPixelsY = distInches * context.getResources().getDisplayMetrics().ydpi; - - mPointerDistanceSquare = (int) (distPixelsX * distPixelsX + distPixelsY * distPixelsY); - } - - /** - * Set scale gesture detector - * - * @param scaleGestureDetector - */ - public void setScaleGestureDetector(ScaleGestureDetector scaleGestureDetector) { - this.scaleGestureDetector = scaleGestureDetector; - } - - /** - * Analyzes the given motion event and if applicable triggers the - * appropriate callbacks on the {@link OnGestureListener} supplied. - * - * @param ev The current motion event. - * @return true if the {@link OnGestureListener} consumed the event, - * else false. - */ - public boolean onTouchEvent(MotionEvent ev) { - boolean handled = false; - final int action = ev.getAction(); - //dumpEvent(ev); - - switch (action & MotionEvent.ACTION_MASK) { - case MotionEvent.ACTION_DOWN: - if (mCurrentDownEvent != null) - mCurrentDownEvent.recycle(); - - mCurrentMode = MODE_UNKNOWN; - mCurrentDownEvent = MotionEvent.obtain(ev); - mCancelDetection = false; - mDoubleInProgress = false; - mScrollDetectionScore = 0; - handled = true; - break; - - case MotionEvent.ACTION_POINTER_UP: - if (mPreviousPointerUpEvent != null) - mPreviousPointerUpEvent.recycle(); - mPreviousPointerUpEvent = MotionEvent.obtain(ev); - break; - - case MotionEvent.ACTION_POINTER_DOWN: - // more than 2 fingers down? cancel - // 2nd finger touched too late? cancel - if (ev.getPointerCount() > 2 || (ev.getEventTime() - mCurrentDownEvent.getEventTime()) > DOUBLE_TOUCH_TIMEOUT) { - cancel(); - break; - } - - // detection cancelled? - if (mCancelDetection) - break; - - // double touch gesture in progress - mDoubleInProgress = true; - if (mCurrentDoubleDownEvent != null) - mCurrentDoubleDownEvent.recycle(); - mCurrentDoubleDownEvent = MotionEvent.obtain(ev); - - // set detection mode to unkown and send a TOUCH timeout event to detect single taps - mCurrentMode = MODE_UNKNOWN; - mHandler.sendEmptyMessageDelayed(TAP, SINGLE_DOUBLE_TOUCH_TIMEOUT); - - handled |= mListener.onDoubleTouchDown(ev); - break; - - case MotionEvent.ACTION_MOVE: - - // detection cancelled or not active? - if (mCancelDetection || !mDoubleInProgress || ev.getPointerCount() != 2) - break; - - // determine mode - if (mCurrentMode == MODE_UNKNOWN) { - // did the pointer distance change? - if (pointerDistanceChanged(mCurrentDoubleDownEvent, ev)) { - handled |= scaleGestureDetector.onTouchEvent(mCurrentDownEvent); - MotionEvent e = MotionEvent.obtain(ev); - e.setAction(mCurrentDoubleDownEvent.getAction()); - handled |= scaleGestureDetector.onTouchEvent(e); - mCurrentMode = MODE_PINCH_ZOOM; - break; - } else { - mScrollDetectionScore++; - if (mScrollDetectionScore >= SCROLL_SCORE_TO_REACH) - mCurrentMode = MODE_SCROLL; - } - } - - switch (mCurrentMode) { - case MODE_PINCH_ZOOM: - if (scaleGestureDetector != null) - handled |= scaleGestureDetector.onTouchEvent(ev); - break; - - case MODE_SCROLL: - handled = mListener.onDoubleTouchScroll(mCurrentDownEvent, ev); - break; - - default: - handled = true; - break; - } - - break; - - case MotionEvent.ACTION_UP: - // fingers were not removed equally? cancel - if (mPreviousPointerUpEvent != null && (ev.getEventTime() - mPreviousPointerUpEvent.getEventTime()) > DOUBLE_TOUCH_TIMEOUT) { - mPreviousPointerUpEvent.recycle(); - mPreviousPointerUpEvent = null; - cancel(); - break; - } - - // detection cancelled or not active? - if (mCancelDetection || !mDoubleInProgress) - break; - - boolean hasTapEvent = mHandler.hasMessages(TAP); - MotionEvent currentUpEvent = MotionEvent.obtain(ev); - if (mCurrentMode == MODE_UNKNOWN && hasTapEvent) - handled = mListener.onDoubleTouchSingleTap(mCurrentDoubleDownEvent); - else if (mCurrentMode == MODE_PINCH_ZOOM) - handled = scaleGestureDetector.onTouchEvent(ev); - - if (mPreviousUpEvent != null) - mPreviousUpEvent.recycle(); - - // Hold the event we obtained above - listeners may have changed the original. - mPreviousUpEvent = currentUpEvent; - handled |= mListener.onDoubleTouchUp(ev); - break; - - case MotionEvent.ACTION_CANCEL: - cancel(); - break; - } - - if ((action == MotionEvent.ACTION_MOVE) && handled == false) - handled = true; - - return handled; - } - - private void cancel() { - mHandler.removeMessages(TAP); - mCurrentMode = MODE_UNKNOWN; - mCancelDetection = true; - mDoubleInProgress = false; - } - - // returns true of the distance between the two pointers changed - private boolean pointerDistanceChanged(MotionEvent oldEvent, MotionEvent newEvent) { - int deltaX1 = Math.abs((int) oldEvent.getX(0) - (int) oldEvent.getX(1)); - int deltaX2 = Math.abs((int) newEvent.getX(0) - (int) newEvent.getX(1)); - int distXSquare = (deltaX2 - deltaX1) * (deltaX2 - deltaX1); - - int deltaY1 = Math.abs((int) oldEvent.getY(0) - (int) oldEvent.getY(1)); - int deltaY2 = Math.abs((int) newEvent.getY(0) - (int) newEvent.getY(1)); - int distYSquare = (deltaY2 - deltaY1) * (deltaY2 - deltaY1); - - return (distXSquare + distYSquare) > mPointerDistanceSquare; - } - - /** - * The listener that is used to notify when gestures occur. - * If you want to listen for all the different gestures then implement - * this interface. If you only want to listen for a subset it might - * be easier to extend {@link SimpleOnGestureListener}. - */ - public interface OnDoubleGestureListener { - - /** - * Notified when a multi tap event starts - */ - boolean onDoubleTouchDown(MotionEvent e); - - /** - * Notified when a multi tap event ends - */ - boolean onDoubleTouchUp(MotionEvent e); - - /** - * Notified when a tap occurs with the up {@link MotionEvent} - * that triggered it. - * - * @param e The up motion event that completed the first tap - * @return true if the event is consumed, else false - */ - boolean onDoubleTouchSingleTap(MotionEvent e); - - /** - * Notified when a scroll occurs with the initial on down {@link MotionEvent} and the - * current move {@link MotionEvent}. The distance in x and y is also supplied for - * convenience. - * - * @param e1 The first down motion event that started the scrolling. - * @param e2 The move motion event that triggered the current onScroll. - * @param distanceX The distance along the X axis that has been scrolled since the last - * call to onScroll. This is NOT the distance between {@code e1} - * and {@code e2}. - * @param distanceY The distance along the Y axis that has been scrolled since the last - * call to onScroll. This is NOT the distance between {@code e1} - * and {@code e2}. - * @return true if the event is consumed, else false - */ - boolean onDoubleTouchScroll(MotionEvent e1, MotionEvent e2); - } - - /* - private void dumpEvent(MotionEvent event) { - String names[] = { "DOWN" , "UP" , "MOVE" , "CANCEL" , "OUTSIDE" , - "POINTER_DOWN" , "POINTER_UP" , "7?" , "8?" , "9?" }; - StringBuilder sb = new StringBuilder(); - int action = event.getAction(); - int actionCode = action & MotionEvent.ACTION_MASK; - sb.append("event ACTION_" ).append(names[actionCode]); - if (actionCode == MotionEvent.ACTION_POINTER_DOWN - || actionCode == MotionEvent.ACTION_POINTER_UP) { - sb.append("(pid " ).append( - action >> MotionEvent.ACTION_POINTER_ID_SHIFT); - sb.append(")" ); - } - sb.append("[" ); - for (int i = 0; i < event.getPointerCount(); i++) { - sb.append("#" ).append(i); - sb.append("(pid " ).append(event.getPointerId(i)); - sb.append(")=" ).append((int) event.getX(i)); - sb.append("," ).append((int) event.getY(i)); - if (i + 1 < event.getPointerCount()) - sb.append(";" ); - } - sb.append("]" ); - Log.d("DoubleDetector", sb.toString()); - } - */ - - private class GestureHandler extends Handler { - GestureHandler() { - super(); - } - - GestureHandler(Handler handler) { - super(handler.getLooper()); - } - - } - +public class DoubleGestureDetector +{ + // timeout during that the second finger has to touch the screen before the double finger + // detection is cancelled + private static final long DOUBLE_TOUCH_TIMEOUT = 100; + // timeout during that an UP event will trigger a single double touch event + private static final long SINGLE_DOUBLE_TOUCH_TIMEOUT = 1000; + // constants for Message.what used by GestureHandler below + private static final int TAP = 1; + // different detection modes + private static final int MODE_UNKNOWN = 0; + private static final int MODE_PINCH_ZOOM = 1; + private static final int MODE_SCROLL = 2; + private static final int SCROLL_SCORE_TO_REACH = 20; + private final OnDoubleGestureListener mListener; + private int mPointerDistanceSquare; + private int mCurrentMode; + private int mScrollDetectionScore; + private ScaleGestureDetector scaleGestureDetector; + private boolean mCancelDetection; + private boolean mDoubleInProgress; + private GestureHandler mHandler; + private MotionEvent mCurrentDownEvent; + private MotionEvent mCurrentDoubleDownEvent; + private MotionEvent mPreviousUpEvent; + private MotionEvent mPreviousPointerUpEvent; + /** + * Creates a GestureDetector with the supplied listener. + * You may only use this constructor from a UI thread (this is the usual situation). + * + * @param context the application's context + * @param listener the listener invoked for all the callbacks, this must + * not be null. + * @throws NullPointerException if {@code listener} is null. + * @see android.os.Handler#Handler() + */ + public DoubleGestureDetector(Context context, Handler handler, OnDoubleGestureListener listener) + { + mListener = listener; + init(context, handler); + } + + private void init(Context context, Handler handler) + { + if (mListener == null) + { + throw new NullPointerException("OnGestureListener must not be null"); + } + + if (handler != null) + mHandler = new GestureHandler(handler); + else + mHandler = new GestureHandler(); + + // we use 1cm distance to decide between scroll and pinch zoom + // - first convert cm to inches + // - then multiply inches by dots per inch + float distInches = 0.5f / 2.54f; + float distPixelsX = distInches * context.getResources().getDisplayMetrics().xdpi; + float distPixelsY = distInches * context.getResources().getDisplayMetrics().ydpi; + + mPointerDistanceSquare = (int)(distPixelsX * distPixelsX + distPixelsY * distPixelsY); + } + + /** + * Set scale gesture detector + * + * @param scaleGestureDetector + */ + public void setScaleGestureDetector(ScaleGestureDetector scaleGestureDetector) + { + this.scaleGestureDetector = scaleGestureDetector; + } + + /** + * Analyzes the given motion event and if applicable triggers the + * appropriate callbacks on the {@link OnGestureListener} supplied. + * + * @param ev The current motion event. + * @return true if the {@link OnGestureListener} consumed the event, + * else false. + */ + public boolean onTouchEvent(MotionEvent ev) + { + boolean handled = false; + final int action = ev.getAction(); + // dumpEvent(ev); + + switch (action & MotionEvent.ACTION_MASK) + { + case MotionEvent.ACTION_DOWN: + if (mCurrentDownEvent != null) + mCurrentDownEvent.recycle(); + + mCurrentMode = MODE_UNKNOWN; + mCurrentDownEvent = MotionEvent.obtain(ev); + mCancelDetection = false; + mDoubleInProgress = false; + mScrollDetectionScore = 0; + handled = true; + break; + + case MotionEvent.ACTION_POINTER_UP: + if (mPreviousPointerUpEvent != null) + mPreviousPointerUpEvent.recycle(); + mPreviousPointerUpEvent = MotionEvent.obtain(ev); + break; + + case MotionEvent.ACTION_POINTER_DOWN: + // more than 2 fingers down? cancel + // 2nd finger touched too late? cancel + if (ev.getPointerCount() > 2 || + (ev.getEventTime() - mCurrentDownEvent.getEventTime()) > DOUBLE_TOUCH_TIMEOUT) + { + cancel(); + break; + } + + // detection cancelled? + if (mCancelDetection) + break; + + // double touch gesture in progress + mDoubleInProgress = true; + if (mCurrentDoubleDownEvent != null) + mCurrentDoubleDownEvent.recycle(); + mCurrentDoubleDownEvent = MotionEvent.obtain(ev); + + // set detection mode to unkown and send a TOUCH timeout event to detect single taps + mCurrentMode = MODE_UNKNOWN; + mHandler.sendEmptyMessageDelayed(TAP, SINGLE_DOUBLE_TOUCH_TIMEOUT); + + handled |= mListener.onDoubleTouchDown(ev); + break; + + case MotionEvent.ACTION_MOVE: + + // detection cancelled or not active? + if (mCancelDetection || !mDoubleInProgress || ev.getPointerCount() != 2) + break; + + // determine mode + if (mCurrentMode == MODE_UNKNOWN) + { + // did the pointer distance change? + if (pointerDistanceChanged(mCurrentDoubleDownEvent, ev)) + { + handled |= scaleGestureDetector.onTouchEvent(mCurrentDownEvent); + MotionEvent e = MotionEvent.obtain(ev); + e.setAction(mCurrentDoubleDownEvent.getAction()); + handled |= scaleGestureDetector.onTouchEvent(e); + mCurrentMode = MODE_PINCH_ZOOM; + break; + } + else + { + mScrollDetectionScore++; + if (mScrollDetectionScore >= SCROLL_SCORE_TO_REACH) + mCurrentMode = MODE_SCROLL; + } + } + + switch (mCurrentMode) + { + case MODE_PINCH_ZOOM: + if (scaleGestureDetector != null) + handled |= scaleGestureDetector.onTouchEvent(ev); + break; + + case MODE_SCROLL: + handled = mListener.onDoubleTouchScroll(mCurrentDownEvent, ev); + break; + + default: + handled = true; + break; + } + + break; + + case MotionEvent.ACTION_UP: + // fingers were not removed equally? cancel + if (mPreviousPointerUpEvent != null && + (ev.getEventTime() - mPreviousPointerUpEvent.getEventTime()) > + DOUBLE_TOUCH_TIMEOUT) + { + mPreviousPointerUpEvent.recycle(); + mPreviousPointerUpEvent = null; + cancel(); + break; + } + + // detection cancelled or not active? + if (mCancelDetection || !mDoubleInProgress) + break; + + boolean hasTapEvent = mHandler.hasMessages(TAP); + MotionEvent currentUpEvent = MotionEvent.obtain(ev); + if (mCurrentMode == MODE_UNKNOWN && hasTapEvent) + handled = mListener.onDoubleTouchSingleTap(mCurrentDoubleDownEvent); + else if (mCurrentMode == MODE_PINCH_ZOOM) + handled = scaleGestureDetector.onTouchEvent(ev); + + if (mPreviousUpEvent != null) + mPreviousUpEvent.recycle(); + + // Hold the event we obtained above - listeners may have changed the original. + mPreviousUpEvent = currentUpEvent; + handled |= mListener.onDoubleTouchUp(ev); + break; + + case MotionEvent.ACTION_CANCEL: + cancel(); + break; + } + + if ((action == MotionEvent.ACTION_MOVE) && handled == false) + handled = true; + + return handled; + } + + private void cancel() + { + mHandler.removeMessages(TAP); + mCurrentMode = MODE_UNKNOWN; + mCancelDetection = true; + mDoubleInProgress = false; + } + + // returns true of the distance between the two pointers changed + private boolean pointerDistanceChanged(MotionEvent oldEvent, MotionEvent newEvent) + { + int deltaX1 = Math.abs((int)oldEvent.getX(0) - (int)oldEvent.getX(1)); + int deltaX2 = Math.abs((int)newEvent.getX(0) - (int)newEvent.getX(1)); + int distXSquare = (deltaX2 - deltaX1) * (deltaX2 - deltaX1); + + int deltaY1 = Math.abs((int)oldEvent.getY(0) - (int)oldEvent.getY(1)); + int deltaY2 = Math.abs((int)newEvent.getY(0) - (int)newEvent.getY(1)); + int distYSquare = (deltaY2 - deltaY1) * (deltaY2 - deltaY1); + + return (distXSquare + distYSquare) > mPointerDistanceSquare; + } + + /** + * The listener that is used to notify when gestures occur. + * If you want to listen for all the different gestures then implement + * this interface. If you only want to listen for a subset it might + * be easier to extend {@link SimpleOnGestureListener}. + */ + public interface OnDoubleGestureListener { + + /** + * Notified when a multi tap event starts + */ + boolean onDoubleTouchDown(MotionEvent e); + + /** + * Notified when a multi tap event ends + */ + boolean onDoubleTouchUp(MotionEvent e); + + /** + * Notified when a tap occurs with the up {@link MotionEvent} + * that triggered it. + * + * @param e The up motion event that completed the first tap + * @return true if the event is consumed, else false + */ + boolean onDoubleTouchSingleTap(MotionEvent e); + + /** + * Notified when a scroll occurs with the initial on down {@link MotionEvent} and the + * current move {@link MotionEvent}. The distance in x and y is also supplied for + * convenience. + * + * @param e1 The first down motion event that started the scrolling. + * @param e2 The move motion event that triggered the current onScroll. + * @param distanceX The distance along the X axis that has been scrolled since the last + * call to onScroll. This is NOT the distance between {@code e1} + * and {@code e2}. + * @param distanceY The distance along the Y axis that has been scrolled since the last + * call to onScroll. This is NOT the distance between {@code e1} + * and {@code e2}. + * @return true if the event is consumed, else false + */ + boolean onDoubleTouchScroll(MotionEvent e1, MotionEvent e2); + } + + /* + private void dumpEvent(MotionEvent event) { + String names[] = { "DOWN" , "UP" , "MOVE" , "CANCEL" , "OUTSIDE" , + "POINTER_DOWN" , "POINTER_UP" , "7?" , "8?" , "9?" }; + StringBuilder sb = new StringBuilder(); + int action = event.getAction(); + int actionCode = action & MotionEvent.ACTION_MASK; + sb.append("event ACTION_" ).append(names[actionCode]); + if (actionCode == MotionEvent.ACTION_POINTER_DOWN + || actionCode == MotionEvent.ACTION_POINTER_UP) { + sb.append("(pid " ).append( + action >> MotionEvent.ACTION_POINTER_ID_SHIFT); + sb.append(")" ); + } + sb.append("[" ); + for (int i = 0; i < event.getPointerCount(); i++) { + sb.append("#" ).append(i); + sb.append("(pid " ).append(event.getPointerId(i)); + sb.append(")=" ).append((int) event.getX(i)); + sb.append("," ).append((int) event.getY(i)); + if (i + 1 < event.getPointerCount()) + sb.append(";" ); + } + sb.append("]" ); + Log.d("DoubleDetector", sb.toString()); + } + */ + + private class GestureHandler extends Handler + { + GestureHandler() + { + super(); + } + + GestureHandler(Handler handler) + { + super(handler.getLooper()); + } + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/GestureDetector.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/GestureDetector.java index 71c1e6f..2e971b5 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/GestureDetector.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/GestureDetector.java @@ -12,7 +12,7 @@ * 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. - * + * * Modified for aFreeRDP by Martin Fleisz (martin.fleisz@thincast.com) */ @@ -26,522 +26,595 @@ import android.util.DisplayMetrics; import android.view.MotionEvent; import android.view.ViewConfiguration; -public class GestureDetector { - - private static final int TAP_TIMEOUT = 100; - private static final int DOUBLE_TAP_TIMEOUT = 200; - // Distance a touch can wander before we think the user is the first touch in a sequence of double tap - private static final int LARGE_TOUCH_SLOP = 18; - // Distance between the first touch and second touch to still be considered a double tap - private static final int DOUBLE_TAP_SLOP = 100; - // constants for Message.what used by GestureHandler below - private static final int SHOW_PRESS = 1; - private static final int LONG_PRESS = 2; - private static final int TAP = 3; - private final Handler mHandler; - private final OnGestureListener mListener; - private int mTouchSlopSquare; - private int mLargeTouchSlopSquare; - private int mDoubleTapSlopSquare; - private int mLongpressTimeout = 100; - private OnDoubleTapListener mDoubleTapListener; - private boolean mStillDown; - private boolean mInLongPress; - private boolean mAlwaysInTapRegion; - private boolean mAlwaysInBiggerTapRegion; - private MotionEvent mCurrentDownEvent; - private MotionEvent mPreviousUpEvent; - /** - * True when the user is still touching for the second tap (down, move, and - * up events). Can only be true if there is a double tap listener attached. - */ - private boolean mIsDoubleTapping; - private float mLastMotionY; - private float mLastMotionX; - private boolean mIsLongpressEnabled; - /** - * True if we are at a target API level of >= Froyo or the developer can - * explicitly set it. If true, input events with > 1 pointer will be ignored - * so we can work side by side with multitouch gesture detectors. - */ - private boolean mIgnoreMultitouch; - /** - * Creates a GestureDetector with the supplied listener. - * You may only use this constructor from a UI thread (this is the usual situation). - * - * @param context the application's context - * @param listener the listener invoked for all the callbacks, this must - * not be null. - * @throws NullPointerException if {@code listener} is null. - * @see android.os.Handler#Handler() - */ - public GestureDetector(Context context, OnGestureListener listener) { - this(context, listener, null); - } - - /** - * Creates a GestureDetector with the supplied listener. - * You may only use this constructor from a UI thread (this is the usual situation). - * - * @param context the application's context - * @param listener the listener invoked for all the callbacks, this must - * not be null. - * @param handler the handler to use - * @throws NullPointerException if {@code listener} is null. - * @see android.os.Handler#Handler() - */ - public GestureDetector(Context context, OnGestureListener listener, Handler handler) { - this(context, listener, handler, context != null && - context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.FROYO); - } - - /** - * Creates a GestureDetector with the supplied listener. - * You may only use this constructor from a UI thread (this is the usual situation). - * - * @param context the application's context - * @param listener the listener invoked for all the callbacks, this must - * not be null. - * @param handler the handler to use - * @param ignoreMultitouch whether events involving more than one pointer should - * be ignored. - * @throws NullPointerException if {@code listener} is null. - * @see android.os.Handler#Handler() - */ - public GestureDetector(Context context, OnGestureListener listener, Handler handler, - boolean ignoreMultitouch) { - if (handler != null) { - mHandler = new GestureHandler(handler); - } else { - mHandler = new GestureHandler(); - } - mListener = listener; - if (listener instanceof OnDoubleTapListener) { - setOnDoubleTapListener((OnDoubleTapListener) listener); - } - init(context, ignoreMultitouch); - } - - private void init(Context context, boolean ignoreMultitouch) { - if (mListener == null) { - throw new NullPointerException("OnGestureListener must not be null"); - } - mIsLongpressEnabled = true; - mIgnoreMultitouch = ignoreMultitouch; - - // Fallback to support pre-donuts releases - int touchSlop, largeTouchSlop, doubleTapSlop; - if (context == null) { - //noinspection deprecation - touchSlop = ViewConfiguration.getTouchSlop(); - largeTouchSlop = touchSlop + 2; - doubleTapSlop = DOUBLE_TAP_SLOP; - } else { - final DisplayMetrics metrics = context.getResources().getDisplayMetrics(); - final float density = metrics.density; - final ViewConfiguration configuration = ViewConfiguration.get(context); - touchSlop = configuration.getScaledTouchSlop(); - largeTouchSlop = (int) (density * LARGE_TOUCH_SLOP + 0.5f); - doubleTapSlop = configuration.getScaledDoubleTapSlop(); - } - mTouchSlopSquare = touchSlop * touchSlop; - mLargeTouchSlopSquare = largeTouchSlop * largeTouchSlop; - mDoubleTapSlopSquare = doubleTapSlop * doubleTapSlop; - } - - /** - * Sets the listener which will be called for double-tap and related - * gestures. - * - * @param onDoubleTapListener the listener invoked for all the callbacks, or - * null to stop listening for double-tap gestures. - */ - public void setOnDoubleTapListener(OnDoubleTapListener onDoubleTapListener) { - mDoubleTapListener = onDoubleTapListener; - } - - /** - * Set whether longpress is enabled, if this is enabled when a user - * presses and holds down you get a longpress event and nothing further. - * If it's disabled the user can press and hold down and then later - * moved their finger and you will get scroll events. By default - * longpress is enabled. - * - * @param isLongpressEnabled whether longpress should be enabled. - */ - public void setIsLongpressEnabled(boolean isLongpressEnabled) { - mIsLongpressEnabled = isLongpressEnabled; - } - - /** - * @return true if longpress is enabled, else false. - */ - public boolean isLongpressEnabled() { - return mIsLongpressEnabled; - } - - public void setLongPressTimeout(int timeout) { - mLongpressTimeout = timeout; - } - - /** - * Analyzes the given motion event and if applicable triggers the - * appropriate callbacks on the {@link OnGestureListener} supplied. - * - * @param ev The current motion event. - * @return true if the {@link OnGestureListener} consumed the event, - * else false. - */ - public boolean onTouchEvent(MotionEvent ev) { - final int action = ev.getAction(); - final float y = ev.getY(); - final float x = ev.getX(); - - boolean handled = false; - - switch (action & MotionEvent.ACTION_MASK) { - case MotionEvent.ACTION_POINTER_DOWN: - if (mIgnoreMultitouch) { - // Multitouch event - abort. - cancel(); - } - break; - - case MotionEvent.ACTION_POINTER_UP: - // Ending a multitouch gesture and going back to 1 finger - if (mIgnoreMultitouch && ev.getPointerCount() == 2) { - int index = (((action & MotionEvent.ACTION_POINTER_INDEX_MASK) - >> MotionEvent.ACTION_POINTER_INDEX_SHIFT) == 0) ? 1 : 0; - mLastMotionX = ev.getX(index); - mLastMotionY = ev.getY(index); - } - break; - - case MotionEvent.ACTION_DOWN: - if (mDoubleTapListener != null) { - boolean hadTapMessage = mHandler.hasMessages(TAP); - if (hadTapMessage) mHandler.removeMessages(TAP); - if ((mCurrentDownEvent != null) && (mPreviousUpEvent != null) && hadTapMessage && - isConsideredDoubleTap(mCurrentDownEvent, mPreviousUpEvent, ev)) { - // This is a second tap - mIsDoubleTapping = true; - // Give a callback with the first tap of the double-tap - handled |= mDoubleTapListener.onDoubleTap(mCurrentDownEvent); - // Give a callback with down event of the double-tap - handled |= mDoubleTapListener.onDoubleTapEvent(ev); - } else { - // This is a first tap - mHandler.sendEmptyMessageDelayed(TAP, DOUBLE_TAP_TIMEOUT); - } - } - - mLastMotionX = x; - mLastMotionY = y; - if (mCurrentDownEvent != null) { - mCurrentDownEvent.recycle(); - } - mCurrentDownEvent = MotionEvent.obtain(ev); - mAlwaysInTapRegion = true; - mAlwaysInBiggerTapRegion = true; - mStillDown = true; - mInLongPress = false; - - if (mIsLongpressEnabled) { - mHandler.removeMessages(LONG_PRESS); - mHandler.sendEmptyMessageAtTime(LONG_PRESS, mCurrentDownEvent.getDownTime() - + TAP_TIMEOUT + mLongpressTimeout); - } - mHandler.sendEmptyMessageAtTime(SHOW_PRESS, mCurrentDownEvent.getDownTime() + TAP_TIMEOUT); - handled |= mListener.onDown(ev); - break; - - case MotionEvent.ACTION_MOVE: - if (mIgnoreMultitouch && ev.getPointerCount() > 1) { - break; - } - final float scrollX = mLastMotionX - x; - final float scrollY = mLastMotionY - y; - if (mIsDoubleTapping) { - // Give the move events of the double-tap - handled |= mDoubleTapListener.onDoubleTapEvent(ev); - } else if (mAlwaysInTapRegion) { - final int deltaX = (int) (x - mCurrentDownEvent.getX()); - final int deltaY = (int) (y - mCurrentDownEvent.getY()); - int distance = (deltaX * deltaX) + (deltaY * deltaY); - if (distance > mTouchSlopSquare) { - mLastMotionX = x; - mLastMotionY = y; - mAlwaysInTapRegion = false; - mHandler.removeMessages(TAP); - mHandler.removeMessages(SHOW_PRESS); - mHandler.removeMessages(LONG_PRESS); - } - if (distance > mLargeTouchSlopSquare) { - mAlwaysInBiggerTapRegion = false; - } - handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY); - } else if ((Math.abs(scrollX) >= 1) || (Math.abs(scrollY) >= 1)) { - handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY); - mLastMotionX = x; - mLastMotionY = y; - } - break; - - case MotionEvent.ACTION_UP: - mStillDown = false; - MotionEvent currentUpEvent = MotionEvent.obtain(ev); - if (mIsDoubleTapping) { - // Finally, give the up event of the double-tap - handled |= mDoubleTapListener.onDoubleTapEvent(ev); - } else if (mInLongPress) { - mHandler.removeMessages(TAP); - mListener.onLongPressUp(ev); - mInLongPress = false; - } else if (mAlwaysInTapRegion) { - handled = mListener.onSingleTapUp(mCurrentDownEvent); - } else { - // A fling must travel the minimum tap distance - } - if (mPreviousUpEvent != null) { - mPreviousUpEvent.recycle(); - } - // Hold the event we obtained above - listeners may have changed the original. - mPreviousUpEvent = currentUpEvent; - mIsDoubleTapping = false; - mHandler.removeMessages(SHOW_PRESS); - mHandler.removeMessages(LONG_PRESS); - handled |= mListener.onUp(ev); - break; - case MotionEvent.ACTION_CANCEL: - cancel(); - break; - } - return handled; - } - - private void cancel() { - mHandler.removeMessages(SHOW_PRESS); - mHandler.removeMessages(LONG_PRESS); - mHandler.removeMessages(TAP); - mAlwaysInTapRegion = false; // ensures that we won't receive an OnSingleTap notification when a 2-Finger tap is performed - mIsDoubleTapping = false; - mStillDown = false; - if (mInLongPress) { - mInLongPress = false; - } - } - - private boolean isConsideredDoubleTap(MotionEvent firstDown, MotionEvent firstUp, - MotionEvent secondDown) { - if (!mAlwaysInBiggerTapRegion) { - return false; - } - - if (secondDown.getEventTime() - firstUp.getEventTime() > DOUBLE_TAP_TIMEOUT) { - return false; - } - - int deltaX = (int) firstDown.getX() - (int) secondDown.getX(); - int deltaY = (int) firstDown.getY() - (int) secondDown.getY(); - return (deltaX * deltaX + deltaY * deltaY < mDoubleTapSlopSquare); - } - - private void dispatchLongPress() { - mHandler.removeMessages(TAP); - mInLongPress = true; - mListener.onLongPress(mCurrentDownEvent); - } - - /** - * The listener that is used to notify when gestures occur. - * If you want to listen for all the different gestures then implement - * this interface. If you only want to listen for a subset it might - * be easier to extend {@link SimpleOnGestureListener}. - */ - public interface OnGestureListener { - - /** - * Notified when a tap occurs with the down {@link MotionEvent} - * that triggered it. This will be triggered immediately for - * every down event. All other events should be preceded by this. - * - * @param e The down motion event. - */ - boolean onDown(MotionEvent e); - - /** - * Notified when a tap finishes with the up {@link MotionEvent} - * that triggered it. This will be triggered immediately for - * every up event. All other events should be preceded by this. - * - * @param e The up motion event. - */ - boolean onUp(MotionEvent e); - - /** - * The user has performed a down {@link MotionEvent} and not performed - * a move or up yet. This event is commonly used to provide visual - * feedback to the user to let them know that their action has been - * recognized i.e. highlight an element. - * - * @param e The down motion event - */ - void onShowPress(MotionEvent e); - - /** - * Notified when a tap occurs with the up {@link MotionEvent} - * that triggered it. - * - * @param e The up motion event that completed the first tap - * @return true if the event is consumed, else false - */ - boolean onSingleTapUp(MotionEvent e); - - /** - * Notified when a scroll occurs with the initial on down {@link MotionEvent} and the - * current move {@link MotionEvent}. The distance in x and y is also supplied for - * convenience. - * - * @param e1 The first down motion event that started the scrolling. - * @param e2 The move motion event that triggered the current onScroll. - * @param distanceX The distance along the X axis that has been scrolled since the last - * call to onScroll. This is NOT the distance between {@code e1} - * and {@code e2}. - * @param distanceY The distance along the Y axis that has been scrolled since the last - * call to onScroll. This is NOT the distance between {@code e1} - * and {@code e2}. - * @return true if the event is consumed, else false - */ - boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY); - - /** - * Notified when a long press occurs with the initial on down {@link MotionEvent} - * that trigged it. - * - * @param e The initial on down motion event that started the longpress. - */ - void onLongPress(MotionEvent e); - - /** - * Notified when a long press ends with the final {@link MotionEvent}. - * - * @param e The up motion event that ended the longpress. - */ - void onLongPressUp(MotionEvent e); - } - - /** - * The listener that is used to notify when a double-tap or a confirmed - * single-tap occur. - */ - public interface OnDoubleTapListener { - /** - * Notified when a single-tap occurs. - *

- * Unlike {@link OnGestureListener#onSingleTapUp(MotionEvent)}, this - * will only be called after the detector is confident that the user's - * first tap is not followed by a second tap leading to a double-tap - * gesture. - * - * @param e The down motion event of the single-tap. - * @return true if the event is consumed, else false - */ - boolean onSingleTapConfirmed(MotionEvent e); - - /** - * Notified when a double-tap occurs. - * - * @param e The down motion event of the first tap of the double-tap. - * @return true if the event is consumed, else false - */ - boolean onDoubleTap(MotionEvent e); - - /** - * Notified when an event within a double-tap gesture occurs, including - * the down, move, and up events. - * - * @param e The motion event that occurred during the double-tap gesture. - * @return true if the event is consumed, else false - */ - boolean onDoubleTapEvent(MotionEvent e); - } - - /** - * A convenience class to extend when you only want to listen for a subset - * of all the gestures. This implements all methods in the - * {@link OnGestureListener} and {@link OnDoubleTapListener} but does - * nothing and return {@code false} for all applicable methods. - */ - public static class SimpleOnGestureListener implements OnGestureListener, OnDoubleTapListener { - public boolean onSingleTapUp(MotionEvent e) { - return false; - } - - public void onLongPress(MotionEvent e) { - } - - public void onLongPressUp(MotionEvent e) { - } - - public boolean onScroll(MotionEvent e1, MotionEvent e2, - float distanceX, float distanceY) { - return false; - } - - public void onShowPress(MotionEvent e) { - } - - public boolean onDown(MotionEvent e) { - return false; - } - - public boolean onUp(MotionEvent e) { - return false; - } - - public boolean onDoubleTap(MotionEvent e) { - return false; - } - - public boolean onDoubleTapEvent(MotionEvent e) { - return false; - } - - public boolean onSingleTapConfirmed(MotionEvent e) { - return false; - } - } - - private class GestureHandler extends Handler { - GestureHandler() { - super(); - } - - GestureHandler(Handler handler) { - super(handler.getLooper()); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case SHOW_PRESS: - mListener.onShowPress(mCurrentDownEvent); - break; - - case LONG_PRESS: - dispatchLongPress(); - break; - - case TAP: - // If the user's finger is still down, do not count it as a tap - if (mDoubleTapListener != null && !mStillDown) { - mDoubleTapListener.onSingleTapConfirmed(mCurrentDownEvent); - } - break; - - default: - throw new RuntimeException("Unknown message " + msg); //never - } - } - } +public class GestureDetector +{ + + private static final int TAP_TIMEOUT = 100; + private static final int DOUBLE_TAP_TIMEOUT = 200; + // Distance a touch can wander before we think the user is the first touch in a sequence of + // double tap + private static final int LARGE_TOUCH_SLOP = 18; + // Distance between the first touch and second touch to still be considered a double tap + private static final int DOUBLE_TAP_SLOP = 100; + // constants for Message.what used by GestureHandler below + private static final int SHOW_PRESS = 1; + private static final int LONG_PRESS = 2; + private static final int TAP = 3; + private final Handler mHandler; + private final OnGestureListener mListener; + private int mTouchSlopSquare; + private int mLargeTouchSlopSquare; + private int mDoubleTapSlopSquare; + private int mLongpressTimeout = 100; + private OnDoubleTapListener mDoubleTapListener; + private boolean mStillDown; + private boolean mInLongPress; + private boolean mAlwaysInTapRegion; + private boolean mAlwaysInBiggerTapRegion; + private MotionEvent mCurrentDownEvent; + private MotionEvent mPreviousUpEvent; + /** + * True when the user is still touching for the second tap (down, move, and + * up events). Can only be true if there is a double tap listener attached. + */ + private boolean mIsDoubleTapping; + private float mLastMotionY; + private float mLastMotionX; + private boolean mIsLongpressEnabled; + /** + * True if we are at a target API level of >= Froyo or the developer can + * explicitly set it. If true, input events with > 1 pointer will be ignored + * so we can work side by side with multitouch gesture detectors. + */ + private boolean mIgnoreMultitouch; + /** + * Creates a GestureDetector with the supplied listener. + * You may only use this constructor from a UI thread (this is the usual situation). + * + * @param context the application's context + * @param listener the listener invoked for all the callbacks, this must + * not be null. + * @throws NullPointerException if {@code listener} is null. + * @see android.os.Handler#Handler() + */ + public GestureDetector(Context context, OnGestureListener listener) + { + this(context, listener, null); + } + + /** + * Creates a GestureDetector with the supplied listener. + * You may only use this constructor from a UI thread (this is the usual situation). + * + * @param context the application's context + * @param listener the listener invoked for all the callbacks, this must + * not be null. + * @param handler the handler to use + * @throws NullPointerException if {@code listener} is null. + * @see android.os.Handler#Handler() + */ + public GestureDetector(Context context, OnGestureListener listener, Handler handler) + { + this(context, listener, handler, + context != null && + context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.FROYO); + } + + /** + * Creates a GestureDetector with the supplied listener. + * You may only use this constructor from a UI thread (this is the usual situation). + * + * @param context the application's context + * @param listener the listener invoked for all the callbacks, this must + * not be null. + * @param handler the handler to use + * @param ignoreMultitouch whether events involving more than one pointer should + * be ignored. + * @throws NullPointerException if {@code listener} is null. + * @see android.os.Handler#Handler() + */ + public GestureDetector(Context context, OnGestureListener listener, Handler handler, + boolean ignoreMultitouch) + { + if (handler != null) + { + mHandler = new GestureHandler(handler); + } + else + { + mHandler = new GestureHandler(); + } + mListener = listener; + if (listener instanceof OnDoubleTapListener) + { + setOnDoubleTapListener((OnDoubleTapListener)listener); + } + init(context, ignoreMultitouch); + } + + private void init(Context context, boolean ignoreMultitouch) + { + if (mListener == null) + { + throw new NullPointerException("OnGestureListener must not be null"); + } + mIsLongpressEnabled = true; + mIgnoreMultitouch = ignoreMultitouch; + + // Fallback to support pre-donuts releases + int touchSlop, largeTouchSlop, doubleTapSlop; + if (context == null) + { + // noinspection deprecation + touchSlop = ViewConfiguration.getTouchSlop(); + largeTouchSlop = touchSlop + 2; + doubleTapSlop = DOUBLE_TAP_SLOP; + } + else + { + final DisplayMetrics metrics = context.getResources().getDisplayMetrics(); + final float density = metrics.density; + final ViewConfiguration configuration = ViewConfiguration.get(context); + touchSlop = configuration.getScaledTouchSlop(); + largeTouchSlop = (int)(density * LARGE_TOUCH_SLOP + 0.5f); + doubleTapSlop = configuration.getScaledDoubleTapSlop(); + } + mTouchSlopSquare = touchSlop * touchSlop; + mLargeTouchSlopSquare = largeTouchSlop * largeTouchSlop; + mDoubleTapSlopSquare = doubleTapSlop * doubleTapSlop; + } + + /** + * Sets the listener which will be called for double-tap and related + * gestures. + * + * @param onDoubleTapListener the listener invoked for all the callbacks, or + * null to stop listening for double-tap gestures. + */ + public void setOnDoubleTapListener(OnDoubleTapListener onDoubleTapListener) + { + mDoubleTapListener = onDoubleTapListener; + } + + /** + * Set whether longpress is enabled, if this is enabled when a user + * presses and holds down you get a longpress event and nothing further. + * If it's disabled the user can press and hold down and then later + * moved their finger and you will get scroll events. By default + * longpress is enabled. + * + * @param isLongpressEnabled whether longpress should be enabled. + */ + public void setIsLongpressEnabled(boolean isLongpressEnabled) + { + mIsLongpressEnabled = isLongpressEnabled; + } + + /** + * @return true if longpress is enabled, else false. + */ + public boolean isLongpressEnabled() + { + return mIsLongpressEnabled; + } + + public void setLongPressTimeout(int timeout) + { + mLongpressTimeout = timeout; + } + + /** + * Analyzes the given motion event and if applicable triggers the + * appropriate callbacks on the {@link OnGestureListener} supplied. + * + * @param ev The current motion event. + * @return true if the {@link OnGestureListener} consumed the event, + * else false. + */ + public boolean onTouchEvent(MotionEvent ev) + { + final int action = ev.getAction(); + final float y = ev.getY(); + final float x = ev.getX(); + + boolean handled = false; + + switch (action & MotionEvent.ACTION_MASK) + { + case MotionEvent.ACTION_POINTER_DOWN: + if (mIgnoreMultitouch) + { + // Multitouch event - abort. + cancel(); + } + break; + + case MotionEvent.ACTION_POINTER_UP: + // Ending a multitouch gesture and going back to 1 finger + if (mIgnoreMultitouch && ev.getPointerCount() == 2) + { + int index = (((action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> + MotionEvent.ACTION_POINTER_INDEX_SHIFT) == 0) + ? 1 + : 0; + mLastMotionX = ev.getX(index); + mLastMotionY = ev.getY(index); + } + break; + + case MotionEvent.ACTION_DOWN: + if (mDoubleTapListener != null) + { + boolean hadTapMessage = mHandler.hasMessages(TAP); + if (hadTapMessage) + mHandler.removeMessages(TAP); + if ((mCurrentDownEvent != null) && (mPreviousUpEvent != null) && + hadTapMessage && + isConsideredDoubleTap(mCurrentDownEvent, mPreviousUpEvent, ev)) + { + // This is a second tap + mIsDoubleTapping = true; + // Give a callback with the first tap of the double-tap + handled |= mDoubleTapListener.onDoubleTap(mCurrentDownEvent); + // Give a callback with down event of the double-tap + handled |= mDoubleTapListener.onDoubleTapEvent(ev); + } + else + { + // This is a first tap + mHandler.sendEmptyMessageDelayed(TAP, DOUBLE_TAP_TIMEOUT); + } + } + + mLastMotionX = x; + mLastMotionY = y; + if (mCurrentDownEvent != null) + { + mCurrentDownEvent.recycle(); + } + mCurrentDownEvent = MotionEvent.obtain(ev); + mAlwaysInTapRegion = true; + mAlwaysInBiggerTapRegion = true; + mStillDown = true; + mInLongPress = false; + + if (mIsLongpressEnabled) + { + mHandler.removeMessages(LONG_PRESS); + mHandler.sendEmptyMessageAtTime(LONG_PRESS, mCurrentDownEvent.getDownTime() + + TAP_TIMEOUT + + mLongpressTimeout); + } + mHandler.sendEmptyMessageAtTime(SHOW_PRESS, + mCurrentDownEvent.getDownTime() + TAP_TIMEOUT); + handled |= mListener.onDown(ev); + break; + + case MotionEvent.ACTION_MOVE: + if (mIgnoreMultitouch && ev.getPointerCount() > 1) + { + break; + } + final float scrollX = mLastMotionX - x; + final float scrollY = mLastMotionY - y; + if (mIsDoubleTapping) + { + // Give the move events of the double-tap + handled |= mDoubleTapListener.onDoubleTapEvent(ev); + } + else if (mAlwaysInTapRegion) + { + final int deltaX = (int)(x - mCurrentDownEvent.getX()); + final int deltaY = (int)(y - mCurrentDownEvent.getY()); + int distance = (deltaX * deltaX) + (deltaY * deltaY); + if (distance > mTouchSlopSquare) + { + mLastMotionX = x; + mLastMotionY = y; + mAlwaysInTapRegion = false; + mHandler.removeMessages(TAP); + mHandler.removeMessages(SHOW_PRESS); + mHandler.removeMessages(LONG_PRESS); + } + if (distance > mLargeTouchSlopSquare) + { + mAlwaysInBiggerTapRegion = false; + } + handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY); + } + else if ((Math.abs(scrollX) >= 1) || (Math.abs(scrollY) >= 1)) + { + handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY); + mLastMotionX = x; + mLastMotionY = y; + } + break; + + case MotionEvent.ACTION_UP: + mStillDown = false; + MotionEvent currentUpEvent = MotionEvent.obtain(ev); + if (mIsDoubleTapping) + { + // Finally, give the up event of the double-tap + handled |= mDoubleTapListener.onDoubleTapEvent(ev); + } + else if (mInLongPress) + { + mHandler.removeMessages(TAP); + mListener.onLongPressUp(ev); + mInLongPress = false; + } + else if (mAlwaysInTapRegion) + { + handled = mListener.onSingleTapUp(mCurrentDownEvent); + } + else + { + // A fling must travel the minimum tap distance + } + if (mPreviousUpEvent != null) + { + mPreviousUpEvent.recycle(); + } + // Hold the event we obtained above - listeners may have changed the original. + mPreviousUpEvent = currentUpEvent; + mIsDoubleTapping = false; + mHandler.removeMessages(SHOW_PRESS); + mHandler.removeMessages(LONG_PRESS); + handled |= mListener.onUp(ev); + break; + case MotionEvent.ACTION_CANCEL: + cancel(); + break; + } + return handled; + } + + private void cancel() + { + mHandler.removeMessages(SHOW_PRESS); + mHandler.removeMessages(LONG_PRESS); + mHandler.removeMessages(TAP); + mAlwaysInTapRegion = false; // ensures that we won't receive an OnSingleTap notification + // when a 2-Finger tap is performed + mIsDoubleTapping = false; + mStillDown = false; + if (mInLongPress) + { + mInLongPress = false; + } + } + + private boolean isConsideredDoubleTap(MotionEvent firstDown, MotionEvent firstUp, + MotionEvent secondDown) + { + if (!mAlwaysInBiggerTapRegion) + { + return false; + } + + if (secondDown.getEventTime() - firstUp.getEventTime() > DOUBLE_TAP_TIMEOUT) + { + return false; + } + + int deltaX = (int)firstDown.getX() - (int)secondDown.getX(); + int deltaY = (int)firstDown.getY() - (int)secondDown.getY(); + return (deltaX * deltaX + deltaY * deltaY < mDoubleTapSlopSquare); + } + + private void dispatchLongPress() + { + mHandler.removeMessages(TAP); + mInLongPress = true; + mListener.onLongPress(mCurrentDownEvent); + } + + /** + * The listener that is used to notify when gestures occur. + * If you want to listen for all the different gestures then implement + * this interface. If you only want to listen for a subset it might + * be easier to extend {@link SimpleOnGestureListener}. + */ + public interface OnGestureListener { + + /** + * Notified when a tap occurs with the down {@link MotionEvent} + * that triggered it. This will be triggered immediately for + * every down event. All other events should be preceded by this. + * + * @param e The down motion event. + */ + boolean onDown(MotionEvent e); + + /** + * Notified when a tap finishes with the up {@link MotionEvent} + * that triggered it. This will be triggered immediately for + * every up event. All other events should be preceded by this. + * + * @param e The up motion event. + */ + boolean onUp(MotionEvent e); + + /** + * The user has performed a down {@link MotionEvent} and not performed + * a move or up yet. This event is commonly used to provide visual + * feedback to the user to let them know that their action has been + * recognized i.e. highlight an element. + * + * @param e The down motion event + */ + void onShowPress(MotionEvent e); + + /** + * Notified when a tap occurs with the up {@link MotionEvent} + * that triggered it. + * + * @param e The up motion event that completed the first tap + * @return true if the event is consumed, else false + */ + boolean onSingleTapUp(MotionEvent e); + + /** + * Notified when a scroll occurs with the initial on down {@link MotionEvent} and the + * current move {@link MotionEvent}. The distance in x and y is also supplied for + * convenience. + * + * @param e1 The first down motion event that started the scrolling. + * @param e2 The move motion event that triggered the current onScroll. + * @param distanceX The distance along the X axis that has been scrolled since the last + * call to onScroll. This is NOT the distance between {@code e1} + * and {@code e2}. + * @param distanceY The distance along the Y axis that has been scrolled since the last + * call to onScroll. This is NOT the distance between {@code e1} + * and {@code e2}. + * @return true if the event is consumed, else false + */ + boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY); + + /** + * Notified when a long press occurs with the initial on down {@link MotionEvent} + * that trigged it. + * + * @param e The initial on down motion event that started the longpress. + */ + void onLongPress(MotionEvent e); + + /** + * Notified when a long press ends with the final {@link MotionEvent}. + * + * @param e The up motion event that ended the longpress. + */ + void onLongPressUp(MotionEvent e); + } + + /** + * The listener that is used to notify when a double-tap or a confirmed + * single-tap occur. + */ + public interface OnDoubleTapListener { + /** + * Notified when a single-tap occurs. + *

+ * Unlike {@link OnGestureListener#onSingleTapUp(MotionEvent)}, this + * will only be called after the detector is confident that the user's + * first tap is not followed by a second tap leading to a double-tap + * gesture. + * + * @param e The down motion event of the single-tap. + * @return true if the event is consumed, else false + */ + boolean onSingleTapConfirmed(MotionEvent e); + + /** + * Notified when a double-tap occurs. + * + * @param e The down motion event of the first tap of the double-tap. + * @return true if the event is consumed, else false + */ + boolean onDoubleTap(MotionEvent e); + + /** + * Notified when an event within a double-tap gesture occurs, including + * the down, move, and up events. + * + * @param e The motion event that occurred during the double-tap gesture. + * @return true if the event is consumed, else false + */ + boolean onDoubleTapEvent(MotionEvent e); + } + + /** + * A convenience class to extend when you only want to listen for a subset + * of all the gestures. This implements all methods in the + * {@link OnGestureListener} and {@link OnDoubleTapListener} but does + * nothing and return {@code false} for all applicable methods. + */ + public static class SimpleOnGestureListener implements OnGestureListener, OnDoubleTapListener + { + public boolean onSingleTapUp(MotionEvent e) + { + return false; + } + + public void onLongPress(MotionEvent e) + { + } + + public void onLongPressUp(MotionEvent e) + { + } + + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) + { + return false; + } + + public void onShowPress(MotionEvent e) + { + } + + public boolean onDown(MotionEvent e) + { + return false; + } + + public boolean onUp(MotionEvent e) + { + return false; + } + + public boolean onDoubleTap(MotionEvent e) + { + return false; + } + + public boolean onDoubleTapEvent(MotionEvent e) + { + return false; + } + + public boolean onSingleTapConfirmed(MotionEvent e) + { + return false; + } + } + + private class GestureHandler extends Handler + { + GestureHandler() + { + super(); + } + + GestureHandler(Handler handler) + { + super(handler.getLooper()); + } + + @Override public void handleMessage(Message msg) + { + switch (msg.what) + { + case SHOW_PRESS: + mListener.onShowPress(mCurrentDownEvent); + break; + + case LONG_PRESS: + dispatchLongPress(); + break; + + case TAP: + // If the user's finger is still down, do not count it as a tap + if (mDoubleTapListener != null && !mStillDown) + { + mDoubleTapListener.onSingleTapConfirmed(mCurrentDownEvent); + } + break; + + default: + throw new RuntimeException("Unknown message " + msg); // never + } + } + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/IntEditTextPreference.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/IntEditTextPreference.java index a3e951c..a383d91 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/IntEditTextPreference.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/IntEditTextPreference.java @@ -3,8 +3,9 @@ Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.utils; @@ -16,72 +17,85 @@ import android.util.AttributeSet; import com.freerdp.freerdpcore.R; -public class IntEditTextPreference extends EditTextPreference { - - private int bounds_min, bounds_max, bounds_default; - - public IntEditTextPreference(Context context) { - super(context); - init(context, null); - } - - public IntEditTextPreference(Context context, AttributeSet attrs) { - super(context, attrs); - init(context, attrs); - } - - public IntEditTextPreference(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - init(context, attrs); - } - - private void init(Context context, AttributeSet attrs) { - if (attrs != null) { - TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.IntEditTextPreference, 0, 0); - bounds_min = array.getInt(R.styleable.IntEditTextPreference_bounds_min, Integer.MIN_VALUE); - bounds_max = array.getInt(R.styleable.IntEditTextPreference_bounds_max, Integer.MAX_VALUE); - bounds_default = array.getInt(R.styleable.IntEditTextPreference_bounds_default, 0); - array.recycle(); - } else { - bounds_min = Integer.MIN_VALUE; - bounds_max = Integer.MAX_VALUE; - bounds_default = 0; - } - } - - public void setBounds(int min, int max, int defaultValue) { - bounds_min = min; - bounds_max = max; - bounds_default = defaultValue; - } - - @Override - protected String getPersistedString(String defaultReturnValue) { - int value = getPersistedInt(-1); - if (value > bounds_max || value < bounds_min) - value = bounds_default; - return String.valueOf(value); - } - - @Override - protected boolean persistString(String value) { - return persistInt(Integer.valueOf(value)); - } - - @Override - protected void onDialogClosed(boolean positiveResult) { - if (positiveResult) { - // prevent exception when an empty value is persisted - if (getEditText().getText().length() == 0) - getEditText().setText("0"); - - // check bounds - int value = Integer.valueOf(getEditText().getText().toString()); - if (value > bounds_max || value < bounds_min) - value = bounds_default; - getEditText().setText(String.valueOf(value)); - } - - super.onDialogClosed(positiveResult); - } +public class IntEditTextPreference extends EditTextPreference +{ + + private int bounds_min, bounds_max, bounds_default; + + public IntEditTextPreference(Context context) + { + super(context); + init(context, null); + } + + public IntEditTextPreference(Context context, AttributeSet attrs) + { + super(context, attrs); + init(context, attrs); + } + + public IntEditTextPreference(Context context, AttributeSet attrs, int defStyle) + { + super(context, attrs, defStyle); + init(context, attrs); + } + + private void init(Context context, AttributeSet attrs) + { + if (attrs != null) + { + TypedArray array = + context.obtainStyledAttributes(attrs, R.styleable.IntEditTextPreference, 0, 0); + bounds_min = + array.getInt(R.styleable.IntEditTextPreference_bounds_min, Integer.MIN_VALUE); + bounds_max = + array.getInt(R.styleable.IntEditTextPreference_bounds_max, Integer.MAX_VALUE); + bounds_default = array.getInt(R.styleable.IntEditTextPreference_bounds_default, 0); + array.recycle(); + } + else + { + bounds_min = Integer.MIN_VALUE; + bounds_max = Integer.MAX_VALUE; + bounds_default = 0; + } + } + + public void setBounds(int min, int max, int defaultValue) + { + bounds_min = min; + bounds_max = max; + bounds_default = defaultValue; + } + + @Override protected String getPersistedString(String defaultReturnValue) + { + int value = getPersistedInt(-1); + if (value > bounds_max || value < bounds_min) + value = bounds_default; + return String.valueOf(value); + } + + @Override protected boolean persistString(String value) + { + return persistInt(Integer.valueOf(value)); + } + + @Override protected void onDialogClosed(boolean positiveResult) + { + if (positiveResult) + { + // prevent exception when an empty value is persisted + if (getEditText().getText().length() == 0) + getEditText().setText("0"); + + // check bounds + int value = Integer.valueOf(getEditText().getText().toString()); + if (value > bounds_max || value < bounds_min) + value = bounds_default; + getEditText().setText(String.valueOf(value)); + } + + super.onDialogClosed(positiveResult); + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/IntListPreference.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/IntListPreference.java index a641061..0b4f643 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/IntListPreference.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/IntListPreference.java @@ -3,8 +3,9 @@ Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.utils; @@ -13,23 +14,26 @@ import android.content.Context; import android.preference.ListPreference; import android.util.AttributeSet; -public class IntListPreference extends ListPreference { +public class IntListPreference extends ListPreference +{ - public IntListPreference(Context context) { - super(context); - } + public IntListPreference(Context context) + { + super(context); + } - public IntListPreference(Context context, AttributeSet attrs) { - super(context, attrs); - } + public IntListPreference(Context context, AttributeSet attrs) + { + super(context, attrs); + } - @Override - protected String getPersistedString(String defaultReturnValue) { - return String.valueOf(getPersistedInt(-1)); - } + @Override protected String getPersistedString(String defaultReturnValue) + { + return String.valueOf(getPersistedInt(-1)); + } - @Override - protected boolean persistString(String value) { - return persistInt(Integer.valueOf(value)); - } + @Override protected boolean persistString(String value) + { + return persistInt(Integer.valueOf(value)); + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/KeyboardMapper.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/KeyboardMapper.java index 170f415..f1456b2 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/KeyboardMapper.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/KeyboardMapper.java @@ -3,11 +3,11 @@ Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ - package com.freerdp.freerdpcore.utils; import android.content.Context; @@ -15,627 +15,711 @@ import android.view.KeyEvent; import com.freerdp.freerdpcore.R; -public class KeyboardMapper { - public static final int KEYBOARD_TYPE_FUNCTIONKEYS = 1; - public static final int KEYBOARD_TYPE_NUMPAD = 2; - public static final int KEYBOARD_TYPE_CURSOR = 3; - - // defines key states for modifier keys - locked means on and no auto-release if an other key is pressed - public static final int KEYSTATE_ON = 1; - public static final int KEYSTATE_LOCKED = 2; - public static final int KEYSTATE_OFF = 3; - final static int VK_LBUTTON = 0x01; - final static int VK_RBUTTON = 0x02; - final static int VK_CANCEL = 0x03; - final static int VK_MBUTTON = 0x04; - final static int VK_XBUTTON1 = 0x05; - final static int VK_XBUTTON2 = 0x06; - final static int VK_BACK = 0x08; - final static int VK_TAB = 0x09; - final static int VK_CLEAR = 0x0C; - final static int VK_RETURN = 0x0D; - final static int VK_SHIFT = 0x10; - final static int VK_CONTROL = 0x11; - final static int VK_MENU = 0x12; - final static int VK_PAUSE = 0x13; - final static int VK_CAPITAL = 0x14; - final static int VK_KANA = 0x15; - final static int VK_HANGUEL = 0x15; - final static int VK_HANGUL = 0x15; - final static int VK_JUNJA = 0x17; - final static int VK_FINAL = 0x18; - final static int VK_HANJA = 0x19; - final static int VK_KANJI = 0x19; - final static int VK_ESCAPE = 0x1B; - final static int VK_CONVERT = 0x1C; - final static int VK_NONCONVERT = 0x1D; - final static int VK_ACCEPT = 0x1E; - final static int VK_MODECHANGE = 0x1F; - final static int VK_SPACE = 0x20; - final static int VK_PRIOR = 0x21; - final static int VK_NEXT = 0x22; - final static int VK_END = 0x23; - final static int VK_HOME = 0x24; - final static int VK_LEFT = 0x25; - final static int VK_UP = 0x26; - final static int VK_RIGHT = 0x27; - final static int VK_DOWN = 0x28; - final static int VK_SELECT = 0x29; - final static int VK_PRINT = 0x2A; - final static int VK_EXECUTE = 0x2B; - final static int VK_SNAPSHOT = 0x2C; - final static int VK_INSERT = 0x2D; - final static int VK_DELETE = 0x2E; - final static int VK_HELP = 0x2F; - final static int VK_KEY_0 = 0x30; - final static int VK_KEY_1 = 0x31; - final static int VK_KEY_2 = 0x32; - final static int VK_KEY_3 = 0x33; - final static int VK_KEY_4 = 0x34; - final static int VK_KEY_5 = 0x35; - final static int VK_KEY_6 = 0x36; - final static int VK_KEY_7 = 0x37; - final static int VK_KEY_8 = 0x38; - final static int VK_KEY_9 = 0x39; - final static int VK_KEY_A = 0x41; - final static int VK_KEY_B = 0x42; - final static int VK_KEY_C = 0x43; - final static int VK_KEY_D = 0x44; - final static int VK_KEY_E = 0x45; - final static int VK_KEY_F = 0x46; - final static int VK_KEY_G = 0x47; - final static int VK_KEY_H = 0x48; - final static int VK_KEY_I = 0x49; - final static int VK_KEY_J = 0x4A; - final static int VK_KEY_K = 0x4B; - final static int VK_KEY_L = 0x4C; - final static int VK_KEY_M = 0x4D; - final static int VK_KEY_N = 0x4E; - final static int VK_KEY_O = 0x4F; - final static int VK_KEY_P = 0x50; - final static int VK_KEY_Q = 0x51; - final static int VK_KEY_R = 0x52; - final static int VK_KEY_S = 0x53; - final static int VK_KEY_T = 0x54; - final static int VK_KEY_U = 0x55; - final static int VK_KEY_V = 0x56; - final static int VK_KEY_W = 0x57; - final static int VK_KEY_X = 0x58; - final static int VK_KEY_Y = 0x59; - final static int VK_KEY_Z = 0x5A; - final static int VK_LWIN = 0x5B; - final static int VK_RWIN = 0x5C; - final static int VK_APPS = 0x5D; - final static int VK_SLEEP = 0x5F; - final static int VK_NUMPAD0 = 0x60; - final static int VK_NUMPAD1 = 0x61; - final static int VK_NUMPAD2 = 0x62; - final static int VK_NUMPAD3 = 0x63; - final static int VK_NUMPAD4 = 0x64; - final static int VK_NUMPAD5 = 0x65; - final static int VK_NUMPAD6 = 0x66; - final static int VK_NUMPAD7 = 0x67; - final static int VK_NUMPAD8 = 0x68; - final static int VK_NUMPAD9 = 0x69; - final static int VK_MULTIPLY = 0x6A; - final static int VK_ADD = 0x6B; - final static int VK_SEPARATOR = 0x6C; - final static int VK_SUBTRACT = 0x6D; - final static int VK_DECIMAL = 0x6E; - final static int VK_DIVIDE = 0x6F; - final static int VK_F1 = 0x70; - final static int VK_F2 = 0x71; - final static int VK_F3 = 0x72; - final static int VK_F4 = 0x73; - final static int VK_F5 = 0x74; - final static int VK_F6 = 0x75; - final static int VK_F7 = 0x76; - final static int VK_F8 = 0x77; - final static int VK_F9 = 0x78; - final static int VK_F10 = 0x79; - final static int VK_F11 = 0x7A; - final static int VK_F12 = 0x7B; - final static int VK_F13 = 0x7C; - final static int VK_F14 = 0x7D; - final static int VK_F15 = 0x7E; - final static int VK_F16 = 0x7F; - final static int VK_F17 = 0x80; - final static int VK_F18 = 0x81; - final static int VK_F19 = 0x82; - final static int VK_F20 = 0x83; - final static int VK_F21 = 0x84; - final static int VK_F22 = 0x85; - final static int VK_F23 = 0x86; - final static int VK_F24 = 0x87; - final static int VK_NUMLOCK = 0x90; - final static int VK_SCROLL = 0x91; - final static int VK_LSHIFT = 0xA0; - final static int VK_RSHIFT = 0xA1; - final static int VK_LCONTROL = 0xA2; - final static int VK_RCONTROL = 0xA3; - final static int VK_LMENU = 0xA4; - final static int VK_RMENU = 0xA5; - final static int VK_BROWSER_BACK = 0xA6; - final static int VK_BROWSER_FORWARD = 0xA7; - final static int VK_BROWSER_REFRESH = 0xA8; - final static int VK_BROWSER_STOP = 0xA9; - final static int VK_BROWSER_SEARCH = 0xAA; - final static int VK_BROWSER_FAVORITES = 0xAB; - final static int VK_BROWSER_HOME = 0xAC; - final static int VK_VOLUME_MUTE = 0xAD; - final static int VK_VOLUME_DOWN = 0xAE; - final static int VK_VOLUME_UP = 0xAF; - final static int VK_MEDIA_NEXT_TRACK = 0xB0; - final static int VK_MEDIA_PREV_TRACK = 0xB1; - final static int VK_MEDIA_STOP = 0xB2; - final static int VK_MEDIA_PLAY_PAUSE = 0xB3; - final static int VK_LAUNCH_MAIL = 0xB4; - final static int VK_LAUNCH_MEDIA_SELECT = 0xB5; - final static int VK_LAUNCH_APP1 = 0xB6; - final static int VK_LAUNCH_APP2 = 0xB7; - final static int VK_OEM_1 = 0xBA; - final static int VK_OEM_PLUS = 0xBB; - final static int VK_OEM_COMMA = 0xBC; - final static int VK_OEM_MINUS = 0xBD; - final static int VK_OEM_PERIOD = 0xBE; - final static int VK_OEM_2 = 0xBF; - final static int VK_OEM_3 = 0xC0; - final static int VK_ABNT_C1 = 0xC1; - final static int VK_ABNT_C2 = 0xC2; - final static int VK_OEM_4 = 0xDB; - final static int VK_OEM_5 = 0xDC; - final static int VK_OEM_6 = 0xDD; - final static int VK_OEM_7 = 0xDE; - final static int VK_OEM_8 = 0xDF; - final static int VK_OEM_102 = 0xE2; - final static int VK_PROCESSKEY = 0xE5; - final static int VK_PACKET = 0xE7; - final static int VK_ATTN = 0xF6; - final static int VK_CRSEL = 0xF7; - final static int VK_EXSEL = 0xF8; - final static int VK_EREOF = 0xF9; - final static int VK_PLAY = 0xFA; - final static int VK_ZOOM = 0xFB; - final static int VK_NONAME = 0xFC; - final static int VK_PA1 = 0xFD; - final static int VK_OEM_CLEAR = 0xFE; - final static int VK_UNICODE = 0x80000000; - final static int VK_EXT_KEY = 0x00000100; - // key codes to switch between custom keyboard - private final static int EXTKEY_KBFUNCTIONKEYS = 0x1100; - private final static int EXTKEY_KBNUMPAD = 0x1101; - private final static int EXTKEY_KBCURSOR = 0x1102; - // this flag indicates if we got a VK or a unicode character in our translation map - private static final int KEY_FLAG_UNICODE = 0x80000000; - // this flag indicates if the key is a toggle key (remains down when pressed and goes up if pressed again) - private static final int KEY_FLAG_TOGGLE = 0x40000000; - private static int[] keymapAndroid; - private static int[] keymapExt; - private static boolean initialized = false; - private KeyProcessingListener listener = null; - private boolean shiftPressed = false; - private boolean ctrlPressed = false; - private boolean altPressed = false; - private boolean winPressed = false; - private long lastModifierTime; - private int lastModifierKeyCode = -1; - private boolean isShiftLocked = false; - private boolean isCtrlLocked = false; - private boolean isAltLocked = false; - private boolean isWinLocked = false; - - public void init(Context context) { - if (initialized == true) - return; - - keymapAndroid = new int[256]; - - keymapAndroid[KeyEvent.KEYCODE_0] = VK_KEY_0; - keymapAndroid[KeyEvent.KEYCODE_1] = VK_KEY_1; - keymapAndroid[KeyEvent.KEYCODE_2] = VK_KEY_2; - keymapAndroid[KeyEvent.KEYCODE_3] = VK_KEY_3; - keymapAndroid[KeyEvent.KEYCODE_4] = VK_KEY_4; - keymapAndroid[KeyEvent.KEYCODE_5] = VK_KEY_5; - keymapAndroid[KeyEvent.KEYCODE_6] = VK_KEY_6; - keymapAndroid[KeyEvent.KEYCODE_7] = VK_KEY_7; - keymapAndroid[KeyEvent.KEYCODE_8] = VK_KEY_8; - keymapAndroid[KeyEvent.KEYCODE_9] = VK_KEY_9; - - keymapAndroid[KeyEvent.KEYCODE_A] = VK_KEY_A; - keymapAndroid[KeyEvent.KEYCODE_B] = VK_KEY_B; - keymapAndroid[KeyEvent.KEYCODE_C] = VK_KEY_C; - keymapAndroid[KeyEvent.KEYCODE_D] = VK_KEY_D; - keymapAndroid[KeyEvent.KEYCODE_E] = VK_KEY_E; - keymapAndroid[KeyEvent.KEYCODE_F] = VK_KEY_F; - keymapAndroid[KeyEvent.KEYCODE_G] = VK_KEY_G; - keymapAndroid[KeyEvent.KEYCODE_H] = VK_KEY_H; - keymapAndroid[KeyEvent.KEYCODE_I] = VK_KEY_I; - keymapAndroid[KeyEvent.KEYCODE_J] = VK_KEY_J; - keymapAndroid[KeyEvent.KEYCODE_K] = VK_KEY_K; - keymapAndroid[KeyEvent.KEYCODE_L] = VK_KEY_L; - keymapAndroid[KeyEvent.KEYCODE_M] = VK_KEY_M; - keymapAndroid[KeyEvent.KEYCODE_N] = VK_KEY_N; - keymapAndroid[KeyEvent.KEYCODE_O] = VK_KEY_O; - keymapAndroid[KeyEvent.KEYCODE_P] = VK_KEY_P; - keymapAndroid[KeyEvent.KEYCODE_Q] = VK_KEY_Q; - keymapAndroid[KeyEvent.KEYCODE_R] = VK_KEY_R; - keymapAndroid[KeyEvent.KEYCODE_S] = VK_KEY_S; - keymapAndroid[KeyEvent.KEYCODE_T] = VK_KEY_T; - keymapAndroid[KeyEvent.KEYCODE_U] = VK_KEY_U; - keymapAndroid[KeyEvent.KEYCODE_V] = VK_KEY_V; - keymapAndroid[KeyEvent.KEYCODE_W] = VK_KEY_W; - keymapAndroid[KeyEvent.KEYCODE_X] = VK_KEY_X; - keymapAndroid[KeyEvent.KEYCODE_Y] = VK_KEY_Y; - keymapAndroid[KeyEvent.KEYCODE_Z] = VK_KEY_Z; - - keymapAndroid[KeyEvent.KEYCODE_DEL] = VK_BACK; - keymapAndroid[KeyEvent.KEYCODE_ENTER] = VK_RETURN; - keymapAndroid[KeyEvent.KEYCODE_SPACE] = VK_SPACE; - keymapAndroid[KeyEvent.KEYCODE_TAB] = VK_TAB; -// keymapAndroid[KeyEvent.KEYCODE_SHIFT_LEFT] = VK_LSHIFT; -// keymapAndroid[KeyEvent.KEYCODE_SHIFT_RIGHT] = VK_RSHIFT; - -// keymapAndroid[KeyEvent.KEYCODE_DPAD_DOWN] = VK_DOWN; -// keymapAndroid[KeyEvent.KEYCODE_DPAD_LEFT] = VK_LEFT; -// keymapAndroid[KeyEvent.KEYCODE_DPAD_RIGHT] = VK_RIGHT; -// keymapAndroid[KeyEvent.KEYCODE_DPAD_UP] = VK_UP; - -// keymapAndroid[KeyEvent.KEYCODE_COMMA] = VK_OEM_COMMA; -// keymapAndroid[KeyEvent.KEYCODE_PERIOD] = VK_OEM_PERIOD; -// keymapAndroid[KeyEvent.KEYCODE_MINUS] = VK_OEM_MINUS; -// keymapAndroid[KeyEvent.KEYCODE_PLUS] = VK_OEM_PLUS; - -// keymapAndroid[KeyEvent.KEYCODE_ALT_LEFT] = VK_LMENU; -// keymapAndroid[KeyEvent.KEYCODE_ALT_RIGHT] = VK_RMENU; - -// keymapAndroid[KeyEvent.KEYCODE_AT] = (KEY_FLAG_UNICODE | 64); -// keymapAndroid[KeyEvent.KEYCODE_APOSTROPHE] = (KEY_FLAG_UNICODE | 39); -// keymapAndroid[KeyEvent.KEYCODE_BACKSLASH] = (KEY_FLAG_UNICODE | 92); -// keymapAndroid[KeyEvent.KEYCODE_COMMA] = (KEY_FLAG_UNICODE | 44); -// keymapAndroid[KeyEvent.KEYCODE_EQUALS] = (KEY_FLAG_UNICODE | 61); -// keymapAndroid[KeyEvent.KEYCODE_GRAVE] = (KEY_FLAG_UNICODE | 96); -// keymapAndroid[KeyEvent.KEYCODE_LEFT_BRACKET] = (KEY_FLAG_UNICODE | 91); -// keymapAndroid[KeyEvent.KEYCODE_RIGHT_BRACKET] = (KEY_FLAG_UNICODE | 93); -// keymapAndroid[KeyEvent.KEYCODE_MINUS] = (KEY_FLAG_UNICODE | 45); -// keymapAndroid[KeyEvent.KEYCODE_PERIOD] = (KEY_FLAG_UNICODE | 46); -// keymapAndroid[KeyEvent.KEYCODE_PLUS] = (KEY_FLAG_UNICODE | 43); -// keymapAndroid[KeyEvent.KEYCODE_POUND] = (KEY_FLAG_UNICODE | 35); -// keymapAndroid[KeyEvent.KEYCODE_SEMICOLON] = (KEY_FLAG_UNICODE | 59); -// keymapAndroid[KeyEvent.KEYCODE_SLASH] = (KEY_FLAG_UNICODE | 47); -// keymapAndroid[KeyEvent.KEYCODE_STAR] = (KEY_FLAG_UNICODE | 42); - - // special keys mapping - keymapExt = new int[256]; - keymapExt[context.getResources().getInteger(R.integer.keycode_F1)] = VK_F1; - keymapExt[context.getResources().getInteger(R.integer.keycode_F2)] = VK_F2; - keymapExt[context.getResources().getInteger(R.integer.keycode_F3)] = VK_F3; - keymapExt[context.getResources().getInteger(R.integer.keycode_F4)] = VK_F4; - keymapExt[context.getResources().getInteger(R.integer.keycode_F5)] = VK_F5; - keymapExt[context.getResources().getInteger(R.integer.keycode_F6)] = VK_F6; - keymapExt[context.getResources().getInteger(R.integer.keycode_F7)] = VK_F7; - keymapExt[context.getResources().getInteger(R.integer.keycode_F8)] = VK_F8; - keymapExt[context.getResources().getInteger(R.integer.keycode_F9)] = VK_F9; - keymapExt[context.getResources().getInteger(R.integer.keycode_F10)] = VK_F10; - keymapExt[context.getResources().getInteger(R.integer.keycode_F11)] = VK_F11; - keymapExt[context.getResources().getInteger(R.integer.keycode_F12)] = VK_F12; - keymapExt[context.getResources().getInteger(R.integer.keycode_tab)] = VK_TAB; - keymapExt[context.getResources().getInteger(R.integer.keycode_print)] = VK_PRINT; - keymapExt[context.getResources().getInteger(R.integer.keycode_insert)] = VK_INSERT | VK_EXT_KEY; - keymapExt[context.getResources().getInteger(R.integer.keycode_delete)] = VK_DELETE | VK_EXT_KEY; - keymapExt[context.getResources().getInteger(R.integer.keycode_home)] = VK_HOME | VK_EXT_KEY; - keymapExt[context.getResources().getInteger(R.integer.keycode_end)] = VK_END | VK_EXT_KEY; - keymapExt[context.getResources().getInteger(R.integer.keycode_pgup)] = VK_PRIOR | VK_EXT_KEY; - keymapExt[context.getResources().getInteger(R.integer.keycode_pgdn)] = VK_NEXT | VK_EXT_KEY; - - // numpad mapping - keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_0)] = VK_NUMPAD0; - keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_1)] = VK_NUMPAD1; - keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_2)] = VK_NUMPAD2; - keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_3)] = VK_NUMPAD3; - keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_4)] = VK_NUMPAD4; - keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_5)] = VK_NUMPAD5; - keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_6)] = VK_NUMPAD6; - keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_7)] = VK_NUMPAD7; - keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_8)] = VK_NUMPAD8; - keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_9)] = VK_NUMPAD9; - keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_numlock)] = VK_NUMLOCK; - keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_add)] = VK_ADD; - keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_comma)] = VK_DECIMAL; - keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_divide)] = VK_DIVIDE | VK_EXT_KEY; - keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_enter)] = VK_RETURN | VK_EXT_KEY; - keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_multiply)] = VK_MULTIPLY; - keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_subtract)] = VK_SUBTRACT; - keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_equals)] = (KEY_FLAG_UNICODE | 61); - keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_left_paren)] = (KEY_FLAG_UNICODE | 40); - keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_right_paren)] = (KEY_FLAG_UNICODE | 41); - - // cursor key codes - keymapExt[context.getResources().getInteger(R.integer.keycode_up)] = VK_UP | VK_EXT_KEY; - keymapExt[context.getResources().getInteger(R.integer.keycode_down)] = VK_DOWN | VK_EXT_KEY; - keymapExt[context.getResources().getInteger(R.integer.keycode_left)] = VK_LEFT | VK_EXT_KEY; - keymapExt[context.getResources().getInteger(R.integer.keycode_right)] = VK_RIGHT | VK_EXT_KEY; - keymapExt[context.getResources().getInteger(R.integer.keycode_enter)] = VK_RETURN | VK_EXT_KEY; - keymapExt[context.getResources().getInteger(R.integer.keycode_backspace)] = VK_BACK; - - // shared keys - keymapExt[context.getResources().getInteger(R.integer.keycode_win)] = VK_LWIN | VK_EXT_KEY; - keymapExt[context.getResources().getInteger(R.integer.keycode_menu)] = VK_APPS | VK_EXT_KEY; - keymapExt[context.getResources().getInteger(R.integer.keycode_esc)] = VK_ESCAPE; - -/* keymapExt[context.getResources().getInteger(R.integer.keycode_modifier_ctrl)] = VK_LCONTROL; - keymapExt[context.getResources().getInteger(R.integer.keycode_modifier_alt)] = VK_LMENU; - keymapExt[context.getResources().getInteger(R.integer.keycode_modifier_shift)] = VK_LSHIFT; -*/ - // get custom keyboard key codes - keymapExt[context.getResources().getInteger(R.integer.keycode_specialkeys_keyboard)] = EXTKEY_KBFUNCTIONKEYS; - keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_keyboard)] = EXTKEY_KBNUMPAD; - keymapExt[context.getResources().getInteger(R.integer.keycode_cursor_keyboard)] = EXTKEY_KBCURSOR; - - keymapExt[context.getResources().getInteger(R.integer.keycode_toggle_shift)] = (KEY_FLAG_TOGGLE | VK_LSHIFT); - keymapExt[context.getResources().getInteger(R.integer.keycode_toggle_ctrl)] = (KEY_FLAG_TOGGLE | VK_LCONTROL); - keymapExt[context.getResources().getInteger(R.integer.keycode_toggle_alt)] = (KEY_FLAG_TOGGLE | VK_LMENU); - keymapExt[context.getResources().getInteger(R.integer.keycode_toggle_win)] = (KEY_FLAG_TOGGLE | VK_LWIN); - - initialized = true; - } - - public void reset(KeyProcessingListener listener) { - shiftPressed = false; - ctrlPressed = false; - altPressed = false; - winPressed = false; - setKeyProcessingListener(listener); - } - - public void setKeyProcessingListener(KeyProcessingListener listener) { - this.listener = listener; - } - - public boolean processAndroidKeyEvent(KeyEvent event) { - switch (event.getAction()) { - // we only process down events - case KeyEvent.ACTION_UP: { - return false; - } - - case KeyEvent.ACTION_DOWN: { - boolean modifierActive = isModifierPressed(); - // if a modifier is pressed we will send a VK event (if possible) so that key combinations will be - // recognized correctly. Otherwise we will send the unicode key. At the end we will reset all modifiers - // and notifiy our listener. - int vkcode = getVirtualKeyCode(event.getKeyCode()); - if ((vkcode & KEY_FLAG_UNICODE) != 0) - listener.processUnicodeKey(vkcode & (~KEY_FLAG_UNICODE)); - // if we got a valid vkcode send it - except for letters/numbers if a modifier is active - else if (vkcode > 0 && (event.getMetaState() & (KeyEvent.META_ALT_ON | KeyEvent.META_SHIFT_ON | KeyEvent.META_SYM_ON)) == 0) { - listener.processVirtualKey(vkcode, true); - listener.processVirtualKey(vkcode, false); - } else if (event.isShiftPressed() && vkcode != 0) { - listener.processVirtualKey(VK_LSHIFT, true); - listener.processVirtualKey(vkcode, true); - listener.processVirtualKey(vkcode, false); - listener.processVirtualKey(VK_LSHIFT, false); - } else if (event.getUnicodeChar() != 0) - listener.processUnicodeKey(event.getUnicodeChar()); - else - return false; - - // reset any pending toggle states if a modifier was pressed - if (modifierActive) - resetModifierKeysAfterInput(false); - return true; - } - - case KeyEvent.ACTION_MULTIPLE: { - String str = event.getCharacters(); - for (int i = 0; i < str.length(); i++) - listener.processUnicodeKey(str.charAt(i)); - return true; - } - - default: - break; - } - return false; - } - - public void processCustomKeyEvent(int keycode) { - int extCode = getExtendedKeyCode(keycode); - if (extCode == 0) - return; - - // toggle button pressed? - if ((extCode & KEY_FLAG_TOGGLE) != 0) { - processToggleButton(extCode & (~KEY_FLAG_TOGGLE)); - return; - } - - // keyboard switch button pressed? - if (extCode == EXTKEY_KBFUNCTIONKEYS || extCode == EXTKEY_KBNUMPAD || extCode == EXTKEY_KBCURSOR) { - switchKeyboard(extCode); - return; - } - - // nope - see if we got a unicode or vk - if ((extCode & KEY_FLAG_UNICODE) != 0) - listener.processUnicodeKey(extCode & (~KEY_FLAG_UNICODE)); - else { - listener.processVirtualKey(extCode, true); - listener.processVirtualKey(extCode, false); - } - - resetModifierKeysAfterInput(false); - } - - public void sendAltF4() { - listener.processVirtualKey(VK_LMENU, true); - listener.processVirtualKey(VK_F4, true); - listener.processVirtualKey(VK_F4, false); - listener.processVirtualKey(VK_LMENU, false); - } - - private boolean isModifierPressed() { - return (shiftPressed || ctrlPressed || altPressed || winPressed); - } - - public int getModifierState(int keycode) { - int modifierCode = getExtendedKeyCode(keycode); - - // check and get real modifier keycode - if ((modifierCode & KEY_FLAG_TOGGLE) == 0) - return -1; - modifierCode = modifierCode & (~KEY_FLAG_TOGGLE); - - switch (modifierCode) { - case VK_LSHIFT: { - return (shiftPressed ? (isShiftLocked ? KEYSTATE_LOCKED : KEYSTATE_ON) : KEYSTATE_OFF); - } - case VK_LCONTROL: { - return (ctrlPressed ? (isCtrlLocked ? KEYSTATE_LOCKED : KEYSTATE_ON) : KEYSTATE_OFF); - } - case VK_LMENU: { - return (altPressed ? (isAltLocked ? KEYSTATE_LOCKED : KEYSTATE_ON) : KEYSTATE_OFF); - } - case VK_LWIN: { - return (winPressed ? (isWinLocked ? KEYSTATE_LOCKED : KEYSTATE_ON) : KEYSTATE_OFF); - } - } - - return -1; - } - - private int getVirtualKeyCode(int keycode) { - if (keycode >= 0 && keycode <= 0xFF) - return keymapAndroid[keycode]; - return 0; - } - - private int getExtendedKeyCode(int keycode) { - if (keycode >= 0 && keycode <= 0xFF) - return keymapExt[keycode]; - return 0; - } - - private void processToggleButton(int keycode) { - switch (keycode) { - case VK_LSHIFT: { - if (!checkToggleModifierLock(VK_LSHIFT)) { - isShiftLocked = false; - shiftPressed = !shiftPressed; - listener.processVirtualKey(VK_LSHIFT, shiftPressed); - } else - isShiftLocked = true; - break; - } - case VK_LCONTROL: { - if (!checkToggleModifierLock(VK_LCONTROL)) { - isCtrlLocked = false; - ctrlPressed = !ctrlPressed; - listener.processVirtualKey(VK_LCONTROL, ctrlPressed); - } else - isCtrlLocked = true; - break; - } - case VK_LMENU: { - if (!checkToggleModifierLock(VK_LMENU)) { - isAltLocked = false; - altPressed = !altPressed; - listener.processVirtualKey(VK_LMENU, altPressed); - } else - isAltLocked = true; - break; - } - case VK_LWIN: { - if (!checkToggleModifierLock(VK_LWIN)) { - isWinLocked = false; - winPressed = !winPressed; - listener.processVirtualKey(VK_LWIN | VK_EXT_KEY, winPressed); - } else - isWinLocked = true; - break; - } - } - listener.modifiersChanged(); - } - - public void clearlAllModifiers() { - resetModifierKeysAfterInput(true); - } - - private void resetModifierKeysAfterInput(boolean force) { - if (shiftPressed && (!isShiftLocked || force)) { - listener.processVirtualKey(VK_LSHIFT, false); - shiftPressed = false; - } - if (ctrlPressed && (!isCtrlLocked || force)) { - listener.processVirtualKey(VK_LCONTROL, false); - ctrlPressed = false; - } - if (altPressed && (!isAltLocked || force)) { - listener.processVirtualKey(VK_LMENU, false); - altPressed = false; - } - if (winPressed && (!isWinLocked || force)) { - listener.processVirtualKey(VK_LWIN | VK_EXT_KEY, false); - winPressed = false; - } - - if (listener != null) - listener.modifiersChanged(); - } - - private void switchKeyboard(int keycode) { - switch (keycode) { - case EXTKEY_KBFUNCTIONKEYS: { - listener.switchKeyboard(KEYBOARD_TYPE_FUNCTIONKEYS); - break; - } - - case EXTKEY_KBNUMPAD: { - listener.switchKeyboard(KEYBOARD_TYPE_NUMPAD); - break; - } - - case EXTKEY_KBCURSOR: { - listener.switchKeyboard(KEYBOARD_TYPE_CURSOR); - break; - } - - default: - break; - } - } - - private boolean checkToggleModifierLock(int keycode) { - long now = System.currentTimeMillis(); - - // was the same modifier hit? - if (lastModifierKeyCode != keycode) { - lastModifierKeyCode = keycode; - lastModifierTime = now; - return false; - } - - // within a certain time interval? - if (lastModifierTime + 800 > now) { - lastModifierTime = 0; - return true; - } else { - lastModifierTime = now; - return false; - } - } - - // interface that gets called for input handling - public interface KeyProcessingListener { - abstract void processVirtualKey(int virtualKeyCode, boolean down); - - abstract void processUnicodeKey(int unicodeKey); - - abstract void switchKeyboard(int keyboardType); - - abstract void modifiersChanged(); - } - +public class KeyboardMapper +{ + public static final int KEYBOARD_TYPE_FUNCTIONKEYS = 1; + public static final int KEYBOARD_TYPE_NUMPAD = 2; + public static final int KEYBOARD_TYPE_CURSOR = 3; + + // defines key states for modifier keys - locked means on and no auto-release if an other key is + // pressed + public static final int KEYSTATE_ON = 1; + public static final int KEYSTATE_LOCKED = 2; + public static final int KEYSTATE_OFF = 3; + final static int VK_LBUTTON = 0x01; + final static int VK_RBUTTON = 0x02; + final static int VK_CANCEL = 0x03; + final static int VK_MBUTTON = 0x04; + final static int VK_XBUTTON1 = 0x05; + final static int VK_XBUTTON2 = 0x06; + final static int VK_BACK = 0x08; + final static int VK_TAB = 0x09; + final static int VK_CLEAR = 0x0C; + final static int VK_RETURN = 0x0D; + final static int VK_SHIFT = 0x10; + final static int VK_CONTROL = 0x11; + final static int VK_MENU = 0x12; + final static int VK_PAUSE = 0x13; + final static int VK_CAPITAL = 0x14; + final static int VK_KANA = 0x15; + final static int VK_HANGUEL = 0x15; + final static int VK_HANGUL = 0x15; + final static int VK_JUNJA = 0x17; + final static int VK_FINAL = 0x18; + final static int VK_HANJA = 0x19; + final static int VK_KANJI = 0x19; + final static int VK_ESCAPE = 0x1B; + final static int VK_CONVERT = 0x1C; + final static int VK_NONCONVERT = 0x1D; + final static int VK_ACCEPT = 0x1E; + final static int VK_MODECHANGE = 0x1F; + final static int VK_SPACE = 0x20; + final static int VK_PRIOR = 0x21; + final static int VK_NEXT = 0x22; + final static int VK_END = 0x23; + final static int VK_HOME = 0x24; + final static int VK_LEFT = 0x25; + final static int VK_UP = 0x26; + final static int VK_RIGHT = 0x27; + final static int VK_DOWN = 0x28; + final static int VK_SELECT = 0x29; + final static int VK_PRINT = 0x2A; + final static int VK_EXECUTE = 0x2B; + final static int VK_SNAPSHOT = 0x2C; + final static int VK_INSERT = 0x2D; + final static int VK_DELETE = 0x2E; + final static int VK_HELP = 0x2F; + final static int VK_KEY_0 = 0x30; + final static int VK_KEY_1 = 0x31; + final static int VK_KEY_2 = 0x32; + final static int VK_KEY_3 = 0x33; + final static int VK_KEY_4 = 0x34; + final static int VK_KEY_5 = 0x35; + final static int VK_KEY_6 = 0x36; + final static int VK_KEY_7 = 0x37; + final static int VK_KEY_8 = 0x38; + final static int VK_KEY_9 = 0x39; + final static int VK_KEY_A = 0x41; + final static int VK_KEY_B = 0x42; + final static int VK_KEY_C = 0x43; + final static int VK_KEY_D = 0x44; + final static int VK_KEY_E = 0x45; + final static int VK_KEY_F = 0x46; + final static int VK_KEY_G = 0x47; + final static int VK_KEY_H = 0x48; + final static int VK_KEY_I = 0x49; + final static int VK_KEY_J = 0x4A; + final static int VK_KEY_K = 0x4B; + final static int VK_KEY_L = 0x4C; + final static int VK_KEY_M = 0x4D; + final static int VK_KEY_N = 0x4E; + final static int VK_KEY_O = 0x4F; + final static int VK_KEY_P = 0x50; + final static int VK_KEY_Q = 0x51; + final static int VK_KEY_R = 0x52; + final static int VK_KEY_S = 0x53; + final static int VK_KEY_T = 0x54; + final static int VK_KEY_U = 0x55; + final static int VK_KEY_V = 0x56; + final static int VK_KEY_W = 0x57; + final static int VK_KEY_X = 0x58; + final static int VK_KEY_Y = 0x59; + final static int VK_KEY_Z = 0x5A; + final static int VK_LWIN = 0x5B; + final static int VK_RWIN = 0x5C; + final static int VK_APPS = 0x5D; + final static int VK_SLEEP = 0x5F; + final static int VK_NUMPAD0 = 0x60; + final static int VK_NUMPAD1 = 0x61; + final static int VK_NUMPAD2 = 0x62; + final static int VK_NUMPAD3 = 0x63; + final static int VK_NUMPAD4 = 0x64; + final static int VK_NUMPAD5 = 0x65; + final static int VK_NUMPAD6 = 0x66; + final static int VK_NUMPAD7 = 0x67; + final static int VK_NUMPAD8 = 0x68; + final static int VK_NUMPAD9 = 0x69; + final static int VK_MULTIPLY = 0x6A; + final static int VK_ADD = 0x6B; + final static int VK_SEPARATOR = 0x6C; + final static int VK_SUBTRACT = 0x6D; + final static int VK_DECIMAL = 0x6E; + final static int VK_DIVIDE = 0x6F; + final static int VK_F1 = 0x70; + final static int VK_F2 = 0x71; + final static int VK_F3 = 0x72; + final static int VK_F4 = 0x73; + final static int VK_F5 = 0x74; + final static int VK_F6 = 0x75; + final static int VK_F7 = 0x76; + final static int VK_F8 = 0x77; + final static int VK_F9 = 0x78; + final static int VK_F10 = 0x79; + final static int VK_F11 = 0x7A; + final static int VK_F12 = 0x7B; + final static int VK_F13 = 0x7C; + final static int VK_F14 = 0x7D; + final static int VK_F15 = 0x7E; + final static int VK_F16 = 0x7F; + final static int VK_F17 = 0x80; + final static int VK_F18 = 0x81; + final static int VK_F19 = 0x82; + final static int VK_F20 = 0x83; + final static int VK_F21 = 0x84; + final static int VK_F22 = 0x85; + final static int VK_F23 = 0x86; + final static int VK_F24 = 0x87; + final static int VK_NUMLOCK = 0x90; + final static int VK_SCROLL = 0x91; + final static int VK_LSHIFT = 0xA0; + final static int VK_RSHIFT = 0xA1; + final static int VK_LCONTROL = 0xA2; + final static int VK_RCONTROL = 0xA3; + final static int VK_LMENU = 0xA4; + final static int VK_RMENU = 0xA5; + final static int VK_BROWSER_BACK = 0xA6; + final static int VK_BROWSER_FORWARD = 0xA7; + final static int VK_BROWSER_REFRESH = 0xA8; + final static int VK_BROWSER_STOP = 0xA9; + final static int VK_BROWSER_SEARCH = 0xAA; + final static int VK_BROWSER_FAVORITES = 0xAB; + final static int VK_BROWSER_HOME = 0xAC; + final static int VK_VOLUME_MUTE = 0xAD; + final static int VK_VOLUME_DOWN = 0xAE; + final static int VK_VOLUME_UP = 0xAF; + final static int VK_MEDIA_NEXT_TRACK = 0xB0; + final static int VK_MEDIA_PREV_TRACK = 0xB1; + final static int VK_MEDIA_STOP = 0xB2; + final static int VK_MEDIA_PLAY_PAUSE = 0xB3; + final static int VK_LAUNCH_MAIL = 0xB4; + final static int VK_LAUNCH_MEDIA_SELECT = 0xB5; + final static int VK_LAUNCH_APP1 = 0xB6; + final static int VK_LAUNCH_APP2 = 0xB7; + final static int VK_OEM_1 = 0xBA; + final static int VK_OEM_PLUS = 0xBB; + final static int VK_OEM_COMMA = 0xBC; + final static int VK_OEM_MINUS = 0xBD; + final static int VK_OEM_PERIOD = 0xBE; + final static int VK_OEM_2 = 0xBF; + final static int VK_OEM_3 = 0xC0; + final static int VK_ABNT_C1 = 0xC1; + final static int VK_ABNT_C2 = 0xC2; + final static int VK_OEM_4 = 0xDB; + final static int VK_OEM_5 = 0xDC; + final static int VK_OEM_6 = 0xDD; + final static int VK_OEM_7 = 0xDE; + final static int VK_OEM_8 = 0xDF; + final static int VK_OEM_102 = 0xE2; + final static int VK_PROCESSKEY = 0xE5; + final static int VK_PACKET = 0xE7; + final static int VK_ATTN = 0xF6; + final static int VK_CRSEL = 0xF7; + final static int VK_EXSEL = 0xF8; + final static int VK_EREOF = 0xF9; + final static int VK_PLAY = 0xFA; + final static int VK_ZOOM = 0xFB; + final static int VK_NONAME = 0xFC; + final static int VK_PA1 = 0xFD; + final static int VK_OEM_CLEAR = 0xFE; + final static int VK_UNICODE = 0x80000000; + final static int VK_EXT_KEY = 0x00000100; + // key codes to switch between custom keyboard + private final static int EXTKEY_KBFUNCTIONKEYS = 0x1100; + private final static int EXTKEY_KBNUMPAD = 0x1101; + private final static int EXTKEY_KBCURSOR = 0x1102; + // this flag indicates if we got a VK or a unicode character in our translation map + private static final int KEY_FLAG_UNICODE = 0x80000000; + // this flag indicates if the key is a toggle key (remains down when pressed and goes up if + // pressed again) + private static final int KEY_FLAG_TOGGLE = 0x40000000; + private static int[] keymapAndroid; + private static int[] keymapExt; + private static boolean initialized = false; + private KeyProcessingListener listener = null; + private boolean shiftPressed = false; + private boolean ctrlPressed = false; + private boolean altPressed = false; + private boolean winPressed = false; + private long lastModifierTime; + private int lastModifierKeyCode = -1; + private boolean isShiftLocked = false; + private boolean isCtrlLocked = false; + private boolean isAltLocked = false; + private boolean isWinLocked = false; + + public void init(Context context) + { + if (initialized == true) + return; + + keymapAndroid = new int[256]; + + keymapAndroid[KeyEvent.KEYCODE_0] = VK_KEY_0; + keymapAndroid[KeyEvent.KEYCODE_1] = VK_KEY_1; + keymapAndroid[KeyEvent.KEYCODE_2] = VK_KEY_2; + keymapAndroid[KeyEvent.KEYCODE_3] = VK_KEY_3; + keymapAndroid[KeyEvent.KEYCODE_4] = VK_KEY_4; + keymapAndroid[KeyEvent.KEYCODE_5] = VK_KEY_5; + keymapAndroid[KeyEvent.KEYCODE_6] = VK_KEY_6; + keymapAndroid[KeyEvent.KEYCODE_7] = VK_KEY_7; + keymapAndroid[KeyEvent.KEYCODE_8] = VK_KEY_8; + keymapAndroid[KeyEvent.KEYCODE_9] = VK_KEY_9; + + keymapAndroid[KeyEvent.KEYCODE_A] = VK_KEY_A; + keymapAndroid[KeyEvent.KEYCODE_B] = VK_KEY_B; + keymapAndroid[KeyEvent.KEYCODE_C] = VK_KEY_C; + keymapAndroid[KeyEvent.KEYCODE_D] = VK_KEY_D; + keymapAndroid[KeyEvent.KEYCODE_E] = VK_KEY_E; + keymapAndroid[KeyEvent.KEYCODE_F] = VK_KEY_F; + keymapAndroid[KeyEvent.KEYCODE_G] = VK_KEY_G; + keymapAndroid[KeyEvent.KEYCODE_H] = VK_KEY_H; + keymapAndroid[KeyEvent.KEYCODE_I] = VK_KEY_I; + keymapAndroid[KeyEvent.KEYCODE_J] = VK_KEY_J; + keymapAndroid[KeyEvent.KEYCODE_K] = VK_KEY_K; + keymapAndroid[KeyEvent.KEYCODE_L] = VK_KEY_L; + keymapAndroid[KeyEvent.KEYCODE_M] = VK_KEY_M; + keymapAndroid[KeyEvent.KEYCODE_N] = VK_KEY_N; + keymapAndroid[KeyEvent.KEYCODE_O] = VK_KEY_O; + keymapAndroid[KeyEvent.KEYCODE_P] = VK_KEY_P; + keymapAndroid[KeyEvent.KEYCODE_Q] = VK_KEY_Q; + keymapAndroid[KeyEvent.KEYCODE_R] = VK_KEY_R; + keymapAndroid[KeyEvent.KEYCODE_S] = VK_KEY_S; + keymapAndroid[KeyEvent.KEYCODE_T] = VK_KEY_T; + keymapAndroid[KeyEvent.KEYCODE_U] = VK_KEY_U; + keymapAndroid[KeyEvent.KEYCODE_V] = VK_KEY_V; + keymapAndroid[KeyEvent.KEYCODE_W] = VK_KEY_W; + keymapAndroid[KeyEvent.KEYCODE_X] = VK_KEY_X; + keymapAndroid[KeyEvent.KEYCODE_Y] = VK_KEY_Y; + keymapAndroid[KeyEvent.KEYCODE_Z] = VK_KEY_Z; + + keymapAndroid[KeyEvent.KEYCODE_DEL] = VK_BACK; + keymapAndroid[KeyEvent.KEYCODE_ENTER] = VK_RETURN; + keymapAndroid[KeyEvent.KEYCODE_SPACE] = VK_SPACE; + keymapAndroid[KeyEvent.KEYCODE_TAB] = VK_TAB; + // keymapAndroid[KeyEvent.KEYCODE_SHIFT_LEFT] = VK_LSHIFT; + // keymapAndroid[KeyEvent.KEYCODE_SHIFT_RIGHT] = VK_RSHIFT; + + // keymapAndroid[KeyEvent.KEYCODE_DPAD_DOWN] = VK_DOWN; + // keymapAndroid[KeyEvent.KEYCODE_DPAD_LEFT] = VK_LEFT; + // keymapAndroid[KeyEvent.KEYCODE_DPAD_RIGHT] = VK_RIGHT; + // keymapAndroid[KeyEvent.KEYCODE_DPAD_UP] = VK_UP; + + // keymapAndroid[KeyEvent.KEYCODE_COMMA] = VK_OEM_COMMA; + // keymapAndroid[KeyEvent.KEYCODE_PERIOD] = VK_OEM_PERIOD; + // keymapAndroid[KeyEvent.KEYCODE_MINUS] = VK_OEM_MINUS; + // keymapAndroid[KeyEvent.KEYCODE_PLUS] = VK_OEM_PLUS; + + // keymapAndroid[KeyEvent.KEYCODE_ALT_LEFT] = VK_LMENU; + // keymapAndroid[KeyEvent.KEYCODE_ALT_RIGHT] = VK_RMENU; + + // keymapAndroid[KeyEvent.KEYCODE_AT] = (KEY_FLAG_UNICODE | 64); + // keymapAndroid[KeyEvent.KEYCODE_APOSTROPHE] = (KEY_FLAG_UNICODE | 39); + // keymapAndroid[KeyEvent.KEYCODE_BACKSLASH] = (KEY_FLAG_UNICODE | 92); + // keymapAndroid[KeyEvent.KEYCODE_COMMA] = (KEY_FLAG_UNICODE | 44); + // keymapAndroid[KeyEvent.KEYCODE_EQUALS] = (KEY_FLAG_UNICODE | 61); + // keymapAndroid[KeyEvent.KEYCODE_GRAVE] = (KEY_FLAG_UNICODE | 96); + // keymapAndroid[KeyEvent.KEYCODE_LEFT_BRACKET] = (KEY_FLAG_UNICODE | 91); + // keymapAndroid[KeyEvent.KEYCODE_RIGHT_BRACKET] = (KEY_FLAG_UNICODE | 93); + // keymapAndroid[KeyEvent.KEYCODE_MINUS] = (KEY_FLAG_UNICODE | 45); + // keymapAndroid[KeyEvent.KEYCODE_PERIOD] = (KEY_FLAG_UNICODE | 46); + // keymapAndroid[KeyEvent.KEYCODE_PLUS] = (KEY_FLAG_UNICODE | 43); + // keymapAndroid[KeyEvent.KEYCODE_POUND] = (KEY_FLAG_UNICODE | 35); + // keymapAndroid[KeyEvent.KEYCODE_SEMICOLON] = (KEY_FLAG_UNICODE | 59); + // keymapAndroid[KeyEvent.KEYCODE_SLASH] = (KEY_FLAG_UNICODE | 47); + // keymapAndroid[KeyEvent.KEYCODE_STAR] = (KEY_FLAG_UNICODE | 42); + + // special keys mapping + keymapExt = new int[256]; + keymapExt[context.getResources().getInteger(R.integer.keycode_F1)] = VK_F1; + keymapExt[context.getResources().getInteger(R.integer.keycode_F2)] = VK_F2; + keymapExt[context.getResources().getInteger(R.integer.keycode_F3)] = VK_F3; + keymapExt[context.getResources().getInteger(R.integer.keycode_F4)] = VK_F4; + keymapExt[context.getResources().getInteger(R.integer.keycode_F5)] = VK_F5; + keymapExt[context.getResources().getInteger(R.integer.keycode_F6)] = VK_F6; + keymapExt[context.getResources().getInteger(R.integer.keycode_F7)] = VK_F7; + keymapExt[context.getResources().getInteger(R.integer.keycode_F8)] = VK_F8; + keymapExt[context.getResources().getInteger(R.integer.keycode_F9)] = VK_F9; + keymapExt[context.getResources().getInteger(R.integer.keycode_F10)] = VK_F10; + keymapExt[context.getResources().getInteger(R.integer.keycode_F11)] = VK_F11; + keymapExt[context.getResources().getInteger(R.integer.keycode_F12)] = VK_F12; + keymapExt[context.getResources().getInteger(R.integer.keycode_tab)] = VK_TAB; + keymapExt[context.getResources().getInteger(R.integer.keycode_print)] = VK_PRINT; + keymapExt[context.getResources().getInteger(R.integer.keycode_insert)] = + VK_INSERT | VK_EXT_KEY; + keymapExt[context.getResources().getInteger(R.integer.keycode_delete)] = + VK_DELETE | VK_EXT_KEY; + keymapExt[context.getResources().getInteger(R.integer.keycode_home)] = VK_HOME | VK_EXT_KEY; + keymapExt[context.getResources().getInteger(R.integer.keycode_end)] = VK_END | VK_EXT_KEY; + keymapExt[context.getResources().getInteger(R.integer.keycode_pgup)] = + VK_PRIOR | VK_EXT_KEY; + keymapExt[context.getResources().getInteger(R.integer.keycode_pgdn)] = VK_NEXT | VK_EXT_KEY; + + // numpad mapping + keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_0)] = VK_NUMPAD0; + keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_1)] = VK_NUMPAD1; + keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_2)] = VK_NUMPAD2; + keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_3)] = VK_NUMPAD3; + keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_4)] = VK_NUMPAD4; + keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_5)] = VK_NUMPAD5; + keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_6)] = VK_NUMPAD6; + keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_7)] = VK_NUMPAD7; + keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_8)] = VK_NUMPAD8; + keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_9)] = VK_NUMPAD9; + keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_numlock)] = VK_NUMLOCK; + keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_add)] = VK_ADD; + keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_comma)] = VK_DECIMAL; + keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_divide)] = + VK_DIVIDE | VK_EXT_KEY; + keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_enter)] = + VK_RETURN | VK_EXT_KEY; + keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_multiply)] = + VK_MULTIPLY; + keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_subtract)] = + VK_SUBTRACT; + keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_equals)] = + (KEY_FLAG_UNICODE | 61); + keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_left_paren)] = + (KEY_FLAG_UNICODE | 40); + keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_right_paren)] = + (KEY_FLAG_UNICODE | 41); + + // cursor key codes + keymapExt[context.getResources().getInteger(R.integer.keycode_up)] = VK_UP | VK_EXT_KEY; + keymapExt[context.getResources().getInteger(R.integer.keycode_down)] = VK_DOWN | VK_EXT_KEY; + keymapExt[context.getResources().getInteger(R.integer.keycode_left)] = VK_LEFT | VK_EXT_KEY; + keymapExt[context.getResources().getInteger(R.integer.keycode_right)] = + VK_RIGHT | VK_EXT_KEY; + keymapExt[context.getResources().getInteger(R.integer.keycode_enter)] = + VK_RETURN | VK_EXT_KEY; + keymapExt[context.getResources().getInteger(R.integer.keycode_backspace)] = VK_BACK; + + // shared keys + keymapExt[context.getResources().getInteger(R.integer.keycode_win)] = VK_LWIN | VK_EXT_KEY; + keymapExt[context.getResources().getInteger(R.integer.keycode_menu)] = VK_APPS | VK_EXT_KEY; + keymapExt[context.getResources().getInteger(R.integer.keycode_esc)] = VK_ESCAPE; + + /* keymapExt[context.getResources().getInteger(R.integer.keycode_modifier_ctrl)] = + VK_LCONTROL; keymapExt[context.getResources().getInteger(R.integer.keycode_modifier_alt)] + = VK_LMENU; + keymapExt[context.getResources().getInteger(R.integer.keycode_modifier_shift)] = + VK_LSHIFT; + */ + // get custom keyboard key codes + keymapExt[context.getResources().getInteger(R.integer.keycode_specialkeys_keyboard)] = + EXTKEY_KBFUNCTIONKEYS; + keymapExt[context.getResources().getInteger(R.integer.keycode_numpad_keyboard)] = + EXTKEY_KBNUMPAD; + keymapExt[context.getResources().getInteger(R.integer.keycode_cursor_keyboard)] = + EXTKEY_KBCURSOR; + + keymapExt[context.getResources().getInteger(R.integer.keycode_toggle_shift)] = + (KEY_FLAG_TOGGLE | VK_LSHIFT); + keymapExt[context.getResources().getInteger(R.integer.keycode_toggle_ctrl)] = + (KEY_FLAG_TOGGLE | VK_LCONTROL); + keymapExt[context.getResources().getInteger(R.integer.keycode_toggle_alt)] = + (KEY_FLAG_TOGGLE | VK_LMENU); + keymapExt[context.getResources().getInteger(R.integer.keycode_toggle_win)] = + (KEY_FLAG_TOGGLE | VK_LWIN); + + initialized = true; + } + + public void reset(KeyProcessingListener listener) + { + shiftPressed = false; + ctrlPressed = false; + altPressed = false; + winPressed = false; + setKeyProcessingListener(listener); + } + + public void setKeyProcessingListener(KeyProcessingListener listener) + { + this.listener = listener; + } + + public boolean processAndroidKeyEvent(KeyEvent event) + { + switch (event.getAction()) + { + // we only process down events + case KeyEvent.ACTION_UP: + { + return false; + } + + case KeyEvent.ACTION_DOWN: + { + boolean modifierActive = isModifierPressed(); + // if a modifier is pressed we will send a VK event (if possible) so that key + // combinations will be recognized correctly. Otherwise we will send the unicode + // key. At the end we will reset all modifiers and notifiy our listener. + int vkcode = getVirtualKeyCode(event.getKeyCode()); + if ((vkcode & KEY_FLAG_UNICODE) != 0) + listener.processUnicodeKey(vkcode & (~KEY_FLAG_UNICODE)); + // if we got a valid vkcode send it - except for letters/numbers if a modifier is + // active + else if (vkcode > 0 && + (event.getMetaState() & (KeyEvent.META_ALT_ON | KeyEvent.META_SHIFT_ON | + KeyEvent.META_SYM_ON)) == 0) + { + listener.processVirtualKey(vkcode, true); + listener.processVirtualKey(vkcode, false); + } + else if (event.isShiftPressed() && vkcode != 0) + { + listener.processVirtualKey(VK_LSHIFT, true); + listener.processVirtualKey(vkcode, true); + listener.processVirtualKey(vkcode, false); + listener.processVirtualKey(VK_LSHIFT, false); + } + else if (event.getUnicodeChar() != 0) + listener.processUnicodeKey(event.getUnicodeChar()); + else + return false; + + // reset any pending toggle states if a modifier was pressed + if (modifierActive) + resetModifierKeysAfterInput(false); + return true; + } + + case KeyEvent.ACTION_MULTIPLE: + { + String str = event.getCharacters(); + for (int i = 0; i < str.length(); i++) + listener.processUnicodeKey(str.charAt(i)); + return true; + } + + default: + break; + } + return false; + } + + public void processCustomKeyEvent(int keycode) + { + int extCode = getExtendedKeyCode(keycode); + if (extCode == 0) + return; + + // toggle button pressed? + if ((extCode & KEY_FLAG_TOGGLE) != 0) + { + processToggleButton(extCode & (~KEY_FLAG_TOGGLE)); + return; + } + + // keyboard switch button pressed? + if (extCode == EXTKEY_KBFUNCTIONKEYS || extCode == EXTKEY_KBNUMPAD || + extCode == EXTKEY_KBCURSOR) + { + switchKeyboard(extCode); + return; + } + + // nope - see if we got a unicode or vk + if ((extCode & KEY_FLAG_UNICODE) != 0) + listener.processUnicodeKey(extCode & (~KEY_FLAG_UNICODE)); + else + { + listener.processVirtualKey(extCode, true); + listener.processVirtualKey(extCode, false); + } + + resetModifierKeysAfterInput(false); + } + + public void sendAltF4() + { + listener.processVirtualKey(VK_LMENU, true); + listener.processVirtualKey(VK_F4, true); + listener.processVirtualKey(VK_F4, false); + listener.processVirtualKey(VK_LMENU, false); + } + + private boolean isModifierPressed() + { + return (shiftPressed || ctrlPressed || altPressed || winPressed); + } + + public int getModifierState(int keycode) + { + int modifierCode = getExtendedKeyCode(keycode); + + // check and get real modifier keycode + if ((modifierCode & KEY_FLAG_TOGGLE) == 0) + return -1; + modifierCode = modifierCode & (~KEY_FLAG_TOGGLE); + + switch (modifierCode) + { + case VK_LSHIFT: + { + return (shiftPressed ? (isShiftLocked ? KEYSTATE_LOCKED : KEYSTATE_ON) + : KEYSTATE_OFF); + } + case VK_LCONTROL: + { + return (ctrlPressed ? (isCtrlLocked ? KEYSTATE_LOCKED : KEYSTATE_ON) + : KEYSTATE_OFF); + } + case VK_LMENU: + { + return (altPressed ? (isAltLocked ? KEYSTATE_LOCKED : KEYSTATE_ON) : KEYSTATE_OFF); + } + case VK_LWIN: + { + return (winPressed ? (isWinLocked ? KEYSTATE_LOCKED : KEYSTATE_ON) : KEYSTATE_OFF); + } + } + + return -1; + } + + private int getVirtualKeyCode(int keycode) + { + if (keycode >= 0 && keycode <= 0xFF) + return keymapAndroid[keycode]; + return 0; + } + + private int getExtendedKeyCode(int keycode) + { + if (keycode >= 0 && keycode <= 0xFF) + return keymapExt[keycode]; + return 0; + } + + private void processToggleButton(int keycode) + { + switch (keycode) + { + case VK_LSHIFT: + { + if (!checkToggleModifierLock(VK_LSHIFT)) + { + isShiftLocked = false; + shiftPressed = !shiftPressed; + listener.processVirtualKey(VK_LSHIFT, shiftPressed); + } + else + isShiftLocked = true; + break; + } + case VK_LCONTROL: + { + if (!checkToggleModifierLock(VK_LCONTROL)) + { + isCtrlLocked = false; + ctrlPressed = !ctrlPressed; + listener.processVirtualKey(VK_LCONTROL, ctrlPressed); + } + else + isCtrlLocked = true; + break; + } + case VK_LMENU: + { + if (!checkToggleModifierLock(VK_LMENU)) + { + isAltLocked = false; + altPressed = !altPressed; + listener.processVirtualKey(VK_LMENU, altPressed); + } + else + isAltLocked = true; + break; + } + case VK_LWIN: + { + if (!checkToggleModifierLock(VK_LWIN)) + { + isWinLocked = false; + winPressed = !winPressed; + listener.processVirtualKey(VK_LWIN | VK_EXT_KEY, winPressed); + } + else + isWinLocked = true; + break; + } + } + listener.modifiersChanged(); + } + + public void clearlAllModifiers() + { + resetModifierKeysAfterInput(true); + } + + private void resetModifierKeysAfterInput(boolean force) + { + if (shiftPressed && (!isShiftLocked || force)) + { + listener.processVirtualKey(VK_LSHIFT, false); + shiftPressed = false; + } + if (ctrlPressed && (!isCtrlLocked || force)) + { + listener.processVirtualKey(VK_LCONTROL, false); + ctrlPressed = false; + } + if (altPressed && (!isAltLocked || force)) + { + listener.processVirtualKey(VK_LMENU, false); + altPressed = false; + } + if (winPressed && (!isWinLocked || force)) + { + listener.processVirtualKey(VK_LWIN | VK_EXT_KEY, false); + winPressed = false; + } + + if (listener != null) + listener.modifiersChanged(); + } + + private void switchKeyboard(int keycode) + { + switch (keycode) + { + case EXTKEY_KBFUNCTIONKEYS: + { + listener.switchKeyboard(KEYBOARD_TYPE_FUNCTIONKEYS); + break; + } + + case EXTKEY_KBNUMPAD: + { + listener.switchKeyboard(KEYBOARD_TYPE_NUMPAD); + break; + } + + case EXTKEY_KBCURSOR: + { + listener.switchKeyboard(KEYBOARD_TYPE_CURSOR); + break; + } + + default: + break; + } + } + + private boolean checkToggleModifierLock(int keycode) + { + long now = System.currentTimeMillis(); + + // was the same modifier hit? + if (lastModifierKeyCode != keycode) + { + lastModifierKeyCode = keycode; + lastModifierTime = now; + return false; + } + + // within a certain time interval? + if (lastModifierTime + 800 > now) + { + lastModifierTime = 0; + return true; + } + else + { + lastModifierTime = now; + return false; + } + } + + // interface that gets called for input handling + public interface KeyProcessingListener { + abstract void processVirtualKey(int virtualKeyCode, boolean down); + + abstract void processUnicodeKey(int unicodeKey); + + abstract void switchKeyboard(int keyboardType); + + abstract void modifiersChanged(); + } } - diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/Mouse.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/Mouse.java index 2461486..11f1d3e 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/Mouse.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/Mouse.java @@ -3,8 +3,9 @@ Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.utils; @@ -13,47 +14,51 @@ import android.content.Context; import com.freerdp.freerdpcore.presentation.ApplicationSettingsActivity; -public class Mouse { - - private final static int PTRFLAGS_LBUTTON = 0x1000; - private final static int PTRFLAGS_RBUTTON = 0x2000; - - private final static int PTRFLAGS_DOWN = 0x8000; - private final static int PTRFLAGS_MOVE = 0x0800; - - private final static int PTRFLAGS_WHEEL = 0x0200; - private final static int PTRFLAGS_WHEEL_NEGATIVE = 0x0100; - - public static int getLeftButtonEvent(Context context, boolean down) { - if (ApplicationSettingsActivity.getSwapMouseButtons(context)) - return (PTRFLAGS_RBUTTON | (down ? PTRFLAGS_DOWN : 0)); - else - return (PTRFLAGS_LBUTTON | (down ? PTRFLAGS_DOWN : 0)); - } - - public static int getRightButtonEvent(Context context, boolean down) { - if (ApplicationSettingsActivity.getSwapMouseButtons(context)) - return (PTRFLAGS_LBUTTON | (down ? PTRFLAGS_DOWN : 0)); - else - return (PTRFLAGS_RBUTTON | (down ? PTRFLAGS_DOWN : 0)); - } - - public static int getMoveEvent() { - return PTRFLAGS_MOVE; - } - - public static int getScrollEvent(Context context, boolean down) { - int flags = PTRFLAGS_WHEEL; - - // invert scrolling? - if (ApplicationSettingsActivity.getInvertScrolling(context)) - down = !down; - - if (down) - flags |= (PTRFLAGS_WHEEL_NEGATIVE | 0x0088); - else - flags |= 0x0078; - return flags; - } - +public class Mouse +{ + + private final static int PTRFLAGS_LBUTTON = 0x1000; + private final static int PTRFLAGS_RBUTTON = 0x2000; + + private final static int PTRFLAGS_DOWN = 0x8000; + private final static int PTRFLAGS_MOVE = 0x0800; + + private final static int PTRFLAGS_WHEEL = 0x0200; + private final static int PTRFLAGS_WHEEL_NEGATIVE = 0x0100; + + public static int getLeftButtonEvent(Context context, boolean down) + { + if (ApplicationSettingsActivity.getSwapMouseButtons(context)) + return (PTRFLAGS_RBUTTON | (down ? PTRFLAGS_DOWN : 0)); + else + return (PTRFLAGS_LBUTTON | (down ? PTRFLAGS_DOWN : 0)); + } + + public static int getRightButtonEvent(Context context, boolean down) + { + if (ApplicationSettingsActivity.getSwapMouseButtons(context)) + return (PTRFLAGS_LBUTTON | (down ? PTRFLAGS_DOWN : 0)); + else + return (PTRFLAGS_RBUTTON | (down ? PTRFLAGS_DOWN : 0)); + } + + public static int getMoveEvent() + { + return PTRFLAGS_MOVE; + } + + public static int getScrollEvent(Context context, boolean down) + { + int flags = PTRFLAGS_WHEEL; + + // invert scrolling? + if (ApplicationSettingsActivity.getInvertScrolling(context)) + down = !down; + + if (down) + flags |= (PTRFLAGS_WHEEL_NEGATIVE | 0x0088); + else + flags |= 0x0078; + return flags; + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/RDPFileParser.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/RDPFileParser.java index c45d41d..413050a 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/RDPFileParser.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/RDPFileParser.java @@ -3,8 +3,9 @@ Copyright 2013 Blaz Bacnik - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.utils; @@ -15,77 +16,96 @@ import java.io.IOException; import java.util.HashMap; import java.util.Locale; -public class RDPFileParser { - - private static final int MAX_ERRORS = 20; - private static final int MAX_LINES = 500; - - private HashMap options; - - public RDPFileParser() { - init(); - } - - public RDPFileParser(String filename) throws IOException { - init(); - parse(filename); - } - - private void init() { - options = new HashMap(); - } - - public void parse(String filename) throws IOException { - BufferedReader br = new BufferedReader(new FileReader(filename)); - String line = null; - - int errors = 0; - int lines = 0; - boolean ok; - - while ((line = br.readLine()) != null) { - lines++; - ok = false; - - if (errors > MAX_ERRORS || lines > MAX_LINES) { - br.close(); - throw new IOException("Parsing limits exceeded"); - } - - String[] fields = line.split(":", 3); - - if (fields.length == 3) { - if (fields[1].equals("s")) { - options.put(fields[0].toLowerCase(Locale.ENGLISH), fields[2]); - ok = true; - } else if (fields[1].equals("i")) { - try { - Integer i = Integer.parseInt(fields[2]); - options.put(fields[0].toLowerCase(Locale.ENGLISH), i); - ok = true; - } catch (NumberFormatException e) { - } - } else if (fields[1].equals("b")) { - ok = true; - } - } - - if (!ok) errors++; - } - br.close(); - } - - public String getString(String optionName) { - if (options.get(optionName) instanceof String) - return (String) options.get(optionName); - else - return null; - } - - public Integer getInteger(String optionName) { - if (options.get(optionName) instanceof Integer) - return (Integer) options.get(optionName); - else - return null; - } +public class RDPFileParser +{ + + private static final int MAX_ERRORS = 20; + private static final int MAX_LINES = 500; + + private HashMap options; + + public RDPFileParser() + { + init(); + } + + public RDPFileParser(String filename) throws IOException + { + init(); + parse(filename); + } + + private void init() + { + options = new HashMap(); + } + + public void parse(String filename) throws IOException + { + BufferedReader br = new BufferedReader(new FileReader(filename)); + String line = null; + + int errors = 0; + int lines = 0; + boolean ok; + + while ((line = br.readLine()) != null) + { + lines++; + ok = false; + + if (errors > MAX_ERRORS || lines > MAX_LINES) + { + br.close(); + throw new IOException("Parsing limits exceeded"); + } + + String[] fields = line.split(":", 3); + + if (fields.length == 3) + { + if (fields[1].equals("s")) + { + options.put(fields[0].toLowerCase(Locale.ENGLISH), fields[2]); + ok = true; + } + else if (fields[1].equals("i")) + { + try + { + Integer i = Integer.parseInt(fields[2]); + options.put(fields[0].toLowerCase(Locale.ENGLISH), i); + ok = true; + } + catch (NumberFormatException e) + { + } + } + else if (fields[1].equals("b")) + { + ok = true; + } + } + + if (!ok) + errors++; + } + br.close(); + } + + public String getString(String optionName) + { + if (options.get(optionName) instanceof String) + return (String)options.get(optionName); + else + return null; + } + + public Integer getInteger(String optionName) + { + if (options.get(optionName) instanceof Integer) + return (Integer)options.get(optionName); + else + return null; + } } diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/SeparatedListAdapter.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/SeparatedListAdapter.java index 7f8d8d2..659732d 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/SeparatedListAdapter.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/SeparatedListAdapter.java @@ -4,8 +4,9 @@ Copyright Jeff Sharkey - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ package com.freerdp.freerdpcore.utils; @@ -22,157 +23,186 @@ import com.freerdp.freerdpcore.R; import java.util.LinkedHashMap; import java.util.Map; -public class SeparatedListAdapter extends BaseAdapter { - - public final static int TYPE_SECTION_HEADER = 0; - public final Map sections = new LinkedHashMap(); - public final ArrayAdapter headers; - - public SeparatedListAdapter(Context context) { - headers = new ArrayAdapter(context, R.layout.list_header); - } - - public void addSection(String section, Adapter adapter) { - this.headers.add(section); - this.sections.put(section, adapter); - } - - public void setSectionTitle(int section, String title) { - String oldTitle = this.headers.getItem(section); - - // remove/add to headers array - this.headers.remove(oldTitle); - this.headers.insert(title, section); - - // remove/add to section map - Adapter adapter = this.sections.get(oldTitle); - this.sections.remove(oldTitle); - this.sections.put(title, adapter); - } - - public Object getItem(int position) { - for (int i = 0; i < headers.getCount(); i++) { - String section = headers.getItem(i); - Adapter adapter = sections.get(section); - - // ignore empty sections - if (adapter.getCount() > 0) { - int size = adapter.getCount() + 1; - - // check if position inside this section - if (position == 0) return section; - if (position < size) return adapter.getItem(position - 1); - - // otherwise jump into next section - position -= size; - } - } - return null; - } - - public int getCount() { - // total together all sections, plus one for each section header (except if the section is empty) - int total = 0; - for (Adapter adapter : this.sections.values()) - total += ((adapter.getCount() > 0) ? adapter.getCount() + 1 : 0); - return total; - } - - public int getViewTypeCount() { - // assume that headers count as one, then total all sections - int total = 1; - for (Adapter adapter : this.sections.values()) - total += adapter.getViewTypeCount(); - return total; - } - - public int getItemViewType(int position) { - int type = 1; - for (int i = 0; i < headers.getCount(); i++) { - String section = headers.getItem(i); - Adapter adapter = sections.get(section); - - // skip empty sections - if (adapter.getCount() > 0) { - int size = adapter.getCount() + 1; - - // check if position inside this section - if (position == 0) return TYPE_SECTION_HEADER; - if (position < size) return type + adapter.getItemViewType(position - 1); - - // otherwise jump into next section - position -= size; - type += adapter.getViewTypeCount(); - } - } - return -1; - } - - public boolean areAllItemsSelectable() { - return false; - } - - public boolean isEnabled(int position) { - return (getItemViewType(position) != TYPE_SECTION_HEADER); - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - int sectionnum = 0; - for (int i = 0; i < headers.getCount(); i++) { - String section = headers.getItem(i); - Adapter adapter = sections.get(section); - - // skip empty sections - if (adapter.getCount() > 0) { - int size = adapter.getCount() + 1; - - // check if position inside this section - if (position == 0) return headers.getView(sectionnum, convertView, parent); - if (position < size) return adapter.getView(position - 1, null, parent); - - // otherwise jump into next section - position -= size; - } - sectionnum++; - } - return null; - } - - @Override - public long getItemId(int position) { - for (int i = 0; i < headers.getCount(); i++) { - String section = headers.getItem(i); - Adapter adapter = sections.get(section); - if (adapter.getCount() > 0) { - int size = adapter.getCount() + 1; - - // check if position inside this section - if (position < size) return adapter.getItemId(position - 1); - - // otherwise jump into next section - position -= size; - } - } - return -1; - } - - public String getSectionForPosition(int position) { - int curPos = 0; - for (int i = 0; i < headers.getCount(); i++) { - String section = headers.getItem(i); - Adapter adapter = sections.get(section); - if (adapter.getCount() > 0) { - int size = adapter.getCount() + 1; - - // check if position inside this section - if (position >= curPos && position < (curPos + size)) return section.toString(); - - // otherwise jump into next section - curPos += size; - } - } - return null; - } - -} \ No newline at end of file +public class SeparatedListAdapter extends BaseAdapter +{ + + public final static int TYPE_SECTION_HEADER = 0; + public final Map sections = new LinkedHashMap(); + public final ArrayAdapter headers; + + public SeparatedListAdapter(Context context) + { + headers = new ArrayAdapter(context, R.layout.list_header); + } + + public void addSection(String section, Adapter adapter) + { + this.headers.add(section); + this.sections.put(section, adapter); + } + + public void setSectionTitle(int section, String title) + { + String oldTitle = this.headers.getItem(section); + + // remove/add to headers array + this.headers.remove(oldTitle); + this.headers.insert(title, section); + + // remove/add to section map + Adapter adapter = this.sections.get(oldTitle); + this.sections.remove(oldTitle); + this.sections.put(title, adapter); + } + + public Object getItem(int position) + { + for (int i = 0; i < headers.getCount(); i++) + { + String section = headers.getItem(i); + Adapter adapter = sections.get(section); + + // ignore empty sections + if (adapter.getCount() > 0) + { + int size = adapter.getCount() + 1; + + // check if position inside this section + if (position == 0) + return section; + if (position < size) + return adapter.getItem(position - 1); + + // otherwise jump into next section + position -= size; + } + } + return null; + } + + public int getCount() + { + // total together all sections, plus one for each section header (except if the section is + // empty) + int total = 0; + for (Adapter adapter : this.sections.values()) + total += ((adapter.getCount() > 0) ? adapter.getCount() + 1 : 0); + return total; + } + + public int getViewTypeCount() + { + // assume that headers count as one, then total all sections + int total = 1; + for (Adapter adapter : this.sections.values()) + total += adapter.getViewTypeCount(); + return total; + } + + public int getItemViewType(int position) + { + int type = 1; + for (int i = 0; i < headers.getCount(); i++) + { + String section = headers.getItem(i); + Adapter adapter = sections.get(section); + + // skip empty sections + if (adapter.getCount() > 0) + { + int size = adapter.getCount() + 1; + + // check if position inside this section + if (position == 0) + return TYPE_SECTION_HEADER; + if (position < size) + return type + adapter.getItemViewType(position - 1); + + // otherwise jump into next section + position -= size; + type += adapter.getViewTypeCount(); + } + } + return -1; + } + + public boolean areAllItemsSelectable() + { + return false; + } + + public boolean isEnabled(int position) + { + return (getItemViewType(position) != TYPE_SECTION_HEADER); + } + + @Override public View getView(int position, View convertView, ViewGroup parent) + { + int sectionnum = 0; + for (int i = 0; i < headers.getCount(); i++) + { + String section = headers.getItem(i); + Adapter adapter = sections.get(section); + + // skip empty sections + if (adapter.getCount() > 0) + { + int size = adapter.getCount() + 1; + + // check if position inside this section + if (position == 0) + return headers.getView(sectionnum, convertView, parent); + if (position < size) + return adapter.getView(position - 1, null, parent); + + // otherwise jump into next section + position -= size; + } + sectionnum++; + } + return null; + } + + @Override public long getItemId(int position) + { + for (int i = 0; i < headers.getCount(); i++) + { + String section = headers.getItem(i); + Adapter adapter = sections.get(section); + if (adapter.getCount() > 0) + { + int size = adapter.getCount() + 1; + + // check if position inside this section + if (position < size) + return adapter.getItemId(position - 1); + + // otherwise jump into next section + position -= size; + } + } + return -1; + } + + public String getSectionForPosition(int position) + { + int curPos = 0; + for (int i = 0; i < headers.getCount(); i++) + { + String section = headers.getItem(i); + Adapter adapter = sections.get(section); + if (adapter.getCount() > 0) + { + int size = adapter.getCount() + 1; + + // check if position inside this section + if (position >= curPos && position < (curPos + size)) + return section.toString(); + + // otherwise jump into next section + curPos += size; + } + } + return null; + } +} \ No newline at end of file diff --git a/client/Android/Studio/freeRDPCore/src/main/res/values-nb-rNO/strings.xml b/client/Android/Studio/freeRDPCore/src/main/res/values-nb-rNO/strings.xml new file mode 100644 index 0000000..7237c39 --- /dev/null +++ b/client/Android/Studio/freeRDPCore/src/main/res/values-nb-rNO/strings.xml @@ -0,0 +1,251 @@ + + + + Ja + Nei + Avbryt + Fortsett + Logg inn + Logg ut + + Avslutt + Om + Hjelp + Ny tilkobling + Innstilling + + Tilkobling + Koble til + Rediger + Slett + + Tastatur + Funksjonstaster + Trykkpeker + hjem + Koble fra + + Manuelle tilkoblinger + Pågående økter + + Koble til datamaskin + + Logg inn + No Servers + Kobler til … + Kobler fra … + Mistet tilknytning + Feil passord + Ugyldig brukernavn + Ny tilkobling + + Vert + Etikett + Vertsnavn + Port + Identitetsdetaljer + Identitetsdetaljer + Brukernavn + Passord + Domene + Innstillinger + Skjerm + Skjeminnstillinger + Farger + + Palett (8-biters) + Høy farge (15-biters) + Høy farge (16-biters) + Sann farge (24-biters) + Høyeste kvalitet (32-biters) + + + + 8 + 15 + 16 + 24 + 32 + + Oppløsning + Automatisk + Tilpass til skjerm + Tilpasset + + Automatic + Tilpass til skjerm + Egendefinert + 640x480 + 720x480 + 800x600 + 1024x768 + 1280x1024 + 1440x900 + 1920x1080 + 1920x1200 + + + + automatic + fitscreen + custom + 640x480 + 720x480 + 800x600 + 1024x768 + 1280x1024 + 1440x900 + 1920x1080 + 1920x1200 + + Bredde + Høyde + Ytelse + Ytelsesinnstillinger + RemoteFX + GFX + H264 + Skrivebordsbakgrunn + Skriftglatting + Skrivebordskomposisjon + Vindusinnhold under dragning + Menyanimasjon + Visuelle stiler + Advansert + Avanserte innstillinger + 3G-innstillinger + 3G-skjerm + 3G-ytelse + Portner + Skru på portner + Portner-innstilinger + Videresend SD-kort + Videresend lyd + + Ikke spill + Spill på tjener + Spill på enhet + + + + 2 + 1 + 0 + + Videresend mikrofon + Sikkerhet + + Automatisk + RDP + TLS + NLA + + + + 0 + 1 + 2 + 3 + + Fjernprogram + Arbeidsmappe + Asynk-kanal + Asynk-inndata + Asynk-oppdatering + Konsollmodus + + ******* + ikke satt + Brukergrensesnitt + Skjul statusfelt + Skjul handlingsfelt + Skjul forstørrelseskontroller + Bytt museknapper + Inverter rulling + Autorulling for trykkpeker + Vis dialogvindu ved avslutning + Strømsparing + Klient + Lukk tilkoblinger ved lediggang + Sikkerhet + Godta alle sertifikater + Tøm sertifikatshurtiglager + Etter %1$d minutt + Avskrudd + + Tilkoblingsinnstillinger + Innstillinger + aFreeRDP - FreeRDP for Android + RDP-tilkoblinger + Hjelp + Om + + Avbryt uten å lagre? + Trykk "Avbryt" for å annullere!\nTrykk "Fortsett" for å angi påkrevde felter! + Klarte ikke å etablere tilknytning til tjeneren! + + Skjerminnstillingene har blitt endret til noe tjeneren støtter istedenfor. + Slettet sertifikatshurtiglageret. + Klarte ikke å slette sertifikatshurtigageret! + + Bekreft sertifikat + Identiteten til datamaskinen annensteds hen kan ikke bekreftes. Ønsker du å koble til likevel? + Skriv inn dine identitetsdetaljer + Opprett snarvei + Snarveisnavn: + Kobler til … + Logger inn … + Om aFreeRDP + Lagre tilkoblingsinnstillinger? + Ønsker du å lagre de ulagrede tilkoblingsinnstillingene? + Lagre tilkobling? + Ønsker du å lagre endringer gjort i tilkoblingsinnstillingene? + Ikke spør igjen + Avslutt program? + Er du sikker på at du vil avslutte programmet? + Slett sertifikater? + Er du sikker på at du vil slette alle sertifikater i hurtiglager? + Feilsøkingsnivå + Avlusingsinnstillinger + Klient + preference_key_client_name + Klientnavn + aFreeRDP + security.accept_certificates + security.clear_certificate_cache + power.disconnect_timeout + ui.hide_status_bar + ui.ask_on_exit + ui.auto_scroll_touchpointer + ui.invert_scrolling + ui.swap_mouse_buttons + ui.hide_zoom_controls + ui.hide_action_bar + + OFF + FATAL + ERROR + WARN + INFO + DEBUG + TRACE + + + + OFF + FATAL + ERROR + WARN + INFO + DEBUG + TRACE + + + bookmark.perf_gfx_h264 + bookmark.perf_gfx_h264 + diff --git a/client/Android/Studio/freeRDPCore/src/main/res/values/strings.xml b/client/Android/Studio/freeRDPCore/src/main/res/values/strings.xml index adcd5f2..1b0838f 100644 --- a/client/Android/Studio/freeRDPCore/src/main/res/values/strings.xml +++ b/client/Android/Studio/freeRDPCore/src/main/res/values/strings.xml @@ -5,8 +5,8 @@ No Cancel Continue - Login - Logout + Log in + Log out Exit About @@ -30,7 +30,7 @@ Connect to Computer - Login + Log in No Servers Connecting … Disconnecting … @@ -41,7 +41,7 @@ Host Label - Host + Hostname Port Credentials Credentials @@ -70,7 +70,7 @@ Resolution Automatic - Fitscreen + Fit screen Custom Automatic @@ -121,7 +121,7 @@ Gateway Enable Gateway Gateway Settings - Redirect SDCard + Redirect SD card Redirect Sound Do not play @@ -186,11 +186,11 @@ Cancel without saving? Press "Cancel" to abort!\nPress "Continue" to specify the required fields! - Failed to establish a connection to the server! + Could not establish a connection to the server! - The screen settings have changed because the server does not support the settings you specified! - Deleted the certificate cache! - Failed to delete certificate cache! + Screen settings changed to ones supported by the server instead. + Certificate cache deleted. + Could not delete the certificate cache! Verify Certificate The identity of the remote computer cannot be verified. Do you want to connect anyway? @@ -201,14 +201,14 @@ Logging in … About aFreeRDP Save Connection Settings? - Your connection settings have not been saved! Do you want to save them? + Do you want to save your unsaved connection settings? Save Connection? Do you want to save any changes you made to the connection settings? Do not ask again - Exit Application? - Are you sure you want to exit the application? + Exit App? + Are you sure you want to exit the app? Delete Certificates? - Are you sure you want to delete all your cached Certificates? + Are you sure you want to delete all your cached certificates? Debug Level Debug Settings Client diff --git a/client/Android/Studio/gradle/wrapper/gradle-wrapper.properties b/client/Android/Studio/gradle/wrapper/gradle-wrapper.properties index af72c19..ecf74d7 100644 --- a/client/Android/Studio/gradle/wrapper/gradle-wrapper.properties +++ b/client/Android/Studio/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip diff --git a/client/Android/android_cliprdr.c b/client/Android/android_cliprdr.c index 94d3791..414a25d 100644 --- a/client/Android/android_cliprdr.c +++ b/client/Android/android_cliprdr.c @@ -49,7 +49,7 @@ UINT android_cliprdr_send_client_format_list(CliprdrClientContext* cliprdr) if (!cliprdr) return ERROR_INVALID_PARAMETER; - androidContext* afc = (androidContext*) cliprdr->custom; + androidContext* afc = (androidContext*)cliprdr->custom; if (!afc || !afc->cliprdr) return ERROR_INVALID_PARAMETER; @@ -57,7 +57,7 @@ UINT android_cliprdr_send_client_format_list(CliprdrClientContext* cliprdr) ZeroMemory(&formatList, sizeof(CLIPRDR_FORMAT_LIST)); pFormatIds = NULL; numFormats = ClipboardGetFormatIds(afc->clipboard, &pFormatIds); - formats = (CLIPRDR_FORMAT*) calloc(numFormats, sizeof(CLIPRDR_FORMAT)); + formats = (CLIPRDR_FORMAT*)calloc(numFormats, sizeof(CLIPRDR_FORMAT)); if (!formats) goto fail; @@ -81,6 +81,7 @@ UINT android_cliprdr_send_client_format_list(CliprdrClientContext* cliprdr) formatList.msgFlags = CB_RESPONSE_OK; formatList.numFormats = numFormats; formatList.formats = formats; + formatList.msgType = CB_FORMAT_LIST; if (!afc->cliprdr->ClientFormatList) goto fail; @@ -92,8 +93,8 @@ fail: return rc; } -static UINT android_cliprdr_send_client_format_data_request( - CliprdrClientContext* cliprdr, UINT32 formatId) +static UINT android_cliprdr_send_client_format_data_request(CliprdrClientContext* cliprdr, + UINT32 formatId) { UINT rc = ERROR_INVALID_PARAMETER; CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest; @@ -102,7 +103,7 @@ static UINT android_cliprdr_send_client_format_data_request( if (!cliprdr) goto fail; - afc = (androidContext*) cliprdr->custom; + afc = (androidContext*)cliprdr->custom; if (!afc || !afc->clipboardRequestEvent || !cliprdr->ClientFormatDataRequest) goto fail; @@ -118,8 +119,7 @@ fail: return rc; } -static UINT android_cliprdr_send_client_capabilities(CliprdrClientContext* - cliprdr) +static UINT android_cliprdr_send_client_capabilities(CliprdrClientContext* cliprdr) { CLIPRDR_CAPABILITIES capabilities; CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet; @@ -128,8 +128,7 @@ static UINT android_cliprdr_send_client_capabilities(CliprdrClientContext* return ERROR_INVALID_PARAMETER; capabilities.cCapabilitiesSets = 1; - capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*) & - (generalCapabilitySet); + capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*)&(generalCapabilitySet); generalCapabilitySet.capabilitySetType = CB_CAPSTYPE_GENERAL; generalCapabilitySet.capabilitySetLength = 12; generalCapabilitySet.version = CB_CAPS_VERSION_2; @@ -143,7 +142,7 @@ static UINT android_cliprdr_send_client_capabilities(CliprdrClientContext* * @return 0 on success, otherwise a Win32 error code */ static UINT android_cliprdr_monitor_ready(CliprdrClientContext* cliprdr, - CLIPRDR_MONITOR_READY* monitorReady) + const CLIPRDR_MONITOR_READY* monitorReady) { UINT rc; androidContext* afc; @@ -151,7 +150,7 @@ static UINT android_cliprdr_monitor_ready(CliprdrClientContext* cliprdr, if (!cliprdr || !monitorReady) return ERROR_INVALID_PARAMETER; - afc = (androidContext*) cliprdr->custom; + afc = (androidContext*)cliprdr->custom; if (!afc) return ERROR_INVALID_PARAMETER; @@ -172,7 +171,7 @@ static UINT android_cliprdr_monitor_ready(CliprdrClientContext* cliprdr, * @return 0 on success, otherwise a Win32 error code */ static UINT android_cliprdr_server_capabilities(CliprdrClientContext* cliprdr, - CLIPRDR_CAPABILITIES* capabilities) + const CLIPRDR_CAPABILITIES* capabilities) { UINT32 index; CLIPRDR_CAPABILITY_SET* capabilitySet; @@ -181,7 +180,7 @@ static UINT android_cliprdr_server_capabilities(CliprdrClientContext* cliprdr, if (!cliprdr || !capabilities) return ERROR_INVALID_PARAMETER; - afc = (androidContext*) cliprdr->custom; + afc = (androidContext*)cliprdr->custom; if (!afc) return ERROR_INVALID_PARAMETER; @@ -193,8 +192,8 @@ static UINT android_cliprdr_server_capabilities(CliprdrClientContext* cliprdr, if ((capabilitySet->capabilitySetType == CB_CAPSTYPE_GENERAL) && (capabilitySet->capabilitySetLength >= CB_CAPSTYPE_GENERAL_LEN)) { - CLIPRDR_GENERAL_CAPABILITY_SET* generalCapabilitySet - = (CLIPRDR_GENERAL_CAPABILITY_SET*) capabilitySet; + CLIPRDR_GENERAL_CAPABILITY_SET* generalCapabilitySet = + (CLIPRDR_GENERAL_CAPABILITY_SET*)capabilitySet; afc->clipboardCapabilities = generalCapabilitySet->generalFlags; break; } @@ -209,7 +208,7 @@ static UINT android_cliprdr_server_capabilities(CliprdrClientContext* cliprdr, * @return 0 on success, otherwise a Win32 error code */ static UINT android_cliprdr_server_format_list(CliprdrClientContext* cliprdr, - CLIPRDR_FORMAT_LIST* formatList) + const CLIPRDR_FORMAT_LIST* formatList) { UINT rc; UINT32 index; @@ -219,7 +218,7 @@ static UINT android_cliprdr_server_format_list(CliprdrClientContext* cliprdr, if (!cliprdr || !formatList) return ERROR_INVALID_PARAMETER; - afc = (androidContext*) cliprdr->custom; + afc = (androidContext*)cliprdr->custom; if (!afc) return ERROR_INVALID_PARAMETER; @@ -238,8 +237,7 @@ static UINT android_cliprdr_server_format_list(CliprdrClientContext* cliprdr, return CHANNEL_RC_OK; afc->numServerFormats = formatList->numFormats; - afc->serverFormats = (CLIPRDR_FORMAT*) calloc(afc->numServerFormats, - sizeof(CLIPRDR_FORMAT)); + afc->serverFormats = (CLIPRDR_FORMAT*)calloc(afc->numServerFormats, sizeof(CLIPRDR_FORMAT)); if (!afc->serverFormats) return CHANNEL_RC_NO_MEMORY; @@ -251,8 +249,7 @@ static UINT android_cliprdr_server_format_list(CliprdrClientContext* cliprdr, if (formatList->formats[index].formatName) { - afc->serverFormats[index].formatName = _strdup( - formatList->formats[index].formatName); + afc->serverFormats[index].formatName = _strdup(formatList->formats[index].formatName); if (!afc->serverFormats[index].formatName) return CHANNEL_RC_NO_MEMORY; @@ -265,16 +262,16 @@ static UINT android_cliprdr_server_format_list(CliprdrClientContext* cliprdr, if (format->formatId == CF_UNICODETEXT) { - if ((rc = android_cliprdr_send_client_format_data_request(cliprdr, - CF_UNICODETEXT)) != CHANNEL_RC_OK) + if ((rc = android_cliprdr_send_client_format_data_request(cliprdr, CF_UNICODETEXT)) != + CHANNEL_RC_OK) return rc; break; } else if (format->formatId == CF_TEXT) { - if ((rc = android_cliprdr_send_client_format_data_request(cliprdr, - CF_TEXT)) != CHANNEL_RC_OK) + if ((rc = android_cliprdr_send_client_format_data_request(cliprdr, CF_TEXT)) != + CHANNEL_RC_OK) return rc; break; @@ -289,9 +286,9 @@ static UINT android_cliprdr_server_format_list(CliprdrClientContext* cliprdr, * * @return 0 on success, otherwise a Win32 error code */ -static UINT android_cliprdr_server_format_list_response( - CliprdrClientContext* cliprdr, - CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse) +static UINT +android_cliprdr_server_format_list_response(CliprdrClientContext* cliprdr, + const CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse) { if (!cliprdr || !formatListResponse) return ERROR_INVALID_PARAMETER; @@ -304,9 +301,9 @@ static UINT android_cliprdr_server_format_list_response( * * @return 0 on success, otherwise a Win32 error code */ -static UINT android_cliprdr_server_lock_clipboard_data(CliprdrClientContext* - cliprdr, - CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData) +static UINT +android_cliprdr_server_lock_clipboard_data(CliprdrClientContext* cliprdr, + const CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData) { if (!cliprdr || !lockClipboardData) return ERROR_INVALID_PARAMETER; @@ -320,8 +317,7 @@ static UINT android_cliprdr_server_lock_clipboard_data(CliprdrClientContext* * @return 0 on success, otherwise a Win32 error code */ static UINT android_cliprdr_server_unlock_clipboard_data( - CliprdrClientContext* cliprdr, - CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData) + CliprdrClientContext* cliprdr, const CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData) { if (!cliprdr || !unlockClipboardData) return ERROR_INVALID_PARAMETER; @@ -334,9 +330,9 @@ static UINT android_cliprdr_server_unlock_clipboard_data( * * @return 0 on success, otherwise a Win32 error code */ -static UINT android_cliprdr_server_format_data_request(CliprdrClientContext* - cliprdr, - CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest) +static UINT +android_cliprdr_server_format_data_request(CliprdrClientContext* cliprdr, + const CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest) { UINT rc; BYTE* data; @@ -348,14 +344,14 @@ static UINT android_cliprdr_server_format_data_request(CliprdrClientContext* if (!cliprdr || !formatDataRequest || !cliprdr->ClientFormatDataResponse) return ERROR_INVALID_PARAMETER; - afc = (androidContext*) cliprdr->custom; + afc = (androidContext*)cliprdr->custom; if (!afc) return ERROR_INVALID_PARAMETER; ZeroMemory(&response, sizeof(CLIPRDR_FORMAT_DATA_RESPONSE)); formatId = formatDataRequest->requestedFormatId; - data = (BYTE*) ClipboardGetData(afc->clipboard, formatId, &size); + data = (BYTE*)ClipboardGetData(afc->clipboard, formatId, &size); response.msgFlags = CB_RESPONSE_OK; response.dataLen = size; response.requestedFormatData = data; @@ -377,9 +373,9 @@ static UINT android_cliprdr_server_format_data_request(CliprdrClientContext* * * @return 0 on success, otherwise a Win32 error code */ -static UINT android_cliprdr_server_format_data_response( - CliprdrClientContext* cliprdr, - CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse) +static UINT +android_cliprdr_server_format_data_response(CliprdrClientContext* cliprdr, + const CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse) { BYTE* data; UINT32 size; @@ -392,12 +388,12 @@ static UINT android_cliprdr_server_format_data_response( if (!cliprdr || !formatDataResponse) return ERROR_INVALID_PARAMETER; - afc = (androidContext*) cliprdr->custom; + afc = (androidContext*)cliprdr->custom; if (!afc) return ERROR_INVALID_PARAMETER; - instance = ((rdpContext*) afc)->instance; + instance = ((rdpContext*)afc)->instance; if (!instance) return ERROR_INVALID_PARAMETER; @@ -421,8 +417,7 @@ static UINT android_cliprdr_server_format_data_response( size = formatDataResponse->dataLen; - if (!ClipboardSetData(afc->clipboard, formatId, - formatDataResponse->requestedFormatData, size)) + if (!ClipboardSetData(afc->clipboard, formatId, formatDataResponse->requestedFormatData, size)) return ERROR_INTERNAL_ERROR; SetEvent(afc->clipboardRequestEvent); @@ -433,7 +428,7 @@ static UINT android_cliprdr_server_format_data_response( jstring jdata; jboolean attached; formatId = ClipboardRegisterFormat(afc->clipboard, "UTF8_STRING"); - data = (void*) ClipboardGetData(afc->clipboard, formatId, &size); + data = (void*)ClipboardGetData(afc->clipboard, formatId, &size); attached = jni_attach_thread(&env); size = strnlen(data, size); jdata = jniNewStringUTF(env, data, size); @@ -454,8 +449,7 @@ static UINT android_cliprdr_server_format_data_response( * @return 0 on success, otherwise a Win32 error code */ static UINT android_cliprdr_server_file_contents_request( - CliprdrClientContext* cliprdr, - CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) + CliprdrClientContext* cliprdr, const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) { if (!cliprdr || !fileContentsRequest) return ERROR_INVALID_PARAMETER; @@ -469,8 +463,7 @@ static UINT android_cliprdr_server_file_contents_request( * @return 0 on success, otherwise a Win32 error code */ static UINT android_cliprdr_server_file_contents_response( - CliprdrClientContext* cliprdr, - CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse) + CliprdrClientContext* cliprdr, const CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse) { if (!cliprdr || !fileContentsResponse) return ERROR_INVALID_PARAMETER; @@ -498,20 +491,17 @@ BOOL android_cliprdr_init(androidContext* afc, CliprdrClientContext* cliprdr) afc->cliprdr = cliprdr; afc->clipboard = clipboard; afc->clipboardRequestEvent = hevent; - cliprdr->custom = (void*) afc; + cliprdr->custom = (void*)afc; cliprdr->MonitorReady = android_cliprdr_monitor_ready; cliprdr->ServerCapabilities = android_cliprdr_server_capabilities; cliprdr->ServerFormatList = android_cliprdr_server_format_list; cliprdr->ServerFormatListResponse = android_cliprdr_server_format_list_response; cliprdr->ServerLockClipboardData = android_cliprdr_server_lock_clipboard_data; - cliprdr->ServerUnlockClipboardData = - android_cliprdr_server_unlock_clipboard_data; + cliprdr->ServerUnlockClipboardData = android_cliprdr_server_unlock_clipboard_data; cliprdr->ServerFormatDataRequest = android_cliprdr_server_format_data_request; cliprdr->ServerFormatDataResponse = android_cliprdr_server_format_data_response; - cliprdr->ServerFileContentsRequest = - android_cliprdr_server_file_contents_request; - cliprdr->ServerFileContentsResponse = - android_cliprdr_server_file_contents_response; + cliprdr->ServerFileContentsRequest = android_cliprdr_server_file_contents_request; + cliprdr->ServerFileContentsResponse = android_cliprdr_server_file_contents_response; return TRUE; } diff --git a/client/Android/android_cliprdr.h b/client/Android/android_cliprdr.h index af142c2..8404d9a 100644 --- a/client/Android/android_cliprdr.h +++ b/client/Android/android_cliprdr.h @@ -25,12 +25,9 @@ #include "android_freerdp.h" -FREERDP_LOCAL UINT android_cliprdr_send_client_format_list( - CliprdrClientContext* cliprdr); +FREERDP_LOCAL UINT android_cliprdr_send_client_format_list(CliprdrClientContext* cliprdr); -FREERDP_LOCAL BOOL android_cliprdr_init(androidContext* afc, - CliprdrClientContext* cliprdr); -FREERDP_LOCAL BOOL android_cliprdr_uninit(androidContext* afc, - CliprdrClientContext* cliprdr); +FREERDP_LOCAL BOOL android_cliprdr_init(androidContext* afc, CliprdrClientContext* cliprdr); +FREERDP_LOCAL BOOL android_cliprdr_uninit(androidContext* afc, CliprdrClientContext* cliprdr); #endif /* FREERDP_CLIENT_ANDROID_CLIPRDR_H */ diff --git a/client/Android/android_event.c b/client/Android/android_event.c index de04157..aa6c647 100644 --- a/client/Android/android_event.c +++ b/client/Android/android_event.c @@ -37,8 +37,7 @@ BOOL android_push_event(freerdp* inst, ANDROID_EVENT* event) int new_size; void* new_events; new_size = aCtx->event_queue->size * 2; - new_events = realloc((void*) aCtx->event_queue->events, - sizeof(ANDROID_EVENT*) * new_size); + new_events = realloc((void*)aCtx->event_queue->events, sizeof(ANDROID_EVENT*) * new_size); if (!new_events) return FALSE; @@ -85,7 +84,7 @@ static BOOL android_process_event(ANDROID_EVENT_QUEUE* queue, freerdp* inst) { ANDROID_EVENT* event; rdpContext* context = inst->context; - androidContext* afc = (androidContext*) context; + androidContext* afc = (androidContext*)context; while (android_peek_event(queue)) { @@ -93,20 +92,19 @@ static BOOL android_process_event(ANDROID_EVENT_QUEUE* queue, freerdp* inst) if (event->type == EVENT_TYPE_KEY) { - ANDROID_EVENT_KEY* key_event = (ANDROID_EVENT_KEY*) event; + ANDROID_EVENT_KEY* key_event = (ANDROID_EVENT_KEY*)event; inst->input->KeyboardEvent(inst->input, key_event->flags, key_event->scancode); android_event_free((ANDROID_EVENT*)key_event); } else if (event->type == EVENT_TYPE_KEY_UNICODE) { - ANDROID_EVENT_KEY* key_event = (ANDROID_EVENT_KEY*) event; - inst->input->UnicodeKeyboardEvent(inst->input, key_event->flags, - key_event->scancode); + ANDROID_EVENT_KEY* key_event = (ANDROID_EVENT_KEY*)event; + inst->input->UnicodeKeyboardEvent(inst->input, key_event->flags, key_event->scancode); android_event_free((ANDROID_EVENT*)key_event); } else if (event->type == EVENT_TYPE_CURSOR) { - ANDROID_EVENT_CURSOR* cursor_event = (ANDROID_EVENT_CURSOR*) event; + ANDROID_EVENT_CURSOR* cursor_event = (ANDROID_EVENT_CURSOR*)event; inst->input->MouseEvent(inst->input, cursor_event->flags, cursor_event->x, cursor_event->y); android_event_free((ANDROID_EVENT*)cursor_event); @@ -115,7 +113,7 @@ static BOOL android_process_event(ANDROID_EVENT_QUEUE* queue, freerdp* inst) { UINT32 size; UINT32 formatId; - ANDROID_EVENT_CLIPBOARD* clipboard_event = (ANDROID_EVENT_CLIPBOARD*) event; + ANDROID_EVENT_CLIPBOARD* clipboard_event = (ANDROID_EVENT_CLIPBOARD*)event; formatId = ClipboardRegisterFormat(afc->clipboard, "UTF8_STRING"); size = clipboard_event->data_length; @@ -179,7 +177,7 @@ BOOL android_check_handle(freerdp* inst) ANDROID_EVENT_KEY* android_event_key_new(int flags, UINT16 scancode) { ANDROID_EVENT_KEY* event; - event = (ANDROID_EVENT_KEY*) calloc(1, sizeof(ANDROID_EVENT_KEY)); + event = (ANDROID_EVENT_KEY*)calloc(1, sizeof(ANDROID_EVENT_KEY)); if (!event) return NULL; @@ -195,15 +193,16 @@ static void android_event_key_free(ANDROID_EVENT_KEY* event) free(event); } -ANDROID_EVENT_KEY* android_event_unicodekey_new(UINT16 key) +ANDROID_EVENT_KEY* android_event_unicodekey_new(UINT16 flags, UINT16 key) { ANDROID_EVENT_KEY* event; - event = (ANDROID_EVENT_KEY*) calloc(1, sizeof(ANDROID_EVENT_KEY)); + event = (ANDROID_EVENT_KEY*)calloc(1, sizeof(ANDROID_EVENT_KEY)); if (!event) return NULL; event->type = EVENT_TYPE_KEY_UNICODE; + event->flags = flags; event->scancode = key; return event; } @@ -216,7 +215,7 @@ static void android_event_unicodekey_free(ANDROID_EVENT_KEY* event) ANDROID_EVENT_CURSOR* android_event_cursor_new(UINT16 flags, UINT16 x, UINT16 y) { ANDROID_EVENT_CURSOR* event; - event = (ANDROID_EVENT_CURSOR*) calloc(1, sizeof(ANDROID_EVENT_CURSOR)); + event = (ANDROID_EVENT_CURSOR*)calloc(1, sizeof(ANDROID_EVENT_CURSOR)); if (!event) return NULL; @@ -236,7 +235,7 @@ static void android_event_cursor_free(ANDROID_EVENT_CURSOR* event) ANDROID_EVENT* android_event_disconnect_new(void) { ANDROID_EVENT* event; - event = (ANDROID_EVENT*) calloc(1, sizeof(ANDROID_EVENT)); + event = (ANDROID_EVENT*)calloc(1, sizeof(ANDROID_EVENT)); if (!event) return NULL; @@ -250,11 +249,10 @@ static void android_event_disconnect_free(ANDROID_EVENT* event) free(event); } -ANDROID_EVENT_CLIPBOARD* android_event_clipboard_new(void* data, - int data_length) +ANDROID_EVENT_CLIPBOARD* android_event_clipboard_new(void* data, int data_length) { ANDROID_EVENT_CLIPBOARD* event; - event = (ANDROID_EVENT_CLIPBOARD*) calloc(1, sizeof(ANDROID_EVENT_CLIPBOARD)); + event = (ANDROID_EVENT_CLIPBOARD*)calloc(1, sizeof(ANDROID_EVENT_CLIPBOARD)); if (!event) return NULL; @@ -291,7 +289,7 @@ BOOL android_event_queue_init(freerdp* inst) { androidContext* aCtx = (androidContext*)inst->context; ANDROID_EVENT_QUEUE* queue; - queue = (ANDROID_EVENT_QUEUE*) calloc(1, sizeof(ANDROID_EVENT_QUEUE)); + queue = (ANDROID_EVENT_QUEUE*)calloc(1, sizeof(ANDROID_EVENT_QUEUE)); if (!queue) { @@ -309,7 +307,7 @@ BOOL android_event_queue_init(freerdp* inst) return FALSE; } - queue->events = (ANDROID_EVENT**) calloc(queue->size, sizeof(ANDROID_EVENT*)); + queue->events = (ANDROID_EVENT**)calloc(queue->size, sizeof(ANDROID_EVENT*)); if (!queue->events) { diff --git a/client/Android/android_event.h b/client/Android/android_event.h index 584d672..b2d7bf2 100644 --- a/client/Android/android_event.h +++ b/client/Android/android_event.h @@ -14,11 +14,11 @@ #include #include -#define EVENT_TYPE_KEY 1 -#define EVENT_TYPE_CURSOR 2 -#define EVENT_TYPE_DISCONNECT 3 -#define EVENT_TYPE_KEY_UNICODE 4 -#define EVENT_TYPE_CLIPBOARD 5 +#define EVENT_TYPE_KEY 1 +#define EVENT_TYPE_CURSOR 2 +#define EVENT_TYPE_DISCONNECT 3 +#define EVENT_TYPE_KEY_UNICODE 4 +#define EVENT_TYPE_CLIPBOARD 5 struct _ANDROID_EVENT { @@ -65,14 +65,11 @@ FREERDP_LOCAL BOOL android_push_event(freerdp* inst, ANDROID_EVENT* event); FREERDP_LOCAL HANDLE android_get_handle(freerdp* inst); FREERDP_LOCAL BOOL android_check_handle(freerdp* inst); -FREERDP_LOCAL ANDROID_EVENT_KEY* android_event_key_new(int flags, - UINT16 scancode); -FREERDP_LOCAL ANDROID_EVENT_KEY* android_event_unicodekey_new(UINT16 key); -FREERDP_LOCAL ANDROID_EVENT_CURSOR* android_event_cursor_new(UINT16 flags, - UINT16 x, UINT16 y); +FREERDP_LOCAL ANDROID_EVENT_KEY* android_event_key_new(int flags, UINT16 scancode); +FREERDP_LOCAL ANDROID_EVENT_KEY* android_event_unicodekey_new(UINT16 flags, UINT16 key); +FREERDP_LOCAL ANDROID_EVENT_CURSOR* android_event_cursor_new(UINT16 flags, UINT16 x, UINT16 y); FREERDP_LOCAL ANDROID_EVENT* android_event_disconnect_new(void); -FREERDP_LOCAL ANDROID_EVENT_CLIPBOARD* android_event_clipboard_new(void* data, - int data_length); +FREERDP_LOCAL ANDROID_EVENT_CLIPBOARD* android_event_clipboard_new(void* data, int data_length); FREERDP_LOCAL void android_event_free(ANDROID_EVENT* event); diff --git a/client/Android/android_freerdp.c b/client/Android/android_freerdp.c index dbf9c7b..f269b46 100644 --- a/client/Android/android_freerdp.c +++ b/client/Android/android_freerdp.c @@ -9,7 +9,8 @@ Copyright 2016 Armin Novak This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ #ifdef HAVE_CONFIG_H @@ -55,99 +56,75 @@ #define TAG CLIENT_TAG("android") /* Defines the JNI version supported by this library. */ -#define FREERDP_JNI_VERSION "2.0.0" +#define FREERDP_JNI_VERSION "2.2.0" -static void android_OnChannelConnectedEventHandler( - void* context, - ChannelConnectedEventArgs* e) +static void android_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e) { rdpSettings* settings; androidContext* afc; if (!context || !e) { - WLog_FATAL(TAG, "%s(context=%p, EventArgs=%p", - __FUNCTION__, context, (void*) e); + WLog_FATAL(TAG, "%s(context=%p, EventArgs=%p", __FUNCTION__, context, (void*)e); return; } - afc = (androidContext*) context; + afc = (androidContext*)context; settings = afc->rdpCtx.settings; if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) { if (settings->SoftwareGdi) { - gdi_graphics_pipeline_init(afc->rdpCtx.gdi, - (RdpgfxClientContext*) e->pInterface); + gdi_graphics_pipeline_init(afc->rdpCtx.gdi, (RdpgfxClientContext*)e->pInterface); } else { WLog_WARN(TAG, "GFX without software GDI requested. " - " This is not supported, add /gdi:sw"); + " This is not supported, add /gdi:sw"); } } else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) { - android_cliprdr_init(afc, (CliprdrClientContext*) e->pInterface); + android_cliprdr_init(afc, (CliprdrClientContext*)e->pInterface); } } -static void android_OnChannelDisconnectedEventHandler( - void* context, ChannelDisconnectedEventArgs* e) +static void android_OnChannelDisconnectedEventHandler(void* context, + ChannelDisconnectedEventArgs* e) { rdpSettings* settings; androidContext* afc; if (!context || !e) { - WLog_FATAL(TAG, "%s(context=%p, EventArgs=%p", - __FUNCTION__, context, (void*) e); + WLog_FATAL(TAG, "%s(context=%p, EventArgs=%p", __FUNCTION__, context, (void*)e); return; } - afc = (androidContext*) context; + afc = (androidContext*)context; settings = afc->rdpCtx.settings; if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) { if (settings->SoftwareGdi) { - gdi_graphics_pipeline_uninit(afc->rdpCtx.gdi, - (RdpgfxClientContext*) e->pInterface); + gdi_graphics_pipeline_uninit(afc->rdpCtx.gdi, (RdpgfxClientContext*)e->pInterface); } else { WLog_WARN(TAG, "GFX without software GDI requested. " - " This is not supported, add /gdi:sw"); + " This is not supported, add /gdi:sw"); } } else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) { - android_cliprdr_uninit(afc, (CliprdrClientContext*) e->pInterface); + android_cliprdr_uninit(afc, (CliprdrClientContext*)e->pInterface); } } static BOOL android_begin_paint(rdpContext* context) { - rdpGdi* gdi; - HGDI_WND hwnd; - - if (!context) - return FALSE; - - gdi = context->gdi; - - if (!gdi || !gdi->primary || !gdi->primary->hdc) - return FALSE; - - hwnd = gdi->primary->hdc->hwnd; - - if (!hwnd || !hwnd->invalid) - return FALSE; - - hwnd->invalid->null = TRUE; - hwnd->ninvalid = 0; return TRUE; } @@ -182,7 +159,7 @@ static BOOL android_end_paint(rdpContext* context) ninvalid = hwnd->ninvalid; - if (ninvalid == 0) + if (ninvalid < 1) return TRUE; cinvalid = hwnd->cinvalid; @@ -203,8 +180,11 @@ static BOOL android_end_paint(rdpContext* context) y2 = MAX(y2, cinvalid[i].y + cinvalid[i].h); } - freerdp_callback("OnGraphicsUpdate", "(JIIII)V", (jlong)context->instance, - x1, y1, x2 - x1, y2 - y1); + freerdp_callback("OnGraphicsUpdate", "(JIIII)V", (jlong)context->instance, x1, y1, x2 - x1, + y2 - y1); + + hwnd->invalid->null = TRUE; + hwnd->ninvalid = 0; return TRUE; } @@ -213,9 +193,9 @@ static BOOL android_desktop_resize(rdpContext* context) if (!context || !context->instance || !context->settings) return FALSE; - freerdp_callback("OnGraphicsResize", "(JIII)V", - (jlong)context->instance, context->settings->DesktopWidth, - context->settings->DesktopHeight, context->settings->ColorDepth); + freerdp_callback("OnGraphicsResize", "(JIII)V", (jlong)context->instance, + context->settings->DesktopWidth, context->settings->DesktopHeight, + context->settings->ColorDepth); return TRUE; } @@ -223,44 +203,17 @@ static BOOL android_pre_connect(freerdp* instance) { int rc; rdpSettings* settings; - BOOL bitmap_cache; if (!instance) return FALSE; settings = instance->settings; - if (!settings || !settings->OrderSupport) + if (!settings) return FALSE; - 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] = TRUE; - 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] = 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; - rc = PubSub_SubscribeChannelConnected( - instance->context->pubSub, - android_OnChannelConnectedEventHandler); + rc = PubSub_SubscribeChannelConnected(instance->context->pubSub, + android_OnChannelConnectedEventHandler); if (rc != CHANNEL_RC_OK) { @@ -268,9 +221,8 @@ static BOOL android_pre_connect(freerdp* instance) return FALSE; } - rc = PubSub_SubscribeChannelDisconnected( - instance->context->pubSub, - android_OnChannelDisconnectedEventHandler); + rc = PubSub_SubscribeChannelDisconnected(instance->context->pubSub, + android_OnChannelDisconnectedEventHandler); if (rc != CHANNEL_RC_OK) { @@ -278,8 +230,7 @@ static BOOL android_pre_connect(freerdp* instance) return FALSE; } - if (!freerdp_client_load_addins(instance->context->channels, - instance->settings)) + if (!freerdp_client_load_addins(instance->context->channels, instance->settings)) { WLog_ERR(TAG, "Failed to load addins [%l08X]", GetLastError()); return FALSE; @@ -303,8 +254,7 @@ static void android_Pointer_Free(rdpContext* context, rdpPointer* pointer) return; } -static BOOL android_Pointer_Set(rdpContext* context, - const rdpPointer* pointer) +static BOOL android_Pointer_Set(rdpContext* context, const rdpPointer* pointer) { if (!context) return FALSE; @@ -312,8 +262,7 @@ static BOOL android_Pointer_Set(rdpContext* context, return TRUE; } -static BOOL android_Pointer_SetPosition(rdpContext* context, - UINT32 x, UINT32 y) +static BOOL android_Pointer_SetPosition(rdpContext* context, UINT32 x, UINT32 y) { if (!context) return FALSE; @@ -375,9 +324,8 @@ static BOOL android_post_connect(freerdp* instance) instance->update->BeginPaint = android_begin_paint; instance->update->EndPaint = android_end_paint; instance->update->DesktopResize = android_desktop_resize; - freerdp_callback("OnSettingsChanged", "(JIII)V", (jlong)instance, - settings->DesktopWidth, settings->DesktopHeight, - settings->ColorDepth); + freerdp_callback("OnSettingsChanged", "(JIII)V", (jlong)instance, settings->DesktopWidth, + settings->DesktopHeight, settings->ColorDepth); freerdp_callback("OnConnectionSuccess", "(J)V", (jlong)instance); return TRUE; } @@ -388,8 +336,8 @@ static void android_post_disconnect(freerdp* instance) gdi_free(instance); } -static BOOL android_authenticate_int(freerdp* instance, char** username, - char** password, char** domain, const char* cb_name) +static BOOL android_authenticate_int(freerdp* instance, char** username, char** password, + char** domain, const char* cb_name) { JNIEnv* env; jboolean attached = jni_attach_thread(&env); @@ -397,12 +345,11 @@ static BOOL android_authenticate_int(freerdp* instance, char** username, jobject jstr2 = create_string_builder(env, *domain); jobject jstr3 = create_string_builder(env, *password); jboolean res; - res = freerdp_callback_bool_result( - cb_name, - "(JLjava/lang/StringBuilder;" - "Ljava/lang/StringBuilder;" - "Ljava/lang/StringBuilder;)Z", - (jlong)instance, jstr1, jstr2, jstr3); + res = freerdp_callback_bool_result(cb_name, + "(JLjava/lang/StringBuilder;" + "Ljava/lang/StringBuilder;" + "Ljava/lang/StringBuilder;)Z", + (jlong)instance, jstr1, jstr2, jstr3); if (res == JNI_TRUE) { @@ -421,24 +368,20 @@ static BOOL android_authenticate_int(freerdp* instance, char** username, return ((res == JNI_TRUE) ? TRUE : FALSE); } -static BOOL android_authenticate(freerdp* instance, char** username, - char** password, char** domain) +static BOOL android_authenticate(freerdp* instance, char** username, char** password, char** domain) { - return android_authenticate_int(instance, username, password, domain, - "OnAuthenticate"); + return android_authenticate_int(instance, username, password, domain, "OnAuthenticate"); } -static BOOL android_gw_authenticate(freerdp* instance, char** username, - char** password, char** domain) +static BOOL android_gw_authenticate(freerdp* instance, char** username, char** password, + char** domain) { - return android_authenticate_int(instance, username, password, domain, - "OnGatewayAuthenticate"); + return android_authenticate_int(instance, username, password, domain, "OnGatewayAuthenticate"); } -static DWORD android_verify_certificate( - freerdp* instance, const char* common_name, - const char* subject, const char* issuer, - const char* fingerprint, BOOL host_mismatch) +static DWORD android_verify_certificate(freerdp* instance, const char* common_name, + const char* subject, const char* issuer, + const char* fingerprint, BOOL host_mismatch) { WLog_DBG(TAG, "Certificate details:"); WLog_DBG(TAG, "\tSubject: %s", subject); @@ -454,9 +397,10 @@ static DWORD android_verify_certificate( jstring jstr1 = (*env)->NewStringUTF(env, subject); jstring jstr2 = (*env)->NewStringUTF(env, issuer); jstring jstr3 = (*env)->NewStringUTF(env, fingerprint); - jint res = freerdp_callback_int_result("OnVerifyCertificate", - "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)I", - (jlong)instance, jstr0, jstr1, jstr2, jstr3, host_mismatch); + jint res = freerdp_callback_int_result( + "OnVerifyCertificate", + "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)I", + (jlong)instance, jstr0, jstr1, jstr2, jstr3, host_mismatch); if (attached == JNI_TRUE) jni_detach_thread(); @@ -464,14 +408,11 @@ static DWORD android_verify_certificate( return res; } -static DWORD android_verify_changed_certificate(freerdp* instance, - const char* common_name, - const char* subject, - const char* issuer, - const char* new_fingerprint, - const char* old_subject, - const char* old_issuer, - const char* old_fingerprint) +static DWORD android_verify_changed_certificate(freerdp* instance, const char* common_name, + const char* subject, const char* issuer, + const char* new_fingerprint, + const char* old_subject, const char* old_issuer, + const char* old_fingerprint) { JNIEnv* env; jboolean attached = jni_attach_thread(&env); @@ -482,10 +423,11 @@ static DWORD android_verify_changed_certificate(freerdp* instance, jstring jstr4 = (*env)->NewStringUTF(env, old_subject); jstring jstr5 = (*env)->NewStringUTF(env, old_issuer); jstring jstr6 = (*env)->NewStringUTF(env, old_fingerprint); - jint res = freerdp_callback_int_result("OnVerifyChangedCertificate", - "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;" - "Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I", - (jlong)instance, jstr0, jstr1, jstr2, jstr3, jstr4, jstr5, jstr6); + jint res = freerdp_callback_int_result( + "OnVerifyChangedCertificate", + "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;" + "Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I", + (jlong)instance, jstr0, jstr1, jstr2, jstr3, jstr4, jstr5, jstr6); if (attached == JNI_TRUE) jni_detach_thread(); @@ -497,7 +439,7 @@ static DWORD WINAPI jni_input_thread(LPVOID arg) { HANDLE event[2]; wMessageQueue* queue; - freerdp* instance = (freerdp*) arg; + freerdp* instance = (freerdp*)arg; WLog_DBG(TAG, "input_thread Start."); if (!(queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE))) @@ -506,8 +448,7 @@ static DWORD WINAPI jni_input_thread(LPVOID arg) if (!(event[0] = android_get_handle(instance))) goto disconnect; - if (!(event[1] = freerdp_get_message_queue_event_handle(instance, - FREERDP_INPUT_MESSAGE_QUEUE))) + if (!(event[1] = freerdp_get_message_queue_event_handle(instance, FREERDP_INPUT_MESSAGE_QUEUE))) goto disconnect; do @@ -528,8 +469,7 @@ static DWORD WINAPI jni_input_thread(LPVOID arg) if (android_check_handle(instance) != TRUE) break; - } - while (1); + } while (1); WLog_DBG(TAG, "input_thread Quit."); disconnect: @@ -548,7 +488,7 @@ static int android_freerdp_run(freerdp* instance) const rdpSettings* settings = instance->context->settings; rdpContext* context = instance->context; BOOL async_input = settings->AsyncInput; - WLog_DBG(TAG, "AsyncInput=%"PRIu8"", settings->AsyncInput); + WLog_DBG(TAG, "AsyncInput=%" PRIu8 "", settings->AsyncInput); if (async_input) { @@ -584,7 +524,8 @@ static int android_freerdp_run(freerdp* instance) if ((status == WAIT_FAILED)) { - WLog_ERR(TAG, "WaitForMultipleObjects failed with %"PRIu32" [%08lX]", status, GetLastError()); + WLog_ERR(TAG, "WaitForMultipleObjects failed with %" PRIu32 " [%08lX]", status, + GetLastError()); break; } @@ -592,8 +533,8 @@ static int android_freerdp_run(freerdp* instance) { /* TODO: Auto reconnect if (xf_auto_reconnect(instance)) - continue; - */ + continue; + */ WLog_ERR(TAG, "Failed to check FreeRDP file descriptor"); status = GetLastError(); break; @@ -618,6 +559,9 @@ disconnect: if (async_input && inputThread) { + wMessageQueue* input_queue = + freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE); + MessageQueue_PostQuit(input_queue, 0); WaitForSingleObject(inputThread, INFINITE); CloseHandle(inputThread); } @@ -656,7 +600,7 @@ static DWORD WINAPI android_thread_func(LPVOID param) goto fail; fail: - WLog_DBG(TAG, "Session ended with %08"PRIX32"", status); + WLog_DBG(TAG, "Session ended with %08" PRIX32 "", status); if (status == CHANNEL_RC_OK) freerdp_callback("OnDisconnected", "(J)V", (jlong)instance); @@ -687,7 +631,6 @@ static BOOL android_client_new(freerdp* instance, rdpContext* context) return TRUE; } - static void android_client_free(freerdp* instance, rdpContext* context) { if (!context) @@ -732,27 +675,26 @@ static jlong JNICALL jni_freerdp_new(JNIEnv* env, jclass cls, jobject context) if (!contextClass || !fileClass) { - WLog_FATAL(TAG, "Failed to load class references %s=%p, %s=%p", - JAVA_CONTEXT_CLASS, (void*) contextClass, JAVA_FILE_CLASS, (void*) fileClass); + WLog_FATAL(TAG, "Failed to load class references %s=%p, %s=%p", JAVA_CONTEXT_CLASS, + (void*)contextClass, JAVA_FILE_CLASS, (void*)fileClass); return (jlong)NULL; } - getFilesDirID = (*env)->GetMethodID(env, contextClass, "getFilesDir", - "()L"JAVA_FILE_CLASS";"); + getFilesDirID = + (*env)->GetMethodID(env, contextClass, "getFilesDir", "()L" JAVA_FILE_CLASS ";"); if (!getFilesDirID) { - WLog_FATAL(TAG, "Failed to find method ID getFilesDir ()L"JAVA_FILE_CLASS";"); + WLog_FATAL(TAG, "Failed to find method ID getFilesDir ()L" JAVA_FILE_CLASS ";"); return (jlong)NULL; } - getAbsolutePathID = (*env)->GetMethodID(env, fileClass, "getAbsolutePath", - "()Ljava/lang/String;"); + getAbsolutePathID = + (*env)->GetMethodID(env, fileClass, "getAbsolutePath", "()Ljava/lang/String;"); if (!getAbsolutePathID) { - WLog_FATAL(TAG, - "Failed to find method ID getAbsolutePath ()Ljava/lang/String;"); + WLog_FATAL(TAG, "Failed to find method ID getAbsolutePath ()Ljava/lang/String;"); return (jlong)NULL; } @@ -791,8 +733,7 @@ static jlong JNICALL jni_freerdp_new(JNIEnv* env, jclass cls, jobject context) if (setenv("HOME", _strdup(envStr), 1) != 0) { - WLog_FATAL(TAG, "Failed to set environemnt HOME=%s %s [%d]", - env, strerror(errno), errno); + WLog_FATAL(TAG, "Failed to set environemnt HOME=%s %s [%d]", env, strerror(errno), errno); return (jlong)NULL; } @@ -802,7 +743,7 @@ static jlong JNICALL jni_freerdp_new(JNIEnv* env, jclass cls, jobject context) if (!ctx) return (jlong)NULL; - return (jlong) ctx->instance; + return (jlong)ctx->instance; } static void JNICALL jni_freerdp_free(JNIEnv* env, jclass cls, jlong instance) @@ -817,8 +758,19 @@ static void JNICALL jni_freerdp_free(JNIEnv* env, jclass cls, jlong instance) #endif } -static jboolean JNICALL jni_freerdp_parse_arguments( - JNIEnv* env, jclass cls, jlong instance, jobjectArray arguments) +static jstring JNICALL jni_freerdp_get_last_error_string(JNIEnv* env, jclass cls, jlong instance) +{ + freerdp* inst = (freerdp*)instance; + + if (!inst || !inst->context) + return (*env)->NewStringUTF(env, ""); + + return (*env)->NewStringUTF( + env, freerdp_get_last_error_string(freerdp_get_last_error(inst->context))); +} + +static jboolean JNICALL jni_freerdp_parse_arguments(JNIEnv* env, jclass cls, jlong instance, + jobjectArray arguments) { freerdp* inst = (freerdp*)instance; int i, count; @@ -842,8 +794,7 @@ static jboolean JNICALL jni_freerdp_parse_arguments( (*env)->ReleaseStringUTFChars(env, str, raw); } - status = freerdp_client_settings_parse_command_line(inst->settings, count, argv, - FALSE); + status = freerdp_client_settings_parse_command_line(inst->settings, count, argv, FALSE); for (i = 0; i < count; i++) free(argv[i]); @@ -852,23 +803,21 @@ static jboolean JNICALL jni_freerdp_parse_arguments( return (status == 0) ? JNI_TRUE : JNI_FALSE; } -static jboolean JNICALL jni_freerdp_connect(JNIEnv* env, jclass cls, - jlong instance) +static jboolean JNICALL jni_freerdp_connect(JNIEnv* env, jclass cls, jlong instance) { freerdp* inst = (freerdp*)instance; androidContext* ctx; if (!inst || !inst->context) { - WLog_FATAL(TAG, "%s(env=%p, cls=%p, instance=%d", __FUNCTION__, - (void*) env, (void*) cls, instance); + WLog_FATAL(TAG, "%s(env=%p, cls=%p, instance=%d", __FUNCTION__, (void*)env, (void*)cls, + instance); return JNI_FALSE; } ctx = (androidContext*)inst->context; - if (!(ctx->thread = CreateThread(NULL, 0, android_thread_func, - inst, 0, NULL))) + if (!(ctx->thread = CreateThread(NULL, 0, android_thread_func, inst, 0, NULL))) { return JNI_FALSE; } @@ -876,8 +825,7 @@ static jboolean JNICALL jni_freerdp_connect(JNIEnv* env, jclass cls, return JNI_TRUE; } -static jboolean JNICALL jni_freerdp_disconnect(JNIEnv* env, jclass cls, - jlong instance) +static jboolean JNICALL jni_freerdp_disconnect(JNIEnv* env, jclass cls, jlong instance) { freerdp* inst = (freerdp*)instance; androidContext* ctx; @@ -885,8 +833,8 @@ static jboolean JNICALL jni_freerdp_disconnect(JNIEnv* env, jclass cls, if (!inst || !inst->context || !cls || !env) { - WLog_FATAL(TAG, "%s(env=%p, cls=%p, instance=%d", __FUNCTION__, - (void*) env, (void*) cls, instance); + WLog_FATAL(TAG, "%s(env=%p, cls=%p, instance=%d", __FUNCTION__, (void*)env, (void*)cls, + instance); return JNI_FALSE; } @@ -908,9 +856,9 @@ static jboolean JNICALL jni_freerdp_disconnect(JNIEnv* env, jclass cls, return JNI_TRUE; } -static jboolean JNICALL jni_freerdp_update_graphics( - JNIEnv* env, jclass cls, jlong instance, jobject bitmap, - jint x, jint y, jint width, jint height) +static jboolean JNICALL jni_freerdp_update_graphics(JNIEnv* env, jclass cls, jlong instance, + jobject bitmap, jint x, jint y, jint width, + jint height) { UINT32 DstFormat; jboolean rc; @@ -922,8 +870,8 @@ static jboolean JNICALL jni_freerdp_update_graphics( if (!env || !cls || !inst) { - WLog_FATAL(TAG, "%s(env=%p, cls=%p, instance=%d", __FUNCTION__, - (void*) env, (void*) cls, instance); + WLog_FATAL(TAG, "%s(env=%p, cls=%p, instance=%d", __FUNCTION__, (void*)env, (void*)cls, + instance); return JNI_FALSE; } @@ -977,9 +925,8 @@ static jboolean JNICALL jni_freerdp_update_graphics( return rc; } -static jboolean JNICALL jni_freerdp_send_key_event( - JNIEnv* env, jclass cls, jlong instance, - jint keycode, jboolean down) +static jboolean JNICALL jni_freerdp_send_key_event(JNIEnv* env, jclass cls, jlong instance, + jint keycode, jboolean down) { DWORD scancode; ANDROID_EVENT* event; @@ -987,7 +934,7 @@ static jboolean JNICALL jni_freerdp_send_key_event( scancode = GetVirtualScanCodeFromVirtualKeyCode(keycode, 4); int flags = (down == JNI_TRUE) ? KBD_FLAGS_DOWN : KBD_FLAGS_RELEASE; flags |= (scancode & KBDEXT) ? KBD_FLAGS_EXTENDED : 0; - event = (ANDROID_EVENT*) android_event_key_new(flags, scancode & 0xFF); + event = (ANDROID_EVENT*)android_event_key_new(flags, scancode & 0xFF); if (!event) return JNI_FALSE; @@ -998,16 +945,17 @@ static jboolean JNICALL jni_freerdp_send_key_event( return JNI_FALSE; } - WLog_DBG(TAG, "send_key_event: %"PRIu32", %d", scancode, flags); + WLog_DBG(TAG, "send_key_event: %" PRIu32 ", %d", scancode, flags); return JNI_TRUE; } -static jboolean JNICALL jni_freerdp_send_unicodekey_event( - JNIEnv* env, jclass cls, jlong instance, jint keycode) +static jboolean JNICALL jni_freerdp_send_unicodekey_event(JNIEnv* env, jclass cls, jlong instance, + jint keycode, jboolean down) { ANDROID_EVENT* event; freerdp* inst = (freerdp*)instance; - event = (ANDROID_EVENT*) android_event_unicodekey_new(keycode); + UINT16 flags = (down == JNI_TRUE) ? 0 : KBD_FLAGS_RELEASE; + event = (ANDROID_EVENT*)android_event_unicodekey_new(flags, keycode); if (!event) return JNI_FALSE; @@ -1022,12 +970,12 @@ static jboolean JNICALL jni_freerdp_send_unicodekey_event( return JNI_TRUE; } -static jboolean JNICALL jni_freerdp_send_cursor_event( - JNIEnv* env, jclass cls, jlong instance, jint x, jint y, jint flags) +static jboolean JNICALL jni_freerdp_send_cursor_event(JNIEnv* env, jclass cls, jlong instance, + jint x, jint y, jint flags) { ANDROID_EVENT* event; freerdp* inst = (freerdp*)instance; - event = (ANDROID_EVENT*) android_event_cursor_new(flags, x, y); + event = (ANDROID_EVENT*)android_event_cursor_new(flags, x, y); if (!event) return JNI_FALSE; @@ -1042,17 +990,15 @@ static jboolean JNICALL jni_freerdp_send_cursor_event( return JNI_TRUE; } -static jboolean JNICALL jni_freerdp_send_clipboard_data( - JNIEnv* env, jclass cls, - jlong instance, jstring jdata) +static jboolean JNICALL jni_freerdp_send_clipboard_data(JNIEnv* env, jclass cls, jlong instance, + jstring jdata) { ANDROID_EVENT* event; freerdp* inst = (freerdp*)instance; - const jbyte* data = jdata != NULL ? (*env)->GetStringUTFChars(env, jdata, - NULL) : NULL; + const jbyte* data = jdata != NULL ? (*env)->GetStringUTFChars(env, jdata, NULL) : NULL; int data_length = data ? strlen(data) : 0; - jboolean ret = JNI_FALSE;; - event = (ANDROID_EVENT*) android_event_clipboard_new((void*)data, data_length); + jboolean ret = JNI_FALSE; + event = (ANDROID_EVENT*)android_event_clipboard_new((void*)data, data_length); if (!event) goto out_fail; @@ -1098,83 +1044,25 @@ static jstring JNICALL jni_freerdp_get_build_config(JNIEnv* env, jclass cls) return (*env)->NewStringUTF(env, freerdp_get_build_config()); } -static JNINativeMethod methods[] = -{ - { - "freerdp_get_jni_version", - "()Ljava/lang/String;", - &jni_freerdp_get_jni_version - }, - { - "freerdp_get_version", - "()Ljava/lang/String;", - &jni_freerdp_get_version - }, - { - "freerdp_get_build_date", - "()Ljava/lang/String;", - &jni_freerdp_get_build_date - }, - { - "freerdp_get_build_revision", - "()Ljava/lang/String;", - &jni_freerdp_get_build_revision - }, - { - "freerdp_get_build_config", - "()Ljava/lang/String;", - &jni_freerdp_get_build_config - }, - { - "freerdp_new", - "(Landroid/content/Context;)J", - &jni_freerdp_new - }, - { - "freerdp_free", - "(J)V", - &jni_freerdp_free - }, - { - "freerdp_parse_arguments", - "(J[Ljava/lang/String;)Z", - &jni_freerdp_parse_arguments - }, - { - "freerdp_connect", - "(J)Z", - &jni_freerdp_connect - }, - { - "freerdp_disconnect", - "(J)Z", - &jni_freerdp_disconnect - }, - { - "freerdp_update_graphics", - "(JLandroid/graphics/Bitmap;IIII)Z", - &jni_freerdp_update_graphics - }, - { - "freerdp_send_cursor_event", - "(JIII)Z", - &jni_freerdp_send_cursor_event - }, - { - "freerdp_send_key_event", - "(JIZ)Z", - &jni_freerdp_send_key_event - }, - { - "freerdp_send_unicodekey_event", - "(JI)Z", - &jni_freerdp_send_unicodekey_event - }, - { - "freerdp_send_clipboard_data", - "(JLjava/lang/String;)Z", - &jni_freerdp_send_clipboard_data - } +static JNINativeMethod methods[] = { + { "freerdp_get_jni_version", "()Ljava/lang/String;", &jni_freerdp_get_jni_version }, + { "freerdp_get_version", "()Ljava/lang/String;", &jni_freerdp_get_version }, + { "freerdp_get_build_date", "()Ljava/lang/String;", &jni_freerdp_get_build_date }, + { "freerdp_get_build_revision", "()Ljava/lang/String;", &jni_freerdp_get_build_revision }, + { "freerdp_get_build_config", "()Ljava/lang/String;", &jni_freerdp_get_build_config }, + { "freerdp_get_last_error_string", "(J)Ljava/lang/String;", + &jni_freerdp_get_last_error_string }, + { "freerdp_new", "(Landroid/content/Context;)J", &jni_freerdp_new }, + { "freerdp_free", "(J)V", &jni_freerdp_free }, + { "freerdp_parse_arguments", "(J[Ljava/lang/String;)Z", &jni_freerdp_parse_arguments }, + { "freerdp_connect", "(J)Z", &jni_freerdp_connect }, + { "freerdp_disconnect", "(J)Z", &jni_freerdp_disconnect }, + { "freerdp_update_graphics", "(JLandroid/graphics/Bitmap;IIII)Z", + &jni_freerdp_update_graphics }, + { "freerdp_send_cursor_event", "(JIII)Z", &jni_freerdp_send_cursor_event }, + { "freerdp_send_key_event", "(JIZ)Z", &jni_freerdp_send_key_event }, + { "freerdp_send_unicodekey_event", "(JIZ)Z", &jni_freerdp_send_unicodekey_event }, + { "freerdp_send_clipboard_data", "(JLjava/lang/String;)Z", &jni_freerdp_send_clipboard_data } }; static jclass gJavaActivityClass = NULL; @@ -1186,11 +1074,11 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) WLog_DBG(TAG, "Setting up JNI environement..."); /* - if (freerdp_handle_signals() != 0) - { - WLog_FATAL(TAG, "Failed to register signal handler"); - return -1; - } + if (freerdp_handle_signals() != 0) + { + WLog_FATAL(TAG, "Failed to register signal handler"); + return -1; + } */ if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_6) != JNI_OK) { @@ -1208,8 +1096,7 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) } // Register methods with env->RegisterNatives. - (*env)->RegisterNatives(env, activityClass, methods, - sizeof(methods) / sizeof(methods[0])); + (*env)->RegisterNatives(env, activityClass, methods, sizeof(methods) / sizeof(methods[0])); /* create global reference for class */ gJavaActivityClass = (*env)->NewGlobalRef(env, activityClass); g_JavaVm = vm; diff --git a/client/Android/android_freerdp.h b/client/Android/android_freerdp.h index ac8ca89..58d127c 100644 --- a/client/Android/android_freerdp.h +++ b/client/Android/android_freerdp.h @@ -3,8 +3,9 @@ Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at + http://mozilla.org/MPL/2.0/. */ #ifndef FREERDP_CLIENT_ANDROID_FREERDP_H @@ -41,5 +42,3 @@ struct android_context typedef struct android_context androidContext; #endif /* FREERDP_CLIENT_ANDROID_FREERDP_H */ - - diff --git a/client/Android/android_freerdp_jni.h b/client/Android/android_freerdp_jni.h index 5bf48a2..c0055f5 100644 --- a/client/Android/android_freerdp_jni.h +++ b/client/Android/android_freerdp_jni.h @@ -25,4 +25,3 @@ #define JAVA_FILE_CLASS "java/io/File" #endif /* FREERDP_CLIENT_ANDROID_FREERDP_JNI_H */ - diff --git a/client/Android/android_jni_callback.c b/client/Android/android_jni_callback.c index d8a5dcf..d57a7ca 100644 --- a/client/Android/android_jni_callback.c +++ b/client/Android/android_jni_callback.c @@ -58,7 +58,8 @@ static void jni_load_class(JNIEnv* env, const char* path, jobject* objptr) (*objptr) = (*env)->NewGlobalRef(env, object); finish: - while (0); + while (0) + ; } jint init_callback_environment(JavaVM* vm, JNIEnv* env) @@ -71,15 +72,14 @@ jint init_callback_environment(JavaVM* vm, JNIEnv* env) /* attach current thread to jvm */ jboolean jni_attach_thread(JNIEnv** env) { - if ((*jVM)->GetEnv(jVM, (void**) env, JNI_VERSION_1_4) != JNI_OK) + if ((*jVM)->GetEnv(jVM, (void**)env, JNI_VERSION_1_4) != JNI_OK) { WLog_DBG(TAG, "android_java_callback: attaching current thread"); (*jVM)->AttachCurrentThread(jVM, env, NULL); - if ((*jVM)->GetEnv(jVM, (void**) env, JNI_VERSION_1_4) != JNI_OK) + if ((*jVM)->GetEnv(jVM, (void**)env, JNI_VERSION_1_4) != JNI_OK) { - WLog_ERR(TAG, - "android_java_callback: failed to obtain current JNI environment"); + WLog_ERR(TAG, "android_java_callback: failed to obtain current JNI environment"); } return JNI_TRUE; @@ -95,8 +95,8 @@ void jni_detach_thread() } /* callback with void result */ -static void java_callback_void(jobject obj, const char* callback, - const char* signature, va_list args) +static void java_callback_void(jobject obj, const char* callback, const char* signature, + va_list args) { jclass jObjClass; jmethodID jCallback; @@ -128,8 +128,8 @@ finish: } /* callback with bool result */ -static jboolean java_callback_bool(jobject obj, const char* callback, - const char* signature, va_list args) +static jboolean java_callback_bool(jobject obj, const char* callback, const char* signature, + va_list args) { jclass jObjClass; jmethodID jCallback; @@ -164,8 +164,8 @@ finish: } /* callback with int result */ -static jint java_callback_int(jobject obj, const char* callback, - const char* signature, va_list args) +static jint java_callback_int(jobject obj, const char* callback, const char* signature, + va_list args) { jclass jObjClass; jmethodID jCallback; @@ -199,7 +199,6 @@ finish: return res; } - /* callback to freerdp class */ void freerdp_callback(const char* callback, const char* signature, ...) { @@ -209,8 +208,7 @@ void freerdp_callback(const char* callback, const char* signature, ...) va_end(vl); } -jboolean freerdp_callback_bool_result(const char* callback, - const char* signature, ...) +jboolean freerdp_callback_bool_result(const char* callback, const char* signature, ...) { va_list vl; va_start(vl, signature); @@ -219,8 +217,7 @@ jboolean freerdp_callback_bool_result(const char* callback, return res; } -jint freerdp_callback_int_result(const char* callback, const char* signature, - ...) +jint freerdp_callback_int_result(const char* callback, const char* signature, ...) { va_list vl; va_start(vl, signature); diff --git a/client/Android/android_jni_callback.h b/client/Android/android_jni_callback.h index 7f91306..861e40d 100644 --- a/client/Android/android_jni_callback.h +++ b/client/Android/android_jni_callback.h @@ -20,12 +20,9 @@ FREERDP_LOCAL jint init_callback_environment(JavaVM* vm, JNIEnv* env); FREERDP_LOCAL jboolean jni_attach_thread(JNIEnv** env); FREERDP_LOCAL void jni_detach_thread(void); -FREERDP_LOCAL void freerdp_callback(const char* callback, const char* signature, - ...); -FREERDP_LOCAL jboolean freerdp_callback_bool_result(const char* callback, - const char* signature, ...); -FREERDP_LOCAL jint freerdp_callback_int_result(const char* callback, - const char* signature, ...); +FREERDP_LOCAL void freerdp_callback(const char* callback, const char* signature, ...); +FREERDP_LOCAL jboolean freerdp_callback_bool_result(const char* callback, const char* signature, + ...); +FREERDP_LOCAL jint freerdp_callback_int_result(const char* callback, const char* signature, ...); #endif /* FREERDP_CLIENT_ANDROID_JNI_CALLBACK_H */ - diff --git a/client/Android/android_jni_utils.c b/client/Android/android_jni_utils.c index f79b39c..9c2ee38 100644 --- a/client/Android/android_jni_utils.c +++ b/client/Android/android_jni_utils.c @@ -20,7 +20,7 @@ #define TAG CLIENT_TAG("android.utils") -JavaVM *g_JavaVm; +JavaVM* g_JavaVm; JavaVM* getJavaVM() { @@ -30,7 +30,7 @@ JavaVM* getJavaVM() JNIEnv* getJNIEnv() { JNIEnv* env = NULL; - if ((*g_JavaVm)->GetEnv(g_JavaVm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) + if ((*g_JavaVm)->GetEnv(g_JavaVm, (void**)&env, JNI_VERSION_1_4) != JNI_OK) { WLog_FATAL(TAG, "Failed to obtain JNIEnv"); return NULL; @@ -38,7 +38,7 @@ JNIEnv* getJNIEnv() return env; } -jobject create_string_builder(JNIEnv *env, char* initialStr) +jobject create_string_builder(JNIEnv* env, char* initialStr) { jclass cls; jmethodID methodId; @@ -46,14 +46,14 @@ jobject create_string_builder(JNIEnv *env, char* initialStr) // get class cls = (*env)->FindClass(env, "java/lang/StringBuilder"); - if(!cls) + if (!cls) return NULL; - if(initialStr) + if (initialStr) { // get method id for constructor methodId = (*env)->GetMethodID(env, cls, "", "(Ljava/lang/String;)V"); - if(!methodId) + if (!methodId) return NULL; // create string that holds our initial string @@ -66,7 +66,7 @@ jobject create_string_builder(JNIEnv *env, char* initialStr) { // get method id for constructor methodId = (*env)->GetMethodID(env, cls, "", "()V"); - if(!methodId) + if (!methodId) return NULL; // construct new StringBuilder @@ -86,12 +86,12 @@ char* get_string_from_string_builder(JNIEnv* env, jobject strBuilder) // get class cls = (*env)->FindClass(env, "java/lang/StringBuilder"); - if(!cls) + if (!cls) return NULL; // get method id for constructor methodId = (*env)->GetMethodID(env, cls, "toString", "()Ljava/lang/String;"); - if(!methodId) + if (!methodId) return NULL; // get jstring representation of our buffer @@ -128,10 +128,10 @@ jstring jniNewStringUTF(JNIEnv* env, const char* in, int len) return NULL; } - for(i = 0; i < len; i++) + for (i = 0; i < len; i++) { unsigned char one = utf8[i]; - switch(one >> 4) + switch (one >> 4) { case 0x00: case 0x01: @@ -147,27 +147,25 @@ jstring jniNewStringUTF(JNIEnv* env, const char* in, int len) case 0x09: case 0x0a: case 0x0b: - //case 0x0f: + // case 0x0f: /* - * Bit pattern 10xx or 1111, which are illegal start bytes. - * Note: 1111 is valid for normal UTF-8, but not the - * modified UTF-8 used here. - */ + * Bit pattern 10xx or 1111, which are illegal start bytes. + * Note: 1111 is valid for normal UTF-8, but not the + * modified UTF-8 used here. + */ break; case 0x0f: case 0x0e: // Bit pattern 111x, so there are two additional bytes. if (i < (len - 2)) { - unsigned char two = utf8[i+1]; - unsigned char three = utf8[i+2]; + unsigned char two = utf8[i + 1]; + unsigned char three = utf8[i + 2]; if ((two & 0xc0) == 0x80 && (three & 0xc0) == 0x80) { i += 2; unicode[result_size++] = - ((one & 0x0f) << 12) - | ((two & 0x3f) << 6) - | (three & 0x3f); + ((one & 0x0f) << 12) | ((two & 0x3f) << 6) | (three & 0x3f); } } break; @@ -176,13 +174,11 @@ jstring jniNewStringUTF(JNIEnv* env, const char* in, int len) // Bit pattern 110x, so there is one additional byte. if (i < (len - 1)) { - unsigned char two = utf8[i+1]; + unsigned char two = utf8[i + 1]; if ((two & 0xc0) == 0x80) { i += 1; - unicode[result_size++] = - ((one & 0x1f) << 6) - | (two & 0x3f); + unicode[result_size++] = ((one & 0x1f) << 6) | (two & 0x3f); } } break; diff --git a/client/Android/android_jni_utils.h b/client/Android/android_jni_utils.h index 5414e33..0ac804d 100644 --- a/client/Android/android_jni_utils.h +++ b/client/Android/android_jni_utils.h @@ -20,15 +20,14 @@ extern "C" { #endif -FREERDP_LOCAL JNIEnv* getJNIEnv(); -FREERDP_LOCAL JavaVM* getJavaVM(); + FREERDP_LOCAL JNIEnv* getJNIEnv(); + FREERDP_LOCAL JavaVM* getJavaVM(); -FREERDP_LOCAL char* get_string_from_string_builder(JNIEnv* env, - jobject strBuilder); -FREERDP_LOCAL jobject create_string_builder(JNIEnv* env, char* initialStr); -FREERDP_LOCAL jstring jniNewStringUTF(JNIEnv* env, const char* in, int len); + FREERDP_LOCAL char* get_string_from_string_builder(JNIEnv* env, jobject strBuilder); + FREERDP_LOCAL jobject create_string_builder(JNIEnv* env, char* initialStr); + FREERDP_LOCAL jstring jniNewStringUTF(JNIEnv* env, const char* in, int len); -FREERDP_LOCAL extern JavaVM* g_JavaVm; + FREERDP_LOCAL extern JavaVM* g_JavaVm; #ifdef __cplusplus } 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/Mac/CMakeLists.txt b/client/Mac/CMakeLists.txt index 6865781..b3eb591 100644 --- a/client/Mac/CMakeLists.txt +++ b/client/Mac/CMakeLists.txt @@ -15,20 +15,24 @@ find_library(FOUNDATION_LIBRARY Foundation) find_library(COCOA_LIBRARY Cocoa) find_library(APPKIT_LIBRARY AppKit) find_library(IOKIT_LIBRARY IOKit) +find_library(COREGRAPHICS_LIBRARY CoreGraphics) mark_as_advanced(COCOA_LIBRARY FOUNDATION_LIBRARY APPKIT_LIBRARY) set(EXTRA_LIBS ${COCOA_LIBRARY} ${FOUNDATION_LIBRARY} ${APPKIT_LIBRARY} ${IOKIT_LIBRARY}) +string(TIMESTAMP VERSION_YEAR "%Y") set(MACOSX_BUNDLE_INFO_STRING "${MODULE_OUTPUT_NAME}") set(MACOSX_BUNDLE_GUI_IDENTIFIER "com.freerdp.mac") set(MACOSX_BUNDLE_BUNDLE_IDENTIFIER "FreeRDP-library.Mac") -set(MACOSX_BUNDLE_LONG_VERSION_STRING "MacFreeRDP library Version 1.1") +set(MACOSX_BUNDLE_LONG_VERSION_STRING "MacFreeRDP library Version ${FREERDP_VERSION}") set(MACOSX_BUNDLE_BUNDLE_NAME "${MODULE_OUTPUT_NAME}") -set(MACOSX_BUNDLE_SHORT_VERSION_STRING 1.1.0) -set(MACOSX_BUNDLE_BUNDLE_VERSION 1.1.0) -set(MACOSX_BUNDLE_COPYRIGHT "Copyright 2013. All Rights Reserved.") +set(MACOSX_BUNDLE_SHORT_VERSION_STRING ${FREERDP_VERSION}) +set(MACOSX_BUNDLE_BUNDLE_VERSION ${FREERDP_VERSION}) +set(MACOSX_BUNDLE_COPYRIGHT "Copyright 2013-${VERSION_YEAR}. All Rights Reserved.") -set(${MODULE_PREFIX}_XIBS PasswordDialog.xib) +set(${MODULE_PREFIX}_XIBS + CertificateDialog.xib + PasswordDialog.xib) set(${MODULE_PREFIX}_SOURCES "") @@ -39,6 +43,7 @@ set(${MODULE_PREFIX}_OBJECTIVE_SOURCES MRDPView.m Keyboard.m Clipboard.m + CertificateDialog.m PasswordDialog.m) list(APPEND ${MODULE_PREFIX}_SOURCES ${${MODULE_PREFIX}_OBJECTIVE_SOURCES}) @@ -50,6 +55,7 @@ set(${MODULE_PREFIX}_HEADERS MRDPView.h Keyboard.h Clipboard.h + CertificateDialog.h PasswordDialog.h) set(${MODULE_PREFIX}_RESOURCES "en.lproj/InfoPlist.strings") @@ -79,9 +85,9 @@ set_target_properties(${MODULE_NAME} PROPERTIES set_target_properties(${MODULE_NAME} PROPERTIES FRAMEWORK TRUE MACOSX_FRAMEWORK_IDENTIFIER com.awakecoding.${MODULE_NAME} - FRAMEWORK_VERSION 1.1.0 - MACOSX_FRAMEWORK_SHORT_VERSION_STRING 1.1.0 - MACOSX_FRAMEWORK_BUNDLE_BUNDLE_VERSION 1.1.0 + FRAMEWORK_VERSION ${FREERDP_VERSION} + MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${FREERDP_VERSION} + MACOSX_FRAMEWORK_BUNDLE_BUNDLE_VERSION ${FREERDP_VERSION} INSTALL_NAME_DIR "@executable_path/../Frameworks" MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_BINARY_DIR}/Info.plist) diff --git a/client/Mac/CertificateDialog.h b/client/Mac/CertificateDialog.h new file mode 100644 index 0000000..6c4455f --- /dev/null +++ b/client/Mac/CertificateDialog.h @@ -0,0 +1,60 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * MacFreeRDP + * + * Copyright 2018 Armin Novak + * Copyright 2018 Thicast 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. + */ + +#import + +@interface CertificateDialog : NSWindowController +{ + @public + NSTextField *textCommonName; + NSTextField *textSubject; + NSTextField *textIssuer; + NSTextField *textFingerprint; + NSTextField *textMismatch; + NSTextField *messageLabel; + NSString *serverHostname; + + BOOL hostMismatch; + BOOL changed; + int result; +} +@property(retain) IBOutlet NSTextField *textCommonName; +@property(retain) IBOutlet NSTextField *textSubject; +@property(retain) IBOutlet NSTextField *textIssuer; +@property(retain) IBOutlet NSTextField *textFingerprint; +@property(retain) IBOutlet NSTextField *textMismatch; +@property(retain) IBOutlet NSTextField *messageLabel; + +- (IBAction)onAccept:(NSObject *)sender; +- (IBAction)onTemporary:(NSObject *)sender; +- (IBAction)onCancel:(NSObject *)sender; + +@property(retain) NSString *serverHostname; +@property(retain) NSString *commonName; +@property(retain) NSString *subject; +@property(retain) NSString *issuer; +@property(retain) NSString *fingerprint; +@property BOOL hostMismatch; +@property BOOL changed; +@property(readonly) int result; + +- (int)runModal:(NSWindow *)mainWindow; + +@end diff --git a/client/Mac/CertificateDialog.m b/client/Mac/CertificateDialog.m new file mode 100644 index 0000000..152fbcd --- /dev/null +++ b/client/Mac/CertificateDialog.m @@ -0,0 +1,135 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * MacFreeRDP + * + * Copyright 2018 Armin Novak + * Copyright 2018 Thicast 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. + */ + +#import "CertificateDialog.h" +#import + +#import + +@interface CertificateDialog () + +@property int result; + +@end + +@implementation CertificateDialog + +@synthesize textCommonName; +@synthesize textFingerprint; +@synthesize textIssuer; +@synthesize textSubject; +@synthesize textMismatch; +@synthesize messageLabel; +@synthesize serverHostname; +@synthesize commonName; +@synthesize fingerprint; +@synthesize issuer; +@synthesize subject; +@synthesize hostMismatch; +@synthesize changed; +@synthesize result; + +- (id)init +{ + return [self initWithWindowNibName:@"CertificateDialog"]; +} + +- (void)windowDidLoad +{ + [super windowDidLoad]; + // Implement this method to handle any initialization after your window controller's window has + // been loaded from its nib file. + [self.window setTitle:self.serverHostname]; + if (self.changed) + [self.messageLabel setStringValue:[NSString stringWithFormat:@"Changed certificate for %@", + self.serverHostname]]; + else + [self.messageLabel setStringValue:[NSString stringWithFormat:@"New Certificate for %@", + self.serverHostname]]; + + if (!self.hostMismatch) + [self.textMismatch + setStringValue:[NSString stringWithFormat: + @"NOTE: The server name matches the certificate, good."]]; + else + [self.textMismatch + setStringValue:[NSString + stringWithFormat: + @"ATTENTION: The common name does not match the server name!"]]; + [self.textCommonName setStringValue:self.commonName]; + [self.textFingerprint setStringValue:self.fingerprint]; + [self.textIssuer setStringValue:self.issuer]; + [self.textSubject setStringValue:self.subject]; +} + +- (IBAction)onAccept:(NSObject *)sender +{ + [NSApp stopModalWithCode:1]; +} + +- (IBAction)onTemporary:(NSObject *)sender +{ + [NSApp stopModalWithCode:2]; +} + +- (IBAction)onCancel:(NSObject *)sender +{ + [NSApp stopModalWithCode:0]; +} + +- (int)runModal:(NSWindow *)mainWindow +{ + if ([mainWindow respondsToSelector:@selector(beginSheet:completionHandler:)]) + { + [mainWindow beginSheet:self.window completionHandler:nil]; + self.result = [NSApp runModalForWindow:self.window]; + [mainWindow endSheet:self.window]; + } + else + { + [NSApp beginSheet:self.window + modalForWindow:mainWindow + modalDelegate:nil + didEndSelector:nil + contextInfo:nil]; + self.result = [NSApp runModalForWindow:self.window]; + [NSApp endSheet:self.window]; + } + + [self.window orderOut:nil]; + return self.result; +} + +- (void)dealloc +{ + [textCommonName release]; + [textFingerprint release]; + [textIssuer release]; + [textSubject release]; + [messageLabel release]; + [serverHostname release]; + [commonName release]; + [fingerprint release]; + [issuer release]; + [subject release]; + [super dealloc]; +} + +@end diff --git a/client/Mac/CertificateDialog.xib b/client/Mac/CertificateDialog.xib new file mode 100644 index 0000000..c154899 --- /dev/null +++ b/client/Mac/CertificateDialog.xib @@ -0,0 +1,169 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/Mac/Clipboard.m b/client/Mac/Clipboard.m index 0d68965..a57725f 100644 --- a/client/Mac/Clipboard.m +++ b/client/Mac/Clipboard.m @@ -20,104 +20,106 @@ #import "Clipboard.h" -int mac_cliprdr_send_client_format_list(CliprdrClientContext* cliprdr) +int mac_cliprdr_send_client_format_list(CliprdrClientContext *cliprdr) { UINT32 index; UINT32 formatId; UINT32 numFormats; - UINT32* pFormatIds; - const char* formatName; - CLIPRDR_FORMAT* formats; - CLIPRDR_FORMAT_LIST formatList; - mfContext* mfc = (mfContext*) cliprdr->custom; - + UINT32 *pFormatIds; + const char *formatName; + CLIPRDR_FORMAT *formats; + CLIPRDR_FORMAT_LIST formatList = { 0 }; + mfContext *mfc = (mfContext *)cliprdr->custom; + ZeroMemory(&formatList, sizeof(CLIPRDR_FORMAT_LIST)); - + pFormatIds = NULL; numFormats = ClipboardGetFormatIds(mfc->clipboard, &pFormatIds); - - formats = (CLIPRDR_FORMAT*) calloc(numFormats, sizeof(CLIPRDR_FORMAT)); - + + formats = (CLIPRDR_FORMAT *)calloc(numFormats, sizeof(CLIPRDR_FORMAT)); + if (!formats) return -1; - + for (index = 0; index < numFormats; index++) { formatId = pFormatIds[index]; formatName = ClipboardGetFormatName(mfc->clipboard, formatId); - + formats[index].formatId = formatId; formats[index].formatName = NULL; - + if ((formatId > CF_MAX) && formatName) formats[index].formatName = _strdup(formatName); } - + formatList.msgFlags = CB_RESPONSE_OK; formatList.numFormats = numFormats; formatList.formats = formats; - + formatList.msgType = CB_FORMAT_LIST; + mfc->cliprdr->ClientFormatList(mfc->cliprdr, &formatList); - + for (index = 0; index < numFormats; index++) { free(formats[index].formatName); } - + free(pFormatIds); free(formats); - + return 1; } -int mac_cliprdr_send_client_format_list_response(CliprdrClientContext* cliprdr, BOOL status) +static int mac_cliprdr_send_client_format_list_response(CliprdrClientContext *cliprdr, 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; - + cliprdr->ClientFormatListResponse(cliprdr, &formatListResponse); - + return 1; } -int mac_cliprdr_send_client_format_data_request(CliprdrClientContext* cliprdr, UINT32 formatId) +static int mac_cliprdr_send_client_format_data_request(CliprdrClientContext *cliprdr, + UINT32 formatId) { CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest; - mfContext* mfc = (mfContext*) cliprdr->custom; - + mfContext *mfc = (mfContext *)cliprdr->custom; + ZeroMemory(&formatDataRequest, sizeof(CLIPRDR_FORMAT_DATA_REQUEST)); - + formatDataRequest.msgType = CB_FORMAT_DATA_REQUEST; formatDataRequest.msgFlags = 0; - + formatDataRequest.requestedFormatId = formatId; mfc->requestedFormatId = formatId; ResetEvent(mfc->clipboardRequestEvent); - + cliprdr->ClientFormatDataRequest(cliprdr, &formatDataRequest); - + return 1; } -int mac_cliprdr_send_client_capabilities(CliprdrClientContext* cliprdr) +static int mac_cliprdr_send_client_capabilities(CliprdrClientContext *cliprdr) { CLIPRDR_CAPABILITIES capabilities; CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet; - + capabilities.cCapabilitiesSets = 1; - capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*) &(generalCapabilitySet); - + 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; - + cliprdr->ClientCapabilities(cliprdr, &capabilities); - + return 1; } @@ -126,14 +128,15 @@ int mac_cliprdr_send_client_capabilities(CliprdrClientContext* cliprdr) * * @return 0 on success, otherwise a Win32 error code */ -UINT mac_cliprdr_monitor_ready(CliprdrClientContext* cliprdr, CLIPRDR_MONITOR_READY* monitorReady) +static UINT mac_cliprdr_monitor_ready(CliprdrClientContext *cliprdr, + const CLIPRDR_MONITOR_READY *monitorReady) { - mfContext* mfc = (mfContext*) cliprdr->custom; - + mfContext *mfc = (mfContext *)cliprdr->custom; + mfc->clipboardSync = TRUE; mac_cliprdr_send_client_capabilities(cliprdr); mac_cliprdr_send_client_format_list(cliprdr); - + return CHANNEL_RC_OK; } @@ -142,27 +145,28 @@ UINT mac_cliprdr_monitor_ready(CliprdrClientContext* cliprdr, CLIPRDR_MONITOR_RE * * @return 0 on success, otherwise a Win32 error code */ -UINT mac_cliprdr_server_capabilities(CliprdrClientContext* cliprdr, CLIPRDR_CAPABILITIES* capabilities) +static UINT mac_cliprdr_server_capabilities(CliprdrClientContext *cliprdr, + const CLIPRDR_CAPABILITIES *capabilities) { UINT32 index; - CLIPRDR_CAPABILITY_SET* capabilitySet; - mfContext* mfc = (mfContext*) cliprdr->custom; - + CLIPRDR_CAPABILITY_SET *capabilitySet; + mfContext *mfc = (mfContext *)cliprdr->custom; + for (index = 0; index < capabilities->cCapabilitiesSets; index++) { capabilitySet = &(capabilities->capabilitySets[index]); - + if ((capabilitySet->capabilitySetType == CB_CAPSTYPE_GENERAL) && (capabilitySet->capabilitySetLength >= CB_CAPSTYPE_GENERAL_LEN)) { - CLIPRDR_GENERAL_CAPABILITY_SET* generalCapabilitySet - = (CLIPRDR_GENERAL_CAPABILITY_SET*) capabilitySet; - + CLIPRDR_GENERAL_CAPABILITY_SET *generalCapabilitySet = + (CLIPRDR_GENERAL_CAPABILITY_SET *)capabilitySet; + mfc->clipboardCapabilities = generalCapabilitySet->generalFlags; break; } } - + return CHANNEL_RC_OK; } @@ -171,48 +175,49 @@ UINT mac_cliprdr_server_capabilities(CliprdrClientContext* cliprdr, CLIPRDR_CAPA * * @return 0 on success, otherwise a Win32 error code */ -UINT mac_cliprdr_server_format_list(CliprdrClientContext* cliprdr, CLIPRDR_FORMAT_LIST* formatList) +static UINT mac_cliprdr_server_format_list(CliprdrClientContext *cliprdr, + const CLIPRDR_FORMAT_LIST *formatList) { UINT32 index; - CLIPRDR_FORMAT* format; - mfContext* mfc = (mfContext*) cliprdr->custom; - + CLIPRDR_FORMAT *format; + mfContext *mfc = (mfContext *)cliprdr->custom; + if (mfc->serverFormats) { for (index = 0; index < mfc->numServerFormats; index++) { free(mfc->serverFormats[index].formatName); } - + free(mfc->serverFormats); mfc->serverFormats = NULL; mfc->numServerFormats = 0; } - + if (formatList->numFormats < 1) return CHANNEL_RC_OK; - + mfc->numServerFormats = formatList->numFormats; - mfc->serverFormats = (CLIPRDR_FORMAT*) calloc(mfc->numServerFormats, sizeof(CLIPRDR_FORMAT)); - + mfc->serverFormats = (CLIPRDR_FORMAT *)calloc(mfc->numServerFormats, sizeof(CLIPRDR_FORMAT)); + if (!mfc->serverFormats) return CHANNEL_RC_NO_MEMORY; - + for (index = 0; index < mfc->numServerFormats; index++) { mfc->serverFormats[index].formatId = formatList->formats[index].formatId; mfc->serverFormats[index].formatName = NULL; - + if (formatList->formats[index].formatName) mfc->serverFormats[index].formatName = _strdup(formatList->formats[index].formatName); } - + mac_cliprdr_send_client_format_list_response(cliprdr, TRUE); - + for (index = 0; index < mfc->numServerFormats; index++) { format = &(mfc->serverFormats[index]); - + if (format->formatId == CF_UNICODETEXT) { mac_cliprdr_send_client_format_data_request(cliprdr, CF_UNICODETEXT); @@ -229,7 +234,7 @@ UINT mac_cliprdr_server_format_list(CliprdrClientContext* cliprdr, CLIPRDR_FORMA break; } } - + return CHANNEL_RC_OK; } @@ -238,7 +243,9 @@ UINT mac_cliprdr_server_format_list(CliprdrClientContext* cliprdr, CLIPRDR_FORMA * * @return 0 on success, otherwise a Win32 error code */ -UINT mac_cliprdr_server_format_list_response(CliprdrClientContext* cliprdr, CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse) +static UINT +mac_cliprdr_server_format_list_response(CliprdrClientContext *cliprdr, + const CLIPRDR_FORMAT_LIST_RESPONSE *formatListResponse) { return CHANNEL_RC_OK; } @@ -248,7 +255,9 @@ UINT mac_cliprdr_server_format_list_response(CliprdrClientContext* cliprdr, CLIP * * @return 0 on success, otherwise a Win32 error code */ -UINT mac_cliprdr_server_lock_clipboard_data(CliprdrClientContext* cliprdr, CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData) +static UINT +mac_cliprdr_server_lock_clipboard_data(CliprdrClientContext *cliprdr, + const CLIPRDR_LOCK_CLIPBOARD_DATA *lockClipboardData) { return CHANNEL_RC_OK; } @@ -258,7 +267,9 @@ UINT mac_cliprdr_server_lock_clipboard_data(CliprdrClientContext* cliprdr, CLIPR * * @return 0 on success, otherwise a Win32 error code */ -UINT mac_cliprdr_server_unlock_clipboard_data(CliprdrClientContext* cliprdr, CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData) +static UINT +mac_cliprdr_server_unlock_clipboard_data(CliprdrClientContext *cliprdr, + const CLIPRDR_UNLOCK_CLIPBOARD_DATA *unlockClipboardData) { return CHANNEL_RC_OK; } @@ -268,34 +279,36 @@ UINT mac_cliprdr_server_unlock_clipboard_data(CliprdrClientContext* cliprdr, CLI * * @return 0 on success, otherwise a Win32 error code */ -UINT mac_cliprdr_server_format_data_request(CliprdrClientContext* cliprdr, CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest) +static UINT +mac_cliprdr_server_format_data_request(CliprdrClientContext *cliprdr, + const CLIPRDR_FORMAT_DATA_REQUEST *formatDataRequest) { - BYTE* data; + BYTE *data; UINT32 size; UINT32 formatId; CLIPRDR_FORMAT_DATA_RESPONSE response; - mfContext* mfc = (mfContext*) cliprdr->custom; - + mfContext *mfc = (mfContext *)cliprdr->custom; + ZeroMemory(&response, sizeof(CLIPRDR_FORMAT_DATA_RESPONSE)); - + formatId = formatDataRequest->requestedFormatId; - data = (BYTE*) ClipboardGetData(mfc->clipboard, formatId, &size); - + data = (BYTE *)ClipboardGetData(mfc->clipboard, formatId, &size); + response.msgFlags = CB_RESPONSE_OK; response.dataLen = size; response.requestedFormatData = data; - + if (!data) { response.msgFlags = CB_RESPONSE_FAIL; response.dataLen = 0; response.requestedFormatData = NULL; } - + cliprdr->ClientFormatDataResponse(cliprdr, &response); - + free(data); - + return CHANNEL_RC_OK; } @@ -304,62 +317,66 @@ UINT mac_cliprdr_server_format_data_request(CliprdrClientContext* cliprdr, CLIPR * * @return 0 on success, otherwise a Win32 error code */ -UINT mac_cliprdr_server_format_data_response(CliprdrClientContext* cliprdr, CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse) +static UINT +mac_cliprdr_server_format_data_response(CliprdrClientContext *cliprdr, + const CLIPRDR_FORMAT_DATA_RESPONSE *formatDataResponse) { - BYTE* data; + BYTE *data; UINT32 size; UINT32 index; UINT32 formatId; - CLIPRDR_FORMAT* format = NULL; - mfContext* mfc = (mfContext*) cliprdr->custom; - MRDPView* view = (MRDPView*) mfc->view; - + CLIPRDR_FORMAT *format = NULL; + mfContext *mfc = (mfContext *)cliprdr->custom; + MRDPView *view = (MRDPView *)mfc->view; + if (formatDataResponse->msgFlags & CB_RESPONSE_FAIL) { SetEvent(mfc->clipboardRequestEvent); return ERROR_INTERNAL_ERROR; } - + for (index = 0; index < mfc->numServerFormats; index++) { if (mfc->requestedFormatId == mfc->serverFormats[index].formatId) format = &(mfc->serverFormats[index]); } - + if (!format) { SetEvent(mfc->clipboardRequestEvent); return ERROR_INTERNAL_ERROR; } - + if (format->formatName) formatId = ClipboardRegisterFormat(mfc->clipboard, format->formatName); else formatId = format->formatId; - + size = formatDataResponse->dataLen; - + ClipboardSetData(mfc->clipboard, formatId, formatDataResponse->requestedFormatData, size); - + SetEvent(mfc->clipboardRequestEvent); - + if ((formatId == CF_TEXT) || (formatId == CF_OEMTEXT) || (formatId == CF_UNICODETEXT)) { formatId = ClipboardRegisterFormat(mfc->clipboard, "UTF8_STRING"); - - data = (void*) ClipboardGetData(mfc->clipboard, formatId, &size); - + + data = (void *)ClipboardGetData(mfc->clipboard, formatId, &size); + if (size > 1) size--; /* we need the size without the null terminator */ - - NSString* str = [[NSString alloc] initWithBytes: (void*) data length:size encoding:NSUTF8StringEncoding]; + + NSString *str = [[NSString alloc] initWithBytes:(void *)data + length:size + encoding:NSUTF8StringEncoding]; free(data); - - NSArray* types = [[NSArray alloc] initWithObjects:NSStringPboardType, nil]; + + NSArray *types = [[NSArray alloc] initWithObjects:NSStringPboardType, nil]; [view->pasteboard_wr declareTypes:types owner:view]; [view->pasteboard_wr setString:str forType:NSStringPboardType]; } - + return CHANNEL_RC_OK; } @@ -368,7 +385,9 @@ UINT mac_cliprdr_server_format_data_response(CliprdrClientContext* cliprdr, CLIP * * @return 0 on success, otherwise a Win32 error code */ -UINT mac_cliprdr_server_file_contents_request(CliprdrClientContext* cliprdr, CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) +static UINT +mac_cliprdr_server_file_contents_request(CliprdrClientContext *cliprdr, + const CLIPRDR_FILE_CONTENTS_REQUEST *fileContentsRequest) { return CHANNEL_RC_OK; } @@ -378,19 +397,20 @@ UINT mac_cliprdr_server_file_contents_request(CliprdrClientContext* cliprdr, CLI * * @return 0 on success, otherwise a Win32 error code */ -UINT mac_cliprdr_server_file_contents_response(CliprdrClientContext* cliprdr, CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse) +static UINT mac_cliprdr_server_file_contents_response( + CliprdrClientContext *cliprdr, const CLIPRDR_FILE_CONTENTS_RESPONSE *fileContentsResponse) { return CHANNEL_RC_OK; } -void mac_cliprdr_init(mfContext* mfc, CliprdrClientContext* cliprdr) +void mac_cliprdr_init(mfContext *mfc, CliprdrClientContext *cliprdr) { - cliprdr->custom = (void*) mfc; + cliprdr->custom = (void *)mfc; mfc->cliprdr = cliprdr; - + mfc->clipboard = ClipboardCreate(); mfc->clipboardRequestEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - + cliprdr->MonitorReady = mac_cliprdr_monitor_ready; cliprdr->ServerCapabilities = mac_cliprdr_server_capabilities; cliprdr->ServerFormatList = mac_cliprdr_server_format_list; @@ -403,11 +423,11 @@ void mac_cliprdr_init(mfContext* mfc, CliprdrClientContext* cliprdr) cliprdr->ServerFileContentsResponse = mac_cliprdr_server_file_contents_response; } -void mac_cliprdr_uninit(mfContext* mfc, CliprdrClientContext* cliprdr) +void mac_cliprdr_uninit(mfContext *mfc, CliprdrClientContext *cliprdr) { cliprdr->custom = NULL; mfc->cliprdr = NULL; - + ClipboardDestroy(mfc->clipboard); CloseHandle(mfc->clipboardRequestEvent); } diff --git a/client/Mac/Keyboard.h b/client/Mac/Keyboard.h index cc6f859..27efcdf 100644 --- a/client/Mac/Keyboard.h +++ b/client/Mac/Keyboard.h @@ -24,4 +24,4 @@ enum APPLE_KEYBOARD_TYPE APPLE_KEYBOARD_TYPE_JIS }; -enum APPLE_KEYBOARD_TYPE mac_detect_keyboard_type(); +enum APPLE_KEYBOARD_TYPE mac_detect_keyboard_type(void); diff --git a/client/Mac/Keyboard.m b/client/Mac/Keyboard.m index 98574b7..9bb9cd4 100644 --- a/client/Mac/Keyboard.m +++ b/client/Mac/Keyboard.m @@ -21,7 +21,8 @@ #include -#include +#include +#include struct _APPLE_KEYBOARD_DESC { @@ -32,8 +33,7 @@ typedef struct _APPLE_KEYBOARD_DESC APPLE_KEYBOARD_DESC; /* VendorID: 0x05AC (Apple, Inc.) */ -static const APPLE_KEYBOARD_DESC APPLE_KEYBOARDS[] = -{ +static const APPLE_KEYBOARD_DESC APPLE_KEYBOARDS[] = { { 0x200, APPLE_KEYBOARD_TYPE_ANSI }, { 0x201, APPLE_KEYBOARD_TYPE_ANSI }, /* USB Keyboard [Alps or Logitech, M2452] */ { 0x202, APPLE_KEYBOARD_TYPE_ANSI }, /* Keyboard [ALPS] */ @@ -49,48 +49,48 @@ static const APPLE_KEYBOARD_DESC APPLE_KEYBOARDS[] = { 0x20C, APPLE_KEYBOARD_TYPE_ANSI }, /* Extended Keyboard [Mitsumi] */ { 0x20D, APPLE_KEYBOARD_TYPE_ANSI }, /* Pro Keyboard [Mitsumi, A1048/JIS layout] */ { 0x20E, APPLE_KEYBOARD_TYPE_ANSI }, /* Internal Keyboard/Trackpad (ANSI) */ - { 0x20F, APPLE_KEYBOARD_TYPE_ISO }, /* Internal Keyboard/Trackpad (ISO) */ + { 0x20F, APPLE_KEYBOARD_TYPE_ISO }, /* Internal Keyboard/Trackpad (ISO) */ { 0x210, APPLE_KEYBOARD_TYPE_ANSI }, { 0x211, APPLE_KEYBOARD_TYPE_ANSI }, { 0x212, APPLE_KEYBOARD_TYPE_ANSI }, { 0x213, APPLE_KEYBOARD_TYPE_ANSI }, { 0x214, APPLE_KEYBOARD_TYPE_ANSI }, /* Internal Keyboard/Trackpad (ANSI) */ - { 0x215, APPLE_KEYBOARD_TYPE_ISO }, /* Internal Keyboard/Trackpad (ISO) */ - { 0x216, APPLE_KEYBOARD_TYPE_JIS }, /* Internal Keyboard/Trackpad (JIS) */ + { 0x215, APPLE_KEYBOARD_TYPE_ISO }, /* Internal Keyboard/Trackpad (ISO) */ + { 0x216, APPLE_KEYBOARD_TYPE_JIS }, /* Internal Keyboard/Trackpad (JIS) */ { 0x217, APPLE_KEYBOARD_TYPE_ANSI }, /* Internal Keyboard/Trackpad (ANSI) */ - { 0x218, APPLE_KEYBOARD_TYPE_ISO }, /* Internal Keyboard/Trackpad (ISO) */ - { 0x219, APPLE_KEYBOARD_TYPE_JIS }, /* Internal Keyboard/Trackpad (JIS) */ + { 0x218, APPLE_KEYBOARD_TYPE_ISO }, /* Internal Keyboard/Trackpad (ISO) */ + { 0x219, APPLE_KEYBOARD_TYPE_JIS }, /* Internal Keyboard/Trackpad (JIS) */ { 0x21A, APPLE_KEYBOARD_TYPE_ANSI }, /* Internal Keyboard/Trackpad (ANSI) */ - { 0x21B, APPLE_KEYBOARD_TYPE_ISO }, /* Internal Keyboard/Trackpad (ISO) */ - { 0x21C, APPLE_KEYBOARD_TYPE_JIS }, /* Internal Keyboard/Trackpad (JIS) */ + { 0x21B, APPLE_KEYBOARD_TYPE_ISO }, /* Internal Keyboard/Trackpad (ISO) */ + { 0x21C, APPLE_KEYBOARD_TYPE_JIS }, /* Internal Keyboard/Trackpad (JIS) */ { 0x21D, APPLE_KEYBOARD_TYPE_ANSI }, /* Aluminum Mini Keyboard (ANSI) */ - { 0x21E, APPLE_KEYBOARD_TYPE_ISO }, /* Aluminum Mini Keyboard (ISO) */ - { 0x21F, APPLE_KEYBOARD_TYPE_JIS }, /* Aluminum Mini Keyboard (JIS) */ + { 0x21E, APPLE_KEYBOARD_TYPE_ISO }, /* Aluminum Mini Keyboard (ISO) */ + { 0x21F, APPLE_KEYBOARD_TYPE_JIS }, /* Aluminum Mini Keyboard (JIS) */ { 0x220, APPLE_KEYBOARD_TYPE_ANSI }, /* Aluminum Keyboard (ANSI) */ - { 0x221, APPLE_KEYBOARD_TYPE_JIS }, /* Aluminum Keyboard (JIS) */ - { 0x222, APPLE_KEYBOARD_TYPE_JIS }, /* Aluminum Keyboard (JIS) */ + { 0x221, APPLE_KEYBOARD_TYPE_JIS }, /* Aluminum Keyboard (JIS) */ + { 0x222, APPLE_KEYBOARD_TYPE_JIS }, /* Aluminum Keyboard (JIS) */ { 0x223, APPLE_KEYBOARD_TYPE_ANSI }, /* Internal Keyboard/Trackpad (ANSI) */ - { 0x224, APPLE_KEYBOARD_TYPE_ISO }, /* Internal Keyboard/Trackpad (ISO) */ - { 0x225, APPLE_KEYBOARD_TYPE_JIS }, /* Internal Keyboard/Trackpad (JIS) */ + { 0x224, APPLE_KEYBOARD_TYPE_ISO }, /* Internal Keyboard/Trackpad (ISO) */ + { 0x225, APPLE_KEYBOARD_TYPE_JIS }, /* Internal Keyboard/Trackpad (JIS) */ { 0x226, APPLE_KEYBOARD_TYPE_ANSI }, { 0x227, APPLE_KEYBOARD_TYPE_ANSI }, { 0x228, APPLE_KEYBOARD_TYPE_ANSI }, { 0x229, APPLE_KEYBOARD_TYPE_ANSI }, /* Internal Keyboard/Trackpad (MacBook Pro) (ANSI) */ - { 0x22A, APPLE_KEYBOARD_TYPE_ISO }, /* Internal Keyboard/Trackpad (MacBook Pro) (ISO) */ - { 0x22B, APPLE_KEYBOARD_TYPE_JIS }, /* Internal Keyboard/Trackpad (MacBook Pro) (JIS) */ + { 0x22A, APPLE_KEYBOARD_TYPE_ISO }, /* Internal Keyboard/Trackpad (MacBook Pro) (ISO) */ + { 0x22B, APPLE_KEYBOARD_TYPE_JIS }, /* Internal Keyboard/Trackpad (MacBook Pro) (JIS) */ { 0x22C, APPLE_KEYBOARD_TYPE_ANSI }, { 0x22D, APPLE_KEYBOARD_TYPE_ANSI }, { 0x22E, APPLE_KEYBOARD_TYPE_ANSI }, { 0x22F, APPLE_KEYBOARD_TYPE_ANSI }, { 0x230, APPLE_KEYBOARD_TYPE_ANSI }, /* Internal Keyboard/Trackpad (MacBook Pro 4,1) (ANSI) */ - { 0x231, APPLE_KEYBOARD_TYPE_ISO }, /* Internal Keyboard/Trackpad (MacBook Pro 4,1) (ISO) */ - { 0x232, APPLE_KEYBOARD_TYPE_JIS }, /* Internal Keyboard/Trackpad (MacBook Pro 4,1) (JIS) */ + { 0x231, APPLE_KEYBOARD_TYPE_ISO }, /* Internal Keyboard/Trackpad (MacBook Pro 4,1) (ISO) */ + { 0x232, APPLE_KEYBOARD_TYPE_JIS }, /* Internal Keyboard/Trackpad (MacBook Pro 4,1) (JIS) */ { 0x233, APPLE_KEYBOARD_TYPE_ANSI }, { 0x234, APPLE_KEYBOARD_TYPE_ANSI }, { 0x235, APPLE_KEYBOARD_TYPE_ANSI }, { 0x236, APPLE_KEYBOARD_TYPE_ANSI }, /* Internal Keyboard/Trackpad (ANSI) */ - { 0x237, APPLE_KEYBOARD_TYPE_ISO }, /* Internal Keyboard/Trackpad (ISO) */ - { 0x238, APPLE_KEYBOARD_TYPE_JIS }, /* Internal Keyboard/Trackpad (JIS) */ + { 0x237, APPLE_KEYBOARD_TYPE_ISO }, /* Internal Keyboard/Trackpad (ISO) */ + { 0x238, APPLE_KEYBOARD_TYPE_JIS }, /* Internal Keyboard/Trackpad (JIS) */ { 0x239, APPLE_KEYBOARD_TYPE_ANSI }, { 0x23A, APPLE_KEYBOARD_TYPE_ANSI }, { 0x23B, APPLE_KEYBOARD_TYPE_ANSI }, @@ -98,14 +98,14 @@ static const APPLE_KEYBOARD_DESC APPLE_KEYBOARDS[] = { 0x23D, APPLE_KEYBOARD_TYPE_ANSI }, { 0x23E, APPLE_KEYBOARD_TYPE_ANSI }, { 0x23F, APPLE_KEYBOARD_TYPE_ANSI }, /* Internal Keyboard/Trackpad (ANSI) */ - { 0x240, APPLE_KEYBOARD_TYPE_ISO }, /* Internal Keyboard/Trackpad (ISO) */ - { 0x241, APPLE_KEYBOARD_TYPE_JIS }, /* Internal Keyboard/Trackpad (JIS) */ + { 0x240, APPLE_KEYBOARD_TYPE_ISO }, /* Internal Keyboard/Trackpad (ISO) */ + { 0x241, APPLE_KEYBOARD_TYPE_JIS }, /* Internal Keyboard/Trackpad (JIS) */ { 0x242, APPLE_KEYBOARD_TYPE_ANSI }, /* Internal Keyboard/Trackpad (ANSI) */ - { 0x243, APPLE_KEYBOARD_TYPE_ISO }, /* Internal Keyboard/Trackpad (ISO) */ - { 0x244, APPLE_KEYBOARD_TYPE_JIS }, /* Internal Keyboard/Trackpad (JIS) */ + { 0x243, APPLE_KEYBOARD_TYPE_ISO }, /* Internal Keyboard/Trackpad (ISO) */ + { 0x244, APPLE_KEYBOARD_TYPE_JIS }, /* Internal Keyboard/Trackpad (JIS) */ { 0x245, APPLE_KEYBOARD_TYPE_ANSI }, /* Internal Keyboard/Trackpad (ANSI) */ - { 0x246, APPLE_KEYBOARD_TYPE_ISO }, /* Internal Keyboard/Trackpad (ISO) */ - { 0x247, APPLE_KEYBOARD_TYPE_JIS }, /* Internal Keyboard/Trackpad (JIS) */ + { 0x246, APPLE_KEYBOARD_TYPE_ISO }, /* Internal Keyboard/Trackpad (ISO) */ + { 0x247, APPLE_KEYBOARD_TYPE_JIS }, /* Internal Keyboard/Trackpad (JIS) */ { 0x248, APPLE_KEYBOARD_TYPE_ANSI }, { 0x249, APPLE_KEYBOARD_TYPE_ANSI }, { 0x24A, APPLE_KEYBOARD_TYPE_ISO }, /* Internal Keyboard/Trackpad (MacBook Air) (ISO) */ @@ -117,8 +117,8 @@ static const APPLE_KEYBOARD_DESC APPLE_KEYBOARDS[] = { 0x250, APPLE_KEYBOARD_TYPE_ISO }, /* Aluminium Keyboard (ISO) */ { 0x251, APPLE_KEYBOARD_TYPE_ANSI }, { 0x252, APPLE_KEYBOARD_TYPE_ANSI }, /* Internal Keyboard/Trackpad (ANSI) */ - { 0x253, APPLE_KEYBOARD_TYPE_ISO }, /* Internal Keyboard/Trackpad (ISO) */ - { 0x254, APPLE_KEYBOARD_TYPE_JIS }, /* Internal Keyboard/Trackpad (JIS) */ + { 0x253, APPLE_KEYBOARD_TYPE_ISO }, /* Internal Keyboard/Trackpad (ISO) */ + { 0x254, APPLE_KEYBOARD_TYPE_JIS }, /* Internal Keyboard/Trackpad (JIS) */ { 0x255, APPLE_KEYBOARD_TYPE_ANSI }, { 0x256, APPLE_KEYBOARD_TYPE_ANSI }, { 0x257, APPLE_KEYBOARD_TYPE_ANSI }, @@ -143,8 +143,7 @@ static const APPLE_KEYBOARD_DESC APPLE_KEYBOARDS[] = { 0x26A, APPLE_KEYBOARD_TYPE_ANSI } }; -static enum APPLE_KEYBOARD_TYPE mac_identify_keyboard_type(uint32_t vendorID, - uint32_t productID) +static enum APPLE_KEYBOARD_TYPE mac_identify_keyboard_type(uint32_t vendorID, uint32_t productID) { enum APPLE_KEYBOARD_TYPE type = APPLE_KEYBOARD_TYPE_ANSI; @@ -158,15 +157,14 @@ static enum APPLE_KEYBOARD_TYPE mac_identify_keyboard_type(uint32_t vendorID, return type; } -enum APPLE_KEYBOARD_TYPE mac_detect_keyboard_type() +enum APPLE_KEYBOARD_TYPE mac_detect_keyboard_type(void) { CFSetRef deviceCFSetRef = NULL; IOHIDDeviceRef inIOHIDDeviceRef = NULL; IOHIDManagerRef tIOHIDManagerRef = NULL; - IOHIDDeviceRef* tIOHIDDeviceRefs = nil; + IOHIDDeviceRef *tIOHIDDeviceRefs = nil; enum APPLE_KEYBOARD_TYPE type = APPLE_KEYBOARD_TYPE_ANSI; - tIOHIDManagerRef = IOHIDManagerCreate(kCFAllocatorDefault, - kIOHIDOptionsTypeNone); + tIOHIDManagerRef = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); if (!tIOHIDManagerRef) return type; @@ -188,7 +186,7 @@ enum APPLE_KEYBOARD_TYPE mac_detect_keyboard_type() if (!tIOHIDDeviceRefs) return type; - CFSetGetValues(deviceCFSetRef, (const void**) tIOHIDDeviceRefs); + CFSetGetValues(deviceCFSetRef, (const void **)tIOHIDDeviceRefs); CFRelease(deviceCFSetRef); deviceCFSetRef = NULL; @@ -207,19 +205,17 @@ enum APPLE_KEYBOARD_TYPE mac_detect_keyboard_type() tCFTypeRef = IOHIDDeviceGetProperty(inIOHIDDeviceRef, CFSTR(kIOHIDVendorIDKey)); if (tCFTypeRef) - CFNumberGetValue((CFNumberRef) tCFTypeRef, kCFNumberSInt32Type, &vendorID); + CFNumberGetValue((CFNumberRef)tCFTypeRef, kCFNumberSInt32Type, &vendorID); - tCFTypeRef = IOHIDDeviceGetProperty(inIOHIDDeviceRef, - CFSTR(kIOHIDProductIDKey)); + tCFTypeRef = IOHIDDeviceGetProperty(inIOHIDDeviceRef, CFSTR(kIOHIDProductIDKey)); if (tCFTypeRef) - CFNumberGetValue((CFNumberRef) tCFTypeRef, kCFNumberSInt32Type, &productID); + CFNumberGetValue((CFNumberRef)tCFTypeRef, kCFNumberSInt32Type, &productID); - tCFTypeRef = IOHIDDeviceGetProperty(inIOHIDDeviceRef, - CFSTR(kIOHIDCountryCodeKey)); + tCFTypeRef = IOHIDDeviceGetProperty(inIOHIDDeviceRef, CFSTR(kIOHIDCountryCodeKey)); if (tCFTypeRef) - CFNumberGetValue((CFNumberRef) tCFTypeRef, kCFNumberSInt32Type, &countryCode); + CFNumberGetValue((CFNumberRef)tCFTypeRef, kCFNumberSInt32Type, &countryCode); ltype = mac_identify_keyboard_type(vendorID, productID); diff --git a/client/Mac/MRDPCursor.h b/client/Mac/MRDPCursor.h index 767ccbc..6b16d79 100644 --- a/client/Mac/MRDPCursor.h +++ b/client/Mac/MRDPCursor.h @@ -23,12 +23,12 @@ @interface MRDPCursor : NSObject { -@public - rdpPointer* pointer; - BYTE* cursor_data; - NSBitmapImageRep* bmiRep; - NSCursor* nsCursor; - NSImage* nsImage; + @public + rdpPointer *pointer; + BYTE *cursor_data; + NSBitmapImageRep *bmiRep; + NSCursor *nsCursor; + NSImage *nsImage; } @end diff --git a/client/Mac/MRDPView.h b/client/Mac/MRDPView.h index 60e47d8..51eb8f5 100644 --- a/client/Mac/MRDPView.h +++ b/client/Mac/MRDPView.h @@ -26,21 +26,23 @@ #import "mf_client.h" #import "Keyboard.h" +#import + @interface MRDPView : NSView { - mfContext* mfc; - NSBitmapImageRep* bmiRep; - NSMutableArray* cursors; - NSMutableArray* windows; - NSTimer* pasteboard_timer; - NSCursor* currentCursor; + mfContext *mfc; + NSBitmapImageRep *bmiRep; + NSMutableArray *cursors; + NSMutableArray *windows; + NSTimer *pasteboard_timer; + NSCursor *currentCursor; NSRect prevWinPosition; - freerdp* instance; - rdpContext* context; + freerdp *instance; + rdpContext *context; CGContextRef bitmap_context; - char* pixel_data; + char *pixel_data; int argc; - char** argv; + char **argv; DWORD kbdModFlags; BOOL initialized; NSPoint savedDragLocation; @@ -49,40 +51,51 @@ BOOL skipResizeOnce; BOOL saveInitialDragLoc; BOOL skipMoveWindowOnce; -@public - NSPasteboard* pasteboard_rd; - NSPasteboard* pasteboard_wr; + @public + NSPasteboard *pasteboard_rd; + NSPasteboard *pasteboard_wr; int pasteboard_changecount; int pasteboard_format; int is_connected; } -- (int) rdpStart :(rdpContext*) rdp_context; -- (void) setCursor: (NSCursor*) cursor; -- (void) setScrollOffset:(int)xOffset y:(int)yOffset w:(int)width h:(int)height; +- (int)rdpStart:(rdpContext *)rdp_context; +- (void)setCursor:(NSCursor *)cursor; +- (void)setScrollOffset:(int)xOffset y:(int)yOffset w:(int)width h:(int)height; -- (void) onPasteboardTimerFired :(NSTimer*) timer; -- (void) pause; -- (void) resume; -- (void) releaseResources; +- (void)onPasteboardTimerFired:(NSTimer *)timer; +- (void)pause; +- (void)resume; +- (void)releaseResources; @property(assign) int is_connected; @end /* Pointer Flags */ -#define PTR_FLAGS_WHEEL 0x0200 -#define PTR_FLAGS_WHEEL_NEGATIVE 0x0100 -#define PTR_FLAGS_MOVE 0x0800 -#define PTR_FLAGS_DOWN 0x8000 -#define PTR_FLAGS_BUTTON1 0x1000 -#define PTR_FLAGS_BUTTON2 0x2000 -#define PTR_FLAGS_BUTTON3 0x4000 -#define WheelRotationMask 0x01FF +#define PTR_FLAGS_WHEEL 0x0200 +#define PTR_FLAGS_WHEEL_NEGATIVE 0x0100 +#define PTR_FLAGS_MOVE 0x0800 +#define PTR_FLAGS_DOWN 0x8000 +#define PTR_FLAGS_BUTTON1 0x1000 +#define PTR_FLAGS_BUTTON2 0x2000 +#define PTR_FLAGS_BUTTON3 0x4000 +#define WheelRotationMask 0x01FF + +BOOL mac_pre_connect(freerdp *instance); +BOOL mac_post_connect(freerdp *instance); +void mac_post_disconnect(freerdp *instance); +BOOL mac_authenticate(freerdp *instance, char **username, char **password, char **domain); +BOOL mac_gw_authenticate(freerdp *instance, char **username, char **password, char **domain); -BOOL mac_pre_connect(freerdp* instance); -BOOL mac_post_connect(freerdp* instance); -BOOL mac_authenticate(freerdp* instance, char** username, char** password, - char** domain); +DWORD mac_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); +DWORD mac_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); +int mac_logon_error_info(freerdp *instance, UINT32 data, UINT32 type); #endif /* FREERDP_CLIENT_MAC_MRDPVIEW_H */ diff --git a/client/Mac/MRDPView.m b/client/Mac/MRDPView.m index a0e20ac..dc07cdc 100644 --- a/client/Mac/MRDPView.m +++ b/client/Mac/MRDPView.m @@ -25,6 +25,7 @@ #import "MRDPCursor.h" #import "Clipboard.h" #import "PasswordDialog.h" +#import "CertificateDialog.h" #include #include @@ -44,47 +45,48 @@ #import "freerdp/client/cmdline.h" #import "freerdp/log.h" +#import + #define TAG CLIENT_TAG("mac") -static BOOL mf_Pointer_New(rdpContext* context, rdpPointer* pointer); -static void mf_Pointer_Free(rdpContext* context, rdpPointer* pointer); -static BOOL mf_Pointer_Set(rdpContext* context, const rdpPointer* pointer); -static BOOL mf_Pointer_SetNull(rdpContext* context); -static BOOL mf_Pointer_SetDefault(rdpContext* context); -static BOOL mf_Pointer_SetPosition(rdpContext* context, UINT32 x, UINT32 y); +static BOOL mf_Pointer_New(rdpContext *context, rdpPointer *pointer); +static void mf_Pointer_Free(rdpContext *context, rdpPointer *pointer); +static BOOL mf_Pointer_Set(rdpContext *context, const rdpPointer *pointer); +static BOOL mf_Pointer_SetNull(rdpContext *context); +static BOOL mf_Pointer_SetDefault(rdpContext *context); +static BOOL mf_Pointer_SetPosition(rdpContext *context, UINT32 x, UINT32 y); -static BOOL mac_begin_paint(rdpContext* context); -static BOOL mac_end_paint(rdpContext* context); -static BOOL mac_desktop_resize(rdpContext* context); +static BOOL mac_begin_paint(rdpContext *context); +static BOOL mac_end_paint(rdpContext *context); +static BOOL mac_desktop_resize(rdpContext *context); -static void update_activity_cb(freerdp* instance); -static void input_activity_cb(freerdp* instance); +static void input_activity_cb(freerdp *instance); -static DWORD mac_client_thread(void* param); +static DWORD WINAPI mac_client_thread(void *param); @implementation MRDPView @synthesize is_connected; -- (int) rdpStart:(rdpContext*) rdp_context +- (int)rdpStart:(rdpContext *)rdp_context { - rdpSettings* settings; + rdpSettings *settings; EmbedWindowEventArgs e; [self initializeView]; context = rdp_context; - mfc = (mfContext*) rdp_context; + mfc = (mfContext *)rdp_context; instance = context->instance; settings = context->settings; EventArgsInit(&e, "mfreerdp"); e.embed = TRUE; - e.handle = (void*) self; + e.handle = (void *)self; PubSub_OnEmbedWindow(context->pubSub, context, &e); - NSScreen* screen = [[NSScreen screens] objectAtIndex:0]; + NSScreen *screen = [[NSScreen screens] objectAtIndex:0]; NSRect screenFrame = [screen frame]; if (instance->settings->Fullscreen) { - instance->settings->DesktopWidth = screenFrame.size.width; + instance->settings->DesktopWidth = screenFrame.size.width; instance->settings->DesktopHeight = screenFrame.size.height; [self enterFullScreenMode:[NSScreen mainScreen] withOptions:nil]; } @@ -96,8 +98,8 @@ static DWORD mac_client_thread(void* param); mfc->client_height = instance->settings->DesktopHeight; mfc->client_width = instance->settings->DesktopWidth; - if (!(mfc->thread = CreateThread(NULL, 0, mac_client_thread, (void*) context, 0, - &mfc->mainThreadId))) + if (!(mfc->thread = + CreateThread(NULL, 0, mac_client_thread, (void *)context, 0, &mfc->mainThreadId))) { WLog_ERR(TAG, "failed to create client thread"); return -1; @@ -106,51 +108,21 @@ static DWORD mac_client_thread(void* param); return 0; } -static DWORD mac_client_update_thread(void* param) -{ - int status; - wMessage message; - wMessageQueue* queue; - rdpContext* context = (rdpContext*) param; - status = 1; - queue = freerdp_get_message_queue(context->instance, - FREERDP_UPDATE_MESSAGE_QUEUE); - - while (MessageQueue_Wait(queue)) - { - while (MessageQueue_Peek(queue, &message, TRUE)) - { - status = freerdp_message_queue_process_message(context->instance, - FREERDP_UPDATE_MESSAGE_QUEUE, &message); - - if (!status) - break; - } - - if (!status) - break; - } - - ExitThread(0); - return 0; -} - static DWORD WINAPI mac_client_input_thread(LPVOID param) { int status; wMessage message; - wMessageQueue* queue; - rdpContext* context = (rdpContext*) param; + wMessageQueue *queue; + rdpContext *context = (rdpContext *)param; status = 1; - queue = freerdp_get_message_queue(context->instance, - FREERDP_INPUT_MESSAGE_QUEUE); + queue = freerdp_get_message_queue(context->instance, FREERDP_INPUT_MESSAGE_QUEUE); while (MessageQueue_Wait(queue)) { while (MessageQueue_Peek(queue, &message, TRUE)) { status = freerdp_message_queue_process_message(context->instance, - FREERDP_INPUT_MESSAGE_QUEUE, &message); + FREERDP_INPUT_MESSAGE_QUEUE, &message); if (!status) break; @@ -164,22 +136,23 @@ static DWORD WINAPI mac_client_input_thread(LPVOID param) return 0; } -DWORD mac_client_thread(void* param) +DWORD WINAPI mac_client_thread(void *param) { @autoreleasepool { int status; + DWORD rc; HANDLE events[16]; HANDLE inputEvent; HANDLE inputThread = NULL; DWORD nCount; DWORD nCountTmp; DWORD nCountBase; - rdpContext* context = (rdpContext*) param; - mfContext* mfc = (mfContext*) context; - freerdp* instance = context->instance; - MRDPView* view = mfc->view; - rdpSettings* settings = context->settings; + rdpContext *context = (rdpContext *)param; + mfContext *mfc = (mfContext *)context; + freerdp *instance = context->instance; + MRDPView *view = mfc->view; + rdpSettings *settings = context->settings; status = freerdp_connect(context->instance); if (!status) @@ -196,14 +169,14 @@ DWORD mac_client_thread(void* param) { if (!(inputThread = CreateThread(NULL, 0, mac_client_input_thread, context, 0, NULL))) { - WLog_ERR(TAG, "failed to create async input thread"); + WLog_ERR(TAG, "failed to create async input thread"); goto disconnect; } } else { if (!(inputEvent = freerdp_get_message_queue_event_handle(instance, - FREERDP_INPUT_MESSAGE_QUEUE))) + FREERDP_INPUT_MESSAGE_QUEUE))) { WLog_ERR(TAG, "failed to get input event handle"); goto disconnect; @@ -218,8 +191,7 @@ DWORD mac_client_thread(void* param) { nCount = nCountBase; { - if (!(nCountTmp = freerdp_get_event_handles(context, &events[nCount], - 16 - nCount))) + if (!(nCountTmp = freerdp_get_event_handles(context, &events[nCount], 16 - nCount))) { WLog_ERR(TAG, "freerdp_get_event_handles failed"); break; @@ -227,15 +199,15 @@ DWORD mac_client_thread(void* param) nCount += nCountTmp; } - status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); + rc = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); - if (status >= (WAIT_OBJECT_0 + nCount)) + if (rc >= (WAIT_OBJECT_0 + nCount)) { - WLog_ERR(TAG, "WaitForMultipleObjects failed (0x%08X)", status); + WLog_ERR(TAG, "WaitForMultipleObjects failed (0x%08X)", rc); break; } - if (status == WAIT_OBJECT_0) + if (rc == WAIT_OBJECT_0) { /* stop event triggered */ break; @@ -259,12 +231,13 @@ DWORD mac_client_thread(void* param) } disconnect: + [view setIs_connected:0]; freerdp_disconnect(instance); if (settings->AsyncInput && inputThread) { - wMessageQueue* inputQueue = freerdp_get_message_queue(instance, - FREERDP_INPUT_MESSAGE_QUEUE); + wMessageQueue *inputQueue = + freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE); if (inputQueue) { @@ -292,21 +265,24 @@ DWORD mac_client_thread(void* param) return self; } -- (void) viewDidLoad +- (void)viewDidLoad { [self initializeView]; } -- (void) initializeView +- (void)initializeView { if (!initialized) { cursors = [[NSMutableArray alloc] initWithCapacity:10]; // setup a mouse tracking area - NSTrackingArea* trackingArea = [[NSTrackingArea alloc] initWithRect:[self - visibleRect] options:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | - NSTrackingCursorUpdate | NSTrackingEnabledDuringMouseDrag | - NSTrackingActiveWhenFirstResponder owner:self userInfo:nil]; + NSTrackingArea *trackingArea = [[NSTrackingArea alloc] + initWithRect:[self visibleRect] + options:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | + NSTrackingCursorUpdate | NSTrackingEnabledDuringMouseDrag | + NSTrackingActiveWhenFirstResponder + owner:self + userInfo:nil]; [self addTrackingArea:trackingArea]; // Set the default cursor currentCursor = [NSCursor arrowCursor]; @@ -314,13 +290,15 @@ DWORD mac_client_thread(void* param) } } -- (void) setCursor: (NSCursor*) cursor +- (void)setCursor:(NSCursor *)cursor { self->currentCursor = cursor; - [[self window] invalidateCursorRectsForView:self]; + dispatch_async(dispatch_get_main_queue(), ^{ + [[self window] invalidateCursorRectsForView:self]; + }); } -- (void) resetCursorRects +- (void)resetCursorRects { [self addCursorRect:[self visibleRect] cursor:currentCursor]; } @@ -330,136 +308,154 @@ DWORD mac_client_thread(void* param) return YES; } -- (void) mouseMoved:(NSEvent*)event +- (void)mouseMoved:(NSEvent *)event { [super mouseMoved:event]; - if (!is_connected) + if (!self.is_connected) return; NSPoint loc = [event locationInWindow]; - int x = (int) loc.x; - int y = (int) loc.y; + int x = (int)loc.x; + int y = (int)loc.y; mf_scale_mouse_event(context, instance->input, PTR_FLAGS_MOVE, x, y); } -- (void)mouseDown:(NSEvent*) event +- (void)mouseDown:(NSEvent *)event { [super mouseDown:event]; - if (!is_connected) + if (!self.is_connected) return; NSPoint loc = [event locationInWindow]; - int x = (int) loc.x; - int y = (int) loc.y; - mf_scale_mouse_event(context, instance->input, - PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON1, x, y); + int x = (int)loc.x; + int y = (int)loc.y; + mf_press_mouse_button(context, instance->input, 0, x, y, TRUE); } -- (void) mouseUp:(NSEvent*) event +- (void)mouseUp:(NSEvent *)event { [super mouseUp:event]; - if (!is_connected) + if (!self.is_connected) return; NSPoint loc = [event locationInWindow]; - int x = (int) loc.x; - int y = (int) loc.y; - mf_scale_mouse_event(context, instance->input, PTR_FLAGS_BUTTON1, x, y); + int x = (int)loc.x; + int y = (int)loc.y; + mf_press_mouse_button(context, instance->input, 0, x, y, FALSE); } -- (void) rightMouseDown:(NSEvent*)event +- (void)rightMouseDown:(NSEvent *)event { [super rightMouseDown:event]; - if (!is_connected) + if (!self.is_connected) return; NSPoint loc = [event locationInWindow]; - int x = (int) loc.x; - int y = (int) loc.y; - mf_scale_mouse_event(context, instance->input, - PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON2, x, y); + int x = (int)loc.x; + int y = (int)loc.y; + mf_press_mouse_button(context, instance->input, 1, x, y, TRUE); } -- (void) rightMouseUp:(NSEvent*)event +- (void)rightMouseUp:(NSEvent *)event { [super rightMouseUp:event]; - if (!is_connected) + if (!self.is_connected) return; NSPoint loc = [event locationInWindow]; - int x = (int) loc.x; - int y = (int) loc.y; - mf_scale_mouse_event(context, instance->input, PTR_FLAGS_BUTTON2, x, y); + int x = (int)loc.x; + int y = (int)loc.y; + mf_press_mouse_button(context, instance->input, 1, x, y, FALSE); } -- (void) otherMouseDown:(NSEvent*)event +- (void)otherMouseDown:(NSEvent *)event { [super otherMouseDown:event]; - if (!is_connected) + if (!self.is_connected) return; NSPoint loc = [event locationInWindow]; - int x = (int) loc.x; - int y = (int) loc.y; - mf_scale_mouse_event(context, instance->input, - PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON3, x, y); + int x = (int)loc.x; + int y = (int)loc.y; + int pressed = [event buttonNumber]; + mf_press_mouse_button(context, instance->input, pressed, x, y, TRUE); } -- (void) otherMouseUp:(NSEvent*)event +- (void)otherMouseUp:(NSEvent *)event { [super otherMouseUp:event]; - if (!is_connected) + if (!self.is_connected) return; NSPoint loc = [event locationInWindow]; - int x = (int) loc.x; - int y = (int) loc.y; - mf_scale_mouse_event(context, instance->input, PTR_FLAGS_BUTTON3, x, y); + int x = (int)loc.x; + int y = (int)loc.y; + int pressed = [event buttonNumber]; + mf_press_mouse_button(context, instance->input, pressed, x, y, FALSE); } -- (void) scrollWheel:(NSEvent*)event +- (void)scrollWheel:(NSEvent *)event { UINT16 flags; [super scrollWheel:event]; - if (!is_connected) + if (!self.is_connected) return; - NSPoint loc = [event locationInWindow]; - int x = (int) loc.x; - int y = (int) loc.y; - flags = PTR_FLAGS_WHEEL; + float dx = [event deltaX]; + float dy = [event deltaY]; /* 1 event = 120 units */ - int units = [event deltaY] * 120; + UINT16 units = 0; + + if (fabsf(dy) > FLT_EPSILON) + { + flags = PTR_FLAGS_HWHEEL; + units = fabsf(dy) * 120; + + if (dy < 0) + flags |= PTR_FLAGS_WHEEL_NEGATIVE; + } + else if (fabsf(dx) > FLT_EPSILON) + { + flags = PTR_FLAGS_WHEEL; + units = fabsf(dx) * 120; + + if (dx > 0) + flags |= PTR_FLAGS_WHEEL_NEGATIVE; + } + else + return; /* send out all accumulated rotations */ + if (units > WheelRotationMask) + units = WheelRotationMask; + while (units != 0) { /* limit to maximum value in WheelRotationMask (9bit signed value) */ - int step = MIN(MAX(-256, units), 255); - mf_scale_mouse_event(context, instance->input, - flags | ((UINT16)step & WheelRotationMask), x, y); + const UINT16 step = units & WheelRotationMask; + mf_scale_mouse_event(context, instance->input, flags | step, 0, 0); units -= step; } } -- (void) mouseDragged:(NSEvent*)event +- (void)mouseDragged:(NSEvent *)event { [super mouseDragged:event]; - if (!is_connected) + if (!self.is_connected) return; NSPoint loc = [event locationInWindow]; - int x = (int) loc.x; - int y = (int) loc.y; + int x = (int)loc.x; + int y = (int)loc.y; // send mouse motion event to RDP server mf_scale_mouse_event(context, instance->input, PTR_FLAGS_MOVE, x, y); } @@ -520,14 +516,14 @@ DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type) return keyCode; } -- (void) keyDown:(NSEvent*) event +- (void)keyDown:(NSEvent *)event { DWORD keyCode; DWORD keyFlags; DWORD vkcode; DWORD scancode; unichar keyChar; - NSString* characters; + NSString *characters; if (!is_connected) return; @@ -556,14 +552,14 @@ DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type) freerdp_input_send_keyboard_event(instance->input, keyFlags, scancode); } -- (void) keyUp:(NSEvent*) event +- (void)keyUp:(NSEvent *)event { DWORD keyCode; DWORD keyFlags; DWORD vkcode; DWORD scancode; unichar keyChar; - NSString* characters; + NSString *characters; if (!is_connected) return; @@ -591,7 +587,7 @@ DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type) freerdp_input_send_keyboard_event(instance->input, keyFlags, scancode); } -- (void) flagsChanged:(NSEvent*) event +- (void)flagsChanged:(NSEvent *)event { int key; DWORD keyFlags; @@ -639,60 +635,44 @@ DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type) #endif if ((modFlags & NSAlphaShiftKeyMask) && !(kbdModFlags & NSAlphaShiftKeyMask)) - freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_DOWN, - scancode); - else if (!(modFlags & NSAlphaShiftKeyMask) - && (kbdModFlags & NSAlphaShiftKeyMask)) - freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_RELEASE, - scancode); + freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_DOWN, scancode); + else if (!(modFlags & NSAlphaShiftKeyMask) && (kbdModFlags & NSAlphaShiftKeyMask)) + freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_RELEASE, scancode); if ((modFlags & NSShiftKeyMask) && !(kbdModFlags & NSShiftKeyMask)) - freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_DOWN, - scancode); + freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_DOWN, scancode); else if (!(modFlags & NSShiftKeyMask) && (kbdModFlags & NSShiftKeyMask)) - freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_RELEASE, - scancode); + freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_RELEASE, scancode); if ((modFlags & NSControlKeyMask) && !(kbdModFlags & NSControlKeyMask)) - freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_DOWN, - scancode); + freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_DOWN, scancode); else if (!(modFlags & NSControlKeyMask) && (kbdModFlags & NSControlKeyMask)) - freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_RELEASE, - scancode); + freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_RELEASE, scancode); if ((modFlags & NSAlternateKeyMask) && !(kbdModFlags & NSAlternateKeyMask)) - freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_DOWN, - scancode); + freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_DOWN, scancode); else if (!(modFlags & NSAlternateKeyMask) && (kbdModFlags & NSAlternateKeyMask)) - freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_RELEASE, - scancode); + freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_RELEASE, scancode); if ((modFlags & NSCommandKeyMask) && !(kbdModFlags & NSCommandKeyMask)) - freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_DOWN, - scancode); + freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_DOWN, scancode); else if (!(modFlags & NSCommandKeyMask) && (kbdModFlags & NSCommandKeyMask)) - freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_RELEASE, - scancode); + freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_RELEASE, scancode); if ((modFlags & NSNumericPadKeyMask) && !(kbdModFlags & NSNumericPadKeyMask)) - freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_DOWN, - scancode); - else if (!(modFlags & NSNumericPadKeyMask) - && (kbdModFlags & NSNumericPadKeyMask)) - freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_RELEASE, - scancode); + freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_DOWN, scancode); + else if (!(modFlags & NSNumericPadKeyMask) && (kbdModFlags & NSNumericPadKeyMask)) + freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_RELEASE, scancode); if ((modFlags & NSHelpKeyMask) && !(kbdModFlags & NSHelpKeyMask)) - freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_DOWN, - scancode); + freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_DOWN, scancode); else if (!(modFlags & NSHelpKeyMask) && (kbdModFlags & NSHelpKeyMask)) - freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_RELEASE, - scancode); + freerdp_input_send_keyboard_event(instance->input, keyFlags | KBD_FLAGS_RELEASE, scancode); kbdModFlags = modFlags; } -- (void) releaseResources +- (void)releaseResources { int i; @@ -702,11 +682,10 @@ DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type) if (!is_connected) return; - gdi_free(context->instance); free(pixel_data); } -- (void) drawRect:(NSRect)rect +- (void)drawRect:(NSRect)rect { if (!context) return; @@ -716,10 +695,11 @@ DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type) CGContextRef cgContext = [[NSGraphicsContext currentContext] graphicsPort]; CGImageRef cgImage = CGBitmapContextCreateImage(self->bitmap_context); CGContextSaveGState(cgContext); - CGContextClipToRect(cgContext, CGRectMake(rect.origin.x, rect.origin.y, - rect.size.width, rect.size.height)); - CGContextDrawImage(cgContext, CGRectMake(0, - 0, [self bounds].size.width, [self bounds].size.height), cgImage); + CGContextClipToRect( + cgContext, CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height)); + CGContextDrawImage(cgContext, + CGRectMake(0, 0, [self bounds].size.width, [self bounds].size.height), + cgImage); CGContextRestoreGState(cgContext); CGImageRelease(cgImage); } @@ -731,23 +711,23 @@ DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type) } } -- (void) onPasteboardTimerFired :(NSTimer*) timer +- (void)onPasteboardTimerFired:(NSTimer *)timer { - const BYTE* data; + const BYTE *data; UINT32 size; UINT32 formatId; BOOL formatMatch; int changeCount; - NSData* formatData; - const char* formatType; - NSPasteboardItem* item; - changeCount = (int) [pasteboard_rd changeCount]; + NSData *formatData; + const char *formatType; + NSPasteboardItem *item; + changeCount = (int)[pasteboard_rd changeCount]; if (changeCount == pasteboard_changecount) return; pasteboard_changecount = changeCount; - NSArray* items = [pasteboard_rd pasteboardItems]; + NSArray *items = [pasteboard_rd pasteboardItems]; if ([items count] < 1) return; @@ -759,7 +739,7 @@ DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type) */ formatMatch = FALSE; - for (NSString * type in [item types]) + for (NSString *type in [item types]) { formatType = [type UTF8String]; @@ -767,7 +747,7 @@ DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type) { formatData = [item dataForType:type]; formatId = ClipboardRegisterFormat(mfc->clipboard, "UTF8_STRING"); - size = (UINT32) [formatData length]; + size = (UINT32)[formatData length]; data = [formatData bytes]; /* size is the string length without the terminating NULL terminator */ ClipboardSetData(mfc->clipboard, formatId, data, size + 1); @@ -783,15 +763,14 @@ DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type) mac_cliprdr_send_client_format_list(mfc->cliprdr); } -- (void) pause +- (void)pause { - dispatch_async(dispatch_get_main_queue(), ^ - { + dispatch_async(dispatch_get_main_queue(), ^{ [self->pasteboard_timer invalidate]; }); - NSArray* trackingAreas = self.trackingAreas; + NSArray *trackingAreas = self.trackingAreas; - for (NSTrackingArea * ta in trackingAreas) + for (NSTrackingArea *ta in trackingAreas) { [self removeTrackingArea:ta]; } @@ -799,19 +778,30 @@ DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type) - (void)resume { - dispatch_async(dispatch_get_main_queue(), ^ - { - self->pasteboard_timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(onPasteboardTimerFired:) userInfo:nil repeats:YES]; + if (!self.is_connected) + return; + + dispatch_async(dispatch_get_main_queue(), ^{ + self->pasteboard_timer = + [NSTimer scheduledTimerWithTimeInterval:0.5 + target:self + selector:@selector(onPasteboardTimerFired:) + userInfo:nil + repeats:YES]; + + NSTrackingArea *trackingArea = [[NSTrackingArea alloc] + initWithRect:[self visibleRect] + options:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | + NSTrackingCursorUpdate | NSTrackingEnabledDuringMouseDrag | + NSTrackingActiveWhenFirstResponder + owner:self + userInfo:nil]; + [self addTrackingArea:trackingArea]; + [trackingArea release]; }); - NSTrackingArea* trackingArea = [[NSTrackingArea alloc] initWithRect:[self - visibleRect] options:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | - NSTrackingCursorUpdate | NSTrackingEnabledDuringMouseDrag | - NSTrackingActiveWhenFirstResponder owner:self userInfo:nil]; - [self addTrackingArea:trackingArea]; - [trackingArea release]; } -- (void) setScrollOffset:(int)xOffset y:(int)yOffset w:(int)width h:(int)height +- (void)setScrollOffset:(int)xOffset y:(int)yOffset w:(int)width h:(int)height { mfc->yCurrentScroll = yOffset; mfc->xCurrentScroll = xOffset; @@ -819,11 +809,10 @@ DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type) mfc->client_width = width; } -void mac_OnChannelConnectedEventHandler(void* context, - ChannelConnectedEventArgs* e) +void mac_OnChannelConnectedEventHandler(void *context, ChannelConnectedEventArgs *e) { - mfContext* mfc = (mfContext*) context; - rdpSettings* settings = mfc->context.settings; + mfContext *mfc = (mfContext *)context; + rdpSettings *settings = mfc->context.settings; if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) { @@ -831,22 +820,21 @@ void mac_OnChannelConnectedEventHandler(void* context, else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) { if (settings->SoftwareGdi) - gdi_graphics_pipeline_init(mfc->context.gdi, (RdpgfxClientContext*) e->pInterface); + gdi_graphics_pipeline_init(mfc->context.gdi, (RdpgfxClientContext *)e->pInterface); } else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) { - mac_cliprdr_init(mfc, (CliprdrClientContext*) e->pInterface); + mac_cliprdr_init(mfc, (CliprdrClientContext *)e->pInterface); } else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0) { } } -void mac_OnChannelDisconnectedEventHandler(void* context, - ChannelDisconnectedEventArgs* e) +void mac_OnChannelDisconnectedEventHandler(void *context, ChannelDisconnectedEventArgs *e) { - mfContext* mfc = (mfContext*) context; - rdpSettings* settings = mfc->context.settings; + mfContext *mfc = (mfContext *)context; + rdpSettings *settings = mfc->context.settings; if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) { @@ -854,21 +842,20 @@ void mac_OnChannelDisconnectedEventHandler(void* context, else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) { if (settings->SoftwareGdi) - gdi_graphics_pipeline_uninit(mfc->context.gdi, - (RdpgfxClientContext*) e->pInterface); + gdi_graphics_pipeline_uninit(mfc->context.gdi, (RdpgfxClientContext *)e->pInterface); } else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) { - mac_cliprdr_uninit(mfc, (CliprdrClientContext*) e->pInterface); + mac_cliprdr_uninit(mfc, (CliprdrClientContext *)e->pInterface); } else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0) { } } -BOOL mac_pre_connect(freerdp* instance) +BOOL mac_pre_connect(freerdp *instance) { - rdpSettings* settings; + rdpSettings *settings; instance->update->BeginPaint = mac_begin_paint; instance->update->EndPaint = mac_end_paint; instance->update->DesktopResize = mac_desktop_resize; @@ -876,59 +863,30 @@ BOOL mac_pre_connect(freerdp* instance) if (!settings->ServerHostname) { - WLog_ERR(TAG, - "error: server hostname was not specified with /v:[:port]"); + WLog_ERR(TAG, "error: server hostname was not specified with /v:[:port]"); [NSApp terminate:nil]; return -1; } settings->OsMajorType = OSMAJORTYPE_MACINTOSH; settings->OsMinorType = OSMINORTYPE_MACINTOSH; - 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->SoftwareGdi) ? TRUE : - FALSE; - settings->OrderSupport[NEG_MEMBLT_V2_INDEX] = settings->BitmapCacheEnabled; - settings->OrderSupport[NEG_MEM3BLT_V2_INDEX] = FALSE; - 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, - mac_OnChannelConnectedEventHandler); + PubSub_SubscribeChannelConnected(instance->context->pubSub, mac_OnChannelConnectedEventHandler); PubSub_SubscribeChannelDisconnected(instance->context->pubSub, mac_OnChannelDisconnectedEventHandler); - if (!freerdp_client_load_addins(instance->context->channels, - instance->settings)) + if (!freerdp_client_load_addins(instance->context->channels, instance->settings)) return FALSE; return TRUE; } -BOOL mac_post_connect(freerdp* instance) +BOOL mac_post_connect(freerdp *instance) { - rdpGdi* gdi; - rdpSettings* settings; + rdpGdi *gdi; + rdpSettings *settings; rdpPointer rdp_pointer; - mfContext* mfc = (mfContext*) instance->context; - MRDPView* view = (MRDPView*) mfc->view; + mfContext *mfc = (mfContext *)instance->context; + MRDPView *view = (MRDPView *)mfc->view; ZeroMemory(&rdp_pointer, sizeof(rdpPointer)); rdp_pointer.size = sizeof(rdpPointer); rdp_pointer.New = mf_Pointer_New; @@ -948,8 +906,7 @@ BOOL mac_post_connect(freerdp* instance) /* setup pasteboard (aka clipboard) for copy operations (write only) */ view->pasteboard_wr = [NSPasteboard generalPasteboard]; /* setup pasteboard for read operations */ - dispatch_async(dispatch_get_main_queue(), ^ - { + dispatch_async(dispatch_get_main_queue(), ^{ view->pasteboard_rd = [NSPasteboard generalPasteboard]; view->pasteboard_changecount = -1; }); @@ -958,38 +915,53 @@ BOOL mac_post_connect(freerdp* instance) return TRUE; } -BOOL mac_authenticate(freerdp* instance, char** username, char** password, - char** domain) +void mac_post_disconnect(freerdp *instance) +{ + mfContext *mfc; + MRDPView *view; + if (!instance || !instance->context) + return; + + mfc = (mfContext *)instance->context; + view = (MRDPView *)mfc->view; + + [view pause]; + + PubSub_UnsubscribeChannelConnected(instance->context->pubSub, + mac_OnChannelConnectedEventHandler); + PubSub_UnsubscribeChannelDisconnected(instance->context->pubSub, + mac_OnChannelDisconnectedEventHandler); + gdi_free(instance); +} + +static BOOL mac_authenticate_int(NSString *title, freerdp *instance, char **username, + char **password, char **domain) { - mfContext* mfc = (mfContext*) instance->context; - MRDPView* view = (MRDPView*) mfc->view; - PasswordDialog* dialog = [PasswordDialog new]; - dialog.serverHostname = [NSString stringWithFormat:@"%@:%u", - [NSString stringWithCString:instance->settings->ServerHostname encoding: - NSUTF8StringEncoding], - instance->settings->ServerPort]; + mfContext *mfc = (mfContext *)instance->context; + MRDPView *view = (MRDPView *)mfc->view; + PasswordDialog *dialog = [PasswordDialog new]; + dialog.serverHostname = title; if (*username) - dialog.username = [NSString stringWithCString:*username encoding: - NSUTF8StringEncoding]; + dialog.username = [NSString stringWithCString:*username encoding:NSUTF8StringEncoding]; if (*password) - dialog.password = [NSString stringWithCString:*password encoding: - NSUTF8StringEncoding]; + dialog.password = [NSString stringWithCString:*password encoding:NSUTF8StringEncoding]; if (*domain) - dialog.domain = [NSString stringWithCString:*domain encoding: - NSUTF8StringEncoding]; + dialog.domain = [NSString stringWithCString:*domain encoding:NSUTF8StringEncoding]; - [dialog performSelectorOnMainThread:@selector(runModal:) withObject:[view - window] waitUntilDone:TRUE]; + dispatch_sync(dispatch_get_main_queue(), ^{ + [dialog performSelectorOnMainThread:@selector(runModal:) + withObject:[view window] + waitUntilDone:TRUE]; + }); BOOL ok = dialog.modalCode; if (ok) { size_t ulen, plen, dlen; - const char* submittedUsername = [dialog.username cStringUsingEncoding: - NSUTF8StringEncoding]; + const char *submittedUsername = [dialog.username cStringUsingEncoding:NSUTF8StringEncoding]; ulen = (strlen(submittedUsername) + 1) * sizeof(char); *username = malloc(ulen); @@ -997,8 +969,7 @@ BOOL mac_authenticate(freerdp* instance, char** username, char** password, return FALSE; sprintf_s(*username, ulen, "%s", submittedUsername); - const char* submittedPassword = [dialog.password cStringUsingEncoding: - NSUTF8StringEncoding]; + const char *submittedPassword = [dialog.password cStringUsingEncoding:NSUTF8StringEncoding]; plen = (strlen(submittedPassword) + 1) * sizeof(char); *password = malloc(plen); @@ -1006,8 +977,7 @@ BOOL mac_authenticate(freerdp* instance, char** username, char** password, return FALSE; sprintf_s(*password, plen, "%s", submittedPassword); - const char* submittedDomain = [dialog.domain cStringUsingEncoding: - NSUTF8StringEncoding]; + const char *submittedDomain = [dialog.domain cStringUsingEncoding:NSUTF8StringEncoding]; dlen = (strlen(submittedDomain) + 1) * sizeof(char); *domain = malloc(dlen); @@ -1020,25 +990,126 @@ BOOL mac_authenticate(freerdp* instance, char** username, char** password, return ok; } -BOOL mf_Pointer_New(rdpContext* context, rdpPointer* pointer) +BOOL mac_authenticate(freerdp *instance, char **username, char **password, char **domain) +{ + NSString *title = + [NSString stringWithFormat:@"%@:%u", + [NSString stringWithCString:instance->settings->ServerHostname + encoding:NSUTF8StringEncoding], + instance -> settings -> ServerPort]; + return mac_authenticate_int(title, instance, username, password, domain); +} + +BOOL mac_gw_authenticate(freerdp *instance, char **username, char **password, char **domain) +{ + NSString *title = + [NSString stringWithFormat:@"%@:%u", + [NSString stringWithCString:instance->settings->GatewayHostname + encoding:NSUTF8StringEncoding], + instance -> settings -> GatewayPort]; + return mac_authenticate_int(title, instance, username, password, domain); +} + +DWORD mac_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) +{ + mfContext *mfc = (mfContext *)instance->context; + MRDPView *view = (MRDPView *)mfc->view; + CertificateDialog *dialog = [CertificateDialog new]; + const char *type = "RDP-Server"; + char hostname[8192]; + + if (flags & VERIFY_CERT_FLAG_GATEWAY) + type = "RDP-Gateway"; + + if (flags & VERIFY_CERT_FLAG_REDIRECT) + type = "RDP-Redirect"; + + sprintf_s(hostname, sizeof(hostname), "%s %s:%" PRIu16, type, host, port); + dialog.serverHostname = [NSString stringWithCString:hostname]; + dialog.commonName = [NSString stringWithCString:common_name encoding:NSUTF8StringEncoding]; + dialog.subject = [NSString stringWithCString:subject encoding:NSUTF8StringEncoding]; + dialog.issuer = [NSString stringWithCString:issuer encoding:NSUTF8StringEncoding]; + dialog.fingerprint = [NSString stringWithCString:fingerprint encoding:NSUTF8StringEncoding]; + + if (flags & VERIFY_CERT_FLAG_MISMATCH) + dialog.hostMismatch = TRUE; + + if (flags & VERIFY_CERT_FLAG_CHANGED) + dialog.changed = TRUE; + + [dialog performSelectorOnMainThread:@selector(runModal:) + withObject:[view window] + waitUntilDone:TRUE]; + return dialog.result; +} + +DWORD mac_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) +{ + mfContext *mfc = (mfContext *)instance->context; + MRDPView *view = (MRDPView *)mfc->view; + CertificateDialog *dialog = [CertificateDialog new]; + const char *type = "RDP-Server"; + char hostname[8192]; + + if (flags & VERIFY_CERT_FLAG_GATEWAY) + type = "RDP-Gateway"; + + if (flags & VERIFY_CERT_FLAG_REDIRECT) + type = "RDP-Redirect"; + + sprintf_s(hostname, sizeof(hostname), "%s %s:%" PRIu16, type, host, port); + dialog.serverHostname = [NSString stringWithCString:hostname]; + dialog.commonName = [NSString stringWithCString:common_name encoding:NSUTF8StringEncoding]; + dialog.subject = [NSString stringWithCString:subject encoding:NSUTF8StringEncoding]; + dialog.issuer = [NSString stringWithCString:issuer encoding:NSUTF8StringEncoding]; + dialog.fingerprint = [NSString stringWithCString:fingerprint encoding:NSUTF8StringEncoding]; + + if (flags & VERIFY_CERT_FLAG_MISMATCH) + dialog.hostMismatch = TRUE; + + if (flags & VERIFY_CERT_FLAG_CHANGED) + dialog.changed = TRUE; + + [dialog performSelectorOnMainThread:@selector(runModal:) + withObject:[view window] + waitUntilDone:TRUE]; + return dialog.result; +} + +int mac_logon_error_info(freerdp *instance, UINT32 data, UINT32 type) { - rdpGdi* gdi; + const char *str_data = freerdp_get_logon_error_info_data(data); + const char *str_type = freerdp_get_logon_error_info_type(type); + // TODO: Error message dialog + WLog_INFO(TAG, "Logon Error Info %s [%s]", str_data, str_type); + return 1; +} + +BOOL mf_Pointer_New(rdpContext *context, rdpPointer *pointer) +{ + rdpGdi *gdi; NSRect rect; - NSImage* image; + NSImage *image; NSPoint hotSpot; - NSCursor* cursor; - BYTE* cursor_data; - NSMutableArray* ma; - NSBitmapImageRep* bmiRep; - MRDPCursor* mrdpCursor = [[MRDPCursor alloc] init]; - mfContext* mfc = (mfContext*) context; - MRDPView* view; + NSCursor *cursor; + BYTE *cursor_data; + NSMutableArray *ma; + NSBitmapImageRep *bmiRep; + MRDPCursor *mrdpCursor = [[MRDPCursor alloc] init]; + mfContext *mfc = (mfContext *)context; + MRDPView *view; UINT32 format; if (!mfc || !context || !pointer) return FALSE; - view = (MRDPView*) mfc->view; + view = (MRDPView *)mfc->view; gdi = context->gdi; if (!gdi || !view) @@ -1048,7 +1119,7 @@ BOOL mf_Pointer_New(rdpContext* context, rdpPointer* pointer) rect.size.height = pointer->height; rect.origin.x = pointer->xPos; rect.origin.y = pointer->yPos; - cursor_data = (BYTE*) malloc(rect.size.width * rect.size.height * 4); + cursor_data = (BYTE *)malloc(rect.size.width * rect.size.height * 4); if (!cursor_data) return FALSE; @@ -1056,12 +1127,10 @@ BOOL mf_Pointer_New(rdpContext* context, rdpPointer* pointer) mrdpCursor->cursor_data = cursor_data; format = PIXEL_FORMAT_RGBA32; - if (!freerdp_image_copy_from_pointer_data( - cursor_data, format, - 0, 0, 0, pointer->width, pointer->height, - pointer->xorMaskData, pointer->lengthXorMask, - pointer->andMaskData, pointer->lengthAndMask, - pointer->xorBpp, NULL)) + if (!freerdp_image_copy_from_pointer_data(cursor_data, format, 0, 0, 0, pointer->width, + pointer->height, pointer->xorMaskData, + pointer->lengthXorMask, pointer->andMaskData, + pointer->lengthAndMask, pointer->xorBpp, NULL)) { free(cursor_data); mrdpCursor->cursor_data = NULL; @@ -1069,28 +1138,28 @@ BOOL mf_Pointer_New(rdpContext* context, rdpPointer* pointer) } /* store cursor bitmap image in representation - required by NSImage */ - bmiRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes: - (unsigned char**) &cursor_data - pixelsWide:rect.size.width - pixelsHigh:rect.size.height - bitsPerSample:8 - samplesPerPixel:4 - hasAlpha:YES - isPlanar:NO - colorSpaceName:NSDeviceRGBColorSpace - bitmapFormat:0 - bytesPerRow:rect.size.width * GetBytesPerPixel(format) - bitsPerPixel:0]; + bmiRep = [[NSBitmapImageRep alloc] + initWithBitmapDataPlanes:(unsigned char **)&cursor_data + pixelsWide:rect.size.width + pixelsHigh:rect.size.height + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bitmapFormat:0 + bytesPerRow:rect.size.width * GetBytesPerPixel(format) + bitsPerPixel:0]; mrdpCursor->bmiRep = bmiRep; /* create an image using above representation */ image = [[NSImage alloc] initWithSize:[bmiRep size]]; - [image addRepresentation: bmiRep]; + [image addRepresentation:bmiRep]; [image setFlipped:NO]; mrdpCursor->nsImage = image; /* need hotspot to create cursor */ hotSpot.x = pointer->xPos; hotSpot.y = pointer->yPos; - cursor = [[NSCursor alloc] initWithImage: image hotSpot:hotSpot]; + cursor = [[NSCursor alloc] initWithImage:image hotSpot:hotSpot]; mrdpCursor->nsCursor = cursor; mrdpCursor->pointer = pointer; /* save cursor for later use in mf_Pointer_Set() */ @@ -1099,13 +1168,13 @@ BOOL mf_Pointer_New(rdpContext* context, rdpPointer* pointer) return TRUE; } -void mf_Pointer_Free(rdpContext* context, rdpPointer* pointer) +void mf_Pointer_Free(rdpContext *context, rdpPointer *pointer) { - mfContext* mfc = (mfContext*) context; - MRDPView* view = (MRDPView*) mfc->view; - NSMutableArray* ma = view->cursors; + mfContext *mfc = (mfContext *)context; + MRDPView *view = (MRDPView *)mfc->view; + NSMutableArray *ma = view->cursors; - for (MRDPCursor * cursor in ma) + for (MRDPCursor *cursor in ma) { if (cursor->pointer == pointer) { @@ -1119,13 +1188,13 @@ void mf_Pointer_Free(rdpContext* context, rdpPointer* pointer) } } -BOOL mf_Pointer_Set(rdpContext* context, const rdpPointer* pointer) +BOOL mf_Pointer_Set(rdpContext *context, const rdpPointer *pointer) { - mfContext* mfc = (mfContext*) context; - MRDPView* view = (MRDPView*) mfc->view; - NSMutableArray* ma = view->cursors; + mfContext *mfc = (mfContext *)context; + MRDPView *view = (MRDPView *)mfc->view; + NSMutableArray *ma = view->cursors; - for (MRDPCursor * cursor in ma) + for (MRDPCursor *cursor in ma) { if (cursor->pointer == pointer) { @@ -1138,22 +1207,22 @@ BOOL mf_Pointer_Set(rdpContext* context, const rdpPointer* pointer) return TRUE; } -BOOL mf_Pointer_SetNull(rdpContext* context) +BOOL mf_Pointer_SetNull(rdpContext *context) { return TRUE; } -BOOL mf_Pointer_SetDefault(rdpContext* context) +BOOL mf_Pointer_SetDefault(rdpContext *context) { - mfContext* mfc = (mfContext*) context; - MRDPView* view = (MRDPView*) mfc->view; + mfContext *mfc = (mfContext *)context; + MRDPView *view = (MRDPView *)mfc->view; [view setCursor:[NSCursor arrowCursor]]; return TRUE; } -static BOOL mf_Pointer_SetPosition(rdpContext* context, UINT32 x, UINT32 y) +static BOOL mf_Pointer_SetPosition(rdpContext *context, UINT32 x, UINT32 y) { - mfContext* mfc = (mfContext*) context; + mfContext *mfc = (mfContext *)context; if (!mfc) return FALSE; @@ -1162,33 +1231,33 @@ static BOOL mf_Pointer_SetPosition(rdpContext* context, UINT32 x, UINT32 y) return TRUE; } -CGContextRef mac_create_bitmap_context(rdpContext* context) +CGContextRef mac_create_bitmap_context(rdpContext *context) { CGContextRef bitmap_context; - rdpGdi* gdi = context->gdi; + rdpGdi *gdi = context->gdi; UINT32 bpp = GetBytesPerPixel(gdi->dstFormat); CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); if (bpp == 2) { - bitmap_context = CGBitmapContextCreate(gdi->primary_buffer, - gdi->width, gdi->height, 5, gdi->stride, - colorSpace, kCGBitmapByteOrder16Little | kCGImageAlphaNoneSkipFirst); + bitmap_context = CGBitmapContextCreate( + gdi->primary_buffer, gdi->width, gdi->height, 5, gdi->stride, colorSpace, + kCGBitmapByteOrder16Little | kCGImageAlphaNoneSkipFirst); } else { - bitmap_context = CGBitmapContextCreate(gdi->primary_buffer, - gdi->width, gdi->height, 8, gdi->stride, - colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst); + bitmap_context = CGBitmapContextCreate( + gdi->primary_buffer, gdi->width, gdi->height, 8, gdi->stride, colorSpace, + kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst); } CGColorSpaceRelease(colorSpace); return bitmap_context; } -BOOL mac_begin_paint(rdpContext* context) +BOOL mac_begin_paint(rdpContext *context) { - rdpGdi* gdi = context->gdi; + rdpGdi *gdi = context->gdi; if (!gdi) return FALSE; @@ -1197,14 +1266,14 @@ BOOL mac_begin_paint(rdpContext* context) return TRUE; } -BOOL mac_end_paint(rdpContext* context) +BOOL mac_end_paint(rdpContext *context) { - rdpGdi* gdi; + rdpGdi *gdi; HGDI_RGN invalid; NSRect newDrawRect; int ww, wh, dw, dh; - mfContext* mfc = (mfContext*) context; - MRDPView* view = (MRDPView*) mfc->view; + mfContext *mfc = (mfContext *)context; + MRDPView *view = (MRDPView *)mfc->view; gdi = context->gdi; if (!gdi) @@ -1243,17 +1312,19 @@ BOOL mac_end_paint(rdpContext* context) } windows_to_apple_cords(mfc->view, &newDrawRect); - [view setNeedsDisplayInRect:newDrawRect]; + dispatch_sync(dispatch_get_main_queue(), ^{ + [view setNeedsDisplayInRect:newDrawRect]; + }); gdi->primary->hdc->hwnd->ninvalid = 0; return TRUE; } -BOOL mac_desktop_resize(rdpContext* context) +BOOL mac_desktop_resize(rdpContext *context) { ResizeWindowEventArgs e; - mfContext* mfc = (mfContext*) context; - MRDPView* view = (MRDPView*) mfc->view; - rdpSettings* settings = context->settings; + mfContext *mfc = (mfContext *)context; + MRDPView *view = (MRDPView *)mfc->view; + rdpSettings *settings = context->settings; if (!context->gdi) return TRUE; @@ -1287,36 +1358,11 @@ BOOL mac_desktop_resize(rdpContext* context) return TRUE; } -void update_activity_cb(freerdp* instance) +void input_activity_cb(freerdp *instance) { int status; wMessage message; - wMessageQueue* queue; - status = 1; - queue = freerdp_get_message_queue(instance, FREERDP_UPDATE_MESSAGE_QUEUE); - - if (queue) - { - while (MessageQueue_Peek(queue, &message, TRUE)) - { - status = freerdp_message_queue_process_message(instance, - FREERDP_UPDATE_MESSAGE_QUEUE, &message); - - if (!status) - break; - } - } - else - { - WLog_ERR(TAG, "update_activity_cb: No queue!"); - } -} - -void input_activity_cb(freerdp* instance) -{ - int status; - wMessage message; - wMessageQueue* queue; + wMessageQueue *queue; status = 1; queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE); @@ -1324,8 +1370,8 @@ void input_activity_cb(freerdp* instance) { while (MessageQueue_Peek(queue, &message, TRUE)) { - status = freerdp_message_queue_process_message(instance, - FREERDP_INPUT_MESSAGE_QUEUE, &message); + status = freerdp_message_queue_process_message(instance, FREERDP_INPUT_MESSAGE_QUEUE, + &message); if (!status) break; @@ -1333,7 +1379,7 @@ void input_activity_cb(freerdp* instance) } else { - WLog_ERR(TAG, "input_activity_cb: No queue!"); + WLog_ERR(TAG, "input_activity_cb: No queue!"); } } @@ -1345,14 +1391,16 @@ void input_activity_cb(freerdp* instance) * */ -void windows_to_apple_cords(MRDPView* view, NSRect* r) +void windows_to_apple_cords(MRDPView *view, NSRect *r) { - r->origin.y = [view frame].size.height - (r->origin.y + r->size.height); + dispatch_sync(dispatch_get_main_queue(), ^{ + r->origin.y = [view frame].size.height - (r->origin.y + r->size.height); + }); } -void sync_keyboard_state(freerdp* instance) +void sync_keyboard_state(freerdp *instance) { - mfContext* context = (mfContext*)instance->context; + mfContext *context = (mfContext *)instance->context; UINT32 flags = 0; CGEventFlags currentFlags = CGEventSourceFlagsState(kCGEventSourceStateHIDSystemState); diff --git a/client/Mac/PasswordDialog.h b/client/Mac/PasswordDialog.h index 833336e..eb24c5c 100644 --- a/client/Mac/PasswordDialog.h +++ b/client/Mac/PasswordDialog.h @@ -21,29 +21,29 @@ @interface PasswordDialog : NSWindowController { -@public - NSTextField* usernameText; - NSTextField* passwordText; - NSTextField* messageLabel; - NSString* serverHostname; - NSString* username; - NSString* password; - NSString* domain; + @public + NSTextField *usernameText; + NSTextField *passwordText; + NSTextField *messageLabel; + NSString *serverHostname; + NSString *username; + NSString *password; + NSString *domain; BOOL modalCode; } -@property(retain) IBOutlet NSTextField* usernameText; -@property(retain) IBOutlet NSTextField* passwordText; -@property(retain) IBOutlet NSTextField* messageLabel; +@property(retain) IBOutlet NSTextField *usernameText; +@property(retain) IBOutlet NSTextField *passwordText; +@property(retain) IBOutlet NSTextField *messageLabel; -- (IBAction)onOK:(NSObject*)sender; -- (IBAction)onCancel:(NSObject*)sender; +- (IBAction)onOK:(NSObject *)sender; +- (IBAction)onCancel:(NSObject *)sender; -@property(retain) NSString* serverHostname; -@property(retain) NSString* username; -@property(retain) NSString* password; -@property(retain) NSString* domain; +@property(retain) NSString *serverHostname; +@property(retain) NSString *username; +@property(retain) NSString *password; +@property(retain) NSString *domain; @property(readonly) BOOL modalCode; -- (BOOL) runModal:(NSWindow*)mainWindow; +- (BOOL)runModal:(NSWindow *)mainWindow; @end diff --git a/client/Mac/PasswordDialog.m b/client/Mac/PasswordDialog.m index 01de275..f4c520b 100644 --- a/client/Mac/PasswordDialog.m +++ b/client/Mac/PasswordDialog.m @@ -20,9 +20,11 @@ #import "PasswordDialog.h" #import -@interface PasswordDialog() +#import - @property BOOL modalCode; +@interface PasswordDialog () + +@property BOOL modalCode; @end @@ -45,15 +47,16 @@ - (void)windowDidLoad { [super windowDidLoad]; - // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file. + // Implement this method to handle any initialization after your window controller's window has + // been loaded from its nib file. [self.window setTitle:self.serverHostname]; - [messageLabel setStringValue:[NSString stringWithFormat:@"Authenticate to %@", - self.serverHostname]]; - NSMutableString* domainUser = [[NSMutableString alloc] initWithString:@""]; + [self.messageLabel + setStringValue:[NSString stringWithFormat:@"Authenticate to %@", self.serverHostname]]; + NSMutableString *domainUser = [[NSMutableString alloc] initWithString:@""]; - if (self.domain != nil - && [[self.domain stringByTrimmingCharactersInSet:[NSCharacterSet - whitespaceCharacterSet]] length] > 0) + if (self.domain != nil && + [[self.domain stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] + length] > 0) { [domainUser appendFormat:@"%@\\", self.domain]; } @@ -61,24 +64,23 @@ if (self.username != nil) { [domainUser appendString:self.username]; - [self.window makeFirstResponder:passwordText]; + [self.window makeFirstResponder:self.passwordText]; } - [usernameText setStringValue:domainUser]; + [self.usernameText setStringValue:domainUser]; } -- (IBAction)onOK:(NSObject*)sender +- (IBAction)onOK:(NSObject *)sender { - char* submittedUser = NULL; - char* submittedDomain = NULL; + char *submittedUser = NULL; + char *submittedDomain = NULL; - if (freerdp_parse_username([self.usernameText.stringValue cStringUsingEncoding: - NSUTF8StringEncoding], &submittedUser, &submittedDomain)) + if (freerdp_parse_username( + [self.usernameText.stringValue cStringUsingEncoding:NSUTF8StringEncoding], + &submittedUser, &submittedDomain)) { - self.username = [NSString stringWithCString: submittedUser encoding: - NSUTF8StringEncoding]; - self.domain = [NSString stringWithCString: submittedDomain encoding: - NSUTF8StringEncoding]; + self.username = [NSString stringWithCString:submittedUser encoding:NSUTF8StringEncoding]; + self.domain = [NSString stringWithCString:submittedDomain encoding:NSUTF8StringEncoding]; } else { @@ -89,28 +91,28 @@ [NSApp stopModalWithCode:TRUE]; } -- (IBAction)onCancel:(NSObject*)sender +- (IBAction)onCancel:(NSObject *)sender { [NSApp stopModalWithCode:FALSE]; } -- (BOOL)runModal:(NSWindow*)mainWindow +- (BOOL)runModal:(NSWindow *)mainWindow { if ([mainWindow respondsToSelector:@selector(beginSheet:completionHandler:)]) { [mainWindow beginSheet:self.window completionHandler:nil]; - self.modalCode = [NSApp runModalForWindow: self.window]; - [mainWindow endSheet: self.window]; + self.modalCode = [NSApp runModalForWindow:self.window]; + [mainWindow endSheet:self.window]; } else { - [NSApp beginSheet: self.window - modalForWindow: mainWindow - modalDelegate: nil - didEndSelector: nil - contextInfo: nil]; - self.modalCode = [NSApp runModalForWindow: self.window]; - [NSApp endSheet: self.window]; + [NSApp beginSheet:self.window + modalForWindow:mainWindow + modalDelegate:nil + didEndSelector:nil + contextInfo:nil]; + self.modalCode = [NSApp runModalForWindow:self.window]; + [NSApp endSheet:self.window]; } [self.window orderOut:nil]; diff --git a/client/Mac/cli/AppDelegate.h b/client/Mac/cli/AppDelegate.h index 91439c0..64b2611 100644 --- a/client/Mac/cli/AppDelegate.h +++ b/client/Mac/cli/AppDelegate.h @@ -12,15 +12,15 @@ @interface AppDelegate : NSObject { -@public - NSWindow* window; - rdpContext* context; - MRDPView* mrdpView; + @public + NSWindow *window; + rdpContext *context; + MRDPView *mrdpView; } -- (void) rdpConnectError: (NSString*) customMessage; +- (void)rdpConnectError:(NSString *)customMessage; -@property (assign) IBOutlet NSWindow *window; -@property (assign) rdpContext *context; +@property(assign) IBOutlet NSWindow *window; +@property(assign) rdpContext *context; @end diff --git a/client/Mac/cli/AppDelegate.m b/client/Mac/cli/AppDelegate.m index 9d4432b..d916e71 100644 --- a/client/Mac/cli/AppDelegate.m +++ b/client/Mac/cli/AppDelegate.m @@ -12,15 +12,12 @@ #import "MacFreeRDP/MRDPView.h" #import -static AppDelegate* _singleDelegate = nil; -void AppDelegate_ConnectionResultEventHandler(void* context, - ConnectionResultEventArgs* e); -void AppDelegate_ErrorInfoEventHandler(void* ctx, ErrorInfoEventArgs* e); -void AppDelegate_EmbedWindowEventHandler(void* context, - EmbedWindowEventArgs* e); -void AppDelegate_ResizeWindowEventHandler(void* context, - ResizeWindowEventArgs* e); -void mac_set_view_size(rdpContext* context, MRDPView* view); +static AppDelegate *_singleDelegate = nil; +void AppDelegate_ConnectionResultEventHandler(void *context, ConnectionResultEventArgs *e); +void AppDelegate_ErrorInfoEventHandler(void *ctx, ErrorInfoEventArgs *e); +void AppDelegate_EmbedWindowEventHandler(void *context, EmbedWindowEventArgs *e); +void AppDelegate_ResizeWindowEventHandler(void *context, ResizeWindowEventArgs *e); +void mac_set_view_size(rdpContext *context, MRDPView *view); @implementation AppDelegate @@ -31,64 +28,64 @@ void mac_set_view_size(rdpContext* context, MRDPView* view); @synthesize window = window; - @synthesize context = context; -- (void) applicationDidFinishLaunching:(NSNotification*)aNotification +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { int status; - mfContext* mfc; + mfContext *mfc; _singleDelegate = self; [self CreateContext]; status = [self ParseCommandLineArguments]; - mfc = (mfContext*) context; - mfc->view = (void*) mrdpView; + mfc = (mfContext *)context; + mfc->view = (void *)mrdpView; - if (status < 0) - { - NSString* winTitle; - winTitle = [[NSString alloc] initWithCString:"ERROR"]; - [window setTitle:winTitle]; - } - else + if (status == 0) { - NSScreen* screen = [[NSScreen screens] objectAtIndex:0]; + NSScreen *screen = [[NSScreen screens] objectAtIndex:0]; NSRect screenFrame = [screen frame]; if (context->instance->settings->Fullscreen) { - context->instance->settings->DesktopWidth = screenFrame.size.width; + context->instance->settings->DesktopWidth = screenFrame.size.width; context->instance->settings->DesktopHeight = screenFrame.size.height; } - PubSub_SubscribeConnectionResult(context->pubSub, - AppDelegate_ConnectionResultEventHandler); + PubSub_SubscribeConnectionResult(context->pubSub, AppDelegate_ConnectionResultEventHandler); PubSub_SubscribeErrorInfo(context->pubSub, AppDelegate_ErrorInfoEventHandler); - PubSub_SubscribeEmbedWindow(context->pubSub, - AppDelegate_EmbedWindowEventHandler); - PubSub_SubscribeResizeWindow(context->pubSub, - AppDelegate_ResizeWindowEventHandler); + PubSub_SubscribeEmbedWindow(context->pubSub, AppDelegate_EmbedWindowEventHandler); + PubSub_SubscribeResizeWindow(context->pubSub, AppDelegate_ResizeWindowEventHandler); freerdp_client_start(context); - NSString* winTitle; + NSString *winTitle; if (mfc->context.settings->WindowTitle && mfc->context.settings->WindowTitle[0]) { - winTitle = [[NSString alloc] initWithCString: - mfc->context.settings->WindowTitle]; + winTitle = [[NSString alloc] initWithCString:mfc->context.settings->WindowTitle]; } else { - winTitle = [[NSString alloc] initWithFormat:@"%@:%u", - [NSString stringWithCString:mfc->context.settings->ServerHostname encoding: - NSUTF8StringEncoding], - mfc->context.settings->ServerPort]; + winTitle = [[NSString alloc] + initWithFormat:@"%@:%u", + [NSString stringWithCString:mfc->context.settings->ServerHostname + encoding:NSUTF8StringEncoding], + mfc -> context.settings->ServerPort]; } [window setTitle:winTitle]; } } -- (void) applicationWillTerminate:(NSNotification*)notification +- (void)applicationWillBecomeActive:(NSNotification *)notification +{ + [mrdpView resume]; +} + +- (void)applicationWillResignActive:(NSNotification *)notification +{ + [mrdpView pause]; +} + +- (void)applicationWillTerminate:(NSNotification *)notification { NSLog(@"Stopping...\n"); freerdp_client_stop(context); @@ -97,23 +94,23 @@ void mac_set_view_size(rdpContext* context, MRDPView* view); NSLog(@"Stopped.\n"); } -- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender +- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender { return YES; } -- (int) ParseCommandLineArguments +- (int)ParseCommandLineArguments { int i; int length; int status; - char* cptr; - NSArray* args = [[NSProcessInfo processInfo] arguments]; - context->argc = (int) [args count]; - context->argv = malloc(sizeof(char*) * context->argc); + char *cptr; + NSArray *args = [[NSProcessInfo processInfo] arguments]; + context->argc = (int)[args count]; + context->argv = malloc(sizeof(char *) * context->argc); i = 0; - for (NSString * str in args) + for (NSString *str in args) { /* filter out some arguments added by XCode */ if ([str isEqualToString:@"YES"]) @@ -123,20 +120,20 @@ void mac_set_view_size(rdpContext* context, MRDPView* view); continue; length = (int)([str length] + 1); - cptr = (char*) malloc(length); + cptr = (char *)malloc(length); sprintf_s(cptr, length, "%s", [str UTF8String]); context->argv[i++] = cptr; } context->argc = i; - status = freerdp_client_settings_parse_command_line(context->settings, - context->argc, context->argv, FALSE); - status = freerdp_client_settings_command_line_status_print(context->settings, - status, context->argc, context->argv); + status = freerdp_client_settings_parse_command_line(context->settings, context->argc, + context->argv, FALSE); + status = freerdp_client_settings_command_line_status_print(context->settings, status, + context->argc, context->argv); return status; } -- (void) CreateContext +- (void)CreateContext { RDP_CLIENT_ENTRY_POINTS clientEntryPoints; ZeroMemory(&clientEntryPoints, sizeof(RDP_CLIENT_ENTRY_POINTS)); @@ -146,12 +143,12 @@ void mac_set_view_size(rdpContext* context, MRDPView* view); context = freerdp_client_context_new(&clientEntryPoints); } -- (void) ReleaseContext +- (void)ReleaseContext { - mfContext* mfc; - MRDPView* view; - mfc = (mfContext*) context; - view = (MRDPView*) mfc->view; + mfContext *mfc; + MRDPView *view; + mfc = (mfContext *)context; + view = (MRDPView *)mfc->view; [view exitFullScreenModeWithOptions:nil]; [view releaseResources]; [view release]; @@ -160,46 +157,42 @@ void mac_set_view_size(rdpContext* context, MRDPView* view); context = nil; } - /** ********************************************************************* * called when we fail to connect to a RDP server - Make sure this is called from the main thread. ***********************************************************************/ -- (void) rdpConnectError : (NSString*) withMessage +- (void)rdpConnectError:(NSString *)withMessage { - mfContext* mfc; - MRDPView* view; - mfc = (mfContext*) context; - view = (MRDPView*) mfc->view; + mfContext *mfc; + MRDPView *view; + mfc = (mfContext *)context; + view = (MRDPView *)mfc->view; [view exitFullScreenModeWithOptions:nil]; - NSString* message = withMessage ? withMessage : @"Error connecting to server"; - NSAlert* alert = [[NSAlert alloc] init]; + NSString *message = withMessage ? withMessage : @"Error connecting to server"; + NSAlert *alert = [[NSAlert alloc] init]; [alert setMessageText:message]; [alert beginSheetModalForWindow:[self window] - modalDelegate:self - didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) - contextInfo:nil]; + modalDelegate:self + didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) + contextInfo:nil]; } - /** ********************************************************************* * just a terminate selector for above call ***********************************************************************/ -- (void) alertDidEnd:(NSAlert*)a returnCode:(NSInteger)rc contextInfo:(void*)ci +- (void)alertDidEnd:(NSAlert *)a returnCode:(NSInteger)rc contextInfo:(void *)ci { [NSApp terminate:nil]; } - @end /** ********************************************************************* * On connection error, display message and quit application ***********************************************************************/ -void AppDelegate_ConnectionResultEventHandler(void* ctx, - ConnectionResultEventArgs* e) +void AppDelegate_ConnectionResultEventHandler(void *ctx, ConnectionResultEventArgs *e) { NSLog(@"ConnectionResult event result:%d\n", e->result); @@ -207,50 +200,52 @@ void AppDelegate_ConnectionResultEventHandler(void* ctx, { if (e->result != 0) { - NSString* message = nil; + NSString *message = nil; if (connectErrorCode == AUTHENTICATIONERROR) { - message = [NSString stringWithFormat:@"%@", - @"Authentication failure, check credentials."]; + message = [NSString + stringWithFormat:@"%@", @"Authentication failure, check credentials."]; } // Making sure this should be invoked on the main UI thread. [_singleDelegate performSelectorOnMainThread:@selector(rdpConnectError:) - withObject:message waitUntilDone:FALSE]; + withObject:message + waitUntilDone:FALSE]; } } } -void AppDelegate_ErrorInfoEventHandler(void* ctx, ErrorInfoEventArgs* e) +void AppDelegate_ErrorInfoEventHandler(void *ctx, ErrorInfoEventArgs *e) { NSLog(@"ErrorInfo event code:%d\n", e->code); if (_singleDelegate) { // Retrieve error message associated with error code - NSString* message = nil; + NSString *message = nil; if (e->code != ERRINFO_NONE) { - const char* errorMessage = freerdp_get_error_info_string(e->code); + const char *errorMessage = freerdp_get_error_info_string(e->code); message = [[NSString alloc] initWithUTF8String:errorMessage]; } // Making sure this should be invoked on the main UI thread. [_singleDelegate performSelectorOnMainThread:@selector(rdpConnectError:) - withObject:message waitUntilDone:TRUE]; + withObject:message + waitUntilDone:TRUE]; [message release]; } } -void AppDelegate_EmbedWindowEventHandler(void* ctx, EmbedWindowEventArgs* e) +void AppDelegate_EmbedWindowEventHandler(void *ctx, EmbedWindowEventArgs *e) { - rdpContext* context = (rdpContext*) ctx; + rdpContext *context = (rdpContext *)ctx; if (_singleDelegate) { - mfContext* mfc = (mfContext*) context; + mfContext *mfc = (mfContext *)context; _singleDelegate->mrdpView = mfc->view; if (_singleDelegate->window) @@ -258,23 +253,27 @@ void AppDelegate_EmbedWindowEventHandler(void* ctx, EmbedWindowEventArgs* e) [[_singleDelegate->window contentView] addSubview:mfc->view]; } - mac_set_view_size(context, mfc->view); + dispatch_async(dispatch_get_main_queue(), ^{ + mac_set_view_size(context, mfc->view); + }); } } -void AppDelegate_ResizeWindowEventHandler(void* ctx, ResizeWindowEventArgs* e) +void AppDelegate_ResizeWindowEventHandler(void *ctx, ResizeWindowEventArgs *e) { - rdpContext* context = (rdpContext*) ctx; + rdpContext *context = (rdpContext *)ctx; fprintf(stderr, "ResizeWindowEventHandler: %d %d\n", e->width, e->height); if (_singleDelegate) { - mfContext* mfc = (mfContext*) context; - mac_set_view_size(context, mfc->view); + mfContext *mfc = (mfContext *)context; + dispatch_async(dispatch_get_main_queue(), ^{ + mac_set_view_size(context, mfc->view); + }); } } -void mac_set_view_size(rdpContext* context, MRDPView* view) +void mac_set_view_size(rdpContext *context, MRDPView *view) { // set client area to specified dimensions NSRect innerRect; diff --git a/client/Mac/cli/CMakeLists.txt b/client/Mac/cli/CMakeLists.txt index d7b7b41..b481ab5 100644 --- a/client/Mac/cli/CMakeLists.txt +++ b/client/Mac/cli/CMakeLists.txt @@ -10,15 +10,16 @@ find_library(FOUNDATION_LIBRARY Foundation) find_library(COCOA_LIBRARY Cocoa) find_library(APPKIT_LIBRARY AppKit) +string(TIMESTAMP VERSION_YEAR "%Y") set(MACOSX_BUNDLE_INFO_STRING "MacFreeRDP") set(MACOSX_BUNDLE_ICON_FILE "FreeRDP.icns") set(MACOSX_BUNDLE_GUI_IDENTIFIER "com.freerdp.mac") set(MACOSX_BUNDLE_BUNDLE_IDENTIFIER "FreeRDP-client.Mac") -set(MACOSX_BUNDLE_LONG_VERSION_STRING "MacFreeRDP Client Version 1.1.0") +set(MACOSX_BUNDLE_LONG_VERSION_STRING "MacFreeRDP Client Version ${FREERDP_VERSION}") set(MACOSX_BUNDLE_BUNDLE_NAME "MacFreeRDP") -set(MACOSX_BUNDLE_SHORT_VERSION_STRING 1.1.0) -set(MACOSX_BUNDLE_BUNDLE_VERSION 1.1.0) -set(MACOSX_BUNDLE_COPYRIGHT "Copyright 2013. All Rights Reserved.") +set(MACOSX_BUNDLE_SHORT_VERSION_STRING ${FREERDP_VERSION}) +set(MACOSX_BUNDLE_BUNDLE_VERSION ${FREERDP_VERSION}) +set(MACOSX_BUNDLE_COPYRIGHT "Copyright 2013-${VERSION_YEAR}. All Rights Reserved.") set(MACOSX_BUNDLE_NSMAIN_NIB_FILE "MainMenu") set(MACOSX_BUNDLE_NSPRINCIPAL_CLASS "NSApplication") diff --git a/client/Mac/cli/MainMenu.xib b/client/Mac/cli/MainMenu.xib index 65e72b1..f647699 100644 --- a/client/Mac/cli/MainMenu.xib +++ b/client/Mac/cli/MainMenu.xib @@ -1,631 +1,120 @@ - - - 1070 - 12E55 - 3084 - 1187.39 - 626.00 - - com.apple.InterfaceBuilder.CocoaPlugin - 3084 - - - NSCustomObject - NSMenu - NSMenuItem - NSView - NSWindowTemplate - - - com.apple.InterfaceBuilder.CocoaPlugin - - - PluginDependencyRecalculationVersion - - - - - NSApplication - - - FirstResponder - - - NSApplication - - - AMainMenu - - - - FreeRDP - - 1048576 - 2147483647 - - NSImage - NSMenuCheckmark - - - NSImage - NSMenuMixedState - - submenuAction: - - FreeRDP - - - - About FreeRDP - - 2147483647 - - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Hide FreeRDP - h - 1048576 - 2147483647 - - - - - - Hide Others - h - 1572864 - 2147483647 - - - - - - Show All - - 1048576 - 2147483647 - - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Quit FreeRDP - q - 1048576 - 2147483647 - - - - - _NSAppleMenu - - - - - File - - 1048576 - 2147483647 - - - - - - Edit - - 1048576 - 2147483647 - - - - - - Format - - 2147483647 - - - - - - View - - 1048576 - 2147483647 - - - - - - Window - - 1048576 - 2147483647 - - - submenuAction: - - Window - - - - Minimize - m - 1048576 - 2147483647 - - - - - - Zoom - - 1048576 - 2147483647 - - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Bring All to Front - - 1048576 - 2147483647 - - - - - _NSWindowsMenu - - - - - Help - - 2147483647 - - - submenuAction: - - Help - - - - Mac Help - ? - 1048576 - 2147483647 - - - - - _NSHelpMenu - - - - _NSMainMenu - - - 15 - 2 - {{163, 10}, {1024, 768}} - 1954021376 - FreeRDP - NSWindow - - - {1024, 768} - {1024, 768} - - - 256 - - {1024, 768} - - - - {{0, 0}, {1920, 1178}} - {1024, 790} - {1024, 790} - 128 - YES - - - AppDelegate - - - NSFontManager - - - - - - - terminate: - - - - 449 - - - - orderFrontStandardAboutPanel: - - - - 142 - - - - delegate - - - - 568 - - - - performMiniaturize: - - - - 37 - - - - arrangeInFront: - - - - 39 - - - - performZoom: - - - - 240 - - - - hide: - - - - 367 - - - - hideOtherApplications: - - - - 368 - - - - unhideAllApplications: - - - - 370 - - - - showHelp: - - - - 493 - - - - window - - - - 570 - - - - - - 0 - - - - - - -2 - - - File's Owner - - - -1 - - - First Responder - - - -3 - - - Application - - - 29 - - - - - - - - - - - - - - 19 - - - - - - - - 56 - - - - - - - - 217 - - - - - - 83 - - - - - - 57 - - - - - - - - - - - - - - 58 - - - - - 134 - - - - - 150 - - - - - 136 - - - - - 236 - - - - - 149 - - - - - 145 - - - - - 24 - - - - - - - - - - - 92 - - - - - 5 - - - - - 239 - - - - - 23 - - - - - 295 - - - - - - 371 - - - - - - - - 372 - - - - - - 375 - - - - - - 420 - - - - - 490 - - - - - - - - 491 - - - - - - - - 492 - - - - - 494 - - - - - - - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - {{380, 496}, {480, 360}} - - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - - - - - - 570 - - - 0 - IBCocoaFramework - - com.apple.InterfaceBuilder.CocoaPlugin.macosx - - - YES - 3 - - {11, 11} - {10, 3} - - YES - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/Mac/cli/main.m b/client/Mac/cli/main.m index 4048b01..69643ef 100644 --- a/client/Mac/cli/main.m +++ b/client/Mac/cli/main.m @@ -10,5 +10,5 @@ int main(int argc, char *argv[]) { - return NSApplicationMain(argc, (const char**) argv); + return NSApplicationMain(argc, argv); } diff --git a/client/Mac/mf_client.h b/client/Mac/mf_client.h index 79712cc..c3b3c85 100644 --- a/client/Mac/mf_client.h +++ b/client/Mac/mf_client.h @@ -25,16 +25,22 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -FREERDP_API void mf_scale_mouse_event(void* context, rdpInput* input, UINT16 flags, UINT16 x, UINT16 y); + FREERDP_API void mf_press_mouse_button(void* context, rdpInput* intput, int button, int x, + int y, BOOL down); + FREERDP_API void mf_scale_mouse_event(void* context, rdpInput* input, UINT16 flags, UINT16 x, + UINT16 y); + FREERDP_API void mf_scale_mouse_event_ex(void* context, rdpInput* input, UINT16 flags, UINT16 x, + UINT16 y); -/** - * Client Interface - */ + /** + * Client Interface + */ -FREERDP_API int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints); + FREERDP_API int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints); #ifdef __cplusplus } diff --git a/client/Mac/mf_client.m b/client/Mac/mf_client.m index 575d448..10fb1b4 100644 --- a/client/Mac/mf_client.m +++ b/client/Mac/mf_client.m @@ -30,36 +30,37 @@ * Client Interface */ -static BOOL mfreerdp_client_global_init() +static BOOL mfreerdp_client_global_init(void) { freerdp_handle_signals(); return TRUE; } -static void mfreerdp_client_global_uninit() +static void mfreerdp_client_global_uninit(void) { } -static int mfreerdp_client_start(rdpContext* context) +static int mfreerdp_client_start(rdpContext *context) { - MRDPView* view; - mfContext* mfc = (mfContext*) context; + MRDPView *view; + mfContext *mfc = (mfContext *)context; if (mfc->view == NULL) { // view not specified beforehand. Create view dynamically - mfc->view = [[MRDPView alloc] initWithFrame : NSMakeRect(0, 0, - context->settings->DesktopWidth, context->settings->DesktopHeight)]; + mfc->view = + [[MRDPView alloc] initWithFrame:NSMakeRect(0, 0, context->settings->DesktopWidth, + context->settings->DesktopHeight)]; mfc->view_ownership = TRUE; } - view = (MRDPView*) mfc->view; + view = (MRDPView *)mfc->view; return [view rdpStart:context]; } -static int mfreerdp_client_stop(rdpContext* context) +static int mfreerdp_client_stop(rdpContext *context) { - mfContext* mfc = (mfContext*) context; + mfContext *mfc = (mfContext *)context; if (mfc->thread) { @@ -71,7 +72,7 @@ static int mfreerdp_client_stop(rdpContext* context) if (mfc->view_ownership) { - MRDPView* view = (MRDPView*) mfc->view; + MRDPView *view = (MRDPView *)mfc->view; [view releaseResources]; [view release]; mfc->view = nil; @@ -80,88 +81,127 @@ static int mfreerdp_client_stop(rdpContext* context) return 0; } -static BOOL mfreerdp_client_new(freerdp* instance, rdpContext* context) +static BOOL mfreerdp_client_new(freerdp *instance, rdpContext *context) { - mfContext* mfc; - rdpSettings* settings; - mfc = (mfContext*) instance->context; + mfContext *mfc; + rdpSettings *settings; + mfc = (mfContext *)instance->context; mfc->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); context->instance->PreConnect = mac_pre_connect; context->instance->PostConnect = mac_post_connect; + context->instance->PostDisconnect = mac_post_disconnect; context->instance->Authenticate = mac_authenticate; - settings = instance->settings; + context->instance->GatewayAuthenticate = mac_gw_authenticate; + context->instance->VerifyCertificateEx = mac_verify_certificate_ex; + context->instance->VerifyChangedCertificateEx = mac_verify_changed_certificate_ex; + context->instance->LogonErrorInfo = mac_logon_error_info; + context->instance->settings = instance->settings; + settings = context->settings; settings->AsyncUpdate = TRUE; settings->AsyncInput = TRUE; return TRUE; } -static void mfreerdp_client_free(freerdp* instance, rdpContext* context) +static void mfreerdp_client_free(freerdp *instance, rdpContext *context) { - mfContext* mfc; - rdpSettings* settings; + mfContext *mfc; if (!instance || !context) return; - mfc = (mfContext*) instance->context; + mfc = (mfContext *)instance->context; CloseHandle(mfc->stopEvent); } -static void freerdp_client_mouse_event(rdpContext* cfc, DWORD flags, int x, - int y) +static void mf_scale_mouse_coordinates(mfContext *mfc, UINT16 *px, UINT16 *py) { - int width, height; - rdpInput* input = cfc->instance->input; - rdpSettings* settings = cfc->instance->settings; - width = settings->DesktopWidth; - height = settings->DesktopHeight; + UINT16 x = *px; + UINT16 y = *py; + UINT32 ww = mfc->client_width; + UINT32 wh = mfc->client_height; + UINT32 dw = mfc->context.settings->DesktopWidth; + UINT32 dh = mfc->context.settings->DesktopHeight; - if (x < 0) - x = 0; + if (!mfc->context.settings->SmartSizing || ((ww == dw) && (wh == dh))) + { + y = y + mfc->yCurrentScroll; + x = x + mfc->xCurrentScroll; - x = width - 1; + y -= (dh - wh); + x -= (dw - ww); + } + else + { + y = y * dh / wh + mfc->yCurrentScroll; + x = x * dw / ww + mfc->xCurrentScroll; + } - if (y < 0) - y = 0; + *px = x; + *py = y; +} - if (y >= height) - y = height - 1; +void mf_scale_mouse_event(void *context, rdpInput *input, UINT16 flags, UINT16 x, UINT16 y) +{ + mfContext *mfc = (mfContext *)context; + MRDPView *view = (MRDPView *)mfc->view; + // Convert to windows coordinates + y = [view frame].size.height - y; + if ((flags & (PTR_FLAGS_WHEEL | PTR_FLAGS_HWHEEL)) == 0) + mf_scale_mouse_coordinates(mfc, &x, &y); freerdp_input_send_mouse_event(input, flags, x, y); } -void mf_scale_mouse_event(void* context, rdpInput* input, UINT16 flags, - UINT16 x, UINT16 y) +void mf_scale_mouse_event_ex(void *context, rdpInput *input, UINT16 flags, UINT16 x, UINT16 y) { - mfContext* mfc = (mfContext*) context; - MRDPView* view = (MRDPView*) mfc->view; - int ww, wh, dw, dh; - ww = mfc->client_width; - wh = mfc->client_height; - dw = mfc->context.settings->DesktopWidth; - dh = mfc->context.settings->DesktopHeight; + mfContext *mfc = (mfContext *)context; + MRDPView *view = (MRDPView *)mfc->view; // Convert to windows coordinates y = [view frame].size.height - y; - if (!mfc->context.settings->SmartSizing || ((ww == dw) && (wh == dh))) - { - y = y + mfc->yCurrentScroll; + mf_scale_mouse_coordinates(mfc, &x, &y); + freerdp_input_send_extended_mouse_event(input, flags, x, y); +} - if (wh != dh) - { - y -= (dh - wh); - } +void mf_press_mouse_button(void *context, rdpInput *input, int button, int x, int y, BOOL down) +{ + UINT16 flags = 0; + UINT16 xflags = 0; - freerdp_input_send_mouse_event(input, flags, x + mfc->xCurrentScroll, y); + if (down) + { + flags |= PTR_FLAGS_DOWN; + xflags |= PTR_XFLAGS_DOWN; } - else + + switch (button) { - y = y * dh / wh + mfc->yCurrentScroll; - freerdp_input_send_mouse_event(input, flags, x * dw / ww + mfc->xCurrentScroll, y); + case 0: + mf_scale_mouse_event(context, input, flags | PTR_FLAGS_BUTTON1, x, y); + break; + + case 1: + mf_scale_mouse_event(context, input, flags | PTR_FLAGS_BUTTON2, x, y); + break; + + case 2: + mf_scale_mouse_event(context, input, flags | PTR_FLAGS_BUTTON3, x, y); + break; + + case 3: + mf_scale_mouse_event_ex(context, input, xflags | PTR_XFLAGS_BUTTON1, x, y); + break; + + case 4: + mf_scale_mouse_event_ex(context, input, xflags | PTR_XFLAGS_BUTTON2, x, y); + break; + + default: + break; } } -int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints) +int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS *pEntryPoints) { pEntryPoints->Version = 1; pEntryPoints->Size = sizeof(RDP_CLIENT_ENTRY_POINTS_V1); diff --git a/client/Mac/mfreerdp.h b/client/Mac/mfreerdp.h index 1d21a96..be39031 100644 --- a/client/Mac/mfreerdp.h +++ b/client/Mac/mfreerdp.h @@ -28,7 +28,7 @@ typedef struct mf_context mfContext; #include "MRDPView.h" #include "Keyboard.h" -#include +#include struct mf_context { @@ -75,15 +75,15 @@ struct mf_context // These variables are required for horizontal scrolling. BOOL updating_scrollbars; BOOL xScrollVisible; - int xMinScroll; // minimum horizontal scroll value - int xCurrentScroll; // current horizontal scroll value - int xMaxScroll; // maximum horizontal scroll value + int xMinScroll; // minimum horizontal scroll value + int xCurrentScroll; // current horizontal scroll value + int xMaxScroll; // maximum horizontal scroll value // These variables are required for vertical scrolling. BOOL yScrollVisible; - int yMinScroll; // minimum vertical scroll value - int yCurrentScroll; // current vertical scroll value - int yMaxScroll; // maximum vertical scroll value + int yMinScroll; // minimum vertical scroll value + int yCurrentScroll; // current vertical scroll value + int yMaxScroll; // maximum vertical scroll value CGEventFlags kbdFlags; }; diff --git a/client/Sample/CMakeLists.txt b/client/Sample/CMakeLists.txt index 1e64733..a8e9a6e 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 @@ -45,3 +48,4 @@ set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-client freerdp) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Client/Sample") +install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT client) diff --git a/client/Sample/tf_channels.c b/client/Sample/tf_channels.c new file mode 100644 index 0000000..7119a1c --- /dev/null +++ b/client/Sample/tf_channels.c @@ -0,0 +1,115 @@ +/** + * 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 "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, + const ENCOMSP_PARTICIPANT_CREATED_PDU* participantCreated) +{ + WINPR_UNUSED(context); + WINPR_UNUSED(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; + + if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) + { + tf->rdpei = (RdpeiClientContext*)e->pInterface; + } + 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; + + if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) + { + tf->rdpei = NULL; + } + 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..b1c0b86 --- /dev/null +++ b/client/Sample/tf_channels.h @@ -0,0 +1,33 @@ +/** + * 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..3ba82c7 --- /dev/null +++ b/client/Sample/tf_freerdp.c @@ -0,0 +1,361 @@ +/** + * 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 */ + WINPR_UNUSED(context); + WINPR_UNUSED(play_sound); + 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 */ + WINPR_UNUSED(context); + WINPR_UNUSED(led_flags); + 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 */ + WINPR_UNUSED(context); +} + +/* 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; + DWORD result = 0; + HANDLE handles[64]; + BOOL rc = freerdp_connect(instance); + + if (instance->settings->AuthenticationOnly) + { + result = freerdp_get_last_error(instance->context); + freerdp_abort_connect(instance); + WLog_ERR(TAG, "Authentication only, exit status 0x%08" PRIx32 "", result); + goto disconnect; + } + + if (!rc) + { + result = freerdp_get_last_error(instance->context); + WLog_ERR(TAG, "connection failure 0x%08" PRIx32, result); + return result; + } + + 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; + } + } + +disconnect: + freerdp_disconnect(instance); + return result; +} + +/* 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); + WINPR_UNUSED(tf); + + 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 */ + WINPR_UNUSED(tf); + return TRUE; +} + +static void tf_client_free(freerdp* instance, rdpContext* context) +{ + tfContext* tf = (tfContext*)instance->context; + + if (!context) + return; + + /* TODO: Client display tear down */ + WINPR_UNUSED(tf); +} + +static int tf_client_start(rdpContext* context) +{ + /* TODO: Start client related stuff */ + WINPR_UNUSED(context); + return 0; +} + +static int tf_client_stop(rdpContext* context) +{ + /* TODO: Stop client related stuff */ + WINPR_UNUSED(context); + 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) + { + rc = 0; + goto fail; + } + + 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..19e0cee --- /dev/null +++ b/client/Sample/tf_freerdp.h @@ -0,0 +1,42 @@ +/** + * 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 + +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..a9e19e3 100644 --- a/client/Wayland/CMakeLists.txt +++ b/client/Wayland/CMakeLists.txt @@ -25,15 +25,22 @@ 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 ) +list (APPEND ${MODULE_PREFIX}_LIBS freerdp-client freerdp uwac) + add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-client freerdp uwac) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT client) diff --git a/client/Wayland/wlf_channels.c b/client/Wayland/wlf_channels.c index c8a4c9d..9c49584 100644 --- a/client/Wayland/wlf_channels.c +++ b/client/Wayland/wlf_channels.c @@ -24,23 +24,64 @@ #include #include "wlf_channels.h" +#include "wlf_cliprdr.h" +#include "wlf_disp.h" #include "wlfreerdp.h" +BOOL encomsp_toggle_control(EncomspClientContext* encomsp, BOOL control) +{ + ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU pdu; + + if (!encomsp) + return FALSE; + + pdu.ParticipantId = 0; + pdu.Flags = ENCOMSP_REQUEST_VIEW; + + if (control) + pdu.Flags |= ENCOMSP_REQUEST_INTERACT; + + encomsp->ChangeParticipantControlLevel(encomsp, &pdu); + return TRUE; +} + /** * Function description * * @return 0 on success, otherwise a Win32 error code */ -static UINT wlf_encomsp_participant_created(EncomspClientContext* context, - ENCOMSP_PARTICIPANT_CREATED_PDU* participantCreated) +static UINT +wlf_encomsp_participant_created(EncomspClientContext* context, + const ENCOMSP_PARTICIPANT_CREATED_PDU* participantCreated) { + wlfContext* wlf; + rdpSettings* settings; + BOOL request; + + if (!context || !context->custom || !participantCreated) + return ERROR_INVALID_PARAMETER; + + wlf = (wlfContext*)context->custom; + settings = wlf->context.settings; + + if (!settings) + return ERROR_INVALID_PARAMETER; + + request = freerdp_settings_get_bool(settings, FreeRDP_RemoteAssistanceRequestControl); + if (request && (participantCreated->Flags & ENCOMSP_MAY_VIEW) && + !(participantCreated->Flags & ENCOMSP_MAY_INTERACT)) + { + if (!encomsp_toggle_control(context, TRUE)) + return ERROR_INTERNAL_ERROR; + } + return CHANNEL_RC_OK; } static void wlf_encomsp_init(wlfContext* wlf, EncomspClientContext* encomsp) { wlf->encomsp = encomsp; - encomsp->custom = (void*) wlf; + encomsp->custom = (void*)wlf; encomsp->ParticipantCreated = wlf_encomsp_participant_created; } @@ -56,68 +97,60 @@ static void wlf_encomsp_uninit(wlfContext* wlf, EncomspClientContext* encomsp) wlf->encomsp = NULL; } - -void wlf_OnChannelConnectedEventHandler(void* context, - ChannelConnectedEventArgs* e) +void wlf_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e) { - wlfContext* wlf = (wlfContext*) context; - rdpSettings* settings; - - settings = wlf->context.settings; + wlfContext* wlf = (wlfContext*)context; if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) { - wlf->rdpei = (RdpeiClientContext*) e->pInterface; - } - else if (strcmp(e->name, TSMF_DVC_CHANNEL_NAME) == 0) - { + wlf->rdpei = (RdpeiClientContext*)e->pInterface; } 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); + 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, - ChannelDisconnectedEventArgs* e) +void wlf_OnChannelDisconnectedEventHandler(void* context, ChannelDisconnectedEventArgs* e) { - wlfContext* wlf = (wlfContext*) context; - rdpSettings* settings; - - settings = wlf->context.settings; + wlfContext* wlf = (wlfContext*)context; if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) { wlf->rdpei = NULL; } - else if (strcmp(e->name, TSMF_DVC_CHANNEL_NAME) == 0) - { - } 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); + 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_channels.h b/client/Wayland/wlf_channels.h index 1b6c591..c56be6a 100644 --- a/client/Wayland/wlf_channels.h +++ b/client/Wayland/wlf_channels.h @@ -23,20 +23,15 @@ #include #include #include -#include #include #include #include #include -int wlf_on_channel_connected(freerdp* instance, const char* name, - void* pInterface); -int wlf_on_channel_disconnected(freerdp* instance, const char* name, - void* pInterface); +int wlf_on_channel_connected(freerdp* instance, const char* name, void* pInterface); +int wlf_on_channel_disconnected(freerdp* instance, const char* name, void* pInterface); -void wlf_OnChannelConnectedEventHandler(void* context, - ChannelConnectedEventArgs* e); -void wlf_OnChannelDisconnectedEventHandler(void* context, - ChannelDisconnectedEventArgs* e); +void wlf_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e); +void wlf_OnChannelDisconnectedEventHandler(void* context, ChannelDisconnectedEventArgs* e); #endif /* FREERDP_CLIENT_WAYLAND_CHANNELS_H */ diff --git a/client/Wayland/wlf_cliprdr.c b/client/Wayland/wlf_cliprdr.c new file mode 100644 index 0000000..dff5998 --- /dev/null +++ b/client/Wayland/wlf_cliprdr.c @@ -0,0 +1,889 @@ +/** + * 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 TAG CLIENT_TAG("wayland.cliprdr") + +#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; + formatList.msgType = CB_FORMAT_LIST; + 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 = CHANNEL_RC_OK; + 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 + { + cdata = NULL; + 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; + } + + if (rc != CHANNEL_RC_OK) + return rc; + + 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; + 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.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; + 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.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; + 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; + /* TODO: set up a filesystem base path for local URI */ + /* clipboard->delegate->basePath = "file:///tmp/foo/bar/gaga"; */ + 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..51a5f9e --- /dev/null +++ b/client/Wayland/wlf_disp.c @@ -0,0 +1,401 @@ +/** + * 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 TAG CLIENT_TAG("wayland.disp") + +#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; + + WINPR_UNUSED(e); + 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; + + WINPR_UNUSED(e); + 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; +} + +int wlf_list_monitors(wlfContext* wlc) +{ + uint32_t i, nmonitors = UwacDisplayGetNbOutputs(wlc->display); + + for (i = 0; i < nmonitors; i++) + { + const UwacOutput* monitor = UwacDisplayGetOutput(wlc->display, i); + UwacSize resolution; + UwacPosition pos; + + if (!monitor) + continue; + UwacOutputGetPosition(monitor, &pos); + UwacOutputGetResolution(monitor, &resolution); + + printf(" %s [%d] %dx%d\t+%d+%d\n", (i == 0) ? "*" : " ", i, resolution.width, + resolution.height, pos.x, pos.y); + } + + return 0; +} diff --git a/client/Wayland/wlf_disp.h b/client/Wayland/wlf_disp.h new file mode 100644 index 0000000..36fa27c --- /dev/null +++ b/client/Wayland/wlf_disp.h @@ -0,0 +1,38 @@ +/** + * 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); + +int wlf_list_monitors(wlfContext* wlc); + +#endif /* FREERDP_CLIENT_WAYLAND_DISP_H */ diff --git a/client/Wayland/wlf_input.c b/client/Wayland/wlf_input.c index 2516cb4..8dcbb5f 100644 --- a/client/Wayland/wlf_input.c +++ b/client/Wayland/wlf_input.c @@ -22,39 +22,81 @@ #include #include +#include +#include +#include "wlfreerdp.h" #include "wlf_input.h" -BOOL wlf_handle_pointer_enter(freerdp* instance, UwacPointerEnterLeaveEvent* ev) +#define TAG CLIENT_TAG("wayland.input") + +#define MAX_CONTACTS 20 + +typedef struct touch_contact { + int id; + double pos_x; + double pos_y; + BOOL emulate_mouse; +} touchContact; + +static touchContact contacts[MAX_CONTACTS]; + +BOOL wlf_handle_pointer_enter(freerdp* instance, const UwacPointerEnterLeaveEvent* ev) +{ + uint32_t x, y; + if (!instance || !ev || !instance->input) return FALSE; - return freerdp_input_send_mouse_event(instance->input, PTR_FLAGS_MOVE, ev->x, ev->y); + x = ev->x; + y = ev->y; + + if (!wlf_scale_coordinates(instance->context, &x, &y, TRUE)) + return FALSE; + + return freerdp_input_send_mouse_event(instance->input, PTR_FLAGS_MOVE, x, y); } -BOOL wlf_handle_pointer_motion(freerdp* instance, UwacPointerMotionEvent* ev) +BOOL wlf_handle_pointer_motion(freerdp* instance, const UwacPointerMotionEvent* ev) { + uint32_t x, y; + if (!instance || !ev || !instance->input) return FALSE; - return freerdp_input_send_mouse_event(instance->input, PTR_FLAGS_MOVE, ev->x, ev->y); + x = ev->x; + y = ev->y; + + if (!wlf_scale_coordinates(instance->context, &x, &y, TRUE)) + return FALSE; + + return freerdp_input_send_mouse_event(instance->input, PTR_FLAGS_MOVE, x, y); } -BOOL wlf_handle_pointer_buttons(freerdp* instance, UwacPointerButtonEvent* ev) +BOOL wlf_handle_pointer_buttons(freerdp* instance, const UwacPointerButtonEvent* ev) { rdpInput* input; - UINT16 flags; + UINT16 flags = 0; + UINT16 xflags = 0; + uint32_t x, y; if (!instance || !ev || !instance->input) return FALSE; + x = ev->x; + y = ev->y; + + if (!wlf_scale_coordinates(instance->context, &x, &y, TRUE)) + return FALSE; + 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,40 +112,84 @@ 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, x, y); + if ((xflags & ~PTR_XFLAGS_DOWN) != 0) + return freerdp_input_send_extended_mouse_event(input, xflags, x, y); + + return FALSE; +} -BOOL wlf_handle_pointer_axis(freerdp* instance, UwacPointerAxisEvent* ev) +BOOL wlf_handle_pointer_axis(freerdp* instance, const UwacPointerAxisEvent* ev) { rdpInput* input; - UINT16 flags; + UINT16 flags = 0; int direction; + uint32_t step; + uint32_t x, y; if (!instance || !ev || !instance->input) return FALSE; + x = ev->x; + y = ev->y; + + if (!wlf_scale_coordinates(instance->context, &x, &y, TRUE)) + return FALSE; + input = instance->input; - flags = PTR_FLAGS_WHEEL; - if (ev->axis == WL_POINTER_AXIS_VERTICAL_SCROLL) + direction = wl_fixed_to_int(ev->value); + switch (ev->axis) { - direction = wl_fixed_to_int(ev->value); + case WL_POINTER_AXIS_VERTICAL_SCROLL: + flags |= PTR_FLAGS_WHEEL; + if (direction > 0) + flags |= PTR_FLAGS_WHEEL_NEGATIVE; + break; + + case WL_POINTER_AXIS_HORIZONTAL_SCROLL: + flags |= PTR_FLAGS_HWHEEL; + if (direction < 0) + flags |= PTR_FLAGS_WHEEL_NEGATIVE; + break; - if (direction < 0) - flags |= 0x0078; - else - flags |= PTR_FLAGS_WHEEL_NEGATIVE | 0x0088; + default: + return FALSE; } - return freerdp_input_send_mouse_event(input, flags, ev->x, ev->y); + /* Wheel rotation steps: + * + * positive: 0 ... 0xFF -> slow ... fast + * negative: 0 ... 0xFF -> fast ... slow + */ + step = abs(direction); + if (step > 0xFF) + step = 0xFF; + + /* Negative rotation, so count down steps from top */ + if (flags & PTR_FLAGS_WHEEL_NEGATIVE) + step = 0xFF - step; + + flags |= step; + + return freerdp_input_send_mouse_event(input, flags, (UINT16)x, (UINT16)y); } -BOOL wlf_handle_key(freerdp* instance, UwacKeyEvent* ev) +BOOL wlf_handle_key(freerdp* instance, const UwacKeyEvent* ev) { rdpInput* input; DWORD rdp_scancode; @@ -120,7 +206,7 @@ BOOL wlf_handle_key(freerdp* instance, UwacKeyEvent* ev) return freerdp_input_send_keyboard_event_ex(input, ev->pressed, rdp_scancode); } -BOOL wlf_keyboard_enter(freerdp* instance, UwacKeyboardEnterLeaveEvent* ev) +BOOL wlf_keyboard_enter(freerdp* instance, const UwacKeyboardEnterLeaveEvent* ev) { rdpInput* input; @@ -129,5 +215,166 @@ 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); +} + +BOOL wlf_handle_touch_up(freerdp* instance, const UwacTouchUp* ev) +{ + uint32_t x, y; + int i; + int touchId; + int contactId; + + if (!instance || !ev || !instance->context) + return FALSE; + + touchId = ev->id; + + for (i = 0; i < MAX_CONTACTS; i++) + { + if (contacts[i].id == touchId) + { + contacts[i].id = 0; + x = contacts[i].pos_x; + y = contacts[i].pos_y; + break; + } + } + + if (i == MAX_CONTACTS) + return FALSE; + + WLog_DBG(TAG, "%s called | event_id: %u | x: %u / y: %u", __FUNCTION__, touchId, x, y); + + if (!wlf_scale_coordinates(instance->context, &x, &y, TRUE)) + return FALSE; + + RdpeiClientContext* rdpei = ((wlfContext*)instance->context)->rdpei; + + if (contacts[i].emulate_mouse == TRUE) + { + UINT16 flags = 0; + flags |= PTR_FLAGS_BUTTON1; + + if ((flags & ~PTR_FLAGS_DOWN) != 0) + return freerdp_input_send_mouse_event(instance->input, flags, x, y); + + return TRUE; + } + + if (!rdpei) + return FALSE; + + rdpei->TouchEnd(rdpei, touchId, x, y, &contactId); + + return TRUE; +} + +BOOL wlf_handle_touch_down(freerdp* instance, const UwacTouchDown* ev) +{ + uint32_t x, y; + int i; + int touchId; + int contactId; + wlfContext* context; + + if (!instance || !ev || !instance->context) + return FALSE; + + x = ev->x; + y = ev->y; + touchId = ev->id; + + for (i = 0; i < MAX_CONTACTS; i++) + { + if (contacts[i].id == 0) + { + contacts[i].id = touchId; + contacts[i].pos_x = x; + contacts[i].pos_y = y; + contacts[i].emulate_mouse = FALSE; + break; + } + } + + if (i == MAX_CONTACTS) + return FALSE; + + WLog_DBG(TAG, "%s called | event_id: %u | x: %u / y: %u", __FUNCTION__, touchId, x, y); + + if (!wlf_scale_coordinates(instance->context, &x, &y, TRUE)) + return FALSE; + + context = (wlfContext*)instance->context; + RdpeiClientContext* rdpei = ((wlfContext*)instance->context)->rdpei; + + // Emulate mouse click if touch is not possible, like in login screen + if (!rdpei) + { + contacts[i].emulate_mouse = TRUE; + + UINT16 flags = 0; + flags |= PTR_FLAGS_DOWN; + flags |= PTR_FLAGS_BUTTON1; + + if ((flags & ~PTR_FLAGS_DOWN) != 0) + return freerdp_input_send_mouse_event(instance->input, flags, x, y); + + return FALSE; + } + + rdpei->TouchBegin(rdpei, touchId, x, y, &contactId); + + return TRUE; +} + +BOOL wlf_handle_touch_motion(freerdp* instance, const UwacTouchMotion* ev) +{ + uint32_t x, y; + int i; + int touchId; + int contactId; + + if (!instance || !ev || !instance->context) + return FALSE; + + x = ev->x; + y = ev->y; + touchId = ev->id; + + for (i = 0; i < MAX_CONTACTS; i++) + { + if (contacts[i].id == touchId) + { + if (contacts[i].pos_x == x && contacts[i].pos_y == y) + { + return TRUE; + } + contacts[i].pos_x = x; + contacts[i].pos_y = y; + break; + } + } + + if (i == MAX_CONTACTS) + return FALSE; + + WLog_DBG(TAG, "%s called | event_id: %u | x: %u / y: %u", __FUNCTION__, touchId, x, y); + + if (!wlf_scale_coordinates(instance->context, &x, &y, TRUE)) + return FALSE; + + RdpeiClientContext* rdpei = ((wlfContext*)instance->context)->rdpei; + + if (contacts[i].emulate_mouse == TRUE) + { + return TRUE; + } + + if (!rdpei) + return FALSE; + + rdpei->TouchUpdate(rdpei, touchId, x, y, &contactId); + + return TRUE; } diff --git a/client/Wayland/wlf_input.h b/client/Wayland/wlf_input.h index 701edf5..32c981a 100644 --- a/client/Wayland/wlf_input.h +++ b/client/Wayland/wlf_input.h @@ -26,13 +26,15 @@ #include #include -BOOL wlf_handle_pointer_enter(freerdp* instance, - UwacPointerEnterLeaveEvent* ev); -BOOL wlf_handle_pointer_motion(freerdp* instance, UwacPointerMotionEvent* ev); -BOOL wlf_handle_pointer_buttons(freerdp* instance, UwacPointerButtonEvent* ev); -BOOL wlf_handle_pointer_axis(freerdp* instance, UwacPointerAxisEvent* ev); +BOOL wlf_handle_pointer_enter(freerdp* instance, const UwacPointerEnterLeaveEvent* ev); +BOOL wlf_handle_pointer_motion(freerdp* instance, const UwacPointerMotionEvent* ev); +BOOL wlf_handle_pointer_buttons(freerdp* instance, const UwacPointerButtonEvent* ev); +BOOL wlf_handle_pointer_axis(freerdp* instance, const UwacPointerAxisEvent* ev); +BOOL wlf_handle_touch_up(freerdp* instance, const UwacTouchUp* ev); +BOOL wlf_handle_touch_down(freerdp* instance, const UwacTouchDown* ev); +BOOL wlf_handle_touch_motion(freerdp* instance, const UwacTouchMotion* ev); -BOOL wlf_handle_key(freerdp* instance, UwacKeyEvent* ev); -BOOL wlf_keyboard_enter(freerdp* instance, UwacKeyboardEnterLeaveEvent* ev); +BOOL wlf_handle_key(freerdp* instance, const UwacKeyEvent* ev); +BOOL wlf_keyboard_enter(freerdp* instance, const UwacKeyboardEnterLeaveEvent* ev); #endif /* FREERDP_CLIENT_WAYLAND_INPUT_H */ diff --git a/client/Wayland/wlf_pointer.c b/client/Wayland/wlf_pointer.c new file mode 100644 index 0000000..6416659 --- /dev/null +++ b/client/Wayland/wlf_pointer.c @@ -0,0 +1,170 @@ +/** + * 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" + +#define TAG CLIENT_TAG("wayland.pointer") + +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_BGRA32, 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; + void* data; + UINT32 w, h, x, y; + size_t size; + UwacReturnCode rc; + BOOL res = FALSE; + RECTANGLE_16 area; + + if (!wlf || !wlf->seat) + return FALSE; + + x = pointer->xPos; + y = pointer->yPos; + w = pointer->width; + h = pointer->height; + + if (!wlf_scale_coordinates(context, &x, &y, FALSE) || + !wlf_scale_coordinates(context, &w, &h, FALSE)) + return FALSE; + + size = w * h * 4; + data = malloc(size); + + if (!data) + return FALSE; + + area.top = 0; + area.left = 0; + area.right = (UINT16)pointer->width; + area.bottom = (UINT16)pointer->height; + + if (!wlf_copy_image(ptr->data, pointer->width * 4, pointer->width, pointer->height, data, w * 4, + w, h, &area, context->settings->SmartSizing)) + goto fail; + + rc = UwacSeatSetMouseCursor(wlf->seat, data, size, w, h, x, y); + + if (rc == UWAC_SUCCESS) + res = TRUE; + +fail: + free(data); + return res; +} + +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/Wayland/wlf_pointer.h b/client/Wayland/wlf_pointer.h new file mode 100644 index 0000000..8ae82e1 --- /dev/null +++ b/client/Wayland/wlf_pointer.h @@ -0,0 +1,28 @@ +/** + * 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. + */ + +#ifndef FREERDP_CLIENT_WAYLAND_POINTER_H +#define FREERDP_CLIENT_WAYLAND_POINTER_H + +#include + +BOOL wlf_register_pointer(rdpGraphics* graphics); + +#endif /* FREERDP_CLIENT_WAYLAND_POINTER_H */ diff --git a/client/Wayland/wlfreerdp.c b/client/Wayland/wlfreerdp.c index eed827f..11b747e 100644 --- a/client/Wayland/wlfreerdp.c +++ b/client/Wayland/wlfreerdp.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -36,22 +37,12 @@ #include "wlfreerdp.h" #include "wlf_input.h" +#include "wlf_cliprdr.h" +#include "wlf_disp.h" #include "wlf_channels.h" +#include "wlf_pointer.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; -} +#define TAG CLIENT_TAG("wayland") static BOOL wl_begin_paint(rdpContext* context) { @@ -69,15 +60,80 @@ 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) +{ + BOOL res = FALSE; + rdpGdi* gdi; + char* data; + UINT32 x, y, w, h; + UwacSize geometry; + size_t stride; + UwacReturnCode rc; + RECTANGLE_16 area; + + if (!context_w) + return FALSE; + + if ((ix < 0) || (iy < 0) || (iw < 0) || (ih < 0)) + return FALSE; + + EnterCriticalSection(&context_w->critical); + 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)) + goto fail; + + gdi = context_w->context.gdi; + + if (!gdi) + goto fail; + + /* Ignore output if the surface size does not match. */ + if (((INT64)x > geometry.width) || ((INT64)y > geometry.height)) + { + res = TRUE; + goto fail; + } + + area.left = x; + area.top = y; + area.right = x + w; + area.bottom = y + h; + + if (!wlf_copy_image(gdi->primary_buffer, gdi->stride, gdi->width, gdi->height, data, stride, + geometry.width, geometry.height, &area, + context_w->context.settings->SmartSizing)) + goto fail; + + if (!wlf_scale_coordinates(&context_w->context, &x, &y, FALSE)) + goto fail; + + if (!wlf_scale_coordinates(&context_w->context, &w, &h, FALSE)) + goto fail; + + if (UwacWindowAddDamage(context_w->window, x, y, w, h) != UWAC_SUCCESS) + goto fail; + + if (UwacWindowSubmitBuffer(context_w->window, false) != UWAC_SUCCESS) + goto fail; + + res = TRUE; +fail: + LeaveCriticalSection(&context_w->critical); + return res; +} 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; @@ -91,40 +147,44 @@ static BOOL wl_end_paint(rdpContext* context) y = gdi->primary->hdc->hwnd->invalid->y; w = gdi->primary->hdc->hwnd->invalid->w; h = gdi->primary->hdc->hwnd->invalid->h; - context_w = (wlfContext*) context; - data = UwacWindowGetDrawingBuffer(context_w->window); + context_w = (wlfContext*)context; + return wl_update_buffer(context_w, x, y, w, h); +} - if (!data) +static BOOL wl_refresh_display(wlfContext* context) +{ + rdpGdi* gdi; + + if (!context || !context->context.gdi) 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)); - } + gdi = context->context.gdi; + return wl_update_buffer(context, 0, 0, gdi->width, gdi->height); +} - if (UwacWindowAddDamage(context_w->window, x, y, w, h) != UWAC_SUCCESS) +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; - context_w->haveDamage = TRUE; - return wl_update_content(context_w); + return wl_refresh_display(wlc); } - static BOOL wl_pre_connect(freerdp* instance) { rdpSettings* settings; wlfContext* context; - UwacOutput* output; + const UwacOutput* output; UwacSize resolution; if (!instance) return FALSE; - context = (wlfContext*) instance->context; + context = (wlfContext*)instance->context; settings = instance->settings; if (!context || !settings) @@ -132,45 +192,19 @@ 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_SubscribeChannelConnected(instance->context->pubSub, wlf_OnChannelConnectedEventHandler); PubSub_SubscribeChannelDisconnected(instance->context->pubSub, wlf_OnChannelDisconnectedEventHandler); if (settings->Fullscreen) { // Use the resolution of the first display output - output = UwacDisplayGetOutput(context->display, 1); + output = UwacDisplayGetOutput(context->display, 0); - if (output != NULL && UwacOutputGetResolution(output, &resolution) == UWAC_SUCCESS) + if ((output != NULL) && (UwacOutputGetResolution(output, &resolution) == UWAC_SUCCESS)) { - settings->DesktopWidth = (UINT32) resolution.width; - settings->DesktopHeight = (UINT32) resolution.height; + settings->DesktopWidth = (UINT32)resolution.width; + settings->DesktopHeight = (UINT32)resolution.height; } else { @@ -178,8 +212,7 @@ static BOOL wl_pre_connect(freerdp* instance) } } - if (!freerdp_client_load_addins(instance->context->channels, - instance->settings)) + if (!freerdp_client_load_addins(instance->context->channels, instance->settings)) return FALSE; return TRUE; @@ -190,36 +223,64 @@ static BOOL wl_post_connect(freerdp* instance) rdpGdi* gdi; UwacWindow* window; wlfContext* context; + rdpSettings* settings; + char* title = "FreeRDP"; + UINT32 w, h; if (!instance || !instance->context) return FALSE; + context = (wlfContext*)instance->context; + settings = instance->context->settings; + + if (settings->WindowTitle) + title = settings->WindowTitle; + if (!gdi_init(instance, PIXEL_FORMAT_BGRA32)) return FALSE; gdi = instance->context->gdi; - if (!gdi) + if (!gdi || (gdi->width < 0) || (gdi->height < 0)) return FALSE; - context = (wlfContext*) instance->context; - context->window = window = UwacCreateWindowShm(context->display, gdi->width, - gdi->height, WL_SHM_FORMAT_XRGB8888); + if (!wlf_register_pointer(instance->context->graphics)) + return FALSE; + + w = (UINT32)gdi->width; + h = (UINT32)gdi->height; + + if (settings->SmartSizing && !context->fullscreen) + { + if (settings->SmartSizingWidth > 0) + w = settings->SmartSizingWidth; + + if (settings->SmartSizingHeight > 0) + h = settings->SmartSizingHeight; + } + + 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); + UwacWindowSetTitle(window, title); + 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) @@ -232,8 +293,10 @@ static void wl_post_disconnect(freerdp* instance) if (!instance->context) return; - context = (wlfContext*) instance->context; + context = (wlfContext*)instance->context; gdi_free(instance); + wlf_clipboard_free(context->clipboard); + wlf_disp_free(context->disp); if (context->window) UwacDestroyWindow(&context->window); @@ -241,12 +304,15 @@ static void wl_post_disconnect(freerdp* instance) static BOOL handle_uwac_events(freerdp* instance, UwacDisplay* display) { + BOOL rc; UwacEvent event; wlfContext* context; if (UwacDisplayDispatch(display, 1) < 0) return FALSE; + context = (wlfContext*)instance->context; + while (UwacHasEvent(display)) { if (UwacNextEvent(display, &event) != UWAC_SUCCESS) @@ -255,16 +321,20 @@ static BOOL handle_uwac_events(freerdp* instance, UwacDisplay* display) /*printf("UWAC event type %d\n", event.type);*/ switch (event.type) { - case UWAC_EVENT_FRAME_DONE: - if (!instance) - continue; + case UWAC_EVENT_NEW_SEAT: + context->seat = event.seat_new.seat; + break; - context = (wlfContext*)instance->context; - context->waitingFrameDone = FALSE; + case UWAC_EVENT_REMOVED_SEAT: + context->seat = NULL; + break; - if (context->haveDamage && !wl_update_content(context)) + case UWAC_EVENT_FRAME_DONE: + EnterCriticalSection(&context->critical); + rc = UwacWindowSubmitBuffer(context->window, false); + LeaveCriticalSection(&context->critical); + if (rc != UWAC_SUCCESS) return FALSE; - break; case UWAC_EVENT_POINTER_ENTER: @@ -297,12 +367,51 @@ static BOOL handle_uwac_events(freerdp* instance, UwacDisplay* display) break; + case UWAC_EVENT_TOUCH_UP: + if (!wlf_handle_touch_up(instance, &event.touchUp)) + return FALSE; + + break; + + case UWAC_EVENT_TOUCH_DOWN: + if (!wlf_handle_touch_down(instance, &event.touchDown)) + return FALSE; + + break; + + case UWAC_EVENT_TOUCH_MOTION: + if (!wlf_handle_touch_motion(instance, &event.touchMotion)) + return FALSE; + + 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; } @@ -311,6 +420,22 @@ static BOOL handle_uwac_events(freerdp* instance, UwacDisplay* display) return TRUE; } +static BOOL handle_window_events(freerdp* instance) +{ + rdpSettings* settings; + + if (!instance || !instance->settings) + return FALSE; + + settings = instance->settings; + + if (!settings->AsyncInput) + { + } + + return TRUE; +} + static int wlfreerdp_run(freerdp* instance) { wlfContext* context; @@ -328,7 +453,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 +464,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 +472,32 @@ 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 (client_auto_reconnect_ex(instance, handle_window_events)) + continue; + else + { + /* + * Indicate an unsuccessful connection attempt if reconnect + * did not succeed and no other error was specified. + */ + if (freerdp_error_info(instance) == 0) + status = 42; + } + 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; } @@ -393,15 +530,15 @@ static int wlf_logon_error_info(freerdp* instance, UINT32 data, UINT32 type) if (!instance || !instance->context) return -1; - wlf = (wlfContext*) instance->context; - WLog_INFO(TAG, "Logon Error Info %s [%s]", str_data, str_type); + wlf = (wlfContext*)instance->context; + WLog_Print(wlf->log, WLOG_INFO, "Logon Error Info %s [%s]", str_data, str_type); return 1; } static BOOL wlf_client_new(freerdp* instance, rdpContext* context) { UwacReturnCode status; - wlfContext* wfl = (wlfContext*) context; + wlfContext* wfl = (wlfContext*)context; if (!instance || !context) return FALSE; @@ -411,27 +548,29 @@ 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, - UwacDisplayGetFd(wfl->display), WINPR_FD_READ); + UwacDisplayGetFd(wfl->display), WINPR_FD_READ); if (!wfl->displayHandle) return FALSE; + InitializeCriticalSection(&wfl->critical); + return TRUE; } - static void wlf_client_free(freerdp* instance, rdpContext* context) { - wlfContext* wlf = (wlfContext*) instance->context; + wlfContext* wlf = (wlfContext*)instance->context; if (!context) return; @@ -441,15 +580,18 @@ static void wlf_client_free(freerdp* instance, rdpContext* context) if (wlf->displayHandle) CloseHandle(wlf->displayHandle); + DeleteCriticalSection(&wlf->critical); } 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,22 +613,33 @@ 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; + rdpSettings* settings; + wlfContext* wlc; + RdpClientEntry(&clientEntryPoints); context = freerdp_client_context_new(&clientEntryPoints); - if (!context) goto fail; + wlc = (wlfContext*)context; + settings = context->settings; - 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); + status = freerdp_client_settings_parse_command_line(settings, argc, argv, FALSE); + status = freerdp_client_settings_command_line_status_print(settings, status, argc, argv); if (status) - return 0; + { + BOOL list = settings->ListMonitors; + if (list) + wlf_list_monitors(wlc); + + freerdp_client_context_free(context); + if (list) + return 0; + return status; + } if (freerdp_client_start(context) != 0) goto fail; @@ -500,3 +653,75 @@ fail: freerdp_client_context_free(context); return rc; } + +BOOL wlf_copy_image(const void* src, size_t srcStride, size_t srcWidth, size_t srcHeight, void* dst, + size_t dstStride, size_t dstWidth, size_t dstHeight, const RECTANGLE_16* area, + BOOL scale) +{ + BOOL rc = FALSE; + + if (!src || !dst || !area) + return FALSE; + + if (scale) + { + return freerdp_image_scale(dst, PIXEL_FORMAT_BGRA32, dstStride, 0, 0, dstWidth, dstHeight, + src, PIXEL_FORMAT_BGRA32, srcStride, 0, 0, srcWidth, srcHeight); + } + else + { + size_t i; + const size_t baseSrcOffset = area->top * srcStride + area->left * 4; + const size_t baseDstOffset = area->top * dstStride + area->left * 4; + const size_t width = MIN((size_t)area->right - area->left, dstWidth - area->left); + const size_t height = MIN((size_t)area->bottom - area->top, dstHeight - area->top); + const BYTE* psrc = (const BYTE*)src; + BYTE* pdst = (BYTE*)dst; + + for (i = 0; i < height; i++) + { + const size_t srcOffset = i * srcStride + baseSrcOffset; + const size_t dstOffset = i * dstStride + baseDstOffset; + memcpy(&pdst[dstOffset], &psrc[srcOffset], width * 4); + } + + rc = TRUE; + } + + return rc; +} + +BOOL wlf_scale_coordinates(rdpContext* context, UINT32* px, UINT32* py, BOOL fromLocalToRDP) +{ + wlfContext* wlf = (wlfContext*)context; + rdpGdi* gdi; + UwacSize geometry; + double sx, sy; + + if (!context || !px || !py || !context->gdi) + return FALSE; + + if (!context->settings->SmartSizing) + return TRUE; + + gdi = context->gdi; + + if (UwacWindowGetDrawingBufferGeometry(wlf->window, &geometry, NULL) != UWAC_SUCCESS) + return FALSE; + + sx = geometry.width / (double)gdi->width; + sy = geometry.height / (double)gdi->height; + + if (!fromLocalToRDP) + { + *px *= sx; + *py *= sy; + } + else + { + *px /= sx; + *py /= sy; + } + + return TRUE; +} diff --git a/client/Wayland/wlfreerdp.h b/client/Wayland/wlfreerdp.h index 7605e46..d647066 100644 --- a/client/Wayland/wlfreerdp.h +++ b/client/Wayland/wlfreerdp.h @@ -28,10 +28,9 @@ #include #include -#define TAG CLIENT_TAG("wayland") - typedef struct wlf_context wlfContext; - +typedef struct wlf_clipboard wfClipboard; +typedef struct _wlfDispContext wlfDispContext; struct wlf_context { @@ -40,15 +39,23 @@ 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; + CRITICAL_SECTION critical; }; -#endif /* FREERDP_CLIENT_WAYLAND_FREERDP_H */ +BOOL wlf_scale_coordinates(rdpContext* context, UINT32* px, UINT32* py, BOOL fromLocalToRDP); +BOOL wlf_copy_image(const void* src, size_t srcStride, size_t srcWidth, size_t srcHeight, void* dst, + size_t dstStride, size_t dstWidth, size_t dstHeight, const RECTANGLE_16* area, + BOOL scale); +#endif /* FREERDP_CLIENT_WAYLAND_FREERDP_H */ diff --git a/client/Windows/CMakeLists.txt b/client/Windows/CMakeLists.txt index c645baf..6274571 100644 --- a/client/Windows/CMakeLists.txt +++ b/client/Windows/CMakeLists.txt @@ -78,6 +78,7 @@ endif() set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-client) set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} msimg32) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) if(WITH_CLIENT_INTERFACE) diff --git a/client/Windows/cli/wfreerdp.c b/client/Windows/cli/wfreerdp.c index ad9160c..7a76eeb 100644 --- a/client/Windows/cli/wfreerdp.c +++ b/client/Windows/cli/wfreerdp.c @@ -42,8 +42,7 @@ #include -INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, - LPSTR lpCmdLine, int nCmdShow) +INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { int status; HANDLE thread; @@ -51,15 +50,18 @@ INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, DWORD dwExitCode; rdpContext* context; rdpSettings* settings; - RDP_CLIENT_ENTRY_POINTS clientEntryPoints; + LPWSTR cmd; + char** argv = NULL; + RDP_CLIENT_ENTRY_POINTS clientEntryPoints = { 0 }; int ret = 1; int argc = 0, i; - LPWSTR* args; - LPWSTR cmd; - char** argv; - ZeroMemory(&clientEntryPoints, sizeof(RDP_CLIENT_ENTRY_POINTS)); - clientEntryPoints.Size = sizeof(RDP_CLIENT_ENTRY_POINTS); - clientEntryPoints.Version = RDP_CLIENT_INTERFACE_VERSION; + LPWSTR* args = NULL; + + WINPR_UNUSED(hInstance); + WINPR_UNUSED(hPrevInstance); + WINPR_UNUSED(lpCmdLine); + WINPR_UNUSED(nCmdShow); + RdpClientEntry(&clientEntryPoints); context = freerdp_client_context_new(&clientEntryPoints); @@ -73,10 +75,10 @@ INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, args = CommandLineToArgvW(cmd, &argc); - if (!args) + if (!args || (argc <= 0)) goto out; - argv = calloc(argc, sizeof(char*)); + argv = calloc((size_t)argc, sizeof(char*)); if (!argv) goto out; @@ -84,24 +86,24 @@ INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, for (i = 0; i < argc; i++) { int size = WideCharToMultiByte(CP_UTF8, 0, args[i], -1, NULL, 0, NULL, NULL); - argv[i] = calloc(size, sizeof(char)); + if (size <= 0) + goto out; + argv[i] = calloc((size_t)size, sizeof(char)); if (!argv[i]) goto out; - if (WideCharToMultiByte(CP_UTF8, 0, args[i], -1, argv[i], size, NULL, - NULL) != size) + if (WideCharToMultiByte(CP_UTF8, 0, args[i], -1, argv[i], size, NULL, NULL) != size) goto out; } settings = context->settings; - wfc = (wfContext*) context; + wfc = (wfContext*)context; if (!settings || !wfc) goto out; - status = freerdp_client_settings_parse_command_line(settings, argc, argv, - FALSE); + status = freerdp_client_settings_parse_command_line(settings, argc, argv, FALSE); if (status) { @@ -119,7 +121,7 @@ INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, if (WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0) { GetExitCodeThread(thread, &dwExitCode); - ret = dwExitCode; + ret = (int)dwExitCode; } } diff --git a/client/Windows/resource.h b/client/Windows/resource.h index 89c1e79..35991fc 100644 --- a/client/Windows/resource.h +++ b/client/Windows/resource.h @@ -1,13 +1,12 @@ -#define IDI_ICON1 101 -#define IDB_BACKGROUND 102 -#define IDB_MINIMIZE 103 -#define IDB_MINIMIZE_ACT 104 -#define IDB_LOCK 105 -#define IDB_LOCK_ACT 106 -#define IDB_UNLOCK 107 -#define IDB_UNLOCK_ACT 108 -#define IDB_CLOSE 109 -#define IDB_CLOSE_ACT 100 -#define IDB_RESTORE 111 -#define IDB_RESTORE_ACT 112 +#define IDI_ICON1 101 +#define IDB_MINIMIZE 103 +#define IDB_MINIMIZE_ACT 104 +#define IDB_LOCK 105 +#define IDB_LOCK_ACT 106 +#define IDB_UNLOCK 107 +#define IDB_UNLOCK_ACT 108 +#define IDB_CLOSE 109 +#define IDB_CLOSE_ACT 100 +#define IDB_RESTORE 111 +#define IDB_RESTORE_ACT 112 diff --git a/client/Windows/resource/close.bmp b/client/Windows/resource/close.bmp index f9bf31e..bb17b28 100644 Binary files a/client/Windows/resource/close.bmp and b/client/Windows/resource/close.bmp differ diff --git a/client/Windows/resource/close_active.bmp b/client/Windows/resource/close_active.bmp index 43dc5b2..a59b2e3 100644 Binary files a/client/Windows/resource/close_active.bmp and b/client/Windows/resource/close_active.bmp differ diff --git a/client/Windows/resource/lock.bmp b/client/Windows/resource/lock.bmp index 6857787..0442c02 100644 Binary files a/client/Windows/resource/lock.bmp and b/client/Windows/resource/lock.bmp differ diff --git a/client/Windows/resource/lock_active.bmp b/client/Windows/resource/lock_active.bmp index b4fa35f..2e37e36 100644 Binary files a/client/Windows/resource/lock_active.bmp and b/client/Windows/resource/lock_active.bmp differ diff --git a/client/Windows/resource/minimize.bmp b/client/Windows/resource/minimize.bmp index 7fce92d..485e170 100644 Binary files a/client/Windows/resource/minimize.bmp and b/client/Windows/resource/minimize.bmp differ diff --git a/client/Windows/resource/minimize_active.bmp b/client/Windows/resource/minimize_active.bmp index 6f0b74d..e16b252 100644 Binary files a/client/Windows/resource/minimize_active.bmp and b/client/Windows/resource/minimize_active.bmp differ diff --git a/client/Windows/resource/restore.bmp b/client/Windows/resource/restore.bmp index b2ae47b..26117b0 100644 Binary files a/client/Windows/resource/restore.bmp and b/client/Windows/resource/restore.bmp differ diff --git a/client/Windows/resource/restore_active.bmp b/client/Windows/resource/restore_active.bmp index a0516af..c2479ba 100644 Binary files a/client/Windows/resource/restore_active.bmp and b/client/Windows/resource/restore_active.bmp differ diff --git a/client/Windows/resource/unlock.bmp b/client/Windows/resource/unlock.bmp index f59b72a..fc1b0d3 100644 Binary files a/client/Windows/resource/unlock.bmp and b/client/Windows/resource/unlock.bmp differ diff --git a/client/Windows/resource/unlock_active.bmp b/client/Windows/resource/unlock_active.bmp index a5d9c38..5a7f007 100644 Binary files a/client/Windows/resource/unlock_active.bmp and b/client/Windows/resource/unlock_active.bmp differ diff --git a/client/Windows/wf_channels.c b/client/Windows/wf_channels.c index 73aac5c..3afd52d 100644 --- a/client/Windows/wf_channels.c +++ b/client/Windows/wf_channels.c @@ -30,10 +30,9 @@ #include #define TAG CLIENT_TAG("windows") -void wf_OnChannelConnectedEventHandler(void* context, - ChannelConnectedEventArgs* e) +void wf_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e) { - wfContext* wfc = (wfContext*) context; + wfContext* wfc = (wfContext*)context; rdpSettings* settings = wfc->context.settings; if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) @@ -42,28 +41,27 @@ void wf_OnChannelConnectedEventHandler(void* context, else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) { if (!settings->SoftwareGdi) - WLog_WARN(TAG, - "Channel "RDPGFX_DVC_CHANNEL_NAME" does not support hardware acceleration, using fallback."); + WLog_WARN(TAG, "Channel " RDPGFX_DVC_CHANNEL_NAME + " does not support hardware acceleration, using fallback."); - gdi_graphics_pipeline_init(wfc->context.gdi, (RdpgfxClientContext*) e->pInterface); + gdi_graphics_pipeline_init(wfc->context.gdi, (RdpgfxClientContext*)e->pInterface); } else if (strcmp(e->name, RAIL_SVC_CHANNEL_NAME) == 0) { - wf_rail_init(wfc, (RailClientContext*) e->pInterface); + wf_rail_init(wfc, (RailClientContext*)e->pInterface); } else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) { - wf_cliprdr_init(wfc, (CliprdrClientContext*) e->pInterface); + wf_cliprdr_init(wfc, (CliprdrClientContext*)e->pInterface); } else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0) { } } -void wf_OnChannelDisconnectedEventHandler(void* context, - ChannelDisconnectedEventArgs* e) +void wf_OnChannelDisconnectedEventHandler(void* context, ChannelDisconnectedEventArgs* e) { - wfContext* wfc = (wfContext*) context; + wfContext* wfc = (wfContext*)context; rdpSettings* settings = wfc->context.settings; if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) @@ -71,16 +69,15 @@ void wf_OnChannelDisconnectedEventHandler(void* context, } else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) { - gdi_graphics_pipeline_uninit(wfc->context.gdi, - (RdpgfxClientContext*) e->pInterface); + gdi_graphics_pipeline_uninit(wfc->context.gdi, (RdpgfxClientContext*)e->pInterface); } else if (strcmp(e->name, RAIL_SVC_CHANNEL_NAME) == 0) { - wf_rail_uninit(wfc, (RailClientContext*) e->pInterface); + wf_rail_uninit(wfc, (RailClientContext*)e->pInterface); } else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) { - wf_cliprdr_uninit(wfc, (CliprdrClientContext*) e->pInterface); + wf_cliprdr_uninit(wfc, (CliprdrClientContext*)e->pInterface); } else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0) { diff --git a/client/Windows/wf_channels.h b/client/Windows/wf_channels.h index 90ee0da..5e4ca52 100644 --- a/client/Windows/wf_channels.h +++ b/client/Windows/wf_channels.h @@ -28,9 +28,7 @@ #include "wf_client.h" -void wf_OnChannelConnectedEventHandler(void* context, - ChannelConnectedEventArgs* e); -void wf_OnChannelDisconnectedEventHandler(void* context, - ChannelDisconnectedEventArgs* e); +void wf_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e); +void wf_OnChannelDisconnectedEventHandler(void* context, ChannelDisconnectedEventArgs* e); #endif /* FREERDP_CLIENT_WIN_CHANNELS_H */ diff --git a/client/Windows/wf_client.c b/client/Windows/wf_client.c index 6369ddf..a9a1d96 100644 --- a/client/Windows/wf_client.c +++ b/client/Windows/wf_client.c @@ -58,15 +58,28 @@ #define TAG CLIENT_TAG("windows") -static int wf_create_console(void) +static BOOL wf_create_console(void) { - if (!AllocConsole()) - return 1; +#if defined(WITH_WIN_CONSOLE) + if (!AttachConsole(ATTACH_PARENT_PROCESS)) + return FALSE; freopen("CONOUT$", "w", stdout); freopen("CONOUT$", "w", stderr); - WLog_INFO(TAG, "Debug console created."); - return 0; + clearerr(stdout); + clearerr(stderr); + fflush(stdout); + fflush(stderr); + + freopen("CONIN$", "r", stdin); + clearerr(stdin); + + WLog_INFO(TAG, "Debug console created."); + + return TRUE; +#else + return FALSE; +#endif } static BOOL wf_end_paint(rdpContext* context) @@ -148,12 +161,11 @@ static BOOL wf_desktop_resize(rdpContext* context) { same = (wfc->primary == wfc->drawing) ? TRUE : FALSE; wf_image_free(wfc->primary); - wfc->primary = wf_image_new(wfc, settings->DesktopWidth, - settings->DesktopHeight, context->gdi->dstFormat, NULL); + wfc->primary = wf_image_new(wfc, settings->DesktopWidth, settings->DesktopHeight, + context->gdi->dstFormat, NULL); } - if (!gdi_resize_ex(context->gdi, settings->DesktopWidth, - settings->DesktopHeight, 0, + if (!gdi_resize_ex(context->gdi, settings->DesktopWidth, settings->DesktopHeight, 0, context->gdi->dstFormat, wfc->primary->pdata, NULL)) return FALSE; @@ -188,40 +200,12 @@ static BOOL wf_pre_connect(freerdp* instance) return FALSE; context = instance->context; - wfc = (wfContext*) instance->context; + wfc = (wfContext*)instance->context; settings = instance->settings; settings->OsMajorType = OSMAJORTYPE_WINDOWS; settings->OsMinorType = OSMINORTYPE_WINDOWS_NT; - 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] = TRUE; - settings->OrderSupport[NEG_POLYGON_CB_INDEX] = TRUE; - settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE; - settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE; wfc->fullscreen = settings->Fullscreen; - wfc->floatbar_active = settings->Floatbar; - - if (wfc->fullscreen) - wfc->fs_toggle = 1; - + wfc->fullscreen_toggle = settings->ToggleFullscreen; desktopWidth = settings->DesktopWidth; desktopHeight = settings->DesktopHeight; @@ -273,9 +257,8 @@ static BOOL wf_pre_connect(freerdp* instance) return -1; freerdp_set_param_uint32(settings, FreeRDP_KeyboardLayout, - (int) GetKeyboardLayout(0) & 0x0000FFFF); - PubSub_SubscribeChannelConnected(instance->context->pubSub, - wf_OnChannelConnectedEventHandler); + (int)GetKeyboardLayout(0) & 0x0000FFFF); + PubSub_SubscribeChannelConnected(instance->context->pubSub, wf_OnChannelConnectedEventHandler); PubSub_SubscribeChannelDisconnected(instance->context->pubSub, wf_OnChannelDisconnectedEventHandler); return TRUE; @@ -283,17 +266,23 @@ static BOOL wf_pre_connect(freerdp* instance) static void wf_add_system_menu(wfContext* wfc) { - HMENU hMenu = GetSystemMenu(wfc->hwnd, FALSE); + HMENU hMenu; MENUITEMINFO item_info; + + if (wfc->fullscreen && !wfc->fullscreen_toggle) + { + return; + } + + hMenu = GetSystemMenu(wfc->hwnd, FALSE); ZeroMemory(&item_info, sizeof(MENUITEMINFO)); - item_info.fMask = MIIM_CHECKMARKS | MIIM_FTYPE | MIIM_ID | MIIM_STRING | - MIIM_DATA; + item_info.fMask = MIIM_CHECKMARKS | MIIM_FTYPE | MIIM_ID | MIIM_STRING | MIIM_DATA; item_info.cbSize = sizeof(MENUITEMINFO); item_info.wID = SYSCOMMAND_ID_SMARTSIZING; item_info.fType = MFT_STRING; item_info.dwTypeData = _wcsdup(_T("Smart sizing")); - item_info.cch = (UINT) _wcslen(_T("Smart sizing")); - item_info.dwItemData = (ULONG_PTR) wfc; + item_info.cch = (UINT)_wcslen(_T("Smart sizing")); + item_info.dwItemData = (ULONG_PTR)wfc; InsertMenuItem(hMenu, 6, TRUE, &item_info); if (wfc->context.settings->SmartSizing) @@ -302,6 +291,40 @@ static void wf_add_system_menu(wfContext* wfc) } } +static WCHAR* wf_window_get_title(rdpSettings* settings) +{ + BOOL port; + WCHAR* windowTitle = NULL; + size_t size; + char* name; + WCHAR prefix[] = L"FreeRDP:"; + + if (!settings) + return NULL; + + name = settings->ServerHostname; + + if (settings->WindowTitle) + { + ConvertToUnicode(CP_UTF8, 0, settings->WindowTitle, -1, &windowTitle, 0); + return windowTitle; + } + + port = (settings->ServerPort != 3389); + size = strlen(name) + 16 + wcslen(prefix); + windowTitle = calloc(size, sizeof(WCHAR)); + + if (!windowTitle) + return NULL; + + if (!port) + _snwprintf_s(windowTitle, size, _TRUNCATE, L"%s %S", prefix, name); + else + _snwprintf_s(windowTitle, size, _TRUNCATE, L"%s %S:%u", prefix, name, settings->ServerPort); + + return windowTitle; +} + static BOOL wf_post_connect(freerdp* instance) { rdpGdi* gdi; @@ -309,16 +332,14 @@ static BOOL wf_post_connect(freerdp* instance) rdpCache* cache; wfContext* wfc; rdpContext* context; - WCHAR lpWindowName[512]; rdpSettings* settings; EmbedWindowEventArgs e; const UINT32 format = PIXEL_FORMAT_BGRX32; settings = instance->settings; context = instance->context; - wfc = (wfContext*) instance->context; + wfc = (wfContext*)instance->context; cache = instance->context->cache; - wfc->primary = wf_image_new(wfc, settings->DesktopWidth, - settings->DesktopHeight, format, NULL); + wfc->primary = wf_image_new(wfc, settings->DesktopWidth, settings->DesktopHeight, format, NULL); if (!gdi_init_ex(instance, format, 0, wfc->primary->pdata, NULL)) return FALSE; @@ -330,14 +351,10 @@ static BOOL wf_post_connect(freerdp* instance) wf_gdi_register_update_callbacks(instance->update); } - if (settings->WindowTitle != NULL) - _snwprintf_s(lpWindowName, ARRAYSIZE(lpWindowName), _TRUNCATE, L"%S", settings->WindowTitle); - else if (settings->ServerPort == 3389) - _snwprintf_s(lpWindowName, ARRAYSIZE(lpWindowName), _TRUNCATE, L"FreeRDP: %S", - settings->ServerHostname); - else - _snwprintf_s(lpWindowName, ARRAYSIZE(lpWindowName), _TRUNCATE, L"FreeRDP: %S:%u", - settings->ServerHostname, settings->ServerPort); + wfc->window_title = wf_window_get_title(settings); + + if (!wfc->window_title) + return FALSE; if (settings->EmbeddedWindow) settings->Decorations = FALSE; @@ -347,25 +364,24 @@ static BOOL wf_post_connect(freerdp* instance) else if (!settings->Decorations) dwStyle = WS_CHILD | WS_BORDER; else - dwStyle = WS_CAPTION | WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX | WS_SIZEBOX - | WS_MAXIMIZEBOX; + dwStyle = + WS_CAPTION | WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX | WS_SIZEBOX | WS_MAXIMIZEBOX; if (!wfc->hwnd) { - wfc->hwnd = CreateWindowEx((DWORD) NULL, wfc->wndClassName, lpWindowName, - dwStyle, - 0, 0, 0, 0, wfc->hWndParent, NULL, wfc->hInstance, NULL); - SetWindowLongPtr(wfc->hwnd, GWLP_USERDATA, (LONG_PTR) wfc); + wfc->hwnd = CreateWindowEx((DWORD)NULL, wfc->wndClassName, wfc->window_title, dwStyle, 0, 0, + 0, 0, wfc->hWndParent, NULL, wfc->hInstance, NULL); + SetWindowLongPtr(wfc->hwnd, GWLP_USERDATA, (LONG_PTR)wfc); } wf_resize_window(wfc); wf_add_system_menu(wfc); - BitBlt(wfc->primary->hdc, 0, 0, settings->DesktopWidth, settings->DesktopHeight, - NULL, 0, 0, BLACKNESS); + BitBlt(wfc->primary->hdc, 0, 0, settings->DesktopWidth, settings->DesktopHeight, NULL, 0, 0, + BLACKNESS); wfc->drawing = wfc->primary; EventArgsInit(&e, "wfreerdp"); e.embed = FALSE; - e.handle = (void*) wfc->hwnd; + e.handle = (void*)wfc->hwnd; PubSub_OnEmbedWindow(context->pubSub, context, &e); ShowWindow(wfc->hwnd, SW_SHOWNORMAL); UpdateWindow(wfc->hwnd); @@ -385,43 +401,53 @@ static BOOL wf_post_connect(freerdp* instance) palette_cache_register_callbacks(instance->update); } - if (wfc->fullscreen) - floatbar_window_create(wfc); - + wfc->floatbar = wf_floatbar_new(wfc, wfc->hInstance, settings->Floatbar); return TRUE; } -static BOOL wf_post_disconnect(freerdp* instance) +static void wf_post_disconnect(freerdp* instance) { - return TRUE; + wfContext* wfc; + + if (!instance || !instance->context || !instance->settings) + return; + + wfc = (wfContext*)instance->context; + free(wfc->window_title); } -static CREDUI_INFOA wfUiInfo = -{ - sizeof(CREDUI_INFOA), - NULL, - "Enter your credentials", - "Remote Desktop Security", - NULL -}; - -static BOOL wf_authenticate_raw(freerdp* instance, const char* title, - char** username, char** password, char** domain) +static CREDUI_INFOA wfUiInfo = { sizeof(CREDUI_INFOA), NULL, "Enter your credentials", + "Remote Desktop Security", NULL }; + +static BOOL wf_authenticate_raw(freerdp* instance, const char* title, char** username, + char** password, char** domain) { + wfContext* wfc; BOOL fSave; DWORD status; DWORD dwFlags; - char UserName[CREDUI_MAX_USERNAME_LENGTH + 1]; - char Password[CREDUI_MAX_PASSWORD_LENGTH + 1]; - char User[CREDUI_MAX_USERNAME_LENGTH + 1]; - char Domain[CREDUI_MAX_DOMAIN_TARGET_LENGTH + 1]; + char UserName[CREDUI_MAX_USERNAME_LENGTH + 1] = { 0 }; + char Password[CREDUI_MAX_PASSWORD_LENGTH + 1] = { 0 }; + char User[CREDUI_MAX_USERNAME_LENGTH + 1] = { 0 }; + char Domain[CREDUI_MAX_DOMAIN_TARGET_LENGTH + 1] = { 0 }; + + if (!instance || !instance->context) + return FALSE; + wfc = (wfContext*)instance->context; + fSave = FALSE; - ZeroMemory(UserName, sizeof(UserName)); - ZeroMemory(Password, sizeof(Password)); dwFlags = CREDUI_FLAGS_DO_NOT_PERSIST | CREDUI_FLAGS_EXCLUDE_CERTIFICATES; - status = CredUIPromptForCredentialsA(&wfUiInfo, title, NULL, 0, - UserName, CREDUI_MAX_USERNAME_LENGTH + 1, - Password, CREDUI_MAX_PASSWORD_LENGTH + 1, &fSave, dwFlags); + + if (username && *username) + strncpy(UserName, *username, CREDUI_MAX_USERNAME_LENGTH); + if (wfc->isConsole) + status = CredUICmdLinePromptForCredentialsA( + title, NULL, 0, UserName, CREDUI_MAX_USERNAME_LENGTH + 1, Password, + CREDUI_MAX_PASSWORD_LENGTH + 1, &fSave, dwFlags); + else + status = CredUIPromptForCredentialsA(&wfUiInfo, title, NULL, 0, UserName, + CREDUI_MAX_USERNAME_LENGTH + 1, Password, + CREDUI_MAX_PASSWORD_LENGTH + 1, &fSave, dwFlags); if (status != NO_ERROR) { @@ -429,11 +455,8 @@ static BOOL wf_authenticate_raw(freerdp* instance, const char* title, return FALSE; } - ZeroMemory(User, sizeof(User)); - ZeroMemory(Domain, sizeof(Domain)); - status = CredUIParseUserNameA(UserName, User, sizeof(User), Domain, - sizeof(Domain)); - //WLog_ERR(TAG, "User: %s Domain: %s Password: %s", User, Domain, Password); + status = CredUIParseUserNameA(UserName, User, sizeof(User), Domain, sizeof(Domain)); + // WLog_ERR(TAG, "User: %s Domain: %s Password: %s", User, Domain, Password); *username = _strdup(User); if (!(*username)) @@ -466,79 +489,153 @@ static BOOL wf_authenticate_raw(freerdp* instance, const char* title, return TRUE; } -static BOOL wf_authenticate(freerdp* instance, - char** username, char** password, char** domain) +static BOOL wf_authenticate(freerdp* instance, char** username, char** password, char** domain) { - return wf_authenticate_raw(instance, instance->settings->ServerHostname, - username, password, domain); + return wf_authenticate_raw(instance, instance->settings->ServerHostname, username, password, + domain); } -static BOOL wf_gw_authenticate(freerdp* instance, - char** username, char** password, char** domain) +static BOOL wf_gw_authenticate(freerdp* instance, char** username, char** password, char** domain) { char tmp[MAX_PATH]; sprintf_s(tmp, sizeof(tmp), "Gateway %s", instance->settings->GatewayHostname); return wf_authenticate_raw(instance, tmp, username, password, domain); } -static DWORD wf_verify_certificate(freerdp* instance, - const char* common_name, - const char* subject, - const char* issuer, - const char* fingerprint, - BOOL host_mismatch) +static WCHAR* wf_format_text(const WCHAR* fmt, ...) { -#if 0 - DWORD mode; - int read_size; - DWORD read_count; - TCHAR answer[2]; - TCHAR* read_buffer; - HANDLE input_handle; -#endif - WLog_INFO(TAG, "Certificate details:"); - WLog_INFO(TAG, "\tCommonName: %s", common_name); - WLog_INFO(TAG, "\tSubject: %s", subject); - WLog_INFO(TAG, "\tIssuer: %s", issuer); - WLog_INFO(TAG, "\tThumbprint: %s", fingerprint); - WLog_INFO(TAG, "\tHostMismatch: %s", host_mismatch ? "Yes" : "No"); - 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.\n"); - /* TODO: ask for user validation */ -#if 0 - input_handle = GetStdHandle(STD_INPUT_HANDLE); - GetConsoleMode(input_handle, &mode); - mode |= ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT; - SetConsoleMode(input_handle, mode); -#endif + int rc; + size_t size = 1024; + WCHAR* buffer = calloc(size, sizeof(WCHAR)); + if (!buffer) + return NULL; + + do + { + WCHAR* tmp; + va_list ap; + va_start(ap, fmt); + rc = vswprintf_s(buffer, size, fmt, ap); + va_end(ap); + if (rc <= 0) + goto fail; + + if ((size_t)rc < size) + return buffer; + + size = (size_t)rc + 1; + tmp = realloc(buffer, size * sizeof(WCHAR)); + if (!tmp) + goto fail; + + buffer = tmp; + } while (TRUE); + +fail: + free(buffer); + return NULL; +} + +static DWORD wf_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) +{ + WCHAR* buffer; + WCHAR* caption; + int what = IDCANCEL; + + buffer = wf_format_text( + L"Certificate details:\n" + L"\tCommonName: %S\n" + L"\tSubject: %S\n" + L"\tIssuer: %S\n" + L"\tThumbprint: %S\n" + L"\tHostMismatch: %S\n" + L"\n" + L"The above X.509 certificate could not be verified, possibly because you do not have " + L"the CA certificate in your certificate store, or the certificate has expired. " + L"Please look at the OpenSSL documentation on how to add a private CA to the store.\n" + L"\n" + L"YES\tAccept permanently\n" + L"NO\tAccept for this session only\n" + L"CANCEL\tAbort connection\n", + common_name, subject, issuer, fingerprint, + flags & VERIFY_CERT_FLAG_MISMATCH ? "Yes" : "No"); + caption = wf_format_text(L"Verify certificate for %S:%hu", host, port); + + if (!buffer || !caption) + goto fail; + + what = MessageBoxW(NULL, buffer, caption, MB_YESNOCANCEL); +fail: + free(buffer); + free(caption); + /* return 1 to accept and store a certificate, 2 to accept * a certificate only for this session, 0 otherwise */ - return 2; + switch (what) + { + case IDYES: + return 1; + case IDNO: + return 2; + default: + return 0; + } } -static DWORD wf_verify_changed_certificate(freerdp* instance, - 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) +static DWORD wf_verify_changed_certificate_ex(freerdp* instance, const char* host, UINT16 port, + const char* common_name, const char* subject, + const char* issuer, const char* new_fingerprint, + const char* old_subject, const char* old_issuer, + const char* old_fingerprint, DWORD flags) { - WLog_ERR(TAG, "!!! Certificate has changed !!!"); - WLog_ERR(TAG, "New Certificate details:"); - WLog_ERR(TAG, "\tSubject: %s", subject); - WLog_ERR(TAG, "\tIssuer: %s", issuer); - WLog_ERR(TAG, "\tThumbprint: %s", fingerprint); - WLog_ERR(TAG, "Old Certificate details:"); - WLog_ERR(TAG, "\tSubject: %s", old_subject); - WLog_ERR(TAG, "\tIssuer: %s", old_issuer); - WLog_ERR(TAG, "\tThumbprint: %s", old_fingerprint); - WLog_ERR(TAG, - "The above X.509 certificate does not match the certificate used for previous connections. " - "This may indicate that the certificate has been tampered with." - "Please contact the administrator of the RDP server and clarify."); - return 0; + WCHAR* buffer; + WCHAR* caption; + int what = IDCANCEL; + + buffer = wf_format_text( + L"New Certificate details:\n" + L"\tCommonName: %S\n" + L"\tSubject: %S\n" + L"\tIssuer: %S\n" + L"\tThumbprint: %S\n" + L"\tHostMismatch: %S\n" + L"\n" + L"Old Certificate details:\n" + L"\tSubject: %S\n" + L"\tIssuer: %S\n" + L"\tThumbprint: %S" + L"The above X.509 certificate could not be verified, possibly because you do not have " + L"the CA certificate in your certificate store, or the certificate has expired. " + L"Please look at the OpenSSL documentation on how to add a private CA to the store.\n" + L"\n" + L"YES\tAccept permanently\n" + L"NO\tAccept for this session only\n" + L"CANCEL\tAbort connection\n", + common_name, subject, issuer, new_fingerprint, + flags & VERIFY_CERT_FLAG_MISMATCH ? "Yes" : "No", old_subject, old_issuer, old_fingerprint); + caption = wf_format_text(L"Verify certificate change for %S:%hu", host, port); + + if (!buffer || !caption) + goto fail; + + what = MessageBoxW(NULL, buffer, caption, MB_YESNOCANCEL); +fail: + free(buffer); + free(caption); + + /* return 1 to accept and store a certificate, 2 to accept + * a certificate only for this session, 0 otherwise */ + switch (what) + { + case IDYES: + return 1; + case IDNO: + return 2; + default: + return 0; + } } static DWORD WINAPI wf_input_thread(LPVOID arg) @@ -546,7 +643,7 @@ static DWORD WINAPI wf_input_thread(LPVOID arg) int status; wMessage message; wMessageQueue* queue; - freerdp* instance = (freerdp*) arg; + freerdp* instance = (freerdp*)arg; assert(NULL != instance); status = 1; queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE); @@ -555,8 +652,8 @@ static DWORD WINAPI wf_input_thread(LPVOID arg) { while (MessageQueue_Peek(queue, &message, TRUE)) { - status = freerdp_message_queue_process_message(instance, - FREERDP_INPUT_MESSAGE_QUEUE, &message); + status = freerdp_message_queue_process_message(instance, FREERDP_INPUT_MESSAGE_QUEUE, + &message); if (!status) break; @@ -587,9 +684,9 @@ static DWORD WINAPI wf_client_thread(LPVOID lpParam) rdpSettings* settings; BOOL async_input; HANDLE input_thread; - instance = (freerdp*) lpParam; + instance = (freerdp*)lpParam; context = instance->context; - wfc = (wfContext*) instance->context; + wfc = (wfContext*)instance->context; if (!freerdp_connect(instance)) goto end; @@ -600,8 +697,7 @@ static DWORD WINAPI wf_client_thread(LPVOID lpParam) if (async_input) { - if (!(input_thread = CreateThread(NULL, 0, wf_input_thread, - instance, 0, NULL))) + if (!(input_thread = CreateThread(NULL, 0, wf_input_thread, instance, 0, NULL))) { WLog_ERR(TAG, "Failed to create async input thread."); goto disconnect; @@ -630,11 +726,9 @@ static DWORD WINAPI wf_client_thread(LPVOID lpParam) nCount += tmp; } - if (MsgWaitForMultipleObjects(nCount, handles, FALSE, 1000, - QS_ALLINPUT) == WAIT_FAILED) + if (MsgWaitForMultipleObjects(nCount, handles, FALSE, 1000, QS_ALLINPUT) == WAIT_FAILED) { - WLog_ERR(TAG, "wfreerdp_run: WaitForMultipleObjects failed: 0x%08lX", - GetLastError()); + WLog_ERR(TAG, "wfreerdp_run: WaitForMultipleObjects failed: 0x%08lX", GetLastError()); break; } @@ -720,10 +814,9 @@ static DWORD WINAPI wf_keyboard_thread(LPVOID lpParam) BOOL status; wfContext* wfc; HHOOK hook_handle; - wfc = (wfContext*) lpParam; + wfc = (wfContext*)lpParam; assert(NULL != wfc); - hook_handle = SetWindowsHookEx(WH_KEYBOARD_LL, wf_ll_kbd_proc, wfc->hInstance, - 0); + hook_handle = SetWindowsHookEx(WH_KEYBOARD_LL, wf_ll_kbd_proc, wfc->hInstance, 0); if (hook_handle) { @@ -750,7 +843,7 @@ static DWORD WINAPI wf_keyboard_thread(LPVOID lpParam) WLog_DBG(TAG, "Keyboard thread exited."); ExitThread(0); - return (DWORD) NULL; + return (DWORD)NULL; } static rdpSettings* freerdp_client_get_settings(wfContext* wfc) @@ -770,21 +863,20 @@ static int freerdp_client_focus_out(wfContext* wfc) return 0; } -static int freerdp_client_set_window_size(wfContext* wfc, int width, int height) +int freerdp_client_set_window_size(wfContext* wfc, int width, int height) { - WLog_DBG(TAG, "freerdp_client_set_window_size %d, %d", width, height); + WLog_DBG(TAG, "freerdp_client_set_window_size %d, %d", width, height); if ((width != wfc->client_width) || (height != wfc->client_height)) { PostThreadMessage(wfc->mainThreadId, WM_SIZE, SIZE_RESTORED, - ((UINT) height << 16) | (UINT) width); + ((UINT)height << 16) | (UINT)width); } return 0; } -void wf_size_scrollbars(wfContext* wfc, UINT32 client_width, - UINT32 client_height) +void wf_size_scrollbars(wfContext* wfc, UINT32 client_width, UINT32 client_height) { if (wfc->disablewindowtracking) return; @@ -810,15 +902,15 @@ void wf_size_scrollbars(wfContext* wfc, UINT32 client_width, { SCROLLINFO si; BOOL horiz = wfc->xScrollVisible; - BOOL vert = wfc->yScrollVisible;; + BOOL vert = wfc->yScrollVisible; if (!horiz && client_width < wfc->context.settings->DesktopWidth) { horiz = TRUE; } - else if (horiz - && client_width >= - wfc->context.settings->DesktopWidth/* - GetSystemMetrics(SM_CXVSCROLL)*/) + else if (horiz && + client_width >= + wfc->context.settings->DesktopWidth /* - GetSystemMetrics(SM_CXVSCROLL)*/) { horiz = FALSE; } @@ -827,15 +919,14 @@ void wf_size_scrollbars(wfContext* wfc, UINT32 client_width, { vert = TRUE; } - else if (vert - && client_height >= - wfc->context.settings->DesktopHeight/* - GetSystemMetrics(SM_CYHSCROLL)*/) + else if (vert && + client_height >= + wfc->context.settings->DesktopHeight /* - GetSystemMetrics(SM_CYHSCROLL)*/) { vert = FALSE; } - if (horiz == vert && (horiz != wfc->xScrollVisible - && vert != wfc->yScrollVisible)) + if (horiz == vert && (horiz != wfc->xScrollVisible && vert != wfc->yScrollVisible)) { if (ShowScrollBar(wfc->hwnd, SB_BOTH, horiz)) { @@ -868,11 +959,11 @@ void wf_size_scrollbars(wfContext* wfc, UINT32 client_width, wfc->xMaxScroll = MAX(wfc->context.settings->DesktopWidth - client_width, 0); wfc->xCurrentScroll = MIN(wfc->xCurrentScroll, wfc->xMaxScroll); si.cbSize = sizeof(si); - si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; - si.nMin = wfc->xMinScroll; - si.nMax = wfc->context.settings->DesktopWidth; - si.nPage = client_width; - si.nPos = wfc->xCurrentScroll; + si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; + si.nMin = wfc->xMinScroll; + si.nMax = wfc->context.settings->DesktopWidth; + si.nPage = client_width; + si.nPos = wfc->xCurrentScroll; SetScrollInfo(wfc->hwnd, SB_HORZ, &si, TRUE); } @@ -881,15 +972,14 @@ void wf_size_scrollbars(wfContext* wfc, UINT32 client_width, // The vertical scrolling range is defined by // (bitmap_height) - (client_height). The current vertical // scroll value remains within the vertical scrolling range. - wfc->yMaxScroll = MAX(wfc->context.settings->DesktopHeight - client_height, - 0); + wfc->yMaxScroll = MAX(wfc->context.settings->DesktopHeight - client_height, 0); wfc->yCurrentScroll = MIN(wfc->yCurrentScroll, wfc->yMaxScroll); si.cbSize = sizeof(si); - si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; - si.nMin = wfc->yMinScroll; - si.nMax = wfc->context.settings->DesktopHeight; - si.nPage = client_height; - si.nPos = wfc->yCurrentScroll; + si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; + si.nMin = wfc->yMinScroll; + si.nMax = wfc->context.settings->DesktopHeight; + si.nPage = client_height; + si.nPos = wfc->yCurrentScroll; SetScrollInfo(wfc->hwnd, SB_VERT, &si, TRUE); } } @@ -902,18 +992,8 @@ static BOOL wfreerdp_client_global_init(void) { WSADATA wsaData; - if (!getenv("HOME")) - { - char home[MAX_PATH * 2] = "HOME="; - strcat(home, getenv("HOMEDRIVE")); - strcat(home, getenv("HOMEPATH")); - _putenv(home); - } - WSAStartup(0x101, &wsaData); -#if defined(WITH_DEBUG) || defined(_DEBUG) - wf_create_console(); -#endif + freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0); return TRUE; } @@ -925,6 +1005,14 @@ static void wfreerdp_client_global_uninit(void) static BOOL wfreerdp_client_new(freerdp* instance, rdpContext* context) { + wfContext* wfc = (wfContext*)context; + if (!wfc) + return FALSE; + + // AttachConsole and stdin do not work well. + // Use GUI input dialogs instead of command line ones. + wfc->isConsole = wf_create_console(); + if (!(wfreerdp_client_global_init())) return FALSE; @@ -933,8 +1021,17 @@ static BOOL wfreerdp_client_new(freerdp* instance, rdpContext* context) instance->PostDisconnect = wf_post_disconnect; instance->Authenticate = wf_authenticate; instance->GatewayAuthenticate = wf_gw_authenticate; - instance->VerifyCertificate = wf_verify_certificate; - instance->VerifyChangedCertificate = wf_verify_changed_certificate; + if (wfc->isConsole) + { + instance->VerifyCertificateEx = client_cli_verify_certificate_ex; + instance->VerifyChangedCertificateEx = client_cli_verify_changed_certificate_ex; + } + else + { + instance->VerifyCertificateEx = wf_verify_certificate_ex; + instance->VerifyChangedCertificateEx = wf_verify_changed_certificate_ex; + } + return TRUE; } @@ -948,10 +1045,10 @@ static int wfreerdp_client_start(rdpContext* context) { HWND hWndParent; HINSTANCE hInstance; - wfContext* wfc = (wfContext*) context; + wfContext* wfc = (wfContext*)context; freerdp* instance = context->instance; hInstance = GetModuleHandle(NULL); - hWndParent = (HWND) instance->settings->ParentWindowId; + hWndParent = (HWND)instance->settings->ParentWindowId; instance->settings->EmbeddedWindow = (hWndParent) ? TRUE : FALSE; wfc->hWndParent = hWndParent; wfc->hInstance = hInstance; @@ -964,21 +1061,20 @@ static int wfreerdp_client_start(rdpContext* context) wfc->wndClass.cbClsExtra = 0; wfc->wndClass.cbWndExtra = 0; wfc->wndClass.hCursor = wfc->cursor; - wfc->wndClass.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH); + wfc->wndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); wfc->wndClass.lpszMenuName = NULL; wfc->wndClass.lpszClassName = wfc->wndClassName; wfc->wndClass.hInstance = hInstance; wfc->wndClass.hIcon = wfc->icon; wfc->wndClass.hIconSm = wfc->icon; RegisterClassEx(&(wfc->wndClass)); - wfc->keyboardThread = CreateThread(NULL, 0, wf_keyboard_thread, (void*) wfc, 0, - &wfc->keyboardThreadId); + wfc->keyboardThread = + CreateThread(NULL, 0, wf_keyboard_thread, (void*)wfc, 0, &wfc->keyboardThreadId); if (!wfc->keyboardThread) return -1; - wfc->thread = CreateThread(NULL, 0, wf_client_thread, (void*) instance, 0, - &wfc->mainThreadId); + wfc->thread = CreateThread(NULL, 0, wf_client_thread, (void*)instance, 0, &wfc->mainThreadId); if (!wfc->thread) return -1; @@ -988,7 +1084,7 @@ static int wfreerdp_client_start(rdpContext* context) static int wfreerdp_client_stop(rdpContext* context) { - wfContext* wfc = (wfContext*) context; + wfContext* wfc = (wfContext*)context; if (wfc->thread) { diff --git a/client/Windows/wf_client.h b/client/Windows/wf_client.h index a7c0658..29f194a 100644 --- a/client/Windows/wf_client.h +++ b/client/Windows/wf_client.h @@ -48,102 +48,101 @@ typedef struct wf_context wfContext; #include "wf_cliprdr.h" #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif // System menu constants #define SYSCOMMAND_ID_SMARTSIZING 1000 -struct wf_bitmap -{ - rdpBitmap _bitmap; - HDC hdc; - HBITMAP bitmap; - HBITMAP org_bitmap; - BYTE* pdata; -}; -typedef struct wf_bitmap wfBitmap; - -struct wf_pointer -{ - rdpPointer pointer; - HCURSOR cursor; -}; -typedef struct wf_pointer wfPointer; - -struct wf_context -{ - rdpContext context; - DEFINE_RDP_CLIENT_COMMON(); - - int offset_x; - int offset_y; - int fs_toggle; - int fullscreen; - int floatbar_active; - int percentscreen; - char window_title[64]; - int client_x; - int client_y; - int client_width; - int client_height; - - HANDLE keyboardThread; - - HICON icon; - HWND hWndParent; - HINSTANCE hInstance; - WNDCLASSEX wndClass; - LPCTSTR wndClassName; - HCURSOR hDefaultCursor; - - HWND hwnd; - POINT diff; - - wfBitmap* primary; - wfBitmap* drawing; - HCURSOR cursor; - HBRUSH brush; - HBRUSH org_brush; - RECT update_rect; - RECT scale_update_rect; - - DWORD mainThreadId; - DWORD keyboardThreadId; - - rdpFile* connectionRdpFile; - - BOOL disablewindowtracking; - - BOOL updating_scrollbars; - BOOL xScrollVisible; - int xMinScroll; - int xCurrentScroll; - int xMaxScroll; - - BOOL yScrollVisible; - int yMinScroll; - int yCurrentScroll; - int yMaxScroll; - - void* clipboard; - CliprdrClientContext* cliprdr; - - FloatBar* floatbar; - - RailClientContext* rail; - wHashTable* railWindows; -}; - -/** - * Client Interface - */ - -FREERDP_API int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints); -FREERDP_API int freerdp_client_set_window_size(wfContext* wfc, int width, - int height); -FREERDP_API void wf_size_scrollbars(wfContext* wfc, UINT32 client_width, - UINT32 client_height); + struct wf_bitmap + { + rdpBitmap _bitmap; + HDC hdc; + HBITMAP bitmap; + HBITMAP org_bitmap; + BYTE* pdata; + }; + typedef struct wf_bitmap wfBitmap; + + struct wf_pointer + { + rdpPointer pointer; + HCURSOR cursor; + }; + typedef struct wf_pointer wfPointer; + + struct wf_context + { + rdpContext context; + DEFINE_RDP_CLIENT_COMMON(); + + int offset_x; + int offset_y; + int fullscreen_toggle; + int fullscreen; + int percentscreen; + WCHAR* window_title; + int client_x; + int client_y; + int client_width; + int client_height; + + HANDLE keyboardThread; + + HICON icon; + HWND hWndParent; + HINSTANCE hInstance; + WNDCLASSEX wndClass; + LPCTSTR wndClassName; + HCURSOR hDefaultCursor; + + HWND hwnd; + POINT diff; + + wfBitmap* primary; + wfBitmap* drawing; + HCURSOR cursor; + HBRUSH brush; + HBRUSH org_brush; + RECT update_rect; + RECT scale_update_rect; + + DWORD mainThreadId; + DWORD keyboardThreadId; + + rdpFile* connectionRdpFile; + + BOOL disablewindowtracking; + + BOOL updating_scrollbars; + BOOL xScrollVisible; + int xMinScroll; + int xCurrentScroll; + int xMaxScroll; + + BOOL yScrollVisible; + int yMinScroll; + int yCurrentScroll; + int yMaxScroll; + + void* clipboard; + CliprdrClientContext* cliprdr; + + wfFloatBar* floatbar; + + RailClientContext* rail; + wHashTable* railWindows; + BOOL isConsole; + }; + + /** + * Client Interface + */ + + FREERDP_API int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints); + FREERDP_API int freerdp_client_set_window_size(wfContext* wfc, int width, int height); + FREERDP_API void wf_size_scrollbars(wfContext* wfc, UINT32 client_width, UINT32 client_height); #ifdef __cplusplus } diff --git a/client/Windows/wf_cliprdr.c b/client/Windows/wf_cliprdr.c index 88413a2..18a5cd2 100644 --- a/client/Windows/wf_cliprdr.c +++ b/client/Windows/wf_cliprdr.c @@ -27,10 +27,10 @@ #define CINTERFACE #define COBJMACROS -#include -#include -#include -#include +#include +#include +#include +#include #include @@ -41,7 +41,7 @@ #include #include -#include +#include #include "wf_cliprdr.h" @@ -50,13 +50,16 @@ #ifdef WITH_DEBUG_CLIPRDR #define DEBUG_CLIPRDR(...) WLog_DBG(TAG, __VA_ARGS__) #else -#define DEBUG_CLIPRDR(...) do { } while (0) +#define DEBUG_CLIPRDR(...) \ + do \ + { \ + } while (0) #endif -typedef BOOL (WINAPI* fnAddClipboardFormatListener)(HWND hwnd); -typedef BOOL (WINAPI* fnRemoveClipboardFormatListener)(HWND hwnd); -typedef BOOL (WINAPI* fnGetUpdatedClipboardFormats)(PUINT lpuiFormats, - UINT cFormats, PUINT pcFormatsOut); +typedef BOOL(WINAPI* fnAddClipboardFormatListener)(HWND hwnd); +typedef BOOL(WINAPI* fnRemoveClipboardFormatListener)(HWND hwnd); +typedef BOOL(WINAPI* fnGetUpdatedClipboardFormats)(PUINT lpuiFormats, UINT cFormats, + PUINT pcFormatsOut); struct format_mapping { @@ -82,7 +85,7 @@ struct _CliprdrStream IStream iStream; LONG m_lRefCount; - LONG m_lIndex; + ULONG m_lIndex; ULARGE_INTEGER m_lSize; ULARGE_INTEGER m_lOffset; FILEDESCRIPTORW m_Dsc; @@ -97,8 +100,8 @@ struct _CliprdrDataObject LONG m_lRefCount; FORMATETC* m_pFormatEtc; STGMEDIUM* m_pStgMedium; - LONG m_nNumFormats; - LONG m_nStreams; + ULONG m_nNumFormats; + ULONG m_nStreams; IStream** m_pStream; void* m_pData; }; @@ -143,35 +146,44 @@ struct wf_clipboard }; typedef struct wf_clipboard wfClipboard; -#define WM_CLIPRDR_MESSAGE (WM_USER + 156) -#define OLE_SETCLIPBOARD 1 +#define WM_CLIPRDR_MESSAGE (WM_USER + 156) +#define OLE_SETCLIPBOARD 1 -static BOOL wf_create_file_obj(wfClipboard* cliprdrrdr, - IDataObject** ppDataObject); +static BOOL wf_create_file_obj(wfClipboard* cliprdrrdr, IDataObject** ppDataObject); static void wf_destroy_file_obj(IDataObject* instance); static UINT32 get_remote_format_id(wfClipboard* clipboard, UINT32 local_format); static UINT cliprdr_send_data_request(wfClipboard* clipboard, UINT32 format); static UINT cliprdr_send_lock(wfClipboard* clipboard); static UINT cliprdr_send_unlock(wfClipboard* clipboard); -static UINT cliprdr_send_request_filecontents(wfClipboard* clipboard, - void* streamid, - int index, int flag, DWORD positionhigh, - DWORD positionlow, ULONG request); +static UINT cliprdr_send_request_filecontents(wfClipboard* clipboard, const void* streamid, + ULONG index, UINT32 flag, DWORD positionhigh, + DWORD positionlow, ULONG request); static void CliprdrDataObject_Delete(CliprdrDataObject* instance); -static CliprdrEnumFORMATETC* CliprdrEnumFORMATETC_New(int nFormats, - FORMATETC* pFormatEtc); +static CliprdrEnumFORMATETC* CliprdrEnumFORMATETC_New(ULONG nFormats, FORMATETC* pFormatEtc); static void CliprdrEnumFORMATETC_Delete(CliprdrEnumFORMATETC* instance); static void CliprdrStream_Delete(CliprdrStream* instance); +static BOOL try_open_clipboard(HWND hwnd) +{ + size_t x; + for (x = 0; x < 10; x++) + { + if (OpenClipboard(hwnd)) + return TRUE; + Sleep(10); + } + return FALSE; +} + /** * IStream */ -static HRESULT STDMETHODCALLTYPE CliprdrStream_QueryInterface(IStream* This, - REFIID riid, void** ppvObject) +static HRESULT STDMETHODCALLTYPE CliprdrStream_QueryInterface(IStream* This, REFIID riid, + void** ppvObject) { if (IsEqualIID(riid, &IID_IStream) || IsEqualIID(riid, &IID_IUnknown)) { @@ -188,7 +200,7 @@ static HRESULT STDMETHODCALLTYPE CliprdrStream_QueryInterface(IStream* This, static ULONG STDMETHODCALLTYPE CliprdrStream_AddRef(IStream* This) { - CliprdrStream* instance = (CliprdrStream*) This; + CliprdrStream* instance = (CliprdrStream*)This; if (!instance) return 0; @@ -199,7 +211,7 @@ static ULONG STDMETHODCALLTYPE CliprdrStream_AddRef(IStream* This) static ULONG STDMETHODCALLTYPE CliprdrStream_Release(IStream* This) { LONG count; - CliprdrStream* instance = (CliprdrStream*) This; + CliprdrStream* instance = (CliprdrStream*)This; if (!instance) return 0; @@ -217,25 +229,25 @@ static ULONG STDMETHODCALLTYPE CliprdrStream_Release(IStream* This) } } -static HRESULT STDMETHODCALLTYPE CliprdrStream_Read(IStream* This, void* pv, - ULONG cb, ULONG* pcbRead) +static HRESULT STDMETHODCALLTYPE CliprdrStream_Read(IStream* This, void* pv, ULONG cb, + ULONG* pcbRead) { int ret; - CliprdrStream* instance = (CliprdrStream*) This; + CliprdrStream* instance = (CliprdrStream*)This; wfClipboard* clipboard; if (!pv || !pcbRead || !instance) return E_INVALIDARG; - clipboard = (wfClipboard*) instance->m_pData; + clipboard = (wfClipboard*)instance->m_pData; *pcbRead = 0; if (instance->m_lOffset.QuadPart >= instance->m_lSize.QuadPart) return S_FALSE; - ret = cliprdr_send_request_filecontents(clipboard, (void*) This, - instance->m_lIndex, FILECONTENTS_RANGE, - instance->m_lOffset.HighPart, instance->m_lOffset.LowPart, cb); + ret = cliprdr_send_request_filecontents(clipboard, (void*)This, instance->m_lIndex, + FILECONTENTS_RANGE, instance->m_lOffset.HighPart, + instance->m_lOffset.LowPart, cb); if (ret < 0) return E_FAIL; @@ -255,9 +267,8 @@ static HRESULT STDMETHODCALLTYPE CliprdrStream_Read(IStream* This, void* pv, return S_OK; } -static HRESULT STDMETHODCALLTYPE CliprdrStream_Write(IStream* This, - const void* pv, - ULONG cb, ULONG* pcbWritten) +static HRESULT STDMETHODCALLTYPE CliprdrStream_Write(IStream* This, const void* pv, ULONG cb, + ULONG* pcbWritten) { (void)This; (void)pv; @@ -266,12 +277,11 @@ static HRESULT STDMETHODCALLTYPE CliprdrStream_Write(IStream* This, return STG_E_ACCESSDENIED; } -static HRESULT STDMETHODCALLTYPE CliprdrStream_Seek(IStream* This, - LARGE_INTEGER dlibMove, - DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) +static HRESULT STDMETHODCALLTYPE CliprdrStream_Seek(IStream* This, LARGE_INTEGER dlibMove, + DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) { ULONGLONG newoffset; - CliprdrStream* instance = (CliprdrStream*) This; + CliprdrStream* instance = (CliprdrStream*)This; if (!instance) return E_INVALIDARG; @@ -307,18 +317,16 @@ static HRESULT STDMETHODCALLTYPE CliprdrStream_Seek(IStream* This, return S_OK; } -static HRESULT STDMETHODCALLTYPE CliprdrStream_SetSize(IStream* This, - ULARGE_INTEGER libNewSize) +static HRESULT STDMETHODCALLTYPE CliprdrStream_SetSize(IStream* This, ULARGE_INTEGER libNewSize) { (void)This; (void)libNewSize; return E_NOTIMPL; } -static HRESULT STDMETHODCALLTYPE CliprdrStream_CopyTo(IStream* This, - IStream* pstm, - ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, - ULARGE_INTEGER* pcbWritten) +static HRESULT STDMETHODCALLTYPE CliprdrStream_CopyTo(IStream* This, IStream* pstm, + ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, + ULARGE_INTEGER* pcbWritten) { (void)This; (void)pstm; @@ -328,8 +336,7 @@ static HRESULT STDMETHODCALLTYPE CliprdrStream_CopyTo(IStream* This, return E_NOTIMPL; } -static HRESULT STDMETHODCALLTYPE CliprdrStream_Commit(IStream* This, - DWORD grfCommitFlags) +static HRESULT STDMETHODCALLTYPE CliprdrStream_Commit(IStream* This, DWORD grfCommitFlags) { (void)This; (void)grfCommitFlags; @@ -342,9 +349,8 @@ static HRESULT STDMETHODCALLTYPE CliprdrStream_Revert(IStream* This) return E_NOTIMPL; } -static HRESULT STDMETHODCALLTYPE CliprdrStream_LockRegion(IStream* This, - ULARGE_INTEGER libOffset, - ULARGE_INTEGER cb, DWORD dwLockType) +static HRESULT STDMETHODCALLTYPE CliprdrStream_LockRegion(IStream* This, ULARGE_INTEGER libOffset, + ULARGE_INTEGER cb, DWORD dwLockType) { (void)This; (void)libOffset; @@ -353,9 +359,8 @@ static HRESULT STDMETHODCALLTYPE CliprdrStream_LockRegion(IStream* This, return E_NOTIMPL; } -static HRESULT STDMETHODCALLTYPE CliprdrStream_UnlockRegion(IStream* This, - ULARGE_INTEGER libOffset, - ULARGE_INTEGER cb, DWORD dwLockType) +static HRESULT STDMETHODCALLTYPE CliprdrStream_UnlockRegion(IStream* This, ULARGE_INTEGER libOffset, + ULARGE_INTEGER cb, DWORD dwLockType) { (void)This; (void)libOffset; @@ -364,10 +369,10 @@ static HRESULT STDMETHODCALLTYPE CliprdrStream_UnlockRegion(IStream* This, return E_NOTIMPL; } -static HRESULT STDMETHODCALLTYPE CliprdrStream_Stat(IStream* This, - STATSTG* pstatstg, DWORD grfStatFlag) +static HRESULT STDMETHODCALLTYPE CliprdrStream_Stat(IStream* This, STATSTG* pstatstg, + DWORD grfStatFlag) { - CliprdrStream* instance = (CliprdrStream*) This; + CliprdrStream* instance = (CliprdrStream*)This; if (!instance) return E_INVALIDARG; @@ -400,29 +405,27 @@ static HRESULT STDMETHODCALLTYPE CliprdrStream_Stat(IStream* This, return S_OK; } -static HRESULT STDMETHODCALLTYPE CliprdrStream_Clone(IStream* This, - IStream** ppstm) +static HRESULT STDMETHODCALLTYPE CliprdrStream_Clone(IStream* This, IStream** ppstm) { (void)This; (void)ppstm; return E_NOTIMPL; } -static CliprdrStream* CliprdrStream_New(LONG index, void* pData, - const FILEDESCRIPTORW* dsc) +static CliprdrStream* CliprdrStream_New(ULONG index, void* pData, const FILEDESCRIPTORW* dsc) { IStream* iStream; BOOL success = FALSE; BOOL isDir = FALSE; CliprdrStream* instance; - wfClipboard* clipboard = (wfClipboard*) pData; - instance = (CliprdrStream*) calloc(1, sizeof(CliprdrStream)); + wfClipboard* clipboard = (wfClipboard*)pData; + instance = (CliprdrStream*)calloc(1, sizeof(CliprdrStream)); if (instance) { instance->m_Dsc = *dsc; iStream = &instance->iStream; - iStream->lpVtbl = (IStreamVtbl*) calloc(1, sizeof(IStreamVtbl)); + iStream->lpVtbl = (IStreamVtbl*)calloc(1, sizeof(IStreamVtbl)); if (iStream->lpVtbl) { @@ -454,14 +457,14 @@ static CliprdrStream* CliprdrStream_New(LONG index, void* pData, if (((instance->m_Dsc.dwFlags & FD_FILESIZE) == 0) && !isDir) { /* get content size of this stream */ - if (cliprdr_send_request_filecontents(clipboard, (void*) instance, - instance->m_lIndex, - FILECONTENTS_SIZE, 0, 0, 8) == CHANNEL_RC_OK) + if (cliprdr_send_request_filecontents(clipboard, (void*)instance, + instance->m_lIndex, FILECONTENTS_SIZE, 0, 0, + 8) == CHANNEL_RC_OK) { success = TRUE; } - instance->m_lSize.QuadPart = *((LONGLONG*) clipboard->req_fdata); + instance->m_lSize.QuadPart = *((LONGLONG*)clipboard->req_fdata); free(clipboard->req_fdata); } else @@ -491,10 +494,9 @@ void CliprdrStream_Delete(CliprdrStream* instance) * IDataObject */ -static int cliprdr_lookup_format(CliprdrDataObject* instance, - FORMATETC* pFormatEtc) +static LONG cliprdr_lookup_format(CliprdrDataObject* instance, FORMATETC* pFormatEtc) { - int i; + ULONG i; if (!instance || !pFormatEtc) return -1; @@ -505,15 +507,15 @@ static int cliprdr_lookup_format(CliprdrDataObject* instance, pFormatEtc->cfFormat == instance->m_pFormatEtc[i].cfFormat && pFormatEtc->dwAspect & instance->m_pFormatEtc[i].dwAspect) { - return i; + return (LONG)i; } } return -1; } -static HRESULT STDMETHODCALLTYPE CliprdrDataObject_QueryInterface( - IDataObject* This, REFIID riid, void** ppvObject) +static HRESULT STDMETHODCALLTYPE CliprdrDataObject_QueryInterface(IDataObject* This, REFIID riid, + void** ppvObject) { (void)This; @@ -535,7 +537,7 @@ static HRESULT STDMETHODCALLTYPE CliprdrDataObject_QueryInterface( static ULONG STDMETHODCALLTYPE CliprdrDataObject_AddRef(IDataObject* This) { - CliprdrDataObject* instance = (CliprdrDataObject*) This; + CliprdrDataObject* instance = (CliprdrDataObject*)This; if (!instance) return E_INVALIDARG; @@ -546,7 +548,7 @@ static ULONG STDMETHODCALLTYPE CliprdrDataObject_AddRef(IDataObject* This) static ULONG STDMETHODCALLTYPE CliprdrDataObject_Release(IDataObject* This) { LONG count; - CliprdrDataObject* instance = (CliprdrDataObject*) This; + CliprdrDataObject* instance = (CliprdrDataObject*)This; if (!instance) return E_INVALIDARG; @@ -562,17 +564,18 @@ static ULONG STDMETHODCALLTYPE CliprdrDataObject_Release(IDataObject* This) return count; } -static HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetData( - IDataObject* This, FORMATETC* pFormatEtc, STGMEDIUM* pMedium) +static HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetData(IDataObject* This, FORMATETC* pFormatEtc, + STGMEDIUM* pMedium) { - int i, idx; - CliprdrDataObject* instance = (CliprdrDataObject*) This; + ULONG i; + LONG idx; + CliprdrDataObject* instance = (CliprdrDataObject*)This; wfClipboard* clipboard; if (!pFormatEtc || !pMedium || !instance) return E_INVALIDARG; - clipboard = (wfClipboard*) instance->m_pData; + clipboard = (wfClipboard*)instance->m_pData; if (!clipboard) return E_INVALIDARG; @@ -583,22 +586,19 @@ static HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetData( pMedium->tymed = instance->m_pFormatEtc[idx].tymed; pMedium->pUnkForRelease = 0; - if (instance->m_pFormatEtc[idx].cfFormat == RegisterClipboardFormat( - CFSTR_FILEDESCRIPTORW)) + if (instance->m_pFormatEtc[idx].cfFormat == RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW)) { FILEGROUPDESCRIPTOR* dsc; - DWORD remote = get_remote_format_id(clipboard, - instance->m_pFormatEtc[idx].cfFormat); + DWORD remote = get_remote_format_id(clipboard, instance->m_pFormatEtc[idx].cfFormat); if (cliprdr_send_data_request(clipboard, remote) != 0) return E_UNEXPECTED; - pMedium->hGlobal = - clipboard->hmem; /* points to a FILEGROUPDESCRIPTOR structure */ + pMedium->hGlobal = clipboard->hmem; /* points to a FILEGROUPDESCRIPTOR structure */ /* GlobalLock returns a pointer to the first byte of the memory block, - * in which is a FILEGROUPDESCRIPTOR structure, whose first UINT member - * is the number of FILEDESCRIPTOR's */ - dsc = (FILEGROUPDESCRIPTOR*) GlobalLock(clipboard->hmem); + * in which is a FILEGROUPDESCRIPTOR structure, whose first UINT member + * is the number of FILEDESCRIPTOR's */ + dsc = (FILEGROUPDESCRIPTOR*)GlobalLock(clipboard->hmem); instance->m_nStreams = dsc->cItems; GlobalUnlock(clipboard->hmem); @@ -606,15 +606,14 @@ static HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetData( { if (!instance->m_pStream) { - instance->m_pStream = (LPSTREAM*) calloc(instance->m_nStreams, - sizeof(LPSTREAM)); + instance->m_pStream = (LPSTREAM*)calloc(instance->m_nStreams, sizeof(LPSTREAM)); if (instance->m_pStream) { for (i = 0; i < instance->m_nStreams; i++) { - instance->m_pStream[i] = (IStream*) CliprdrStream_New(i, clipboard, - &dsc->fgd[i]); + instance->m_pStream[i] = + (IStream*)CliprdrStream_New(i, clipboard, &dsc->fgd[i]); if (!instance->m_pStream[i]) return E_OUTOFMEMORY; @@ -635,8 +634,7 @@ static HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetData( return E_OUTOFMEMORY; } } - else if (instance->m_pFormatEtc[idx].cfFormat == RegisterClipboardFormat( - CFSTR_FILECONTENTS)) + else if (instance->m_pFormatEtc[idx].cfFormat == RegisterClipboardFormat(CFSTR_FILECONTENTS)) { if (pFormatEtc->lindex < instance->m_nStreams) { @@ -652,8 +650,9 @@ static HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetData( return S_OK; } -static HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetDataHere( - IDataObject* This, FORMATETC* pformatetc, STGMEDIUM* pmedium) +static HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetDataHere(IDataObject* This, + FORMATETC* pformatetc, + STGMEDIUM* pmedium) { (void)This; (void)pformatetc; @@ -661,10 +660,10 @@ static HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetDataHere( return E_NOTIMPL; } -static HRESULT STDMETHODCALLTYPE CliprdrDataObject_QueryGetData( - IDataObject* This, FORMATETC* pformatetc) +static HRESULT STDMETHODCALLTYPE CliprdrDataObject_QueryGetData(IDataObject* This, + FORMATETC* pformatetc) { - CliprdrDataObject* instance = (CliprdrDataObject*) This; + CliprdrDataObject* instance = (CliprdrDataObject*)This; if (!pformatetc) return E_INVALIDARG; @@ -675,8 +674,9 @@ static HRESULT STDMETHODCALLTYPE CliprdrDataObject_QueryGetData( return S_OK; } -static HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetCanonicalFormatEtc( - IDataObject* This, FORMATETC* pformatectIn, FORMATETC* pformatetcOut) +static HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetCanonicalFormatEtc(IDataObject* This, + FORMATETC* pformatectIn, + FORMATETC* pformatetcOut) { (void)This; (void)pformatectIn; @@ -688,8 +688,8 @@ static HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetCanonicalFormatEtc( return E_NOTIMPL; } -static HRESULT STDMETHODCALLTYPE CliprdrDataObject_SetData( - IDataObject* This, FORMATETC* pformatetc, STGMEDIUM* pmedium, BOOL fRelease) +static HRESULT STDMETHODCALLTYPE CliprdrDataObject_SetData(IDataObject* This, FORMATETC* pformatetc, + STGMEDIUM* pmedium, BOOL fRelease) { (void)This; (void)pformatetc; @@ -698,18 +698,19 @@ static HRESULT STDMETHODCALLTYPE CliprdrDataObject_SetData( return E_NOTIMPL; } -static HRESULT STDMETHODCALLTYPE CliprdrDataObject_EnumFormatEtc( - IDataObject* This, DWORD dwDirection, IEnumFORMATETC** ppenumFormatEtc) +static HRESULT STDMETHODCALLTYPE CliprdrDataObject_EnumFormatEtc(IDataObject* This, + DWORD dwDirection, + IEnumFORMATETC** ppenumFormatEtc) { - CliprdrDataObject* instance = (CliprdrDataObject*) This; + CliprdrDataObject* instance = (CliprdrDataObject*)This; if (!instance || !ppenumFormatEtc) return E_INVALIDARG; if (dwDirection == DATADIR_GET) { - *ppenumFormatEtc = (IEnumFORMATETC*) CliprdrEnumFORMATETC_New( - instance->m_nNumFormats, instance->m_pFormatEtc); + *ppenumFormatEtc = (IEnumFORMATETC*)CliprdrEnumFORMATETC_New(instance->m_nNumFormats, + instance->m_pFormatEtc); return (*ppenumFormatEtc) ? S_OK : E_OUTOFMEMORY; } else @@ -718,9 +719,9 @@ static HRESULT STDMETHODCALLTYPE CliprdrDataObject_EnumFormatEtc( } } -static HRESULT STDMETHODCALLTYPE CliprdrDataObject_DAdvise( - IDataObject* This, FORMATETC* pformatetc, DWORD advf, - IAdviseSink* pAdvSink, DWORD* pdwConnection) +static HRESULT STDMETHODCALLTYPE CliprdrDataObject_DAdvise(IDataObject* This, FORMATETC* pformatetc, + DWORD advf, IAdviseSink* pAdvSink, + DWORD* pdwConnection) { (void)This; (void)pformatetc; @@ -730,35 +731,34 @@ static HRESULT STDMETHODCALLTYPE CliprdrDataObject_DAdvise( return OLE_E_ADVISENOTSUPPORTED; } -static HRESULT STDMETHODCALLTYPE CliprdrDataObject_DUnadvise( - IDataObject* This, DWORD dwConnection) +static HRESULT STDMETHODCALLTYPE CliprdrDataObject_DUnadvise(IDataObject* This, DWORD dwConnection) { (void)This; (void)dwConnection; return OLE_E_ADVISENOTSUPPORTED; } -static HRESULT STDMETHODCALLTYPE CliprdrDataObject_EnumDAdvise( - IDataObject* This, IEnumSTATDATA** ppenumAdvise) +static HRESULT STDMETHODCALLTYPE CliprdrDataObject_EnumDAdvise(IDataObject* This, + IEnumSTATDATA** ppenumAdvise) { (void)This; (void)ppenumAdvise; return OLE_E_ADVISENOTSUPPORTED; } -static CliprdrDataObject* CliprdrDataObject_New( - FORMATETC* fmtetc, STGMEDIUM* stgmed, int count, void* data) +static CliprdrDataObject* CliprdrDataObject_New(FORMATETC* fmtetc, STGMEDIUM* stgmed, ULONG count, + void* data) { int i; CliprdrDataObject* instance; IDataObject* iDataObject; - instance = (CliprdrDataObject*) calloc(1, sizeof(CliprdrDataObject)); + instance = (CliprdrDataObject*)calloc(1, sizeof(CliprdrDataObject)); if (!instance) goto error; iDataObject = &instance->iDataObject; - iDataObject->lpVtbl = (IDataObjectVtbl*) calloc(1, sizeof(IDataObjectVtbl)); + iDataObject->lpVtbl = (IDataObjectVtbl*)calloc(1, sizeof(IDataObjectVtbl)); if (!iDataObject->lpVtbl) goto error; @@ -769,8 +769,7 @@ static CliprdrDataObject* CliprdrDataObject_New( iDataObject->lpVtbl->GetData = CliprdrDataObject_GetData; iDataObject->lpVtbl->GetDataHere = CliprdrDataObject_GetDataHere; iDataObject->lpVtbl->QueryGetData = CliprdrDataObject_QueryGetData; - iDataObject->lpVtbl->GetCanonicalFormatEtc = - CliprdrDataObject_GetCanonicalFormatEtc; + iDataObject->lpVtbl->GetCanonicalFormatEtc = CliprdrDataObject_GetCanonicalFormatEtc; iDataObject->lpVtbl->SetData = CliprdrDataObject_SetData; iDataObject->lpVtbl->EnumFormatEtc = CliprdrDataObject_EnumFormatEtc; iDataObject->lpVtbl->DAdvise = CliprdrDataObject_DAdvise; @@ -784,12 +783,12 @@ static CliprdrDataObject* CliprdrDataObject_New( if (count > 0) { - instance->m_pFormatEtc = (FORMATETC*) calloc(count, sizeof(FORMATETC)); + instance->m_pFormatEtc = (FORMATETC*)calloc(count, sizeof(FORMATETC)); if (!instance->m_pFormatEtc) goto error; - instance->m_pStgMedium = (STGMEDIUM*) calloc(count, sizeof(STGMEDIUM)); + instance->m_pStgMedium = (STGMEDIUM*)calloc(count, sizeof(STGMEDIUM)); if (!instance->m_pStgMedium) goto error; @@ -817,7 +816,7 @@ void CliprdrDataObject_Delete(CliprdrDataObject* instance) if (instance->m_pStream) { - LONG i; + ULONG i; for (i = 0; i < instance->m_nStreams; i++) CliprdrStream_Release(instance->m_pStream[i]); @@ -829,8 +828,7 @@ void CliprdrDataObject_Delete(CliprdrDataObject* instance) } } -static BOOL wf_create_file_obj(wfClipboard* clipboard, - IDataObject** ppDataObject) +static BOOL wf_create_file_obj(wfClipboard* clipboard, IDataObject** ppDataObject) { FORMATETC fmtetc[2]; STGMEDIUM stgmeds[2]; @@ -854,8 +852,7 @@ static BOOL wf_create_file_obj(wfClipboard* clipboard, stgmeds[1].tymed = TYMED_ISTREAM; stgmeds[1].pstm = NULL; stgmeds[1].pUnkForRelease = NULL; - *ppDataObject = (IDataObject*) CliprdrDataObject_New(fmtetc, stgmeds, 2, - clipboard); + *ppDataObject = (IDataObject*)CliprdrDataObject_New(fmtetc, stgmeds, 2, clipboard); return (*ppDataObject) ? TRUE : FALSE; } @@ -875,15 +872,15 @@ static void cliprdr_format_deep_copy(FORMATETC* dest, FORMATETC* source) if (source->ptd) { - dest->ptd = (DVTARGETDEVICE*) CoTaskMemAlloc(sizeof(DVTARGETDEVICE)); + dest->ptd = (DVTARGETDEVICE*)CoTaskMemAlloc(sizeof(DVTARGETDEVICE)); if (dest->ptd) *(dest->ptd) = *(source->ptd); } } -static HRESULT STDMETHODCALLTYPE CliprdrEnumFORMATETC_QueryInterface( - IEnumFORMATETC* This, REFIID riid, void** ppvObject) +static HRESULT STDMETHODCALLTYPE CliprdrEnumFORMATETC_QueryInterface(IEnumFORMATETC* This, + REFIID riid, void** ppvObject) { (void)This; @@ -902,7 +899,7 @@ static HRESULT STDMETHODCALLTYPE CliprdrEnumFORMATETC_QueryInterface( static ULONG STDMETHODCALLTYPE CliprdrEnumFORMATETC_AddRef(IEnumFORMATETC* This) { - CliprdrEnumFORMATETC* instance = (CliprdrEnumFORMATETC*) This; + CliprdrEnumFORMATETC* instance = (CliprdrEnumFORMATETC*)This; if (!instance) return 0; @@ -910,11 +907,10 @@ static ULONG STDMETHODCALLTYPE CliprdrEnumFORMATETC_AddRef(IEnumFORMATETC* This) return InterlockedIncrement(&instance->m_lRefCount); } -static ULONG STDMETHODCALLTYPE CliprdrEnumFORMATETC_Release( - IEnumFORMATETC* This) +static ULONG STDMETHODCALLTYPE CliprdrEnumFORMATETC_Release(IEnumFORMATETC* This) { LONG count; - CliprdrEnumFORMATETC* instance = (CliprdrEnumFORMATETC*) This; + CliprdrEnumFORMATETC* instance = (CliprdrEnumFORMATETC*)This; if (!instance) return 0; @@ -932,20 +928,18 @@ static ULONG STDMETHODCALLTYPE CliprdrEnumFORMATETC_Release( } } -static HRESULT STDMETHODCALLTYPE CliprdrEnumFORMATETC_Next(IEnumFORMATETC* This, - ULONG celt, - FORMATETC* rgelt, ULONG* pceltFetched) +static HRESULT STDMETHODCALLTYPE CliprdrEnumFORMATETC_Next(IEnumFORMATETC* This, ULONG celt, + FORMATETC* rgelt, ULONG* pceltFetched) { - ULONG copied = 0; - CliprdrEnumFORMATETC* instance = (CliprdrEnumFORMATETC*) This; + ULONG copied = 0; + CliprdrEnumFORMATETC* instance = (CliprdrEnumFORMATETC*)This; if (!instance || !celt || !rgelt) return E_INVALIDARG; while ((instance->m_nIndex < instance->m_nNumFormats) && (copied < celt)) { - cliprdr_format_deep_copy(&rgelt[copied++], - &instance->m_pFormatEtc[instance->m_nIndex++]); + cliprdr_format_deep_copy(&rgelt[copied++], &instance->m_pFormatEtc[instance->m_nIndex++]); } if (pceltFetched != 0) @@ -954,25 +948,23 @@ static HRESULT STDMETHODCALLTYPE CliprdrEnumFORMATETC_Next(IEnumFORMATETC* This, return (copied == celt) ? S_OK : E_FAIL; } -static HRESULT STDMETHODCALLTYPE CliprdrEnumFORMATETC_Skip(IEnumFORMATETC* This, - ULONG celt) +static HRESULT STDMETHODCALLTYPE CliprdrEnumFORMATETC_Skip(IEnumFORMATETC* This, ULONG celt) { - CliprdrEnumFORMATETC* instance = (CliprdrEnumFORMATETC*) This; + CliprdrEnumFORMATETC* instance = (CliprdrEnumFORMATETC*)This; if (!instance) return E_INVALIDARG; - if (instance->m_nIndex + (LONG) celt > instance->m_nNumFormats) + if (instance->m_nIndex + (LONG)celt > instance->m_nNumFormats) return E_FAIL; instance->m_nIndex += celt; return S_OK; } -static HRESULT STDMETHODCALLTYPE CliprdrEnumFORMATETC_Reset( - IEnumFORMATETC* This) +static HRESULT STDMETHODCALLTYPE CliprdrEnumFORMATETC_Reset(IEnumFORMATETC* This) { - CliprdrEnumFORMATETC* instance = (CliprdrEnumFORMATETC*) This; + CliprdrEnumFORMATETC* instance = (CliprdrEnumFORMATETC*)This; if (!instance) return E_INVALIDARG; @@ -981,42 +973,40 @@ static HRESULT STDMETHODCALLTYPE CliprdrEnumFORMATETC_Reset( return S_OK; } -static HRESULT STDMETHODCALLTYPE CliprdrEnumFORMATETC_Clone( - IEnumFORMATETC* This, IEnumFORMATETC** ppEnum) +static HRESULT STDMETHODCALLTYPE CliprdrEnumFORMATETC_Clone(IEnumFORMATETC* This, + IEnumFORMATETC** ppEnum) { - CliprdrEnumFORMATETC* instance = (CliprdrEnumFORMATETC*) This; + CliprdrEnumFORMATETC* instance = (CliprdrEnumFORMATETC*)This; if (!instance || !ppEnum) return E_INVALIDARG; - *ppEnum = (IEnumFORMATETC*) CliprdrEnumFORMATETC_New(instance->m_nNumFormats, - instance->m_pFormatEtc); + *ppEnum = + (IEnumFORMATETC*)CliprdrEnumFORMATETC_New(instance->m_nNumFormats, instance->m_pFormatEtc); if (!*ppEnum) return E_OUTOFMEMORY; - ((CliprdrEnumFORMATETC*) *ppEnum)->m_nIndex = instance->m_nIndex; + ((CliprdrEnumFORMATETC*)*ppEnum)->m_nIndex = instance->m_nIndex; return S_OK; } -CliprdrEnumFORMATETC* CliprdrEnumFORMATETC_New(int nFormats, - FORMATETC* pFormatEtc) +CliprdrEnumFORMATETC* CliprdrEnumFORMATETC_New(ULONG nFormats, FORMATETC* pFormatEtc) { - int i; + ULONG i; CliprdrEnumFORMATETC* instance; IEnumFORMATETC* iEnumFORMATETC; if ((nFormats != 0) && !pFormatEtc) return NULL; - instance = (CliprdrEnumFORMATETC*) calloc(1, sizeof(CliprdrEnumFORMATETC)); + instance = (CliprdrEnumFORMATETC*)calloc(1, sizeof(CliprdrEnumFORMATETC)); if (!instance) goto error; iEnumFORMATETC = &instance->iEnumFORMATETC; - iEnumFORMATETC->lpVtbl = (IEnumFORMATETCVtbl*) calloc(1, - sizeof(IEnumFORMATETCVtbl)); + iEnumFORMATETC->lpVtbl = (IEnumFORMATETCVtbl*)calloc(1, sizeof(IEnumFORMATETCVtbl)); if (!iEnumFORMATETC->lpVtbl) goto error; @@ -1028,13 +1018,13 @@ CliprdrEnumFORMATETC* CliprdrEnumFORMATETC_New(int nFormats, iEnumFORMATETC->lpVtbl->Skip = CliprdrEnumFORMATETC_Skip; iEnumFORMATETC->lpVtbl->Reset = CliprdrEnumFORMATETC_Reset; iEnumFORMATETC->lpVtbl->Clone = CliprdrEnumFORMATETC_Clone; - instance->m_lRefCount = 0; + instance->m_lRefCount = 1; instance->m_nIndex = 0; instance->m_nNumFormats = nFormats; if (nFormats > 0) { - instance->m_pFormatEtc = (FORMATETC*) calloc(nFormats, sizeof(FORMATETC)); + instance->m_pFormatEtc = (FORMATETC*)calloc(nFormats, sizeof(FORMATETC)); if (!instance->m_pFormatEtc) goto error; @@ -1074,8 +1064,7 @@ void CliprdrEnumFORMATETC_Delete(CliprdrEnumFORMATETC* instance) /***********************************************************************************/ -static UINT32 get_local_format_id_by_name(wfClipboard* clipboard, - const TCHAR* format_name) +static UINT32 get_local_format_id_by_name(wfClipboard* clipboard, const TCHAR* format_name) { size_t i; formatMapping* map; @@ -1096,8 +1085,7 @@ static UINT32 get_local_format_id_by_name(wfClipboard* clipboard, if (!unicode_name) return 0; - MultiByteToWideChar(CP_OEMCP, 0, format_name, strlen(format_name), unicode_name, - size); + MultiByteToWideChar(CP_OEMCP, 0, format_name, strlen(format_name), unicode_name, size); #endif if (!unicode_name) @@ -1123,8 +1111,7 @@ static UINT32 get_local_format_id_by_name(wfClipboard* clipboard, static INLINE BOOL file_transferring(wfClipboard* clipboard) { - return get_local_format_id_by_name(clipboard, - CFSTR_FILEDESCRIPTORW) ? TRUE : FALSE; + return get_local_format_id_by_name(clipboard, CFSTR_FILEDESCRIPTORW) ? TRUE : FALSE; } static UINT32 get_remote_format_id(wfClipboard* clipboard, UINT32 local_format) @@ -1156,8 +1143,8 @@ static void map_ensure_capacity(wfClipboard* clipboard) size_t new_size; formatMapping* new_map; new_size = clipboard->map_capacity * 2; - new_map = (formatMapping*) realloc(clipboard->format_mappings, - sizeof(formatMapping) * new_size); + new_map = + (formatMapping*)realloc(clipboard->format_mappings, sizeof(formatMapping) * new_size); if (!new_map) return; @@ -1198,28 +1185,30 @@ static UINT cliprdr_send_tempdir(wfClipboard* clipboard) if (!clipboard) return -1; - if (GetEnvironmentVariableA("TEMP", tempDirectory.szTempDir, - sizeof(tempDirectory.szTempDir)) == 0) + if (GetEnvironmentVariableA("TEMP", tempDirectory.szTempDir, sizeof(tempDirectory.szTempDir)) == + 0) return -1; return clipboard->context->TempDirectory(clipboard->context, &tempDirectory); } -BOOL cliprdr_GetUpdatedClipboardFormats(wfClipboard* clipboard, - PUINT lpuiFormats, UINT cFormats, PUINT pcFormatsOut) +static BOOL cliprdr_GetUpdatedClipboardFormats(wfClipboard* clipboard, PUINT lpuiFormats, + UINT cFormats, PUINT pcFormatsOut) { UINT index = 0; UINT format = 0; BOOL clipboardOpen = FALSE; if (!clipboard->legacyApi) - return clipboard->GetUpdatedClipboardFormats(lpuiFormats, cFormats, - pcFormatsOut); + return clipboard->GetUpdatedClipboardFormats(lpuiFormats, cFormats, pcFormatsOut); - clipboardOpen = OpenClipboard(clipboard->hwnd); + clipboardOpen = try_open_clipboard(clipboard->hwnd); if (!clipboardOpen) - return FALSE; + { + *pcFormatsOut = 0; + return TRUE; /* Other app holding clipboard */ + } while (index < cFormats) { @@ -1240,64 +1229,65 @@ BOOL cliprdr_GetUpdatedClipboardFormats(wfClipboard* clipboard, static UINT cliprdr_send_format_list(wfClipboard* clipboard) { UINT rc; - int count; + int count = 0; UINT32 index; - UINT32 numFormats; + UINT32 numFormats = 0; UINT32 formatId = 0; char formatName[1024]; - CLIPRDR_FORMAT* formats; - CLIPRDR_FORMAT_LIST formatList; + CLIPRDR_FORMAT* formats = NULL; + CLIPRDR_FORMAT_LIST formatList = { 0 }; if (!clipboard) return ERROR_INTERNAL_ERROR; ZeroMemory(&formatList, sizeof(CLIPRDR_FORMAT_LIST)); - if (!OpenClipboard(clipboard->hwnd)) - return ERROR_INTERNAL_ERROR; - - count = CountClipboardFormats(); - numFormats = (UINT32) count; - formats = (CLIPRDR_FORMAT*) calloc(numFormats, sizeof(CLIPRDR_FORMAT)); - - if (!formats) + /* Ignore if other app is holding clipboard */ + if (try_open_clipboard(clipboard->hwnd)) { - CloseClipboard(); - return CHANNEL_RC_NO_MEMORY; - } + count = CountClipboardFormats(); + numFormats = (UINT32)count; + formats = (CLIPRDR_FORMAT*)calloc(numFormats, sizeof(CLIPRDR_FORMAT)); - index = 0; + if (!formats) + { + CloseClipboard(); + return CHANNEL_RC_NO_MEMORY; + } - if (IsClipboardFormatAvailable(CF_HDROP)) - { - formats[index++].formatId = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW); - formats[index++].formatId = RegisterClipboardFormat(CFSTR_FILECONTENTS); - } - else - { - while (formatId = EnumClipboardFormats(formatId)) - formats[index++].formatId = formatId; - } + index = 0; - numFormats = index; + if (IsClipboardFormatAvailable(CF_HDROP)) + { + formats[index++].formatId = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW); + formats[index++].formatId = RegisterClipboardFormat(CFSTR_FILECONTENTS); + } + else + { + while (formatId = EnumClipboardFormats(formatId)) + formats[index++].formatId = formatId; + } - if (!CloseClipboard()) - { - free(formats); - return ERROR_INTERNAL_ERROR; - } + numFormats = index; - for (index = 0; index < numFormats; index++) - { - if(GetClipboardFormatNameA(formats[index].formatId, formatName, - sizeof(formatName))) + if (!CloseClipboard()) + { + free(formats); + return ERROR_INTERNAL_ERROR; + } + + for (index = 0; index < numFormats; index++) { - formats[index].formatName = _strdup(formatName); + if (GetClipboardFormatNameA(formats[index].formatId, formatName, sizeof(formatName))) + { + formats[index].formatName = _strdup(formatName); + } } } formatList.numFormats = numFormats; formatList.formats = formats; + formatList.msgType = CB_FORMAT_LIST; rc = clipboard->context->ClientFormatList(clipboard->context, &formatList); for (index = 0; index < numFormats; index++) @@ -1312,17 +1302,14 @@ static UINT cliprdr_send_data_request(wfClipboard* clipboard, UINT32 formatId) UINT rc; CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest; - if (!clipboard || !clipboard->context || - !clipboard->context->ClientFormatDataRequest) + if (!clipboard || !clipboard->context || !clipboard->context->ClientFormatDataRequest) return ERROR_INTERNAL_ERROR; formatDataRequest.requestedFormatId = formatId; clipboard->requestedFormatId = formatId; - rc = clipboard->context->ClientFormatDataRequest(clipboard->context, - &formatDataRequest); + rc = clipboard->context->ClientFormatDataRequest(clipboard->context, &formatDataRequest); - if (WaitForSingleObject(clipboard->response_data_event, - INFINITE) != WAIT_OBJECT_0) + if (WaitForSingleObject(clipboard->response_data_event, INFINITE) != WAIT_OBJECT_0) rc = ERROR_INTERNAL_ERROR; else if (!ResetEvent(clipboard->response_data_event)) rc = ERROR_INTERNAL_ERROR; @@ -1330,19 +1317,17 @@ static UINT cliprdr_send_data_request(wfClipboard* clipboard, UINT32 formatId) return rc; } -static UINT cliprdr_send_request_filecontents(wfClipboard* clipboard, - const void* streamid, - int index, int flag, DWORD positionhigh, - DWORD positionlow, ULONG nreq) +UINT cliprdr_send_request_filecontents(wfClipboard* clipboard, const void* streamid, ULONG index, + UINT32 flag, DWORD positionhigh, DWORD positionlow, + ULONG nreq) { UINT rc; CLIPRDR_FILE_CONTENTS_REQUEST fileContentsRequest; - if (!clipboard || !clipboard->context || - !clipboard->context->ClientFileContentsRequest) + if (!clipboard || !clipboard->context || !clipboard->context->ClientFileContentsRequest) return ERROR_INTERNAL_ERROR; - fileContentsRequest.streamId = (UINT32) streamid; + fileContentsRequest.streamId = (UINT32)streamid; fileContentsRequest.listIndex = index; fileContentsRequest.dwFlags = flag; fileContentsRequest.nPositionLow = positionlow; @@ -1350,8 +1335,7 @@ static UINT cliprdr_send_request_filecontents(wfClipboard* clipboard, fileContentsRequest.cbRequested = nreq; fileContentsRequest.clipDataId = 0; fileContentsRequest.msgFlags = 0; - rc = clipboard->context->ClientFileContentsRequest(clipboard->context, - &fileContentsRequest); + rc = clipboard->context->ClientFileContentsRequest(clipboard->context, &fileContentsRequest); if (WaitForSingleObject(clipboard->req_fevent, INFINITE) != WAIT_OBJECT_0) rc = ERROR_INTERNAL_ERROR; @@ -1361,13 +1345,12 @@ static UINT cliprdr_send_request_filecontents(wfClipboard* clipboard, return rc; } -static UINT cliprdr_send_response_filecontents(wfClipboard* clipboard, - UINT32 streamId, UINT32 size, BYTE* data) +static UINT cliprdr_send_response_filecontents(wfClipboard* clipboard, UINT32 streamId, UINT32 size, + BYTE* data) { CLIPRDR_FILE_CONTENTS_RESPONSE fileContentsResponse; - if (!clipboard || !clipboard->context || - !clipboard->context->ClientFileContentsResponse) + if (!clipboard || !clipboard->context || !clipboard->context->ClientFileContentsResponse) return ERROR_INTERNAL_ERROR; fileContentsResponse.streamId = streamId; @@ -1375,11 +1358,10 @@ static UINT cliprdr_send_response_filecontents(wfClipboard* clipboard, fileContentsResponse.requestedData = data; fileContentsResponse.msgFlags = CB_RESPONSE_OK; return clipboard->context->ClientFileContentsResponse(clipboard->context, - &fileContentsResponse); + &fileContentsResponse); } -static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, - LPARAM lParam) +static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { static wfClipboard* clipboard = NULL; @@ -1387,7 +1369,7 @@ static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, { case WM_CREATE: DEBUG_CLIPRDR("info: WM_CREATE"); - clipboard = (wfClipboard*)((CREATESTRUCT*) lParam)->lpCreateParams; + clipboard = (wfClipboard*)((CREATESTRUCT*)lParam)->lpCreateParams; clipboard->hwnd = hWnd; if (!clipboard->legacyApi) @@ -1435,7 +1417,7 @@ static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, DEBUG_CLIPRDR("info: WM_RENDERALLFORMATS"); /* discard all contexts in clipboard */ - if (!OpenClipboard(clipboard->hwnd)) + if (!try_open_clipboard(clipboard->hwnd)) { DEBUG_CLIPRDR("OpenClipboard failed with 0x%x", GetLastError()); break; @@ -1448,13 +1430,13 @@ static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, case WM_RENDERFORMAT: DEBUG_CLIPRDR("info: WM_RENDERFORMAT"); - if (cliprdr_send_data_request(clipboard, (UINT32) wParam) != 0) + if (cliprdr_send_data_request(clipboard, (UINT32)wParam) != 0) { DEBUG_CLIPRDR("error: cliprdr_send_data_request failed."); break; } - if (!SetClipboardData((UINT) wParam, clipboard->hmem)) + if (!SetClipboardData((UINT)wParam, clipboard->hmem)) { DEBUG_CLIPRDR("SetClipboardData failed with 0x%x", GetLastError()); @@ -1485,8 +1467,8 @@ static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, case WM_CHANGECBCHAIN: if (clipboard->legacyApi) { - HWND hWndCurrViewer = (HWND) wParam; - HWND hWndNextViewer = (HWND) lParam; + HWND hWndCurrViewer = (HWND)wParam; + HWND hWndNextViewer = (HWND)lParam; if (hWndCurrViewer == clipboard->hWndNextViewer) clipboard->hWndNextViewer = hWndNextViewer; @@ -1504,12 +1486,15 @@ static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, case OLE_SETCLIPBOARD: DEBUG_CLIPRDR("info: OLE_SETCLIPBOARD"); - if (wf_create_file_obj(clipboard, &clipboard->data_obj)) + if (S_FALSE == OleIsCurrentClipboard(clipboard->data_obj)) { - if (OleSetClipboard(clipboard->data_obj) != S_OK) + if (wf_create_file_obj(clipboard, &clipboard->data_obj)) { - wf_destroy_file_obj(clipboard->data_obj); - clipboard->data_obj = NULL; + if (OleSetClipboard(clipboard->data_obj) != S_OK) + { + wf_destroy_file_obj(clipboard->data_obj); + clipboard->data_obj = NULL; + } } } @@ -1551,10 +1536,9 @@ static int create_cliprdr_window(wfClipboard* clipboard) wnd_cls.hInstance = GetModuleHandle(NULL); wnd_cls.hIconSm = NULL; RegisterClassEx(&wnd_cls); - clipboard->hwnd = CreateWindowEx(WS_EX_LEFT, - _T("ClipboardHiddenMessageProcessor"), - _T("rdpclip"), 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, GetModuleHandle(NULL), - clipboard); + clipboard->hwnd = + CreateWindowEx(WS_EX_LEFT, _T("ClipboardHiddenMessageProcessor"), _T("rdpclip"), 0, 0, 0, 0, + 0, HWND_MESSAGE, NULL, GetModuleHandle(NULL), clipboard); if (!clipboard->hwnd) { @@ -1570,11 +1554,12 @@ static DWORD WINAPI cliprdr_thread_func(LPVOID arg) int ret; MSG msg; BOOL mcode; - wfClipboard* clipboard = (wfClipboard*) arg; + wfClipboard* clipboard = (wfClipboard*)arg; OleInitialize(0); if ((ret = create_cliprdr_window(clipboard)) != 0) { + OleUninitialize(); DEBUG_CLIPRDR("error: create clipboard window failed."); return 0; } @@ -1634,9 +1619,8 @@ static void clear_file_array(wfClipboard* clipboard) clipboard->nFiles = 0; } -static BOOL wf_cliprdr_get_file_contents(WCHAR* file_name, BYTE* buffer, - LONG positionLow, LONG positionHigh, - DWORD nRequested, DWORD* puSize) +static BOOL wf_cliprdr_get_file_contents(WCHAR* file_name, BYTE* buffer, LONG positionLow, + LONG positionHigh, DWORD nRequested, DWORD* puSize) { BOOL res = FALSE; HANDLE hFile; @@ -1644,12 +1628,11 @@ static BOOL wf_cliprdr_get_file_contents(WCHAR* file_name, BYTE* buffer, if (!file_name || !buffer || !puSize) { - WLog_ERR(TAG, "get file contents Invalid Arguments."); + WLog_ERR(TAG, "get file contents Invalid Arguments."); return FALSE; } - hFile = CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ, NULL, - OPEN_EXISTING, + hFile = CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, NULL); if (hFile == INVALID_HANDLE_VALUE) @@ -1679,18 +1662,17 @@ error: } /* path_name has a '\' at the end. e.g. c:\newfolder\, file_name is c:\newfolder\new.txt */ -static FILEDESCRIPTORW* wf_cliprdr_get_file_descriptor(WCHAR* file_name, - size_t pathLen) +static FILEDESCRIPTORW* wf_cliprdr_get_file_descriptor(WCHAR* file_name, size_t pathLen) { HANDLE hFile; FILEDESCRIPTORW* fd; - fd = (FILEDESCRIPTORW*) calloc(1, sizeof(FILEDESCRIPTORW)); + fd = (FILEDESCRIPTORW*)calloc(1, sizeof(FILEDESCRIPTORW)); if (!fd) return NULL; - hFile = CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, NULL); + hFile = CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, NULL); if (hFile == INVALID_HANDLE_VALUE) { @@ -1723,13 +1705,13 @@ static BOOL wf_cliprdr_array_ensure_capacity(wfClipboard* clipboard) FILEDESCRIPTORW** new_fd; WCHAR** new_name; new_size = (clipboard->file_array_size + 1) * 2; - new_fd = (FILEDESCRIPTORW**) realloc(clipboard->fileDescriptor, - new_size * sizeof(FILEDESCRIPTORW*)); + new_fd = (FILEDESCRIPTORW**)realloc(clipboard->fileDescriptor, + new_size * sizeof(FILEDESCRIPTORW*)); if (new_fd) clipboard->fileDescriptor = new_fd; - new_name = (WCHAR**) realloc(clipboard->file_names, new_size * sizeof(WCHAR*)); + new_name = (WCHAR**)realloc(clipboard->file_names, new_size * sizeof(WCHAR*)); if (new_name) clipboard->file_names = new_name; @@ -1743,14 +1725,14 @@ static BOOL wf_cliprdr_array_ensure_capacity(wfClipboard* clipboard) return TRUE; } -static BOOL wf_cliprdr_add_to_file_arrays(wfClipboard* clipboard, - WCHAR* full_file_name, size_t pathLen) +static BOOL wf_cliprdr_add_to_file_arrays(wfClipboard* clipboard, WCHAR* full_file_name, + size_t pathLen) { if (!wf_cliprdr_array_ensure_capacity(clipboard)) return FALSE; /* add to name array */ - clipboard->file_names[clipboard->nFiles] = (LPWSTR) malloc(MAX_PATH * 2); + clipboard->file_names[clipboard->nFiles] = (LPWSTR)malloc(MAX_PATH * 2); if (!clipboard->file_names[clipboard->nFiles]) return FALSE; @@ -1770,8 +1752,7 @@ static BOOL wf_cliprdr_add_to_file_arrays(wfClipboard* clipboard, return TRUE; } -static BOOL wf_cliprdr_traverse_directory(wfClipboard* clipboard, - WCHAR* Dir, size_t pathLen) +static BOOL wf_cliprdr_traverse_directory(wfClipboard* clipboard, WCHAR* Dir, size_t pathLen) { HANDLE hFind; WCHAR DirSpec[MAX_PATH]; @@ -1792,9 +1773,9 @@ static BOOL wf_cliprdr_traverse_directory(wfClipboard* clipboard, while (FindNextFile(hFind, &FindFileData)) { - if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0 - && wcscmp(FindFileData.cFileName, _T(".")) == 0 - || wcscmp(FindFileData.cFileName, _T("..")) == 0) + if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0 && + wcscmp(FindFileData.cFileName, _T(".")) == 0 || + wcscmp(FindFileData.cFileName, _T("..")) == 0) { continue; } @@ -1833,22 +1814,17 @@ static UINT wf_cliprdr_send_client_capabilities(wfClipboard* clipboard) CLIPRDR_CAPABILITIES capabilities; CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet; - if (!clipboard || !clipboard->context || - !clipboard->context->ClientCapabilities) + if (!clipboard || !clipboard->context || !clipboard->context->ClientCapabilities) return ERROR_INTERNAL_ERROR; capabilities.cCapabilitiesSets = 1; - capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*) & - (generalCapabilitySet); + 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 | - CB_STREAM_FILECLIP_ENABLED | - CB_FILECLIP_NO_FILE_PATHS; - return clipboard->context->ClientCapabilities(clipboard->context, - &capabilities); + CB_USE_LONG_FORMAT_NAMES | CB_STREAM_FILECLIP_ENABLED | CB_FILECLIP_NO_FILE_PATHS; + return clipboard->context->ClientCapabilities(clipboard->context, &capabilities); } /** @@ -1857,10 +1833,10 @@ static UINT wf_cliprdr_send_client_capabilities(wfClipboard* clipboard) * @return 0 on success, otherwise a Win32 error code */ static UINT wf_cliprdr_monitor_ready(CliprdrClientContext* context, - CLIPRDR_MONITOR_READY* monitorReady) + const CLIPRDR_MONITOR_READY* monitorReady) { UINT rc; - wfClipboard* clipboard = (wfClipboard*) context->custom; + wfClipboard* clipboard = (wfClipboard*)context->custom; if (!context || !monitorReady) return ERROR_INTERNAL_ERROR; @@ -1880,11 +1856,11 @@ static UINT wf_cliprdr_monitor_ready(CliprdrClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT wf_cliprdr_server_capabilities(CliprdrClientContext* context, - CLIPRDR_CAPABILITIES* capabilities) + const CLIPRDR_CAPABILITIES* capabilities) { UINT32 index; CLIPRDR_CAPABILITY_SET* capabilitySet; - wfClipboard* clipboard = (wfClipboard*) context->custom; + wfClipboard* clipboard = (wfClipboard*)context->custom; if (!context || !capabilities) return ERROR_INTERNAL_ERROR; @@ -1896,8 +1872,8 @@ static UINT wf_cliprdr_server_capabilities(CliprdrClientContext* context, if ((capabilitySet->capabilitySetType == CB_CAPSTYPE_GENERAL) && (capabilitySet->capabilitySetLength >= CB_CAPSTYPE_GENERAL_LEN)) { - CLIPRDR_GENERAL_CAPABILITY_SET* generalCapabilitySet - = (CLIPRDR_GENERAL_CAPABILITY_SET*) capabilitySet; + CLIPRDR_GENERAL_CAPABILITY_SET* generalCapabilitySet = + (CLIPRDR_GENERAL_CAPABILITY_SET*)capabilitySet; clipboard->capabilities = generalCapabilitySet->generalFlags; break; } @@ -1912,13 +1888,13 @@ static UINT wf_cliprdr_server_capabilities(CliprdrClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT wf_cliprdr_server_format_list(CliprdrClientContext* context, - CLIPRDR_FORMAT_LIST* formatList) + const CLIPRDR_FORMAT_LIST* formatList) { UINT rc = ERROR_INTERNAL_ERROR; UINT32 i; formatMapping* mapping; CLIPRDR_FORMAT* format; - wfClipboard* clipboard = (wfClipboard*) context->custom; + wfClipboard* clipboard = (wfClipboard*)context->custom; if (!clear_format_map(clipboard)) return ERROR_INTERNAL_ERROR; @@ -1932,15 +1908,14 @@ static UINT wf_cliprdr_server_format_list(CliprdrClientContext* context, if (format->formatName) { int size = MultiByteToWideChar(CP_UTF8, 0, format->formatName, - strlen(format->formatName), - NULL, 0); + strlen(format->formatName), NULL, 0); mapping->name = calloc(size + 1, sizeof(WCHAR)); if (mapping->name) { MultiByteToWideChar(CP_UTF8, 0, format->formatName, strlen(format->formatName), mapping->name, size); - mapping->local_format_id = RegisterClipboardFormatW((LPWSTR) mapping->name); + mapping->local_format_id = RegisterClipboardFormatW((LPWSTR)mapping->name); } } else @@ -1960,12 +1935,12 @@ static UINT wf_cliprdr_server_format_list(CliprdrClientContext* context, } else { - if (!OpenClipboard(clipboard->hwnd)) - return ERROR_INTERNAL_ERROR; + if (!try_open_clipboard(clipboard->hwnd)) + return CHANNEL_RC_OK; /* Ignore, other app holding clipboard */ if (EmptyClipboard()) { - for (i = 0; i < (UINT32) clipboard->map_size; i++) + for (i = 0; i < (UINT32)clipboard->map_size; i++) SetClipboardData(clipboard->format_mappings[i].local_format_id, NULL); rc = CHANNEL_RC_OK; @@ -1983,9 +1958,9 @@ static UINT wf_cliprdr_server_format_list(CliprdrClientContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT wf_cliprdr_server_format_list_response(CliprdrClientContext* - context, - CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse) +static UINT +wf_cliprdr_server_format_list_response(CliprdrClientContext* context, + const CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse) { (void)context; (void)formatListResponse; @@ -2001,8 +1976,9 @@ static UINT wf_cliprdr_server_format_list_response(CliprdrClientContext* * * @return 0 on success, otherwise a Win32 error code */ -static UINT wf_cliprdr_server_lock_clipboard_data(CliprdrClientContext* context, - CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData) +static UINT +wf_cliprdr_server_lock_clipboard_data(CliprdrClientContext* context, + const CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData) { (void)context; (void)lockClipboardData; @@ -2014,17 +1990,16 @@ static UINT wf_cliprdr_server_lock_clipboard_data(CliprdrClientContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT wf_cliprdr_server_unlock_clipboard_data(CliprdrClientContext* - context, - CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData) +static UINT +wf_cliprdr_server_unlock_clipboard_data(CliprdrClientContext* context, + const CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData) { (void)context; (void)unlockClipboardData; return CHANNEL_RC_OK; } -static BOOL wf_cliprdr_process_filename(wfClipboard* clipboard, - WCHAR* wFileName, size_t str_len) +static BOOL wf_cliprdr_process_filename(wfClipboard* clipboard, WCHAR* wFileName, size_t str_len) { size_t pathLen; size_t offset = str_len; @@ -2062,8 +2037,9 @@ static BOOL wf_cliprdr_process_filename(wfClipboard* clipboard, * * @return 0 on success, otherwise a Win32 error code */ -static UINT wf_cliprdr_server_format_data_request(CliprdrClientContext* context, - CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest) +static UINT +wf_cliprdr_server_format_data_request(CliprdrClientContext* context, + const CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest) { UINT rc; size_t size = 0; @@ -2077,7 +2053,7 @@ static UINT wf_cliprdr_server_format_data_request(CliprdrClientContext* context, if (!context || !formatDataRequest) return ERROR_INTERNAL_ERROR; - clipboard = (wfClipboard*) context->custom; + clipboard = (wfClipboard*)context->custom; if (!clipboard) return ERROR_INTERNAL_ERROR; @@ -2115,7 +2091,7 @@ static UINT wf_cliprdr_server_format_data_request(CliprdrClientContext* context, goto exit; } - dropFiles = (DROPFILES*) GlobalLock(stg_medium.hGlobal); + dropFiles = (DROPFILES*)GlobalLock(stg_medium.hGlobal); if (!dropFiles) { @@ -2140,13 +2116,13 @@ static UINT wf_cliprdr_server_format_data_request(CliprdrClientContext* context, { char* p; - for (p = (char*)((char*)dropFiles + dropFiles->pFiles); - (len = strlen(p)) > 0; p += len + 1, clipboard->nFiles++) + for (p = (char*)((char*)dropFiles + dropFiles->pFiles); (len = strlen(p)) > 0; + p += len + 1, clipboard->nFiles++) { int cchWideChar; WCHAR* wFileName; cchWideChar = MultiByteToWideChar(CP_ACP, MB_COMPOSITE, p, len, NULL, 0); - wFileName = (LPWSTR) calloc(cchWideChar, sizeof(WCHAR)); + wFileName = (LPWSTR)calloc(cchWideChar, sizeof(WCHAR)); MultiByteToWideChar(CP_ACP, MB_COMPOSITE, p, len, wFileName, cchWideChar); wf_cliprdr_process_filename(clipboard, wFileName, cchWideChar); } @@ -2156,7 +2132,7 @@ static UINT wf_cliprdr_server_format_data_request(CliprdrClientContext* context, ReleaseStgMedium(&stg_medium); exit: size = 4 + clipboard->nFiles * sizeof(FILEDESCRIPTORW); - groupDsc = (FILEGROUPDESCRIPTORW*) malloc(size); + groupDsc = (FILEGROUPDESCRIPTORW*)malloc(size); if (groupDsc) { @@ -2175,30 +2151,30 @@ static UINT wf_cliprdr_server_format_data_request(CliprdrClientContext* context, } else { - if (!OpenClipboard(clipboard->hwnd)) - return ERROR_INTERNAL_ERROR; + /* Ignore if other app is holding the clipboard */ + if (try_open_clipboard(clipboard->hwnd)) + { + hClipdata = GetClipboardData(requestedFormatId); - hClipdata = GetClipboardData(requestedFormatId); + if (!hClipdata) + { + CloseClipboard(); + return ERROR_INTERNAL_ERROR; + } - if (!hClipdata) - { + globlemem = (char*)GlobalLock(hClipdata); + size = (int)GlobalSize(hClipdata); + buff = malloc(size); + CopyMemory(buff, globlemem, size); + GlobalUnlock(hClipdata); CloseClipboard(); - return ERROR_INTERNAL_ERROR; } - - globlemem = (char*) GlobalLock(hClipdata); - size = (int) GlobalSize(hClipdata); - buff = malloc(size); - CopyMemory(buff, globlemem, size); - GlobalUnlock(hClipdata); - CloseClipboard(); } response.msgFlags = CB_RESPONSE_OK; response.dataLen = size; - response.requestedFormatData = (BYTE*) buff; - rc = clipboard->context->ClientFormatDataResponse(clipboard->context, - &response); + response.requestedFormatData = (BYTE*)buff; + rc = clipboard->context->ClientFormatDataResponse(clipboard->context, &response); free(buff); return rc; } @@ -2208,9 +2184,9 @@ static UINT wf_cliprdr_server_format_data_request(CliprdrClientContext* context, * * @return 0 on success, otherwise a Win32 error code */ -static UINT wf_cliprdr_server_format_data_response(CliprdrClientContext* - context, - CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse) +static UINT +wf_cliprdr_server_format_data_response(CliprdrClientContext* context, + const CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse) { BYTE* data; HANDLE hMem; @@ -2222,7 +2198,7 @@ static UINT wf_cliprdr_server_format_data_response(CliprdrClientContext* if (formatDataResponse->msgFlags != CB_RESPONSE_OK) return E_FAIL; - clipboard = (wfClipboard*) context->custom; + clipboard = (wfClipboard*)context->custom; if (!clipboard) return ERROR_INTERNAL_ERROR; @@ -2232,7 +2208,7 @@ static UINT wf_cliprdr_server_format_data_response(CliprdrClientContext* if (!hMem) return ERROR_INTERNAL_ERROR; - data = (BYTE*) GlobalLock(hMem); + data = (BYTE*)GlobalLock(hMem); if (!data) { @@ -2240,8 +2216,7 @@ static UINT wf_cliprdr_server_format_data_response(CliprdrClientContext* return ERROR_INTERNAL_ERROR; } - CopyMemory(data, formatDataResponse->requestedFormatData, - formatDataResponse->dataLen); + CopyMemory(data, formatDataResponse->requestedFormatData, formatDataResponse->dataLen); if (!GlobalUnlock(hMem) && GetLastError()) { @@ -2262,35 +2237,37 @@ static UINT wf_cliprdr_server_format_data_response(CliprdrClientContext* * * @return 0 on success, otherwise a Win32 error code */ -static UINT wf_cliprdr_server_file_contents_request(CliprdrClientContext* - context, - CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) +static UINT +wf_cliprdr_server_file_contents_request(CliprdrClientContext* context, + const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) { DWORD uSize = 0; BYTE* pData = NULL; - HRESULT hRet = S_OK; + HRESULT hRet = S_OK; FORMATETC vFormatEtc; LPDATAOBJECT pDataObj = NULL; STGMEDIUM vStgMedium; BOOL bIsStreamFile = TRUE; - static LPSTREAM pStreamStc = NULL; + static LPSTREAM pStreamStc = NULL; static UINT32 uStreamIdStc = 0; wfClipboard* clipboard; UINT rc = ERROR_INTERNAL_ERROR; UINT sRc; + UINT32 cbRequested; if (!context || !fileContentsRequest) return ERROR_INTERNAL_ERROR; - clipboard = (wfClipboard*) context->custom; + clipboard = (wfClipboard*)context->custom; if (!clipboard) return ERROR_INTERNAL_ERROR; + cbRequested = fileContentsRequest->cbRequested; if (fileContentsRequest->dwFlags == FILECONTENTS_SIZE) - fileContentsRequest->cbRequested = sizeof(UINT64); + cbRequested = sizeof(UINT64); - pData = (BYTE*) calloc(1, fileContentsRequest->cbRequested); + pData = (BYTE*)calloc(1, cbRequested); if (!pData) goto error; @@ -2299,7 +2276,7 @@ static UINT wf_cliprdr_server_file_contents_request(CliprdrClientContext* if (FAILED(hRet)) { - WLog_ERR(TAG, "filecontents: get ole clipboard failed."); + WLog_ERR(TAG, "filecontents: get ole clipboard failed."); goto error; } @@ -2348,8 +2325,7 @@ static UINT wf_cliprdr_server_file_contents_request(CliprdrClientContext* break; } } - } - while (hRet == S_OK); + } while (hRet == S_OK); } } @@ -2363,9 +2339,9 @@ static UINT wf_cliprdr_server_file_contents_request(CliprdrClientContext* if (hRet == S_OK) { - *((UINT32*) &pData[0]) = vStatStg.cbSize.LowPart; - *((UINT32*) &pData[4]) = vStatStg.cbSize.HighPart; - uSize = fileContentsRequest->cbRequested; + *((UINT32*)&pData[0]) = vStatStg.cbSize.LowPart; + *((UINT32*)&pData[4]) = vStatStg.cbSize.HighPart; + uSize = cbRequested; } } else if (fileContentsRequest->dwFlags == FILECONTENTS_RANGE) @@ -2377,27 +2353,26 @@ static UINT wf_cliprdr_server_file_contents_request(CliprdrClientContext* hRet = IStream_Seek(pStreamStc, dlibMove, STREAM_SEEK_SET, &dlibNewPosition); if (SUCCEEDED(hRet)) - hRet = IStream_Read(pStreamStc, pData, fileContentsRequest->cbRequested, - (PULONG) &uSize); + hRet = IStream_Read(pStreamStc, pData, cbRequested, (PULONG)&uSize); } } else { if (fileContentsRequest->dwFlags == FILECONTENTS_SIZE) { - *((UINT32*) &pData[0]) = + *((UINT32*)&pData[0]) = clipboard->fileDescriptor[fileContentsRequest->listIndex]->nFileSizeLow; - *((UINT32*) &pData[4]) = + *((UINT32*)&pData[4]) = clipboard->fileDescriptor[fileContentsRequest->listIndex]->nFileSizeHigh; - uSize = fileContentsRequest->cbRequested; + uSize = cbRequested; } else if (fileContentsRequest->dwFlags == FILECONTENTS_RANGE) { BOOL bRet; bRet = wf_cliprdr_get_file_contents( - clipboard->file_names[fileContentsRequest->listIndex], pData, - fileContentsRequest->nPositionLow, fileContentsRequest->nPositionHigh, - fileContentsRequest->cbRequested, &uSize); + clipboard->file_names[fileContentsRequest->listIndex], pData, + fileContentsRequest->nPositionLow, fileContentsRequest->nPositionHigh, cbRequested, + &uSize); if (bRet == FALSE) { @@ -2420,9 +2395,8 @@ error: pData = NULL; } - sRc = cliprdr_send_response_filecontents(clipboard, - fileContentsRequest->streamId, - uSize, pData); + sRc = + cliprdr_send_response_filecontents(clipboard, fileContentsRequest->streamId, uSize, pData); free(pData); if (sRc != CHANNEL_RC_OK) @@ -2436,9 +2410,9 @@ error: * * @return 0 on success, otherwise a Win32 error code */ -static UINT wf_cliprdr_server_file_contents_response(CliprdrClientContext* - context, - const CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse) +static UINT +wf_cliprdr_server_file_contents_response(CliprdrClientContext* context, + const CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse) { wfClipboard* clipboard; @@ -2448,13 +2422,13 @@ static UINT wf_cliprdr_server_file_contents_response(CliprdrClientContext* if (fileContentsResponse->msgFlags != CB_RESPONSE_OK) return E_FAIL; - clipboard = (wfClipboard*) context->custom; + clipboard = (wfClipboard*)context->custom; if (!clipboard) return ERROR_INTERNAL_ERROR; clipboard->req_fsize = fileContentsResponse->cbRequested; - clipboard->req_fdata = (char*) malloc(fileContentsResponse->cbRequested); + clipboard->req_fdata = (char*)malloc(fileContentsResponse->cbRequested); if (!clipboard->req_fdata) return ERROR_INTERNAL_ERROR; @@ -2474,12 +2448,12 @@ static UINT wf_cliprdr_server_file_contents_response(CliprdrClientContext* BOOL wf_cliprdr_init(wfContext* wfc, CliprdrClientContext* cliprdr) { wfClipboard* clipboard; - rdpContext* context = (rdpContext*) wfc; + rdpContext* context = (rdpContext*)wfc; if (!context || !cliprdr) return FALSE; - wfc->clipboard = (wfClipboard*) calloc(1, sizeof(wfClipboard)); + wfc->clipboard = (wfClipboard*)calloc(1, sizeof(wfClipboard)); if (!wfc->clipboard) return FALSE; @@ -2495,29 +2469,26 @@ BOOL wf_cliprdr_init(wfContext* wfc, CliprdrClientContext* cliprdr) if (clipboard->hUser32) { - clipboard->AddClipboardFormatListener = (fnAddClipboardFormatListener) - GetProcAddress(clipboard->hUser32, "AddClipboardFormatListener"); - clipboard->RemoveClipboardFormatListener = (fnRemoveClipboardFormatListener) - GetProcAddress(clipboard->hUser32, "RemoveClipboardFormatListener"); - clipboard->GetUpdatedClipboardFormats = (fnGetUpdatedClipboardFormats) - GetProcAddress(clipboard->hUser32, "GetUpdatedClipboardFormats"); + clipboard->AddClipboardFormatListener = (fnAddClipboardFormatListener)GetProcAddress( + clipboard->hUser32, "AddClipboardFormatListener"); + clipboard->RemoveClipboardFormatListener = (fnRemoveClipboardFormatListener)GetProcAddress( + clipboard->hUser32, "RemoveClipboardFormatListener"); + clipboard->GetUpdatedClipboardFormats = (fnGetUpdatedClipboardFormats)GetProcAddress( + clipboard->hUser32, "GetUpdatedClipboardFormats"); } - if (!(clipboard->hUser32 && clipboard->AddClipboardFormatListener - && clipboard->RemoveClipboardFormatListener - && clipboard->GetUpdatedClipboardFormats)) + if (!(clipboard->hUser32 && clipboard->AddClipboardFormatListener && + clipboard->RemoveClipboardFormatListener && clipboard->GetUpdatedClipboardFormats)) clipboard->legacyApi = TRUE; - if (!(clipboard->format_mappings = (formatMapping*) calloc(clipboard->map_capacity, - sizeof(formatMapping)))) + if (!(clipboard->format_mappings = + (formatMapping*)calloc(clipboard->map_capacity, sizeof(formatMapping)))) goto error; - if (!(clipboard->response_data_event = CreateEvent(NULL, TRUE, FALSE, - _T("response_data_event")))) + if (!(clipboard->response_data_event = CreateEvent(NULL, TRUE, FALSE, NULL))) goto error; - if (!(clipboard->req_fevent = CreateEvent(NULL, TRUE, FALSE, - _T("request_filecontents_event")))) + if (!(clipboard->req_fevent = CreateEvent(NULL, TRUE, FALSE, NULL))) goto error; if (!(clipboard->thread = CreateThread(NULL, 0, cliprdr_thread_func, clipboard, 0, NULL))) @@ -2533,7 +2504,7 @@ BOOL wf_cliprdr_init(wfContext* wfc, CliprdrClientContext* cliprdr) cliprdr->ServerFormatDataResponse = wf_cliprdr_server_format_data_response; cliprdr->ServerFileContentsRequest = wf_cliprdr_server_file_contents_request; cliprdr->ServerFileContentsResponse = wf_cliprdr_server_file_contents_response; - cliprdr->custom = (void*) wfc->clipboard; + cliprdr->custom = (void*)wfc->clipboard; return TRUE; error: wf_cliprdr_uninit(wfc, cliprdr); @@ -2554,9 +2525,6 @@ BOOL wf_cliprdr_uninit(wfContext* wfc, CliprdrClientContext* cliprdr) cliprdr->custom = NULL; - if (!clipboard) - return FALSE; - if (clipboard->hwnd) PostMessage(clipboard->hwnd, WM_QUIT, 0, 0); @@ -2564,14 +2532,13 @@ BOOL wf_cliprdr_uninit(wfContext* wfc, CliprdrClientContext* cliprdr) { WaitForSingleObject(clipboard->thread, INFINITE); CloseHandle(clipboard->thread); - clipboard->thread = NULL; } if (clipboard->response_data_event) - { CloseHandle(clipboard->response_data_event); - clipboard->response_data_event = NULL; - } + + if (clipboard->req_fevent) + CloseHandle(clipboard->req_fevent); clear_file_array(clipboard); clear_format_map(clipboard); diff --git a/client/Windows/wf_event.c b/client/Windows/wf_event.c index 8057999..7de3487 100644 --- a/client/Windows/wf_event.c +++ b/client/Windows/wf_event.c @@ -36,13 +36,12 @@ static HWND g_focus_hWnd; -#define X_POS(lParam) ((UINT16) (lParam & 0xFFFF)) -#define Y_POS(lParam) ((UINT16) ((lParam >> 16) & 0xFFFF)) +#define X_POS(lParam) ((UINT16)(lParam & 0xFFFF)) +#define Y_POS(lParam) ((UINT16)((lParam >> 16) & 0xFFFF)) -static BOOL wf_scale_blt(wfContext* wfc, HDC hdc, int x, int y, int w, int h, - HDC hdcSrc, int x1, int y1, DWORD rop); -static BOOL wf_scale_mouse_event(wfContext* wfc, rdpInput* input, UINT16 flags, - UINT16 x, UINT16 y); +static BOOL wf_scale_blt(wfContext* wfc, HDC hdc, int x, int y, int w, int h, HDC hdcSrc, int x1, + int y1, DWORD rop); +static BOOL wf_scale_mouse_event(wfContext* wfc, rdpInput* input, UINT16 flags, UINT16 x, UINT16 y); #if (_WIN32_WINNT >= 0x0500) static BOOL wf_scale_mouse_event_ex(wfContext* wfc, rdpInput* input, UINT16 flags, UINT16 buttonMask, UINT16 x, UINT16 y); @@ -53,8 +52,7 @@ static BOOL g_flipping_out; static BOOL alt_ctrl_down() { - return ((GetAsyncKeyState(VK_CONTROL) & 0x8000) || - (GetAsyncKeyState(VK_MENU) & 0x8000)); + return ((GetAsyncKeyState(VK_CONTROL) & 0x8000) || (GetAsyncKeyState(VK_MENU) & 0x8000)); } LRESULT CALLBACK wf_ll_kbd_proc(int nCode, WPARAM wParam, LPARAM lParam) @@ -63,8 +61,7 @@ LRESULT CALLBACK wf_ll_kbd_proc(int nCode, WPARAM wParam, LPARAM lParam) DWORD rdp_scancode; rdpInput* input; PKBDLLHOOKSTRUCT p; - DEBUG_KBD("Low-level keyboard hook, hWnd %X nCode %X wParam %X", g_focus_hWnd, - nCode, wParam); + DEBUG_KBD("Low-level keyboard hook, hWnd %X nCode %X wParam %X", g_focus_hWnd, nCode, wParam); if (g_flipping_in) { @@ -82,18 +79,18 @@ LRESULT CALLBACK wf_ll_kbd_proc(int nCode, WPARAM wParam, LPARAM lParam) case WM_SYSKEYDOWN: case WM_KEYUP: case WM_SYSKEYUP: - wfc = (wfContext*) GetWindowLongPtr(g_focus_hWnd, GWLP_USERDATA); - p = (PKBDLLHOOKSTRUCT) lParam; + wfc = (wfContext*)GetWindowLongPtr(g_focus_hWnd, GWLP_USERDATA); + p = (PKBDLLHOOKSTRUCT)lParam; if (!wfc || !p) return 1; input = wfc->context.input; - rdp_scancode = MAKE_RDP_SCANCODE((BYTE) p->scanCode, p->flags & LLKHF_EXTENDED); + rdp_scancode = MAKE_RDP_SCANCODE((BYTE)p->scanCode, p->flags & LLKHF_EXTENDED); DEBUG_KBD("keydown %d scanCode 0x%08lX flags 0x%08lX vkCode 0x%08lX", (wParam == WM_KEYDOWN), p->scanCode, p->flags, p->vkCode); - if (wfc->fs_toggle && + if (wfc->fullscreen_toggle && ((p->vkCode == VK_RETURN) || (p->vkCode == VK_CANCEL)) && (GetAsyncKeyState(VK_CONTROL) & 0x8000) && (GetAsyncKeyState(VK_MENU) & 0x8000)) /* could also use flags & LLKHF_ALTDOWN */ @@ -114,7 +111,7 @@ LRESULT CALLBACK wf_ll_kbd_proc(int nCode, WPARAM wParam, LPARAM lParam) else if (rdp_scancode == RDP_SCANCODE_NUMLOCK) { /* Windows sends Pause as if it was a RDP NumLock (handled above). - * It must however be sent as a one-shot Ctrl+NumLock */ + * It must however be sent as a one-shot Ctrl+NumLock */ if (wParam == WM_KEYDOWN) { DEBUG_KBD("Pause, sent as Ctrl+NumLock"); @@ -136,12 +133,12 @@ LRESULT CALLBACK wf_ll_kbd_proc(int nCode, WPARAM wParam, LPARAM lParam) rdp_scancode = RDP_SCANCODE_RSHIFT; } - freerdp_input_send_keyboard_event_ex(input, !(p->flags & LLKHF_UP), - rdp_scancode); + freerdp_input_send_keyboard_event_ex(input, !(p->flags & LLKHF_UP), rdp_scancode); - if (p->vkCode == VK_NUMLOCK || p->vkCode == VK_CAPITAL - || p->vkCode == VK_SCROLL || p->vkCode == VK_KANA) - DEBUG_KBD("lock keys are processed on client side too to toggle their indicators"); + if (p->vkCode == VK_NUMLOCK || p->vkCode == VK_CAPITAL || p->vkCode == VK_SCROLL || + p->vkCode == VK_KANA) + DEBUG_KBD( + "lock keys are processed on client side too to toggle their indicators"); else return 1; @@ -192,15 +189,15 @@ void wf_event_focus_in(wfContext* wfc) input->MouseEvent(input, PTR_FLAGS_MOVE, (UINT16)pt.x, (UINT16)pt.y); } -static BOOL wf_event_process_WM_MOUSEWHEEL(wfContext* wfc, HWND hWnd, UINT Msg, - WPARAM wParam, LPARAM lParam, BOOL horizontal, UINT16 x, UINT16 y) +static BOOL wf_event_process_WM_MOUSEWHEEL(wfContext* wfc, HWND hWnd, UINT Msg, WPARAM wParam, + LPARAM lParam, BOOL horizontal, UINT16 x, UINT16 y) { int delta; UINT16 flags = 0; rdpInput* input; DefWindowProc(hWnd, Msg, wParam, lParam); input = wfc->context.input; - delta = ((signed short) HIWORD(wParam)); /* GET_WHEEL_DELTA_WPARAM(wParam); */ + delta = ((signed short)HIWORD(wParam)); /* GET_WHEEL_DELTA_WPARAM(wParam); */ if (horizontal) flags |= PTR_FLAGS_HWHEEL; @@ -212,8 +209,8 @@ static BOOL wf_event_process_WM_MOUSEWHEEL(wfContext* wfc, HWND hWnd, UINT Msg, flags |= PTR_FLAGS_WHEEL_NEGATIVE; delta = -delta; } - flags |= delta; + flags |= delta; return wf_scale_mouse_event(wfc, input, flags, x, y); } @@ -225,7 +222,7 @@ static void wf_sizing(wfContext* wfc, WPARAM wParam, LPARAM lParam) if (settings->SmartSizing && (GetAsyncKeyState(VK_CONTROL) & 0x8000)) { - rect = (LPRECT) wParam; + rect = (LPRECT)wParam; switch (lParam) { @@ -233,8 +230,8 @@ static void wf_sizing(wfContext* wfc, WPARAM wParam, LPARAM lParam) case WMSZ_RIGHT: case WMSZ_BOTTOMRIGHT: // Adjust height - rect->bottom = rect->top + settings->DesktopHeight * (rect->right - - rect->left) / settings->DesktopWidth; + rect->bottom = rect->top + settings->DesktopHeight * (rect->right - rect->left) / + settings->DesktopWidth; break; case WMSZ_TOP: @@ -242,21 +239,20 @@ static void wf_sizing(wfContext* wfc, WPARAM wParam, LPARAM lParam) case WMSZ_TOPRIGHT: // Adjust width rect->right = rect->left + settings->DesktopWidth * (rect->bottom - rect->top) / - settings->DesktopHeight; + settings->DesktopHeight; break; case WMSZ_BOTTOMLEFT: case WMSZ_TOPLEFT: // adjust width - rect->left = rect->right - (settings->DesktopWidth * (rect->bottom - - rect->top) / settings->DesktopHeight); + rect->left = rect->right - (settings->DesktopWidth * (rect->bottom - rect->top) / + settings->DesktopHeight); break; } } } -LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, - LPARAM lParam) +LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { HDC hdc; LONG_PTR ptr; @@ -269,7 +265,7 @@ LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, SCROLLINFO si; processed = TRUE; ptr = GetWindowLongPtr(hWnd, GWLP_USERDATA); - wfc = (wfContext*) ptr; + wfc = (wfContext*)ptr; if (wfc != NULL) { @@ -281,8 +277,8 @@ LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, case WM_MOVE: if (!wfc->disablewindowtracking) { - int x = (int)(short) LOWORD(lParam); - int y = (int)(short) HIWORD(lParam); + int x = (int)(short)LOWORD(lParam); + int y = (int)(short)HIWORD(lParam); wfc->client_x = x; wfc->client_y = y; } @@ -297,11 +293,11 @@ LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, else { // Set maximum window size for resizing - minmax = (MINMAXINFO*) lParam; + minmax = (MINMAXINFO*)lParam; - //always use the last determined canvas diff, because it could be - //that the window is minimized when this gets called - //wf_update_canvas_diff(wfc); + // always use the last determined canvas diff, because it could be + // that the window is minimized when this gets called + // wf_update_canvas_diff(wfc); if (!wfc->fullscreen) { @@ -332,10 +328,12 @@ LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, { wf_size_scrollbars(wfc, LOWORD(lParam), HIWORD(lParam)); - // Workaround: when the window is maximized, the call to "ShowScrollBars" returns TRUE but has no effect. + // Workaround: when the window is maximized, the call to "ShowScrollBars" + // returns TRUE but has no effect. if (wParam == SIZE_MAXIMIZED && !wfc->fullscreen) SetWindowPos(wfc->hwnd, HWND_TOP, 0, 0, windowRect.right - windowRect.left, - windowRect.bottom - windowRect.top, SWP_NOMOVE | SWP_FRAMECHANGED); + windowRect.bottom - windowRect.top, + SWP_NOMOVE | SWP_FRAMECHANGED); } break; @@ -346,7 +344,7 @@ LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, case WM_ERASEBKGND: /* Say we handled it - prevents flickering */ - return (LRESULT) 1; + return (LRESULT)1; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); @@ -359,16 +357,18 @@ LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, y - wfc->offset_y + wfc->yCurrentScroll, SRCCOPY); EndPaint(hWnd, &ps); break; - #if (_WIN32_WINNT >= 0x0500) + case WM_XBUTTONDOWN: wf_scale_mouse_event_ex(wfc, input, PTR_XFLAGS_DOWN, GET_XBUTTON_WPARAM(wParam), - X_POS(lParam) - wfc->offset_x, Y_POS(lParam) - wfc->offset_y); + X_POS(lParam) - wfc->offset_x, + Y_POS(lParam) - wfc->offset_y); break; case WM_XBUTTONUP: wf_scale_mouse_event_ex(wfc, input, 0, GET_XBUTTON_WPARAM(wParam), - X_POS(lParam) - wfc->offset_x, Y_POS(lParam) - wfc->offset_y); + X_POS(lParam) - wfc->offset_x, + Y_POS(lParam) - wfc->offset_y); break; #endif @@ -378,8 +378,8 @@ LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, break; case WM_MBUTTONUP: - wf_scale_mouse_event(wfc, input, PTR_FLAGS_BUTTON3, - X_POS(lParam) - wfc->offset_x, Y_POS(lParam) - wfc->offset_y); + wf_scale_mouse_event(wfc, input, PTR_FLAGS_BUTTON3, X_POS(lParam) - wfc->offset_x, + Y_POS(lParam) - wfc->offset_y); break; case WM_LBUTTONDOWN: @@ -388,8 +388,8 @@ LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, break; case WM_LBUTTONUP: - wf_scale_mouse_event(wfc, input, PTR_FLAGS_BUTTON1, - X_POS(lParam) - wfc->offset_x, Y_POS(lParam) - wfc->offset_y); + wf_scale_mouse_event(wfc, input, PTR_FLAGS_BUTTON1, X_POS(lParam) - wfc->offset_x, + Y_POS(lParam) - wfc->offset_y); break; case WM_RBUTTONDOWN: @@ -398,28 +398,28 @@ LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, break; case WM_RBUTTONUP: - wf_scale_mouse_event(wfc, input, PTR_FLAGS_BUTTON2, - X_POS(lParam) - wfc->offset_x, Y_POS(lParam) - wfc->offset_y); + wf_scale_mouse_event(wfc, input, PTR_FLAGS_BUTTON2, X_POS(lParam) - wfc->offset_x, + Y_POS(lParam) - wfc->offset_y); break; case WM_MOUSEMOVE: wf_scale_mouse_event(wfc, input, PTR_FLAGS_MOVE, X_POS(lParam) - wfc->offset_x, Y_POS(lParam) - wfc->offset_y); break; - #if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400) + case WM_MOUSEWHEEL: wf_event_process_WM_MOUSEWHEEL(wfc, hWnd, Msg, wParam, lParam, FALSE, - X_POS(lParam) - wfc->offset_x, - Y_POS(lParam) - wfc->offset_y); + X_POS(lParam) - wfc->offset_x, + Y_POS(lParam) - wfc->offset_y); break; #endif - #if (_WIN32_WINNT >= 0x0600) + case WM_MOUSEHWHEEL: wf_event_process_WM_MOUSEWHEEL(wfc, hWnd, Msg, wParam, lParam, TRUE, - X_POS(lParam) - wfc->offset_x, - Y_POS(lParam) - wfc->offset_y); + X_POS(lParam) - wfc->offset_x, + Y_POS(lParam) - wfc->offset_y); break; #endif @@ -432,160 +432,159 @@ LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, break; case WM_HSCROLL: + { + int xDelta; // xDelta = new_pos - current_pos + int xNewPos; // new position + int yDelta = 0; + + switch (LOWORD(wParam)) { - int xDelta; // xDelta = new_pos - current_pos - int xNewPos; // new position - int yDelta = 0; + // User clicked the scroll bar shaft left of the scroll box. + case SB_PAGEUP: + xNewPos = wfc->xCurrentScroll - 50; + break; - switch (LOWORD(wParam)) - { - // User clicked the scroll bar shaft left of the scroll box. - case SB_PAGEUP: - xNewPos = wfc->xCurrentScroll - 50; - break; - - // User clicked the scroll bar shaft right of the scroll box. - case SB_PAGEDOWN: - xNewPos = wfc->xCurrentScroll + 50; - break; - - // User clicked the left arrow. - case SB_LINEUP: - xNewPos = wfc->xCurrentScroll - 5; - break; - - // User clicked the right arrow. - case SB_LINEDOWN: - xNewPos = wfc->xCurrentScroll + 5; - break; - - // User dragged the scroll box. - case SB_THUMBPOSITION: - xNewPos = HIWORD(wParam); - - // user is dragging the scrollbar - case SB_THUMBTRACK : - xNewPos = HIWORD(wParam); - break; - - default: - xNewPos = wfc->xCurrentScroll; - } + // User clicked the scroll bar shaft right of the scroll box. + case SB_PAGEDOWN: + xNewPos = wfc->xCurrentScroll + 50; + break; + + // User clicked the left arrow. + case SB_LINEUP: + xNewPos = wfc->xCurrentScroll - 5; + break; + + // User clicked the right arrow. + case SB_LINEDOWN: + xNewPos = wfc->xCurrentScroll + 5; + break; - // New position must be between 0 and the screen width. - xNewPos = MAX(0, xNewPos); - xNewPos = MIN(wfc->xMaxScroll, xNewPos); + // User dragged the scroll box. + case SB_THUMBPOSITION: + xNewPos = HIWORD(wParam); + break; - // If the current position does not change, do not scroll. - if (xNewPos == wfc->xCurrentScroll) + // user is dragging the scrollbar + case SB_THUMBTRACK: + xNewPos = HIWORD(wParam); break; - // Determine the amount scrolled (in pixels). - xDelta = xNewPos - wfc->xCurrentScroll; - // Reset the current scroll position. - wfc->xCurrentScroll = xNewPos; - // Scroll the window. (The system repaints most of the - // client area when ScrollWindowEx is called; however, it is - // necessary to call UpdateWindow in order to repaint the - // rectangle of pixels that were invalidated.) - ScrollWindowEx(wfc->hwnd, -xDelta, -yDelta, (CONST RECT*) NULL, - (CONST RECT*) NULL, (HRGN) NULL, (PRECT) NULL, - SW_INVALIDATE); - UpdateWindow(wfc->hwnd); - // Reset the scroll bar. - si.cbSize = sizeof(si); - si.fMask = SIF_POS; - si.nPos = wfc->xCurrentScroll; - SetScrollInfo(wfc->hwnd, SB_HORZ, &si, TRUE); + default: + xNewPos = wfc->xCurrentScroll; } - break; + + // New position must be between 0 and the screen width. + xNewPos = MAX(0, xNewPos); + xNewPos = MIN(wfc->xMaxScroll, xNewPos); + + // If the current position does not change, do not scroll. + if (xNewPos == wfc->xCurrentScroll) + break; + + // Determine the amount scrolled (in pixels). + xDelta = xNewPos - wfc->xCurrentScroll; + // Reset the current scroll position. + wfc->xCurrentScroll = xNewPos; + // Scroll the window. (The system repaints most of the + // client area when ScrollWindowEx is called; however, it is + // necessary to call UpdateWindow in order to repaint the + // rectangle of pixels that were invalidated.) + ScrollWindowEx(wfc->hwnd, -xDelta, -yDelta, (CONST RECT*)NULL, (CONST RECT*)NULL, + (HRGN)NULL, (PRECT)NULL, SW_INVALIDATE); + UpdateWindow(wfc->hwnd); + // Reset the scroll bar. + si.cbSize = sizeof(si); + si.fMask = SIF_POS; + si.nPos = wfc->xCurrentScroll; + SetScrollInfo(wfc->hwnd, SB_HORZ, &si, TRUE); + } + break; case WM_VSCROLL: + { + int xDelta = 0; + int yDelta; // yDelta = new_pos - current_pos + int yNewPos; // new position + + switch (LOWORD(wParam)) { - int xDelta = 0; - int yDelta; // yDelta = new_pos - current_pos - int yNewPos; // new position + // User clicked the scroll bar shaft above the scroll box. + case SB_PAGEUP: + yNewPos = wfc->yCurrentScroll - 50; + break; - switch (LOWORD(wParam)) - { - // User clicked the scroll bar shaft above the scroll box. - case SB_PAGEUP: - yNewPos = wfc->yCurrentScroll - 50; - break; - - // User clicked the scroll bar shaft below the scroll box. - case SB_PAGEDOWN: - yNewPos = wfc->yCurrentScroll + 50; - break; - - // User clicked the top arrow. - case SB_LINEUP: - yNewPos = wfc->yCurrentScroll - 5; - break; - - // User clicked the bottom arrow. - case SB_LINEDOWN: - yNewPos = wfc->yCurrentScroll + 5; - break; - - // User dragged the scroll box. - case SB_THUMBPOSITION: - yNewPos = HIWORD(wParam); - break; - - // user is dragging the scrollbar - case SB_THUMBTRACK : - yNewPos = HIWORD(wParam); - break; - - default: - yNewPos = wfc->yCurrentScroll; - } + // User clicked the scroll bar shaft below the scroll box. + case SB_PAGEDOWN: + yNewPos = wfc->yCurrentScroll + 50; + break; + + // User clicked the top arrow. + case SB_LINEUP: + yNewPos = wfc->yCurrentScroll - 5; + break; + + // User clicked the bottom arrow. + case SB_LINEDOWN: + yNewPos = wfc->yCurrentScroll + 5; + break; - // New position must be between 0 and the screen height. - yNewPos = MAX(0, yNewPos); - yNewPos = MIN(wfc->yMaxScroll, yNewPos); + // User dragged the scroll box. + case SB_THUMBPOSITION: + yNewPos = HIWORD(wParam); + break; - // If the current position does not change, do not scroll. - if (yNewPos == wfc->yCurrentScroll) + // user is dragging the scrollbar + case SB_THUMBTRACK: + yNewPos = HIWORD(wParam); break; - // Determine the amount scrolled (in pixels). - yDelta = yNewPos - wfc->yCurrentScroll; - // Reset the current scroll position. - wfc->yCurrentScroll = yNewPos; - // Scroll the window. (The system repaints most of the - // client area when ScrollWindowEx is called; however, it is - // necessary to call UpdateWindow in order to repaint the - // rectangle of pixels that were invalidated.) - ScrollWindowEx(wfc->hwnd, -xDelta, -yDelta, (CONST RECT*) NULL, - (CONST RECT*) NULL, (HRGN) NULL, (PRECT) NULL, - SW_INVALIDATE); - UpdateWindow(wfc->hwnd); - // Reset the scroll bar. - si.cbSize = sizeof(si); - si.fMask = SIF_POS; - si.nPos = wfc->yCurrentScroll; - SetScrollInfo(wfc->hwnd, SB_VERT, &si, TRUE); + default: + yNewPos = wfc->yCurrentScroll; } - break; + + // New position must be between 0 and the screen height. + yNewPos = MAX(0, yNewPos); + yNewPos = MIN(wfc->yMaxScroll, yNewPos); + + // If the current position does not change, do not scroll. + if (yNewPos == wfc->yCurrentScroll) + break; + + // Determine the amount scrolled (in pixels). + yDelta = yNewPos - wfc->yCurrentScroll; + // Reset the current scroll position. + wfc->yCurrentScroll = yNewPos; + // Scroll the window. (The system repaints most of the + // client area when ScrollWindowEx is called; however, it is + // necessary to call UpdateWindow in order to repaint the + // rectangle of pixels that were invalidated.) + ScrollWindowEx(wfc->hwnd, -xDelta, -yDelta, (CONST RECT*)NULL, (CONST RECT*)NULL, + (HRGN)NULL, (PRECT)NULL, SW_INVALIDATE); + UpdateWindow(wfc->hwnd); + // Reset the scroll bar. + si.cbSize = sizeof(si); + si.fMask = SIF_POS; + si.nPos = wfc->yCurrentScroll; + SetScrollInfo(wfc->hwnd, SB_VERT, &si, TRUE); + } + break; case WM_SYSCOMMAND: + { + if (wParam == SYSCOMMAND_ID_SMARTSIZING) { - if (wParam == SYSCOMMAND_ID_SMARTSIZING) - { - HMENU hMenu = GetSystemMenu(wfc->hwnd, FALSE); - freerdp_set_param_bool(wfc->context.settings, FreeRDP_SmartSizing, - !wfc->context.settings->SmartSizing); - CheckMenuItem(hMenu, SYSCOMMAND_ID_SMARTSIZING, - wfc->context.settings->SmartSizing ? MF_CHECKED : MF_UNCHECKED); - } - else - { - processed = FALSE; - } + HMENU hMenu = GetSystemMenu(wfc->hwnd, FALSE); + freerdp_set_param_bool(wfc->context.settings, FreeRDP_SmartSizing, + !wfc->context.settings->SmartSizing); + CheckMenuItem(hMenu, SYSCOMMAND_ID_SMARTSIZING, + wfc->context.settings->SmartSizing ? MF_CHECKED : MF_UNCHECKED); } - break; + else + { + processed = FALSE; + } + } + break; default: processed = FALSE; @@ -630,24 +629,24 @@ LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, break; case WM_ACTIVATE: - { - int activate = (int)(short) LOWORD(wParam); + { + int activate = (int)(short)LOWORD(wParam); - if (activate != WA_INACTIVE) - { - if (alt_ctrl_down()) - g_flipping_in = TRUE; + if (activate != WA_INACTIVE) + { + if (alt_ctrl_down()) + g_flipping_in = TRUE; - g_focus_hWnd = hWnd; - } + g_focus_hWnd = hWnd; + } + else + { + if (alt_ctrl_down()) + g_flipping_out = TRUE; else - { - if (alt_ctrl_down()) - g_flipping_out = TRUE; - else - g_focus_hWnd = NULL; - } + g_focus_hWnd = NULL; } + } default: return DefWindowProc(hWnd, Msg, wParam, lParam); @@ -657,8 +656,8 @@ LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, return 0; } -BOOL wf_scale_blt(wfContext* wfc, HDC hdc, int x, int y, int w, int h, - HDC hdcSrc, int x1, int y1, DWORD rop) +BOOL wf_scale_blt(wfContext* wfc, HDC hdc, int x, int y, int w, int h, HDC hdcSrc, int x1, int y1, + DWORD rop) { rdpSettings* settings; UINT32 ww, wh, dw, dh; @@ -681,8 +680,7 @@ BOOL wf_scale_blt(wfContext* wfc, HDC hdc, int x, int y, int w, int h, if (!wh) wh = dh; - if (wfc->fullscreen || !wfc->context.settings->SmartSizing || (ww == dw - && wh == dh)) + if (wfc->fullscreen || !wfc->context.settings->SmartSizing || (ww == dw && wh == dh)) { return BitBlt(hdc, x, y, w, h, wfc->primary->hdc, x1, y1, SRCCOPY); } @@ -701,11 +699,12 @@ static BOOL wf_scale_mouse_pos(wfContext* wfc, UINT16* x, UINT16* y) int ww, wh, dw, dh; rdpContext* context; rdpSettings* settings; - + if (!wfc || !x || !y) return FALSE; settings = wfc->context.settings; + if (!settings) return FALSE; @@ -734,8 +733,7 @@ static BOOL wf_scale_mouse_pos(wfContext* wfc, UINT16* x, UINT16* y) return TRUE; } -static BOOL wf_scale_mouse_event(wfContext* wfc, rdpInput* input, UINT16 flags, - UINT16 x, UINT16 y) +static BOOL wf_scale_mouse_event(wfContext* wfc, rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) { MouseEventEventArgs eventArgs; @@ -752,14 +750,15 @@ static BOOL wf_scale_mouse_event(wfContext* wfc, rdpInput* input, UINT16 flags, return TRUE; } -#if(_WIN32_WINNT >= 0x0500) -static BOOL wf_scale_mouse_event_ex(wfContext* wfc, rdpInput* input, UINT16 flags, UINT16 buttonMask, - UINT16 x, UINT16 y) +#if (_WIN32_WINNT >= 0x0500) +static BOOL wf_scale_mouse_event_ex(wfContext* wfc, rdpInput* input, UINT16 flags, + UINT16 buttonMask, UINT16 x, UINT16 y) { MouseEventExEventArgs eventArgs; if (buttonMask & XBUTTON1) flags |= PTR_XFLAGS_BUTTON1; + if (buttonMask & XBUTTON2) flags |= PTR_XFLAGS_BUTTON2; diff --git a/client/Windows/wf_event.h b/client/Windows/wf_event.h index a9d7108..f879f87 100644 --- a/client/Windows/wf_event.h +++ b/client/Windows/wf_event.h @@ -26,8 +26,7 @@ #include LRESULT CALLBACK wf_ll_kbd_proc(int nCode, WPARAM wParam, LPARAM lParam); -LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, - LPARAM lParam); +LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); void wf_event_focus_in(wfContext* wfc); @@ -35,7 +34,10 @@ void wf_event_focus_in(wfContext* wfc); #ifdef WITH_DEBUG_KBD #define DEBUG_KBD(...) WLog_DBG(KBD_TAG, __VA_ARGS__) #else -#define DEBUG_KBD(...) do { } while (0) +#define DEBUG_KBD(...) \ + do \ + { \ + } while (0) #endif #endif /* FREERDP_CLIENT_WIN_EVENT_H */ diff --git a/client/Windows/wf_floatbar.c b/client/Windows/wf_floatbar.c index 71f9898..512c66b 100644 --- a/client/Windows/wf_floatbar.c +++ b/client/Windows/wf_floatbar.c @@ -25,36 +25,42 @@ #include "wf_client.h" #include "wf_floatbar.h" #include "wf_gdi.h" +#pragma comment(lib, "Msimg32.lib") + +#define TAG CLIENT_TAG("windows.floatbar") typedef struct _Button Button; /* TIMERs */ -#define TIMER_HIDE 1 -#define TIMER_ANIMAT_SHOW 2 -#define TIMER_ANIMAT_HIDE 3 +#define TIMER_HIDE 1 +#define TIMER_ANIMAT_SHOW 2 +#define TIMER_ANIMAT_HIDE 3 /* Button Type */ -#define BUTTON_LOCKPIN 0 -#define BUTTON_MINIMIZE 1 -#define BUTTON_RESTORE 2 -#define BUTTON_CLOSE 3 -#define BTN_MAX 4 +#define BUTTON_LOCKPIN 0 +#define BUTTON_MINIMIZE 1 +#define BUTTON_RESTORE 2 +#define BUTTON_CLOSE 3 +#define BTN_MAX 4 /* bmp size */ -#define BACKGROUND_W 581 -#define BACKGROUND_H 29 -#define LOCK_X 13 -#define MINIMIZE_X (BACKGROUND_W - 91) -#define CLOSE_X (BACKGROUND_W - 37) -#define RESTORE_X (BACKGROUND_W - 64) - -#define BUTTON_Y 2 -#define BUTTON_WIDTH 24 -#define BUTTON_HEIGHT 24 +#define BACKGROUND_W 576 +#define BACKGROUND_H 27 +#define BUTTON_OFFSET 5 +#define BUTTON_Y 2 +#define BUTTON_WIDTH 23 +#define BUTTON_HEIGHT 21 +#define BUTTON_SPACING 1 + +#define LOCK_X (BACKGROUND_H + BUTTON_OFFSET) +#define CLOSE_X ((BACKGROUND_W - (BACKGROUND_H + BUTTON_OFFSET)) - BUTTON_WIDTH) +#define RESTORE_X (CLOSE_X - (BUTTON_WIDTH + BUTTON_SPACING)) +#define MINIMIZE_X (RESTORE_X - (BUTTON_WIDTH + BUTTON_SPACING)) +#define TEXT_X (BACKGROUND_H + ((BUTTON_WIDTH + BUTTON_SPACING) * 3) + 5) struct _Button { - FloatBar* floatbar; + wfFloatBar* floatbar; int type; int x, y, h, w; int active; @@ -70,40 +76,169 @@ struct _Button struct _FloatBar { + HINSTANCE root_window; + DWORD flags; HWND parent; HWND hwnd; RECT rect; LONG width; LONG height; + LONG offset; wfContext* wfc; Button* buttons[BTN_MAX]; BOOL shown; BOOL locked; HDC hdcmem; - HBITMAP background; + RECT textRect; + UINT_PTR animating; }; -static int button_hit(Button* button) +static BOOL floatbar_kill_timers(wfFloatBar* floatbar) +{ + size_t x; + UINT_PTR timers[] = { TIMER_HIDE, TIMER_ANIMAT_HIDE, TIMER_ANIMAT_SHOW }; + + if (!floatbar) + return FALSE; + + for (x = 0; x < ARRAYSIZE(timers); x++) + KillTimer(floatbar->hwnd, timers[x]); + + floatbar->animating = 0; + return TRUE; +} + +static BOOL floatbar_animation(wfFloatBar* const floatbar, const BOOL show) +{ + UINT_PTR timer = show ? TIMER_ANIMAT_SHOW : TIMER_ANIMAT_HIDE; + + if (!floatbar) + return FALSE; + + if (floatbar->shown == show) + return TRUE; + + if (floatbar->animating == timer) + return TRUE; + + floatbar->animating = timer; + + if (SetTimer(floatbar->hwnd, timer, USER_TIMER_MINIMUM, NULL) == NULL) + { + DWORD err = GetLastError(); + WLog_ERR(TAG, "SetTimer failed with %08" PRIx32, err); + return FALSE; + } + + return TRUE; +} + +static BOOL floatbar_trigger_hide(wfFloatBar* floatbar) +{ + if (!floatbar_kill_timers(floatbar)) + return FALSE; + + if (!floatbar->locked && floatbar->shown) + { + if (SetTimer(floatbar->hwnd, TIMER_HIDE, 3000, NULL) == NULL) + { + DWORD err = GetLastError(); + WLog_ERR(TAG, "SetTimer failed with %08" PRIx32, err); + return FALSE; + } + } + + return TRUE; +} + +static BOOL floatbar_hide(wfFloatBar* floatbar) +{ + if (!floatbar_kill_timers(floatbar)) + return FALSE; + + floatbar->offset = floatbar->height - 2; + + if (!MoveWindow(floatbar->hwnd, floatbar->rect.left, -floatbar->offset, floatbar->width, + floatbar->height, TRUE)) + { + DWORD err = GetLastError(); + WLog_ERR(TAG, "MoveWindow failed with %08" PRIx32, err); + return FALSE; + } + + floatbar->shown = FALSE; + + if (!floatbar_trigger_hide(floatbar)) + return FALSE; + + return TRUE; +} + +static BOOL floatbar_show(wfFloatBar* floatbar) +{ + if (!floatbar_kill_timers(floatbar)) + return FALSE; + + floatbar->offset = 0; + + if (!MoveWindow(floatbar->hwnd, floatbar->rect.left, -floatbar->offset, floatbar->width, + floatbar->height, TRUE)) + { + DWORD err = GetLastError(); + WLog_ERR(TAG, "MoveWindow failed with %08" PRIx32, err); + return FALSE; + } + + floatbar->shown = TRUE; + + if (!floatbar_trigger_hide(floatbar)) + return FALSE; + + return TRUE; +} + +static BOOL button_set_locked(Button* button, BOOL locked) +{ + if (locked) + { + button->bmp = button->locked_bmp; + button->bmp_act = button->locked_bmp_act; + } + else + { + button->bmp = button->unlocked_bmp; + button->bmp_act = button->unlocked_bmp_act; + } + + InvalidateRect(button->floatbar->hwnd, NULL, FALSE); + UpdateWindow(button->floatbar->hwnd); + return TRUE; +} + +static BOOL update_locked_state(wfFloatBar* floatbar) { - FloatBar* floatbar = button->floatbar; + Button* button; + + if (!floatbar) + return FALSE; + + button = floatbar->buttons[3]; + + if (!button_set_locked(button, floatbar->locked)) + return FALSE; + + return TRUE; +} + +static int button_hit(Button* const button) +{ + wfFloatBar* const floatbar = button->floatbar; switch (button->type) { case BUTTON_LOCKPIN: - if (!floatbar->locked) - { - button->bmp = button->locked_bmp; - button->bmp_act = button->locked_bmp_act; - } - else - { - button->bmp = button->unlocked_bmp; - button->bmp_act = button->unlocked_bmp_act; - } - - floatbar->locked = ~floatbar->locked; - InvalidateRect(button->floatbar->hwnd, NULL, FALSE); - UpdateWindow(button->floatbar->hwnd); + floatbar->locked = !floatbar->locked; + update_locked_state(floatbar); break; case BUTTON_MINIMIZE: @@ -115,7 +250,7 @@ static int button_hit(Button* button) break; case BUTTON_CLOSE: - SendMessage(floatbar->parent, WM_DESTROY, 0 , 0); + SendMessage(floatbar->parent, WM_DESTROY, 0, 0); break; default: @@ -125,20 +260,29 @@ static int button_hit(Button* button) return 0; } -static int button_paint(Button* button, HDC hdc) +static int button_paint(const Button* const button, const HDC hdc) { - FloatBar* floatbar = button->floatbar; - SelectObject(floatbar->hdcmem, button->active ? button->bmp_act : button->bmp); - StretchBlt(hdc, button->x, button->y, button->w, button->h, floatbar->hdcmem, 0, - 0, button->w, button->h, SRCCOPY); + if (button != NULL) + { + wfFloatBar* floatbar = button->floatbar; + BLENDFUNCTION bf; + SelectObject(floatbar->hdcmem, button->active ? button->bmp_act : button->bmp); + bf.BlendOp = AC_SRC_OVER; + bf.BlendFlags = 0; + bf.SourceConstantAlpha = 255; + bf.AlphaFormat = AC_SRC_ALPHA; + AlphaBlend(hdc, button->x, button->y, button->w, button->h, floatbar->hdcmem, 0, 0, + button->w, button->h, bf); + } + return 0; } -static Button* floatbar_create_button(FloatBar* floatbar, int type, int resid, - int resid_act, int x, int y, int h, int w) +static Button* floatbar_create_button(wfFloatBar* const floatbar, const int type, const int resid, + const int resid_act, const int x, const int y, const int h, + const int w) { - Button* button; - button = (Button*)malloc(sizeof(Button)); + Button* button = (Button*)calloc(1, sizeof(Button)); if (!button) return NULL; @@ -150,91 +294,136 @@ static Button* floatbar_create_button(FloatBar* floatbar, int type, int resid, button->w = w; button->h = h; button->active = FALSE; - button->bmp = (HBITMAP)LoadImage(floatbar->wfc->hInstance, - MAKEINTRESOURCE(resid), IMAGE_BITMAP, w, h, LR_DEFAULTCOLOR); - button->bmp_act = (HBITMAP)LoadImage(floatbar->wfc->hInstance, - MAKEINTRESOURCE(resid_act), IMAGE_BITMAP, w, h, LR_DEFAULTCOLOR); + button->bmp = (HBITMAP)LoadImage(floatbar->root_window, MAKEINTRESOURCE(resid), IMAGE_BITMAP, 0, + 0, LR_DEFAULTCOLOR); + button->bmp_act = (HBITMAP)LoadImage(floatbar->root_window, MAKEINTRESOURCE(resid_act), + IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); return button; } -static Button* floatbar_create_lock_button(FloatBar* floatbar, - int unlock_resid, int unlock_resid_act, - int lock_resid, int lock_resid_act, - int x, int y, int h, int w) +static Button* floatbar_create_lock_button(wfFloatBar* const floatbar, const int unlock_resid, + const int unlock_resid_act, const int lock_resid, + const int lock_resid_act, const int x, const int y, + const int h, const int w) { - Button* button; - button = floatbar_create_button(floatbar, BUTTON_LOCKPIN, unlock_resid, - unlock_resid_act, x, y, h, w); + Button* button = floatbar_create_button(floatbar, BUTTON_LOCKPIN, unlock_resid, + unlock_resid_act, x, y, h, w); if (!button) return NULL; button->unlocked_bmp = button->bmp; button->unlocked_bmp_act = button->bmp_act; - button->locked_bmp = (HBITMAP)LoadImage(floatbar->wfc->hInstance, - MAKEINTRESOURCE(lock_resid), IMAGE_BITMAP, w, h, LR_DEFAULTCOLOR); - button->locked_bmp_act = (HBITMAP)LoadImage(floatbar->wfc->hInstance, - MAKEINTRESOURCE(lock_resid_act), IMAGE_BITMAP, w, h, LR_DEFAULTCOLOR); + button->locked_bmp = (HBITMAP)LoadImage(floatbar->wfc->hInstance, MAKEINTRESOURCE(lock_resid), + IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); + button->locked_bmp_act = + (HBITMAP)LoadImage(floatbar->wfc->hInstance, MAKEINTRESOURCE(lock_resid_act), IMAGE_BITMAP, + 0, 0, LR_DEFAULTCOLOR); return button; } -static Button* floatbar_get_button(FloatBar* floatbar, int x, int y) +static Button* floatbar_get_button(const wfFloatBar* const floatbar, const int x, const int y) { int i; - if (y > BUTTON_Y && y < BUTTON_Y + BUTTON_HEIGHT) + if ((y > BUTTON_Y) && (y < BUTTON_Y + BUTTON_HEIGHT)) + { for (i = 0; i < BTN_MAX; i++) - if (x > floatbar->buttons[i]->x - && x < floatbar->buttons[i]->x + floatbar->buttons[i]->w) + { + if ((floatbar->buttons[i] != NULL) && (x > floatbar->buttons[i]->x) && + (x < floatbar->buttons[i]->x + floatbar->buttons[i]->w)) + { return floatbar->buttons[i]; + } + } + } return NULL; } -static int floatbar_paint(FloatBar* floatbar, HDC hdc) +static BOOL floatbar_paint(wfFloatBar* const floatbar, const HDC hdc) { int i; + HPEN hpen; + HGDIOBJECT orig; /* paint background */ - SelectObject(floatbar->hdcmem, floatbar->background); - StretchBlt(hdc, 0, 0, BACKGROUND_W, BACKGROUND_H, floatbar->hdcmem, 0, 0, - BACKGROUND_W, BACKGROUND_H, SRCCOPY); + GRADIENT_RECT gradientRect = { 0, 1 }; + COLORREF rgbTop = RGB(117, 154, 198); + COLORREF rgbBottom = RGB(6, 55, 120); + const int top = 0; + int left = 0; + int bottom = BACKGROUND_H - 1; + int right = BACKGROUND_W - 1; + const int angleOffset = BACKGROUND_H - 1; + TRIVERTEX triVertext[2] = { left, + top, + GetRValue(rgbTop) << 8, + GetGValue(rgbTop) << 8, + GetBValue(rgbTop) << 8, + 0x0000, + right, + bottom, + GetRValue(rgbBottom) << 8, + GetGValue(rgbBottom) << 8, + GetBValue(rgbBottom) << 8, + 0x0000 }; + + if (!floatbar) + return FALSE; + + GradientFill(hdc, triVertext, 2, &gradientRect, 1, GRADIENT_FILL_RECT_V); + /* paint shadow */ + hpen = CreatePen(PS_SOLID, 1, RGB(71, 71, 71)); + orig = SelectObject(hdc, hpen); + MoveToEx(hdc, left, top, NULL); + LineTo(hdc, left + angleOffset, bottom); + LineTo(hdc, right - angleOffset, bottom); + LineTo(hdc, right + 1, top - 1); + DeleteObject(hpen); + hpen = CreatePen(PS_SOLID, 1, RGB(107, 141, 184)); + SelectObject(hdc, hpen); + left += 1; + bottom -= 1; + right -= 1; + MoveToEx(hdc, left, top, NULL); + LineTo(hdc, left + (angleOffset - 1), bottom); + LineTo(hdc, right - (angleOffset - 1), bottom); + LineTo(hdc, right + 1, top - 1); + DeleteObject(hpen); + SelectObject(hdc, orig); + DrawText(hdc, floatbar->wfc->window_title, wcslen(floatbar->wfc->window_title), + &floatbar->textRect, + DT_CENTER | DT_VCENTER | DT_END_ELLIPSIS | DT_NOPREFIX | DT_SINGLELINE); /* paint buttons */ + for (i = 0; i < BTN_MAX; i++) button_paint(floatbar->buttons[i], hdc); - return 0; + return TRUE; } -static int floatbar_animation(FloatBar* floatbar, BOOL show) -{ - SetTimer(floatbar->hwnd, show ? TIMER_ANIMAT_SHOW : TIMER_ANIMAT_HIDE, 10, - NULL); - floatbar->shown = show; - return 0; -} - -LRESULT CALLBACK floatbar_proc(HWND hWnd, UINT Msg, WPARAM wParam, - LPARAM lParam) +static LRESULT CALLBACK floatbar_proc(const HWND hWnd, const UINT Msg, const WPARAM wParam, + const LPARAM lParam) { static int dragging = FALSE; static int lbtn_dwn = FALSE; static int btn_dwn_x = 0; - static FloatBar* floatbar; + static wfFloatBar* floatbar; static TRACKMOUSEEVENT tme; PAINTSTRUCT ps; Button* button; HDC hdc; int pos_x; int pos_y; + NONCLIENTMETRICS ncm; int xScreen = GetSystemMetrics(SM_CXSCREEN); switch (Msg) { case WM_CREATE: - floatbar = (FloatBar*)((CREATESTRUCT*)lParam)->lpCreateParams; + floatbar = ((wfFloatBar*)((CREATESTRUCT*)lParam)->lpCreateParams); floatbar->hwnd = hWnd; - floatbar->parent = GetParent(hWnd); GetWindowRect(floatbar->hwnd, &floatbar->rect); floatbar->width = floatbar->rect.right - floatbar->rect.left; floatbar->height = floatbar->rect.bottom - floatbar->rect.top; @@ -245,7 +434,15 @@ LRESULT CALLBACK floatbar_proc(HWND hWnd, UINT Msg, WPARAM wParam, tme.dwFlags = TME_LEAVE; tme.hwndTrack = hWnd; tme.dwHoverTime = HOVER_DEFAULT; - SetTimer(hWnd, TIMER_HIDE, 3000, NULL); + // Use caption font, white, draw transparent + GetClientRect(hWnd, &floatbar->textRect); + InflateRect(&floatbar->textRect, -TEXT_X, 0); + SetBkMode(hdc, TRANSPARENT); + SetTextColor(hdc, RGB(255, 255, 255)); + ncm.cbSize = sizeof(NONCLIENTMETRICS); + SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0); + SelectObject(hdc, CreateFontIndirect(&ncm.lfCaptionFont)); + floatbar_trigger_hide(floatbar); break; case WM_PAINT: @@ -289,11 +486,10 @@ LRESULT CALLBACK floatbar_proc(HWND hWnd, UINT Msg, WPARAM wParam, break; case WM_MOUSEMOVE: - KillTimer(hWnd, TIMER_HIDE); pos_x = lParam & 0xffff; pos_y = (lParam >> 16) & 0xffff; - if (!floatbar->shown) + if (!floatbar->locked) floatbar_animation(floatbar, TRUE); if (dragging) @@ -305,15 +501,19 @@ LRESULT CALLBACK floatbar_proc(HWND hWnd, UINT Msg, WPARAM wParam, else if (floatbar->rect.left > xScreen - floatbar->width) floatbar->rect.left = xScreen - floatbar->width; - MoveWindow(hWnd, floatbar->rect.left, floatbar->rect.top, floatbar->width, - floatbar->height, TRUE); + MoveWindow(hWnd, floatbar->rect.left, 0, floatbar->width, floatbar->height, TRUE); } else { int i; for (i = 0; i < BTN_MAX; i++) - floatbar->buttons[i]->active = FALSE; + { + if (floatbar->buttons[i] != NULL) + { + floatbar->buttons[i]->active = FALSE; + } + } button = floatbar_get_button(floatbar, pos_x, pos_y); @@ -332,60 +532,53 @@ LRESULT CALLBACK floatbar_proc(HWND hWnd, UINT Msg, WPARAM wParam, break; case WM_MOUSELEAVE: - { - int i; + { + int i; - for (i = 0; i < BTN_MAX; i++) + for (i = 0; i < BTN_MAX; i++) + { + if (floatbar->buttons[i] != NULL) + { floatbar->buttons[i]->active = FALSE; - - InvalidateRect(hWnd, NULL, FALSE); - UpdateWindow(hWnd); - SetTimer(hWnd, TIMER_HIDE, 3000, NULL); - break; + } } + InvalidateRect(hWnd, NULL, FALSE); + UpdateWindow(hWnd); + floatbar_trigger_hide(floatbar); + break; + } + case WM_TIMER: switch (wParam) { case TIMER_HIDE: - { - KillTimer(hWnd, TIMER_HIDE); - - if (!floatbar->locked) - floatbar_animation(floatbar, FALSE); - - break; - } + floatbar_animation(floatbar, FALSE); + break; case TIMER_ANIMAT_SHOW: - { - static int y = 0; - MoveWindow(floatbar->hwnd, floatbar->rect.left, (y++ - floatbar->height), - floatbar->width, floatbar->height, TRUE); + { + floatbar->offset--; + MoveWindow(floatbar->hwnd, floatbar->rect.left, -floatbar->offset, + floatbar->width, floatbar->height, TRUE); - if (y == floatbar->height) - { - y = 0; - KillTimer(hWnd, wParam); - } + if (floatbar->offset <= 0) + floatbar_show(floatbar); - break; - } + break; + } case TIMER_ANIMAT_HIDE: - { - static int y = 0; - MoveWindow(floatbar->hwnd, floatbar->rect.left, -y++, floatbar->width, - floatbar->height, TRUE); + { + floatbar->offset++; + MoveWindow(floatbar->hwnd, floatbar->rect.left, -floatbar->offset, + floatbar->width, floatbar->height, TRUE); - if (y == floatbar->height) - { - y = 0; - KillTimer(hWnd, wParam); - } + if (floatbar->offset >= floatbar->height - 2) + floatbar_hide(floatbar); - break; - } + break; + } default: break; @@ -405,76 +598,148 @@ LRESULT CALLBACK floatbar_proc(HWND hWnd, UINT Msg, WPARAM wParam, return 0; } -static FloatBar* floatbar_create(wfContext* wfc) +static BOOL floatbar_window_create(wfFloatBar* floatbar) { - FloatBar* floatbar; - floatbar = (FloatBar*)malloc(sizeof(FloatBar)); + WNDCLASSEX wnd_cls; + HWND barWnd; + HRGN hRgn; + POINT pt[4]; + RECT rect; + LONG x; if (!floatbar) + return FALSE; + + if (!GetWindowRect(floatbar->parent, &rect)) + return FALSE; + + x = (rect.right - rect.left - BACKGROUND_W) / 2; + wnd_cls.cbSize = sizeof(WNDCLASSEX); + wnd_cls.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; + wnd_cls.lpfnWndProc = floatbar_proc; + wnd_cls.cbClsExtra = 0; + wnd_cls.cbWndExtra = 0; + wnd_cls.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wnd_cls.hCursor = LoadCursor(floatbar->root_window, IDC_ARROW); + wnd_cls.hbrBackground = NULL; + wnd_cls.lpszMenuName = NULL; + wnd_cls.lpszClassName = L"floatbar"; + wnd_cls.hInstance = floatbar->root_window; + wnd_cls.hIconSm = LoadIcon(NULL, IDI_APPLICATION); + RegisterClassEx(&wnd_cls); + barWnd = CreateWindowEx(WS_EX_TOPMOST, L"floatbar", L"floatbar", WS_CHILD, x, 0, BACKGROUND_W, + BACKGROUND_H, floatbar->parent, NULL, floatbar->root_window, floatbar); + + if (barWnd == NULL) + return FALSE; + + pt[0].x = 0; + pt[0].y = 0; + pt[1].x = BACKGROUND_W; + pt[1].y = 0; + pt[2].x = BACKGROUND_W - BACKGROUND_H; + pt[2].y = BACKGROUND_H; + pt[3].x = BACKGROUND_H; + pt[3].y = BACKGROUND_H; + hRgn = CreatePolygonRgn(pt, 4, ALTERNATE); + SetWindowRgn(barWnd, hRgn, TRUE); + return TRUE; +} + +void wf_floatbar_free(wfFloatBar* floatbar) +{ + if (!floatbar) + return; + + free(floatbar); +} + +wfFloatBar* wf_floatbar_new(wfContext* wfc, HINSTANCE window, DWORD flags) +{ + wfFloatBar* floatbar; + + /* Floatbar not enabled */ + if ((flags & 0x0001) == 0) return NULL; - floatbar->locked = FALSE; - floatbar->shown = TRUE; + if (!wfc) + return NULL; + + // TODO: Disable for remote app + floatbar = (wfFloatBar*)calloc(1, sizeof(wfFloatBar)); + + if (!floatbar) + return NULL; + + floatbar->root_window = window; + floatbar->flags = flags; + floatbar->wfc = wfc; + floatbar->locked = (flags & 0x0002) != 0; + floatbar->shown = (flags & 0x0006) != 0; /* If it is loked or shown show it */ floatbar->hwnd = NULL; floatbar->parent = wfc->hwnd; - floatbar->wfc = wfc; floatbar->hdcmem = NULL; - floatbar->background = (HBITMAP)LoadImage(wfc->hInstance, - MAKEINTRESOURCE(IDB_BACKGROUND), IMAGE_BITMAP, BACKGROUND_W, BACKGROUND_H, - LR_DEFAULTCOLOR); - floatbar->buttons[0] = floatbar_create_button(floatbar, BUTTON_MINIMIZE, - IDB_MINIMIZE, IDB_MINIMIZE_ACT, MINIMIZE_X, BUTTON_Y, BUTTON_HEIGHT, - BUTTON_WIDTH); - floatbar->buttons[1] = floatbar_create_button(floatbar, BUTTON_RESTORE, - IDB_RESTORE, IDB_RESTORE_ACT, RESTORE_X, BUTTON_Y, BUTTON_HEIGHT, BUTTON_WIDTH); - floatbar->buttons[2] = floatbar_create_button(floatbar, BUTTON_CLOSE, IDB_CLOSE, - IDB_CLOSE_ACT, CLOSE_X, BUTTON_Y, BUTTON_HEIGHT, BUTTON_WIDTH); - floatbar->buttons[3] = floatbar_create_lock_button(floatbar, IDB_UNLOCK, - IDB_UNLOCK_ACT, IDB_LOCK, IDB_LOCK_ACT, LOCK_X, BUTTON_Y, BUTTON_HEIGHT, - BUTTON_WIDTH); + + if (wfc->fullscreen_toggle) + { + floatbar->buttons[0] = + floatbar_create_button(floatbar, BUTTON_MINIMIZE, IDB_MINIMIZE, IDB_MINIMIZE_ACT, + MINIMIZE_X, BUTTON_Y, BUTTON_HEIGHT, BUTTON_WIDTH); + floatbar->buttons[1] = + floatbar_create_button(floatbar, BUTTON_RESTORE, IDB_RESTORE, IDB_RESTORE_ACT, + RESTORE_X, BUTTON_Y, BUTTON_HEIGHT, BUTTON_WIDTH); + } + else + { + floatbar->buttons[0] = NULL; + floatbar->buttons[1] = NULL; + } + + floatbar->buttons[2] = floatbar_create_button(floatbar, BUTTON_CLOSE, IDB_CLOSE, IDB_CLOSE_ACT, + CLOSE_X, BUTTON_Y, BUTTON_HEIGHT, BUTTON_WIDTH); + floatbar->buttons[3] = + floatbar_create_lock_button(floatbar, IDB_UNLOCK, IDB_UNLOCK_ACT, IDB_LOCK, IDB_LOCK_ACT, + LOCK_X, BUTTON_Y, BUTTON_HEIGHT, BUTTON_WIDTH); + + if (!floatbar_window_create(floatbar)) + goto fail; + + if (!update_locked_state(floatbar)) + goto fail; + + if (!wf_floatbar_toggle_fullscreen(floatbar, wfc->context.settings->Fullscreen)) + goto fail; + return floatbar; +fail: + wf_floatbar_free(floatbar); + return NULL; } -int floatbar_hide(FloatBar* floatbar) +BOOL wf_floatbar_toggle_fullscreen(wfFloatBar* floatbar, BOOL fullscreen) { - KillTimer(floatbar->hwnd, TIMER_HIDE); - MoveWindow(floatbar->hwnd, floatbar->rect.left, -floatbar->height, - floatbar->width, floatbar->height, TRUE); - return 0; -} + BOOL show_fs, show_wn; -int floatbar_show(FloatBar* floatbar) -{ - SetTimer(floatbar->hwnd, TIMER_HIDE, 3000, NULL); - MoveWindow(floatbar->hwnd, floatbar->rect.left, floatbar->rect.top, - floatbar->width, floatbar->height, TRUE); - return 0; -} + if (!floatbar) + return FALSE; -void floatbar_window_create(wfContext* wfc) -{ - WNDCLASSEX wnd_cls; - HWND barWnd; - int x = (GetSystemMetrics(SM_CXSCREEN) - BACKGROUND_W) / 2; - wnd_cls.cbSize = sizeof(WNDCLASSEX); - wnd_cls.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; - wnd_cls.lpfnWndProc = floatbar_proc; - wnd_cls.cbClsExtra = 0; - wnd_cls.cbWndExtra = 0; - wnd_cls.hIcon = LoadIcon(NULL, IDI_APPLICATION); - wnd_cls.hCursor = LoadCursor(wfc->hInstance, IDC_ARROW); - wnd_cls.hbrBackground = NULL; - wnd_cls.lpszMenuName = NULL; - wnd_cls.lpszClassName = L"floatbar"; - wnd_cls.hInstance = wfc->hInstance; - wnd_cls.hIconSm = LoadIcon(NULL, IDI_APPLICATION); - RegisterClassEx(&wnd_cls); - wfc->floatbar = floatbar_create(wfc); - barWnd = CreateWindowEx(WS_EX_TOPMOST, L"floatbar", L"floatbar", WS_CHILD, x, 0, - BACKGROUND_W, BACKGROUND_H, wfc->hwnd, NULL, wfc->hInstance, wfc->floatbar); + show_fs = (floatbar->flags & 0x0010) != 0; + show_wn = (floatbar->flags & 0x0020) != 0; - if (barWnd == NULL) - return; + if ((show_fs && fullscreen) || (show_wn && !fullscreen)) + { + ShowWindow(floatbar->hwnd, SW_SHOWNORMAL); + Sleep(10); + + if (floatbar->shown) + floatbar_show(floatbar); + else + floatbar_hide(floatbar); + } + else + { + ShowWindow(floatbar->hwnd, SW_HIDE); + } - ShowWindow(barWnd, SW_SHOWNORMAL); + return TRUE; } diff --git a/client/Windows/wf_floatbar.h b/client/Windows/wf_floatbar.h index 9867e9d..2636aba 100644 --- a/client/Windows/wf_floatbar.h +++ b/client/Windows/wf_floatbar.h @@ -20,11 +20,14 @@ #ifndef FREERDP_CLIENT_WIN_FLOATBAR_H #define FREERDP_CLIENT_WIN_FLOATBAR_H -typedef struct _FloatBar FloatBar; +#include + +typedef struct _FloatBar wfFloatBar; typedef struct wf_context wfContext; -void floatbar_window_create(wfContext* wfc); -int floatbar_show(FloatBar* floatbar); -int floatbar_hide(FloatBar* floatbar); +wfFloatBar* wf_floatbar_new(wfContext* wfc, HINSTANCE window, DWORD flags); +void wf_floatbar_free(wfFloatBar* floatbar); + +BOOL wf_floatbar_toggle_fullscreen(wfFloatBar* floatbar, BOOL fullscreen); #endif /* FREERDP_CLIENT_WIN_FLOATBAR_H */ diff --git a/client/Windows/wf_gdi.c b/client/Windows/wf_gdi.c index 2306575..329f43a 100644 --- a/client/Windows/wf_gdi.c +++ b/client/Windows/wf_gdi.c @@ -43,8 +43,7 @@ #define TAG CLIENT_TAG("windows.gdi") -static const BYTE wf_rop2_table[] = -{ +static const BYTE wf_rop2_table[] = { R2_BLACK, /* 0 */ R2_NOTMERGEPEN, /* DPon */ R2_MASKNOTPEN, /* DPna */ @@ -63,8 +62,7 @@ static const BYTE wf_rop2_table[] = R2_WHITE, /* 1 */ }; -static BOOL wf_decode_color(wfContext* wfc, const UINT32 srcColor, - COLORREF* color, UINT32* format) +static BOOL wf_decode_color(wfContext* wfc, const UINT32 srcColor, COLORREF* color, UINT32* format) { rdpGdi* gdi; rdpSettings* settings; @@ -102,8 +100,7 @@ static BOOL wf_decode_color(wfContext* wfc, const UINT32 srcColor, return FALSE; } - *color = FreeRDPConvertColor(srcColor, SrcFormat, - DstFormat, &gdi->palette); + *color = FreeRDPConvertColor(srcColor, SrcFormat, DstFormat, &gdi->palette); return TRUE; } @@ -111,7 +108,7 @@ static BOOL wf_set_rop2(HDC hdc, int rop2) { if ((rop2 < 0x01) || (rop2 > 0x10)) { - WLog_ERR(TAG, "Unsupported ROP2: %d", rop2); + WLog_ERR(TAG, "Unsupported ROP2: %d", rop2); return FALSE; } @@ -122,8 +119,7 @@ static BOOL wf_set_rop2(HDC hdc, int rop2) static wfBitmap* wf_glyph_new(wfContext* wfc, GLYPH_DATA* glyph) { wfBitmap* glyph_bmp; - glyph_bmp = wf_image_new(wfc, glyph->cx, glyph->cy, PIXEL_FORMAT_MONO, - glyph->aj); + glyph_bmp = wf_image_new(wfc, glyph->cx, glyph->cy, PIXEL_FORMAT_MONO, glyph->aj); return glyph_bmp; } @@ -143,7 +139,7 @@ static BYTE* wf_glyph_convert(wfContext* wfc, int width, int height, BYTE* data) int dst_bytes_per_row; src_bytes_per_row = (width + 7) / 8; dst_bytes_per_row = src_bytes_per_row + (src_bytes_per_row % 2); - cdata = (BYTE*) malloc(dst_bytes_per_row * height); + cdata = (BYTE*)malloc(dst_bytes_per_row * height); src = data; for (indexy = 0; indexy < height; indexy++) @@ -162,8 +158,7 @@ static BYTE* wf_glyph_convert(wfContext* wfc, int width, int height, BYTE* data) return cdata; } -static HBRUSH wf_create_brush(wfContext* wfc, rdpBrush* brush, UINT32 color, - UINT32 bpp) +static HBRUSH wf_create_brush(wfContext* wfc, rdpBrush* brush, UINT32 color, UINT32 bpp) { UINT32 i; HBRUSH br; @@ -173,8 +168,8 @@ static HBRUSH wf_create_brush(wfContext* wfc, rdpBrush* brush, UINT32 color, HBITMAP pattern = NULL; lbr.lbStyle = brush->style; - if (lbr.lbStyle == BS_DIBPATTERN || lbr.lbStyle == BS_DIBPATTERN8X8 - || lbr.lbStyle == BS_DIBPATTERNPT) + if (lbr.lbStyle == BS_DIBPATTERN || lbr.lbStyle == BS_DIBPATTERN8X8 || + lbr.lbStyle == BS_DIBPATTERNPT) lbr.lbColor = DIB_RGB_COLORS; else lbr.lbColor = color; @@ -185,7 +180,7 @@ static HBRUSH wf_create_brush(wfContext* wfc, rdpBrush* brush, UINT32 color, { UINT32 format = gdi_get_pixel_format(bpp); pattern = wf_create_dib(wfc, 8, 8, format, brush->data, NULL); - lbr.lbHatch = (ULONG_PTR) pattern; + lbr.lbHatch = (ULONG_PTR)pattern; } else { @@ -194,7 +189,7 @@ static HBRUSH wf_create_brush(wfContext* wfc, rdpBrush* brush, UINT32 color, cdata = wf_glyph_convert(wfc, 8, 8, ipattern); pattern = CreateBitmap(8, 8, 1, 1, cdata); - lbr.lbHatch = (ULONG_PTR) pattern; + lbr.lbHatch = (ULONG_PTR)pattern; free(cdata); } } @@ -262,8 +257,7 @@ static BOOL wf_scale_rect(wfContext* wfc, RECT* source) return TRUE; } -void wf_invalidate_region(wfContext* wfc, UINT32 x, UINT32 y, UINT32 width, - UINT32 height) +void wf_invalidate_region(wfContext* wfc, UINT32 x, UINT32 y, UINT32 width, UINT32 height) { RECT rect; rdpGdi* gdi = wfc->context.gdi; @@ -278,8 +272,7 @@ void wf_invalidate_region(wfContext* wfc, UINT32 x, UINT32 y, UINT32 width, rect.top = y; rect.bottom = height; wf_scale_rect(wfc, &rect); - gdi_InvalidateRegion(gdi->primary->hdc, rect.left, rect.top, rect.right, - rect.bottom); + gdi_InvalidateRegion(gdi->primary->hdc, rect.left, rect.top, rect.right, rect.bottom); } void wf_update_offset(wfContext* wfc) @@ -351,25 +344,36 @@ void wf_resize_window(wfContext* wfc) else if (!wfc->context.settings->Decorations) { SetWindowLongPtr(wfc->hwnd, GWL_STYLE, WS_CHILD); + if (settings->EmbeddedWindow) { + if (!wfc->client_height) + wfc->client_height = settings->DesktopHeight; + + if (!wfc->client_width) + wfc->client_width = settings->DesktopWidth; + wf_update_canvas_diff(wfc); + /* Now resize to get full canvas size and room for caption and borders */ + SetWindowPos(wfc->hwnd, HWND_TOP, wfc->client_x, wfc->client_y, + wfc->client_width + wfc->diff.x, wfc->client_height + wfc->diff.y, + 0 /*SWP_FRAMECHANGED*/); } else { /* Now resize to get full canvas size and room for caption and borders */ - SetWindowPos(wfc->hwnd, HWND_TOP, 0, 0, settings->DesktopWidth, - settings->DesktopHeight, SWP_FRAMECHANGED); + SetWindowPos(wfc->hwnd, HWND_TOP, 0, 0, settings->DesktopWidth, settings->DesktopHeight, + SWP_FRAMECHANGED); wf_update_canvas_diff(wfc); SetWindowPos(wfc->hwnd, HWND_TOP, -1, -1, settings->DesktopWidth + wfc->diff.x, - settings->DesktopHeight + wfc->diff.y, SWP_NOMOVE | SWP_FRAMECHANGED); + settings->DesktopHeight + wfc->diff.y, SWP_NOMOVE | SWP_FRAMECHANGED); } } else { SetWindowLongPtr(wfc->hwnd, GWL_STYLE, WS_CAPTION | WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX | WS_SIZEBOX | - WS_MAXIMIZEBOX); + WS_MAXIMIZEBOX); if (!wfc->client_height) wfc->client_height = settings->DesktopHeight; @@ -388,7 +392,7 @@ void wf_resize_window(wfContext* wfc) SetWindowPos(wfc->hwnd, HWND_TOP, wfc->client_x, wfc->client_y, wfc->client_width + wfc->diff.x, wfc->client_height + wfc->diff.y, 0 /*SWP_FRAMECHANGED*/); - //wf_size_scrollbars(wfc, wfc->client_width, wfc->client_height); + // wf_size_scrollbars(wfc, wfc->client_width, wfc->client_height); } wf_update_offset(wfc); @@ -404,11 +408,7 @@ void wf_toggle_fullscreen(wfContext* wfc) wfc->disablewindowtracking = TRUE; } - if (wfc->fullscreen && wfc->floatbar_active) - floatbar_show(wfc->floatbar); - else - floatbar_hide(wfc->floatbar); - + wf_floatbar_toggle_fullscreen(wfc->floatbar, wfc->fullscreen); SetParent(wfc->hwnd, wfc->fullscreen ? NULL : wfc->hWndParent); wf_resize_window(wfc); ShowWindow(wfc->hwnd, SW_SHOW); @@ -416,13 +416,13 @@ void wf_toggle_fullscreen(wfContext* wfc) if (!wfc->fullscreen) { - // Reenable window tracking AFTER resizing it back, otherwise it can lean to repositioning errors. + // Reenable window tracking AFTER resizing it back, otherwise it can lean to repositioning + // errors. wfc->disablewindowtracking = FALSE; } } -static BOOL wf_gdi_palette_update(rdpContext* context, - const PALETTE_UPDATE* palette) +static BOOL wf_gdi_palette_update(rdpContext* context, const PALETTE_UPDATE* palette) { return TRUE; } @@ -450,8 +450,7 @@ static BOOL wf_gdi_set_bounds(rdpContext* context, const rdpBounds* bounds) if (bounds != NULL) { - hrgn = CreateRectRgn(bounds->left, bounds->top, bounds->right + 1, - bounds->bottom + 1); + hrgn = CreateRectRgn(bounds->left, bounds->top, bounds->right + 1, bounds->bottom + 1); SelectClipRgn(wfc->drawing->hdc, hrgn); DeleteObject(hrgn); } @@ -468,12 +467,11 @@ static BOOL wf_gdi_dstblt(rdpContext* context, const DSTBLT_ORDER* dstblt) if (!context || !dstblt) return FALSE; - if (!BitBlt(wfc->drawing->hdc, dstblt->nLeftRect, dstblt->nTopRect, - dstblt->nWidth, dstblt->nHeight, NULL, 0, 0, gdi_rop3_code(dstblt->bRop))) + if (!BitBlt(wfc->drawing->hdc, dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth, + dstblt->nHeight, NULL, 0, 0, gdi_rop3_code(dstblt->bRop))) return FALSE; - wf_invalidate_region(wfc, dstblt->nLeftRect, dstblt->nTopRect, - dstblt->nWidth, dstblt->nHeight); + wf_invalidate_region(wfc, dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth, dstblt->nHeight); return TRUE; } @@ -498,14 +496,13 @@ static BOOL wf_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt) if (!wf_decode_color(wfc, patblt->backColor, &bgcolor, NULL)) return FALSE; - brush = wf_create_brush(wfc, &patblt->brush, fgcolor, - context->settings->ColorDepth); + brush = wf_create_brush(wfc, &patblt->brush, fgcolor, context->settings->ColorDepth); org_bkmode = SetBkMode(wfc->drawing->hdc, OPAQUE); org_bkcolor = SetBkColor(wfc->drawing->hdc, bgcolor); org_textcolor = SetTextColor(wfc->drawing->hdc, fgcolor); org_brush = (HBRUSH)SelectObject(wfc->drawing->hdc, brush); - rc = PatBlt(wfc->drawing->hdc, patblt->nLeftRect, patblt->nTopRect, - patblt->nWidth, patblt->nHeight, gdi_rop3_code(patblt->bRop)); + rc = PatBlt(wfc->drawing->hdc, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth, + patblt->nHeight, gdi_rop3_code(patblt->bRop)); SelectObject(wfc->drawing->hdc, org_brush); DeleteObject(brush); SetBkMode(wfc->drawing->hdc, org_bkmode); @@ -526,18 +523,16 @@ static BOOL wf_gdi_scrblt(rdpContext* context, const SCRBLT_ORDER* scrblt) if (!context || !scrblt || !wfc->drawing) return FALSE; - if (!BitBlt(wfc->drawing->hdc, scrblt->nLeftRect, scrblt->nTopRect, - scrblt->nWidth, scrblt->nHeight, wfc->primary->hdc, - scrblt->nXSrc, scrblt->nYSrc, gdi_rop3_code(scrblt->bRop))) + if (!BitBlt(wfc->drawing->hdc, scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth, + scrblt->nHeight, wfc->primary->hdc, scrblt->nXSrc, scrblt->nYSrc, + gdi_rop3_code(scrblt->bRop))) return FALSE; - wf_invalidate_region(wfc, scrblt->nLeftRect, scrblt->nTopRect, - scrblt->nWidth, scrblt->nHeight); + wf_invalidate_region(wfc, scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth, scrblt->nHeight); return TRUE; } -static BOOL wf_gdi_opaque_rect(rdpContext* context, - const OPAQUE_RECT_ORDER* opaque_rect) +static BOOL wf_gdi_opaque_rect(rdpContext* context, const OPAQUE_RECT_ORDER* opaque_rect) { RECT rect; HBRUSH brush; @@ -577,8 +572,7 @@ static BOOL wf_gdi_multi_opaque_rect(rdpContext* context, if (!context || !multi_opaque_rect) return FALSE; - if (!wf_decode_color(wfc, multi_opaque_rect->color, &brush_color, - NULL)) + if (!wf_decode_color(wfc, multi_opaque_rect->color, &brush_color, NULL)) return FALSE; for (i = 0; i < multi_opaque_rect->numRectangles; i++) @@ -617,15 +611,15 @@ static BOOL wf_gdi_line_to(rdpContext* context, const LINE_TO_ORDER* line_to) pen = CreatePen(line_to->penStyle, line_to->penWidth, pen_color); wf_set_rop2(wfc->drawing->hdc, line_to->bRop2); - org_pen = (HPEN) SelectObject(wfc->drawing->hdc, pen); + org_pen = (HPEN)SelectObject(wfc->drawing->hdc, pen); MoveToEx(wfc->drawing->hdc, line_to->nXStart, line_to->nYStart, NULL); LineTo(wfc->drawing->hdc, line_to->nXEnd, line_to->nYEnd); x = (line_to->nXStart < line_to->nXEnd) ? line_to->nXStart : line_to->nXEnd; y = (line_to->nYStart < line_to->nYEnd) ? line_to->nYStart : line_to->nYEnd; w = (line_to->nXStart < line_to->nXEnd) ? (line_to->nXEnd - line_to->nXStart) - : (line_to->nXStart - line_to->nXEnd); + : (line_to->nXStart - line_to->nXEnd); h = (line_to->nYStart < line_to->nYEnd) ? (line_to->nYEnd - line_to->nYStart) - : (line_to->nYStart - line_to->nYEnd); + : (line_to->nYStart - line_to->nYEnd); if (wfc->drawing == wfc->primary) wf_invalidate_region(wfc, x, y, w, h); @@ -651,20 +645,20 @@ static BOOL wf_gdi_polyline(rdpContext* context, const POLYLINE_ORDER* polyline) hpen = CreatePen(0, 1, pen_color); org_rop2 = wf_set_rop2(wfc->drawing->hdc, polyline->bRop2); - org_hpen = (HPEN) SelectObject(wfc->drawing->hdc, hpen); + org_hpen = (HPEN)SelectObject(wfc->drawing->hdc, hpen); if (polyline->numDeltaEntries > 0) { - POINT* pts; - POINT temp; - int numPoints; - int i; + POINT* pts; + POINT temp; + int numPoints; + int i; numPoints = polyline->numDeltaEntries + 1; - pts = (POINT*) malloc(sizeof(POINT) * numPoints); + pts = (POINT*)malloc(sizeof(POINT) * numPoints); pts[0].x = temp.x = polyline->xStart; pts[0].y = temp.y = polyline->yStart; - for (i = 0; i < (int) polyline->numDeltaEntries; i++) + for (i = 0; i < (int)polyline->numDeltaEntries; i++) { temp.x += polyline->points[i].x; temp.y += polyline->points[i].y; @@ -694,14 +688,14 @@ static BOOL wf_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt) if (!context || !memblt) return FALSE; - bitmap = (wfBitmap*) memblt->bitmap; + bitmap = (wfBitmap*)memblt->bitmap; if (!bitmap || !wfc->drawing || !wfc->drawing->hdc) return FALSE; - if (!BitBlt(wfc->drawing->hdc, memblt->nLeftRect, memblt->nTopRect, - memblt->nWidth, memblt->nHeight, bitmap->hdc, - memblt->nXSrc, memblt->nYSrc, gdi_rop3_code(memblt->bRop))) + if (!BitBlt(wfc->drawing->hdc, memblt->nLeftRect, memblt->nTopRect, memblt->nWidth, + memblt->nHeight, bitmap->hdc, memblt->nXSrc, memblt->nYSrc, + gdi_rop3_code(memblt->bRop))) return FALSE; if (wfc->drawing == wfc->primary) @@ -723,7 +717,7 @@ static BOOL wf_gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt) if (!context || !mem3blt) return FALSE; - bitmap = (wfBitmap*) mem3blt->bitmap; + bitmap = (wfBitmap*)mem3blt->bitmap; if (!bitmap || !wfc->drawing || !wfc->drawing->hdc) return FALSE; @@ -746,11 +740,11 @@ static BOOL wf_gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt) case GDI_BS_HATCHED: case GDI_BS_PATTERN: - { - HBITMAP bmp = CreateBitmap(8, 8, 1, mem3blt->brush.bpp, mem3blt->brush.data); - brush = CreatePatternBrush(bmp); - } - break; + { + HBITMAP bmp = CreateBitmap(8, 8, 1, mem3blt->brush.bpp, mem3blt->brush.data); + brush = CreatePatternBrush(bmp); + } + break; default: goto fail; @@ -758,14 +752,12 @@ static BOOL wf_gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt) orgBrush = SelectObject(hdc, brush); - if (!BitBlt(hdc, mem3blt->nLeftRect, mem3blt->nTopRect, - mem3blt->nWidth, mem3blt->nHeight, bitmap->hdc, - mem3blt->nXSrc, mem3blt->nYSrc, gdi_rop3_code(mem3blt->bRop))) + if (!BitBlt(hdc, mem3blt->nLeftRect, mem3blt->nTopRect, mem3blt->nWidth, mem3blt->nHeight, + bitmap->hdc, mem3blt->nXSrc, mem3blt->nYSrc, gdi_rop3_code(mem3blt->bRop))) goto fail; if (wfc->drawing == wfc->primary) - wf_invalidate_region(wfc, mem3blt->nLeftRect, mem3blt->nTopRect, - mem3blt->nWidth, + wf_invalidate_region(wfc, mem3blt->nLeftRect, mem3blt->nTopRect, mem3blt->nWidth, mem3blt->nHeight); rc = TRUE; @@ -791,8 +783,8 @@ static BOOL wf_gdi_surface_frame_marker(rdpContext* context, if (!settings) return FALSE; - if (surface_frame_marker->frameAction == SURFACECMD_FRAMEACTION_END - && settings->FrameAcknowledge > 0) + if (surface_frame_marker->frameAction == SURFACECMD_FRAMEACTION_END && + settings->FrameAcknowledge > 0) { IFCALL(context->instance->update->SurfaceFrameAcknowledge, context, surface_frame_marker->frameId); diff --git a/client/Windows/wf_gdi.h b/client/Windows/wf_gdi.h index 3ceec49..a093e1a 100644 --- a/client/Windows/wf_gdi.h +++ b/client/Windows/wf_gdi.h @@ -24,10 +24,8 @@ #include "wf_client.h" -void wf_invalidate_region(wfContext* wfc, UINT32 x, UINT32 y, UINT32 width, - UINT32 height); -wfBitmap* wf_image_new(wfContext* wfc, UINT32 width, UINT32 height, UINT32 bpp, - const BYTE* data); +void wf_invalidate_region(wfContext* wfc, UINT32 x, UINT32 y, UINT32 width, UINT32 height); +wfBitmap* wf_image_new(wfContext* wfc, UINT32 width, UINT32 height, UINT32 bpp, const BYTE* data); void wf_image_free(wfBitmap* image); void wf_update_offset(wfContext* wfc); void wf_resize_window(wfContext* wfc); diff --git a/client/Windows/wf_graphics.c b/client/Windows/wf_graphics.c index 28682cd..8a146f3 100644 --- a/client/Windows/wf_graphics.c +++ b/client/Windows/wf_graphics.c @@ -31,8 +31,8 @@ #define TAG CLIENT_TAG("windows") -HBITMAP wf_create_dib(wfContext* wfc, UINT32 width, UINT32 height, - UINT32 srcFormat, const BYTE* data, BYTE** pdata) +HBITMAP wf_create_dib(wfContext* wfc, UINT32 width, UINT32 height, UINT32 srcFormat, + const BYTE* data, BYTE** pdata) { HDC hdc; int negHeight; @@ -54,11 +54,11 @@ HBITMAP wf_create_dib(wfContext* wfc, UINT32 width, UINT32 height, bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = GetBitsPerPixel(dstFormat); bmi.bmiHeader.biCompression = BI_RGB; - bitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, (void**) &cdata, NULL, 0); + bitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, (void**)&cdata, NULL, 0); if (data) - freerdp_image_copy(cdata, dstFormat, 0, 0, 0, width, height, data, srcFormat, 0, - 0, 0, &wfc->context.gdi->palette, FREERDP_FLIP_NONE); + freerdp_image_copy(cdata, dstFormat, 0, 0, 0, width, height, data, srcFormat, 0, 0, 0, + &wfc->context.gdi->palette, FREERDP_FLIP_NONE); if (pdata) *pdata = cdata; @@ -68,17 +68,15 @@ HBITMAP wf_create_dib(wfContext* wfc, UINT32 width, UINT32 height, return bitmap; } -wfBitmap* wf_image_new(wfContext* wfc, UINT32 width, UINT32 height, - UINT32 format, const BYTE* data) +wfBitmap* wf_image_new(wfContext* wfc, UINT32 width, UINT32 height, UINT32 format, const BYTE* data) { HDC hdc; wfBitmap* image; hdc = GetDC(NULL); - image = (wfBitmap*) malloc(sizeof(wfBitmap)); + image = (wfBitmap*)malloc(sizeof(wfBitmap)); image->hdc = CreateCompatibleDC(hdc); - image->bitmap = wf_create_dib(wfc, width, height, format, data, - &(image->pdata)); - image->org_bitmap = (HBITMAP) SelectObject(image->hdc, image->bitmap); + image->bitmap = wf_create_dib(wfc, width, height, format, data, &(image->pdata)); + image->org_bitmap = (HBITMAP)SelectObject(image->hdc, image->bitmap); ReleaseDC(NULL, hdc); return image; } @@ -100,30 +98,29 @@ static BOOL wf_Bitmap_New(rdpContext* context, rdpBitmap* bitmap) { HDC hdc; wfContext* wfc = (wfContext*)context; - wfBitmap* wf_bitmap = (wfBitmap*) bitmap; + wfBitmap* wf_bitmap = (wfBitmap*)bitmap; if (!context || !bitmap) return FALSE; - wf_bitmap = (wfBitmap*) bitmap; + wf_bitmap = (wfBitmap*)bitmap; hdc = GetDC(NULL); wf_bitmap->hdc = CreateCompatibleDC(hdc); if (!bitmap->data) wf_bitmap->bitmap = CreateCompatibleBitmap(hdc, bitmap->width, bitmap->height); else - wf_bitmap->bitmap = wf_create_dib(wfc, bitmap->width, bitmap->height, - bitmap->format, bitmap->data, NULL); + wf_bitmap->bitmap = + wf_create_dib(wfc, bitmap->width, bitmap->height, bitmap->format, bitmap->data, NULL); - wf_bitmap->org_bitmap = (HBITMAP) SelectObject(wf_bitmap->hdc, - wf_bitmap->bitmap); + wf_bitmap->org_bitmap = (HBITMAP)SelectObject(wf_bitmap->hdc, wf_bitmap->bitmap); ReleaseDC(NULL, hdc); return TRUE; } static void wf_Bitmap_Free(rdpContext* context, rdpBitmap* bitmap) { - wfBitmap* wf_bitmap = (wfBitmap*) bitmap; + wfBitmap* wf_bitmap = (wfBitmap*)bitmap; if (wf_bitmap != 0) { @@ -141,24 +138,23 @@ static BOOL wf_Bitmap_Paint(rdpContext* context, rdpBitmap* bitmap) BOOL rc; UINT32 width, height; wfContext* wfc = (wfContext*)context; - wfBitmap* wf_bitmap = (wfBitmap*) bitmap; + wfBitmap* wf_bitmap = (wfBitmap*)bitmap; if (!context || !bitmap) return FALSE; width = bitmap->right - bitmap->left + 1; height = bitmap->bottom - bitmap->top + 1; - rc = BitBlt(wfc->primary->hdc, bitmap->left, bitmap->top, - width, height, wf_bitmap->hdc, 0, 0, SRCCOPY); + rc = BitBlt(wfc->primary->hdc, bitmap->left, bitmap->top, width, height, wf_bitmap->hdc, 0, 0, + SRCCOPY); wf_invalidate_region(wfc, bitmap->left, bitmap->top, width, height); return rc; } -static BOOL wf_Bitmap_SetSurface(rdpContext* context, rdpBitmap* bitmap, - BOOL primary) +static BOOL wf_Bitmap_SetSurface(rdpContext* context, rdpBitmap* bitmap, BOOL primary) { wfContext* wfc = (wfContext*)context; - wfBitmap* bmp = (wfBitmap*) bitmap; + wfBitmap* bmp = (wfBitmap*)bitmap; rdpGdi* gdi = context->gdi; if (!gdi || !wfc) @@ -176,8 +172,7 @@ static BOOL wf_Bitmap_SetSurface(rdpContext* context, rdpBitmap* bitmap, /* Pointer Class */ -static BOOL flip_bitmap(const BYTE* src, BYTE* dst, UINT32 scanline, - UINT32 nHeight) +static BOOL flip_bitmap(const BYTE* src, BYTE* dst, UINT32 scanline, UINT32 nHeight) { UINT32 x; BYTE* bottomLine = dst + scanline * (nHeight - 1); @@ -213,15 +208,13 @@ static BOOL wf_Pointer_New(rdpContext* context, const rdpPointer* pointer) if (pointer->xorBpp == 1) { - BYTE* pdata = (BYTE*) _aligned_malloc(pointer->lengthAndMask + - pointer->lengthXorMask, 16); + BYTE* pdata = (BYTE*)_aligned_malloc(pointer->lengthAndMask + pointer->lengthXorMask, 16); if (!pdata) goto fail; CopyMemory(pdata, pointer->andMaskData, pointer->lengthAndMask); - CopyMemory(pdata + pointer->lengthAndMask, pointer->xorMaskData, - pointer->lengthXorMask); + CopyMemory(pdata + pointer->lengthAndMask, pointer->xorMaskData, pointer->lengthXorMask); info.hbmMask = CreateBitmap(pointer->width, pointer->height * 2, 1, 1, pdata); _aligned_free(pdata); info.hbmColor = NULL; @@ -229,13 +222,12 @@ static BOOL wf_Pointer_New(rdpContext* context, const rdpPointer* pointer) else { UINT32 srcFormat; - BYTE* pdata = (BYTE*) _aligned_malloc(pointer->lengthAndMask, 16); + BYTE* pdata = (BYTE*)_aligned_malloc(pointer->lengthAndMask, 16); if (!pdata) goto fail; - flip_bitmap(pointer->andMaskData, pdata, (pointer->width + 7) / 8, - pointer->height); + flip_bitmap(pointer->andMaskData, pdata, (pointer->width + 7) / 8, pointer->height); info.hbmMask = CreateBitmap(pointer->width, pointer->height, 1, 1, pdata); _aligned_free(pdata); @@ -245,22 +237,23 @@ static BOOL wf_Pointer_New(rdpContext* context, const rdpPointer* pointer) if (!srcFormat) goto fail; - info.hbmColor = wf_create_dib((wfContext*)context, pointer->width, pointer->height, srcFormat, NULL, &pdata); + info.hbmColor = wf_create_dib((wfContext*)context, pointer->width, pointer->height, + gdi->dstFormat, NULL, &pdata); if (!info.hbmColor) goto fail; - if (!freerdp_image_copy_from_pointer_data(pdata, gdi->dstFormat, 0, 0, 0, - pointer->width, pointer->height, - pointer->xorMaskData, pointer->lengthXorMask, - pointer->andMaskData, pointer->lengthAndMask, pointer->xorBpp, &gdi->palette)) + if (!freerdp_image_copy_from_pointer_data( + pdata, gdi->dstFormat, 0, 0, 0, pointer->width, pointer->height, + pointer->xorMaskData, pointer->lengthXorMask, pointer->andMaskData, + pointer->lengthAndMask, pointer->xorBpp, &gdi->palette)) { goto fail; } } hCur = CreateIconIndirect(&info); - ((wfPointer*) pointer)->cursor = hCur; + ((wfPointer*)pointer)->cursor = hCur; rc = TRUE; fail: @@ -280,7 +273,7 @@ static BOOL wf_Pointer_Free(rdpContext* context, rdpPointer* pointer) if (!context || !pointer) return FALSE; - hCur = ((wfPointer*) pointer)->cursor; + hCur = ((wfPointer*)pointer)->cursor; if (hCur != 0) DestroyIcon(hCur); @@ -296,7 +289,7 @@ static BOOL wf_Pointer_Set(rdpContext* context, const rdpPointer* pointer) if (!context || !pointer) return FALSE; - hCur = ((wfPointer*) pointer)->cursor; + hCur = ((wfPointer*)pointer)->cursor; if (hCur != NULL) { @@ -339,7 +332,7 @@ BOOL wf_register_pointer(rdpGraphics* graphics) if (!graphics) return FALSE; - wfc = (wfContext*) graphics->context; + wfc = (wfContext*)graphics->context; ZeroMemory(&pointer, sizeof(rdpPointer)); pointer.size = sizeof(wfPointer); pointer.New = wf_Pointer_New; @@ -363,7 +356,7 @@ BOOL wf_register_graphics(rdpGraphics* graphics) if (!graphics) return FALSE; - wfc = (wfContext*) graphics->context; + wfc = (wfContext*)graphics->context; bitmap = *graphics->Bitmap_Prototype; bitmap.size = sizeof(wfBitmap); bitmap.New = wf_Bitmap_New; diff --git a/client/Windows/wf_graphics.h b/client/Windows/wf_graphics.h index da2e36e..241575f 100644 --- a/client/Windows/wf_graphics.h +++ b/client/Windows/wf_graphics.h @@ -22,10 +22,10 @@ #include "wf_client.h" -HBITMAP wf_create_dib(wfContext* wfc, UINT32 width, UINT32 height, - UINT32 format, const BYTE* data, BYTE** pdata); -wfBitmap* wf_image_new(wfContext* wfc, UINT32 width, UINT32 height, - UINT32 format, const BYTE* data); +HBITMAP wf_create_dib(wfContext* wfc, UINT32 width, UINT32 height, UINT32 format, const BYTE* data, + BYTE** pdata); +wfBitmap* wf_image_new(wfContext* wfc, UINT32 width, UINT32 height, UINT32 format, + const BYTE* data); void wf_image_free(wfBitmap* image); BOOL wf_register_pointer(rdpGraphics* graphics); diff --git a/client/Windows/wf_rail.c b/client/Windows/wf_rail.c index 87f3be1..0d97f85 100644 --- a/client/Windows/wf_rail.c +++ b/client/Windows/wf_rail.c @@ -29,8 +29,8 @@ #define TAG CLIENT_TAG("windows") -#define GET_X_LPARAM(lParam) ((UINT16) (lParam & 0xFFFF)) -#define GET_Y_LPARAM(lParam) ((UINT16) ((lParam >> 16) & 0xFFFF)) +#define GET_X_LPARAM(lParam) ((UINT16)(lParam & 0xFFFF)) +#define GET_Y_LPARAM(lParam) ((UINT16)((lParam >> 16) & 0xFFFF)) /* RemoteApp Core Protocol Extension */ @@ -42,35 +42,31 @@ struct _WINDOW_STYLE }; typedef struct _WINDOW_STYLE WINDOW_STYLE; -static const WINDOW_STYLE WINDOW_STYLES[] = -{ - { WS_BORDER, "WS_BORDER", FALSE }, - { WS_CAPTION, "WS_CAPTION", FALSE }, - { WS_CHILD, "WS_CHILD", FALSE }, - { WS_CLIPCHILDREN, "WS_CLIPCHILDREN", FALSE }, - { WS_CLIPSIBLINGS, "WS_CLIPSIBLINGS", FALSE }, - { WS_DISABLED, "WS_DISABLED", FALSE }, - { WS_DLGFRAME, "WS_DLGFRAME", FALSE }, - { WS_GROUP, "WS_GROUP", FALSE }, - { WS_HSCROLL, "WS_HSCROLL", FALSE }, - { WS_ICONIC, "WS_ICONIC", FALSE }, - { WS_MAXIMIZE, "WS_MAXIMIZE", FALSE }, - { WS_MAXIMIZEBOX, "WS_MAXIMIZEBOX", FALSE }, - { WS_MINIMIZE, "WS_MINIMIZE", FALSE }, - { WS_MINIMIZEBOX, "WS_MINIMIZEBOX", FALSE }, - { WS_OVERLAPPED, "WS_OVERLAPPED", FALSE }, - { WS_OVERLAPPEDWINDOW, "WS_OVERLAPPEDWINDOW", TRUE }, - { WS_POPUP, "WS_POPUP", FALSE }, - { WS_POPUPWINDOW, "WS_POPUPWINDOW", TRUE }, - { WS_SIZEBOX, "WS_SIZEBOX", FALSE }, - { WS_SYSMENU, "WS_SYSMENU", FALSE }, - { WS_TABSTOP, "WS_TABSTOP", FALSE }, - { WS_THICKFRAME, "WS_THICKFRAME", FALSE }, - { WS_VISIBLE, "WS_VISIBLE", FALSE } -}; - -static const WINDOW_STYLE EXTENDED_WINDOW_STYLES[] = -{ +static const WINDOW_STYLE WINDOW_STYLES[] = { { WS_BORDER, "WS_BORDER", FALSE }, + { WS_CAPTION, "WS_CAPTION", FALSE }, + { WS_CHILD, "WS_CHILD", FALSE }, + { WS_CLIPCHILDREN, "WS_CLIPCHILDREN", FALSE }, + { WS_CLIPSIBLINGS, "WS_CLIPSIBLINGS", FALSE }, + { WS_DISABLED, "WS_DISABLED", FALSE }, + { WS_DLGFRAME, "WS_DLGFRAME", FALSE }, + { WS_GROUP, "WS_GROUP", FALSE }, + { WS_HSCROLL, "WS_HSCROLL", FALSE }, + { WS_ICONIC, "WS_ICONIC", FALSE }, + { WS_MAXIMIZE, "WS_MAXIMIZE", FALSE }, + { WS_MAXIMIZEBOX, "WS_MAXIMIZEBOX", FALSE }, + { WS_MINIMIZE, "WS_MINIMIZE", FALSE }, + { WS_MINIMIZEBOX, "WS_MINIMIZEBOX", FALSE }, + { WS_OVERLAPPED, "WS_OVERLAPPED", FALSE }, + { WS_OVERLAPPEDWINDOW, "WS_OVERLAPPEDWINDOW", TRUE }, + { WS_POPUP, "WS_POPUP", FALSE }, + { WS_POPUPWINDOW, "WS_POPUPWINDOW", TRUE }, + { WS_SIZEBOX, "WS_SIZEBOX", FALSE }, + { WS_SYSMENU, "WS_SYSMENU", FALSE }, + { WS_TABSTOP, "WS_TABSTOP", FALSE }, + { WS_THICKFRAME, "WS_THICKFRAME", FALSE }, + { WS_VISIBLE, "WS_VISIBLE", FALSE } }; + +static const WINDOW_STYLE EXTENDED_WINDOW_STYLES[] = { { WS_EX_ACCEPTFILES, "WS_EX_ACCEPTFILES", FALSE }, { WS_EX_APPWINDOW, "WS_EX_APPWINDOW", FALSE }, { WS_EX_CLIENTEDGE, "WS_EX_CLIENTEDGE", FALSE }, @@ -130,8 +126,7 @@ void PrintExtendedWindowStyles(UINT32 style) { if (EXTENDED_WINDOW_STYLES[i].multi) { - if ((style & EXTENDED_WINDOW_STYLES[i].style) != - EXTENDED_WINDOW_STYLES[i].style) + if ((style & EXTENDED_WINDOW_STYLES[i].style) != EXTENDED_WINDOW_STYLES[i].style) continue; } @@ -140,8 +135,8 @@ void PrintExtendedWindowStyles(UINT32 style) } } -void PrintRailWindowState(WINDOW_ORDER_INFO* orderInfo, - WINDOW_STATE_ORDER* windowState) +static void PrintRailWindowState(const WINDOW_ORDER_INFO* orderInfo, + const WINDOW_STATE_ORDER* windowState) { if (orderInfo->fieldFlags & WINDOW_ORDER_STATE_NEW) WLog_INFO(TAG, "WindowCreate: WindowId: 0x%08X", orderInfo->windowId); @@ -157,8 +152,8 @@ void PrintRailWindowState(WINDOW_ORDER_INFO* orderInfo, if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_STYLE) { - WLog_INFO(TAG, "\tStyle: 0x%08X ExtendedStyle: 0x%08X", - windowState->style, windowState->extendedStyle); + WLog_INFO(TAG, "\tStyle: 0x%08X ExtendedStyle: 0x%08X", windowState->style, + windowState->extendedStyle); PrintWindowStyles(windowState->style); PrintExtendedWindowStyles(windowState->extendedStyle); } @@ -171,23 +166,22 @@ void PrintRailWindowState(WINDOW_ORDER_INFO* orderInfo, if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_TITLE) { char* title = NULL; - ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) windowState->titleInfo.string, + ConvertFromUnicode(CP_UTF8, 0, (WCHAR*)windowState->titleInfo.string, windowState->titleInfo.length / 2, &title, 0, NULL, NULL); - WLog_INFO(TAG, "\tTitleInfo: %s (length = %hu)", title, - windowState->titleInfo.length); + WLog_INFO(TAG, "\tTitleInfo: %s (length = %hu)", title, windowState->titleInfo.length); free(title); } if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET) { - WLog_INFO(TAG, "\tClientOffsetX: %d ClientOffsetY: %d", - windowState->clientOffsetX, windowState->clientOffsetY); + WLog_INFO(TAG, "\tClientOffsetX: %d ClientOffsetY: %d", windowState->clientOffsetX, + windowState->clientOffsetY); } if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE) { - WLog_INFO(TAG, "\tClientAreaWidth: %u ClientAreaHeight: %u", - windowState->clientAreaWidth, windowState->clientAreaHeight); + WLog_INFO(TAG, "\tClientAreaWidth: %u ClientAreaHeight: %u", windowState->clientAreaWidth, + windowState->clientAreaHeight); } if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_RP_CONTENT) @@ -202,8 +196,8 @@ void PrintRailWindowState(WINDOW_ORDER_INFO* orderInfo, if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) { - WLog_INFO(TAG, "\tWindowOffsetX: %d WindowOffsetY: %d", - windowState->windowOffsetX, windowState->windowOffsetY); + WLog_INFO(TAG, "\tWindowOffsetX: %d WindowOffsetY: %d", windowState->windowOffsetX, + windowState->windowOffsetY); } if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA) @@ -214,8 +208,8 @@ void PrintRailWindowState(WINDOW_ORDER_INFO* orderInfo, if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE) { - WLog_INFO(TAG, "\tWindowWidth: %u WindowHeight: %u", - windowState->windowWidth, windowState->windowHeight); + WLog_INFO(TAG, "\tWindowWidth: %u WindowHeight: %u", windowState->windowWidth, + windowState->windowHeight); } if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS) @@ -227,15 +221,15 @@ void PrintRailWindowState(WINDOW_ORDER_INFO* orderInfo, for (index = 0; index < windowState->numWindowRects; index++) { rect = &windowState->windowRects[index]; - WLog_INFO(TAG, "\twindowRect[%u]: left: %hu top: %hu right: %hu bottom: %hu", - index, rect->left, rect->top, rect->right, rect->bottom); + WLog_INFO(TAG, "\twindowRect[%u]: left: %hu top: %hu right: %hu bottom: %hu", index, + rect->left, rect->top, rect->right, rect->bottom); } } if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_VIS_OFFSET) { - WLog_INFO(TAG, "\tvisibileOffsetX: %d visibleOffsetY: %d", - windowState->visibleOffsetX, windowState->visibleOffsetY); + WLog_INFO(TAG, "\tvisibileOffsetX: %d visibleOffsetY: %d", windowState->visibleOffsetX, + windowState->visibleOffsetY); } if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY) @@ -247,15 +241,15 @@ void PrintRailWindowState(WINDOW_ORDER_INFO* orderInfo, for (index = 0; index < windowState->numVisibilityRects; index++) { rect = &windowState->visibilityRects[index]; - WLog_INFO(TAG, "\tvisibilityRect[%u]: left: %hu top: %hu right: %hu bottom: %hu", - index, rect->left, rect->top, rect->right, rect->bottom); + WLog_INFO(TAG, "\tvisibilityRect[%u]: left: %hu top: %hu right: %hu bottom: %hu", index, + rect->left, rect->top, rect->right, rect->bottom); } } WLog_INFO(TAG, "}"); } -static void PrintRailIconInfo(WINDOW_ORDER_INFO* orderInfo, ICON_INFO* iconInfo) +static void PrintRailIconInfo(const WINDOW_ORDER_INFO* orderInfo, const ICON_INFO* iconInfo) { WLog_INFO(TAG, "ICON_INFO"); WLog_INFO(TAG, "{"); @@ -269,14 +263,13 @@ static void PrintRailIconInfo(WINDOW_ORDER_INFO* orderInfo, ICON_INFO* iconInfo) WLog_INFO(TAG, "\tcbColorTable: %u", iconInfo->cbColorTable); WLog_INFO(TAG, "\tcbBitsMask: %u", iconInfo->cbBitsMask); WLog_INFO(TAG, "\tcbBitsColor: %u", iconInfo->cbBitsColor); - WLog_INFO(TAG, "\tcolorTable: %p", (void*) iconInfo->colorTable); - WLog_INFO(TAG, "\tbitsMask: %p", (void*) iconInfo->bitsMask); - WLog_INFO(TAG, "\tbitsColor: %p", (void*) iconInfo->bitsColor); + WLog_INFO(TAG, "\tcolorTable: %p", (void*)iconInfo->colorTable); + WLog_INFO(TAG, "\tbitsMask: %p", (void*)iconInfo->bitsMask); + WLog_INFO(TAG, "\tbitsColor: %p", (void*)iconInfo->bitsColor); WLog_INFO(TAG, "}"); } -LRESULT CALLBACK wf_RailWndProc(HWND hWnd, UINT msg, WPARAM wParam, - LPARAM lParam) +LRESULT CALLBACK wf_RailWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { HDC hDC; int x, y; @@ -290,13 +283,13 @@ LRESULT CALLBACK wf_RailWndProc(HWND hWnd, UINT msg, WPARAM wParam, rdpInput* input = NULL; rdpContext* context = NULL; wfRailWindow* railWindow; - railWindow = (wfRailWindow*) GetWindowLongPtr(hWnd, GWLP_USERDATA); + railWindow = (wfRailWindow*)GetWindowLongPtr(hWnd, GWLP_USERDATA); if (railWindow) wfc = railWindow->wfc; if (wfc) - context = (rdpContext*) wfc; + context = (rdpContext*)wfc; if (context) input = context->input; @@ -304,90 +297,90 @@ LRESULT CALLBACK wf_RailWndProc(HWND hWnd, UINT msg, WPARAM wParam, switch (msg) { case WM_PAINT: - { - if (!wfc) - return 0; - - hDC = BeginPaint(hWnd, &ps); - x = ps.rcPaint.left; - y = ps.rcPaint.top; - width = ps.rcPaint.right - ps.rcPaint.left + 1; - height = ps.rcPaint.bottom - ps.rcPaint.top + 1; - BitBlt(hDC, x, y, width, height, wfc->primary->hdc, - railWindow->x + x, railWindow->y + y, SRCCOPY); - EndPaint(hWnd, &ps); - } - break; + { + if (!wfc) + return 0; + + hDC = BeginPaint(hWnd, &ps); + x = ps.rcPaint.left; + y = ps.rcPaint.top; + width = ps.rcPaint.right - ps.rcPaint.left + 1; + height = ps.rcPaint.bottom - ps.rcPaint.top + 1; + BitBlt(hDC, x, y, width, height, wfc->primary->hdc, railWindow->x + x, + railWindow->y + y, SRCCOPY); + EndPaint(hWnd, &ps); + } + break; case WM_LBUTTONDOWN: - { - if (!railWindow || !input) - return 0; + { + if (!railWindow || !input) + return 0; - xPos = GET_X_LPARAM(lParam) + railWindow->x; - yPos = GET_Y_LPARAM(lParam) + railWindow->y; - inputFlags = PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON1; + xPos = GET_X_LPARAM(lParam) + railWindow->x; + yPos = GET_Y_LPARAM(lParam) + railWindow->y; + inputFlags = PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON1; - if (input) - input->MouseEvent(input, inputFlags, xPos, yPos); - } - break; + if (input) + input->MouseEvent(input, inputFlags, xPos, yPos); + } + break; case WM_LBUTTONUP: - { - if (!railWindow || !input) - return 0; + { + if (!railWindow || !input) + return 0; - xPos = GET_X_LPARAM(lParam) + railWindow->x; - yPos = GET_Y_LPARAM(lParam) + railWindow->y; - inputFlags = PTR_FLAGS_BUTTON1; + xPos = GET_X_LPARAM(lParam) + railWindow->x; + yPos = GET_Y_LPARAM(lParam) + railWindow->y; + inputFlags = PTR_FLAGS_BUTTON1; - if (input) - input->MouseEvent(input, inputFlags, xPos, yPos); - } - break; + if (input) + input->MouseEvent(input, inputFlags, xPos, yPos); + } + break; case WM_RBUTTONDOWN: - { - if (!railWindow || !input) - return 0; + { + if (!railWindow || !input) + return 0; - xPos = GET_X_LPARAM(lParam) + railWindow->x; - yPos = GET_Y_LPARAM(lParam) + railWindow->y; - inputFlags = PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON2; + xPos = GET_X_LPARAM(lParam) + railWindow->x; + yPos = GET_Y_LPARAM(lParam) + railWindow->y; + inputFlags = PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON2; - if (input) - input->MouseEvent(input, inputFlags, xPos, yPos); - } - break; + if (input) + input->MouseEvent(input, inputFlags, xPos, yPos); + } + break; case WM_RBUTTONUP: - { - if (!railWindow || !input) - return 0; + { + if (!railWindow || !input) + return 0; - xPos = GET_X_LPARAM(lParam) + railWindow->x; - yPos = GET_Y_LPARAM(lParam) + railWindow->y; - inputFlags = PTR_FLAGS_BUTTON2; + xPos = GET_X_LPARAM(lParam) + railWindow->x; + yPos = GET_Y_LPARAM(lParam) + railWindow->y; + inputFlags = PTR_FLAGS_BUTTON2; - if (input) - input->MouseEvent(input, inputFlags, xPos, yPos); - } - break; + if (input) + input->MouseEvent(input, inputFlags, xPos, yPos); + } + break; case WM_MOUSEMOVE: - { - if (!railWindow || !input) - return 0; + { + if (!railWindow || !input) + return 0; - xPos = GET_X_LPARAM(lParam) + railWindow->x; - yPos = GET_Y_LPARAM(lParam) + railWindow->y; - inputFlags = PTR_FLAGS_MOVE; + xPos = GET_X_LPARAM(lParam) + railWindow->x; + yPos = GET_Y_LPARAM(lParam) + railWindow->y; + inputFlags = PTR_FLAGS_MOVE; - if (input) - input->MouseEvent(input, inputFlags, xPos, yPos); - } - break; + if (input) + input->MouseEvent(input, inputFlags, xPos, yPos); + } + break; case WM_MOUSEWHEEL: break; @@ -407,15 +400,17 @@ LRESULT CALLBACK wf_RailWndProc(HWND hWnd, UINT msg, WPARAM wParam, return 0; } -#define RAIL_DISABLED_WINDOW_STYLES (WS_BORDER | WS_THICKFRAME | WS_DLGFRAME | WS_CAPTION | \ - WS_OVERLAPPED | WS_VSCROLL | WS_HSCROLL | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX) -#define RAIL_DISABLED_EXTENDED_WINDOW_STYLES (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE | WS_EX_WINDOWEDGE) +#define RAIL_DISABLED_WINDOW_STYLES \ + (WS_BORDER | WS_THICKFRAME | WS_DLGFRAME | WS_CAPTION | WS_OVERLAPPED | WS_VSCROLL | \ + WS_HSCROLL | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX) +#define RAIL_DISABLED_EXTENDED_WINDOW_STYLES \ + (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE | WS_EX_WINDOWEDGE) -static BOOL wf_rail_window_common(rdpContext* context, - WINDOW_ORDER_INFO* orderInfo, WINDOW_STATE_ORDER* windowState) +static BOOL wf_rail_window_common(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo, + const WINDOW_STATE_ORDER* windowState) { wfRailWindow* railWindow = NULL; - wfContext* wfc = (wfContext*) context; + wfContext* wfc = (wfContext*)context; RailClientContext* rail = wfc->rail; UINT32 fieldFlags = orderInfo->fieldFlags; PrintRailWindowState(orderInfo, windowState); @@ -425,7 +420,7 @@ static BOOL wf_rail_window_common(rdpContext* context, HANDLE hInstance; WCHAR* titleW = NULL; WNDCLASSEX wndClassEx; - railWindow = (wfRailWindow*) calloc(1, sizeof(wfRailWindow)); + railWindow = (wfRailWindow*)calloc(1, sizeof(wfRailWindow)); if (!railWindow) return FALSE; @@ -452,8 +447,9 @@ static BOOL wf_rail_window_common(rdpContext* context, /* error handled below */ } } - else if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) windowState->titleInfo.string, - windowState->titleInfo.length / 2, &title, 0, NULL, NULL) < 1) + else if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*)windowState->titleInfo.string, + windowState->titleInfo.length / 2, &title, 0, NULL, + NULL) < 1) { WLog_ERR(TAG, "failed to convert window title"); /* error handled below */ @@ -489,38 +485,45 @@ static BOOL wf_rail_window_common(rdpContext* context, wndClassEx.hInstance = hInstance; wndClassEx.hIconSm = NULL; RegisterClassEx(&wndClassEx); - railWindow->hWnd = CreateWindowExW( - railWindow->dwExStyle, /* dwExStyle */ - _T("RdpRailWindow"), /* lpClassName */ - titleW, /* lpWindowName */ - railWindow->dwStyle, /* dwStyle */ - railWindow->x, /* x */ - railWindow->y, /* y */ - railWindow->width, /* nWidth */ - railWindow->height, /* nHeight */ - NULL, /* hWndParent */ - NULL, /* hMenu */ - hInstance, /* hInstance */ - NULL /* lpParam */ - ); - SetWindowLongPtr(railWindow->hWnd, GWLP_USERDATA, (LONG_PTR) railWindow); - HashTable_Add(wfc->railWindows, (void*)(UINT_PTR) orderInfo->windowId, - (void*) railWindow); + railWindow->hWnd = CreateWindowExW(railWindow->dwExStyle, /* dwExStyle */ + _T("RdpRailWindow"), /* lpClassName */ + titleW, /* lpWindowName */ + railWindow->dwStyle, /* dwStyle */ + railWindow->x, /* x */ + railWindow->y, /* y */ + railWindow->width, /* nWidth */ + railWindow->height, /* nHeight */ + NULL, /* hWndParent */ + NULL, /* hMenu */ + hInstance, /* hInstance */ + NULL /* lpParam */ + ); + + if (!railWindow->hWnd) + { + free(titleW); + free(railWindow->title); + free(railWindow); + WLog_ERR(TAG, "CreateWindowExW failed with error %" PRIu32 "", GetLastError()); + return FALSE; + } + + SetWindowLongPtr(railWindow->hWnd, GWLP_USERDATA, (LONG_PTR)railWindow); + HashTable_Add(wfc->railWindows, (void*)(UINT_PTR)orderInfo->windowId, (void*)railWindow); free(titleW); UpdateWindow(railWindow->hWnd); return TRUE; } else { - railWindow = (wfRailWindow*) HashTable_GetItemValue(wfc->railWindows, - (void*)(UINT_PTR) orderInfo->windowId); + railWindow = (wfRailWindow*)HashTable_GetItemValue(wfc->railWindows, + (void*)(UINT_PTR)orderInfo->windowId); } if (!railWindow) return TRUE; - if ((fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) || - (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE)) + if ((fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) || (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE)) { if (fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) { @@ -534,12 +537,8 @@ static BOOL wf_rail_window_common(rdpContext* context, railWindow->height = windowState->windowHeight; } - SetWindowPos(railWindow->hWnd, NULL, - railWindow->x, - railWindow->y, - railWindow->width, - railWindow->height, - 0); + SetWindowPos(railWindow->hWnd, NULL, railWindow->x, railWindow->y, railWindow->width, + railWindow->height, 0); } if (fieldFlags & WINDOW_ORDER_FIELD_OWNER) @@ -552,8 +551,8 @@ static BOOL wf_rail_window_common(rdpContext* context, railWindow->dwStyle &= ~RAIL_DISABLED_WINDOW_STYLES; railWindow->dwExStyle = windowState->extendedStyle; railWindow->dwExStyle &= ~RAIL_DISABLED_EXTENDED_WINDOW_STYLES; - SetWindowLongPtr(railWindow->hWnd, GWL_STYLE, (LONG) railWindow->dwStyle); - SetWindowLongPtr(railWindow->hWnd, GWL_EXSTYLE, (LONG) railWindow->dwExStyle); + SetWindowLongPtr(railWindow->hWnd, GWL_STYLE, (LONG)railWindow->dwStyle); + SetWindowLongPtr(railWindow->hWnd, GWL_EXSTYLE, (LONG)railWindow->dwExStyle); } if (fieldFlags & WINDOW_ORDER_FIELD_SHOW) @@ -574,7 +573,7 @@ static BOOL wf_rail_window_common(rdpContext* context, return FALSE; } } - else if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) windowState->titleInfo.string, + else if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*)windowState->titleInfo.string, windowState->titleInfo.length / 2, &title, 0, NULL, NULL) < 1) { WLog_ERR(TAG, "failed to convert window title"); @@ -645,27 +644,26 @@ static BOOL wf_rail_window_common(rdpContext* context, return TRUE; } -static BOOL wf_rail_window_delete(rdpContext* context, - WINDOW_ORDER_INFO* orderInfo) +static BOOL wf_rail_window_delete(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo) { wfRailWindow* railWindow = NULL; - wfContext* wfc = (wfContext*) context; + wfContext* wfc = (wfContext*)context; RailClientContext* rail = wfc->rail; WLog_DBG(TAG, "RailWindowDelete"); - railWindow = (wfRailWindow*) HashTable_GetItemValue(wfc->railWindows, - (void*)(UINT_PTR) orderInfo->windowId); + railWindow = (wfRailWindow*)HashTable_GetItemValue(wfc->railWindows, + (void*)(UINT_PTR)orderInfo->windowId); if (!railWindow) return TRUE; - HashTable_Remove(wfc->railWindows, (void*)(UINT_PTR) orderInfo->windowId); + HashTable_Remove(wfc->railWindows, (void*)(UINT_PTR)orderInfo->windowId); DestroyWindow(railWindow->hWnd); free(railWindow); return TRUE; } -static BOOL wf_rail_window_icon(rdpContext* context, - WINDOW_ORDER_INFO* orderInfo, WINDOW_ICON_ORDER* windowIcon) +static BOOL wf_rail_window_icon(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo, + const WINDOW_ICON_ORDER* windowIcon) { HDC hDC; int bpp; @@ -677,12 +675,12 @@ static BOOL wf_rail_window_icon(rdpContext* context, BITMAPINFO bitmapInfo; wfRailWindow* railWindow; BITMAPINFOHEADER* bitmapInfoHeader; - wfContext* wfc = (wfContext*) context; + wfContext* wfc = (wfContext*)context; RailClientContext* rail = wfc->rail; WLog_DBG(TAG, "RailWindowIcon"); PrintRailIconInfo(orderInfo, windowIcon->iconInfo); - railWindow = (wfRailWindow*) HashTable_GetItemValue(wfc->railWindows, - (void*)(UINT_PTR) orderInfo->windowId); + railWindow = (wfRailWindow*)HashTable_GetItemValue(wfc->railWindows, + (void*)(UINT_PTR)orderInfo->windowId); if (!railWindow) return TRUE; @@ -708,22 +706,19 @@ static BOOL wf_rail_window_icon(rdpContext* context, bitmapInfoHeader->biYPelsPerMeter = height; bitmapInfoHeader->biClrUsed = 0; bitmapInfoHeader->biClrImportant = 0; - iconInfo.hbmMask = CreateDIBitmap(hDC, - bitmapInfoHeader, CBM_INIT, - windowIcon->iconInfo->bitsMask, - &bitmapInfo, DIB_RGB_COLORS); - iconInfo.hbmColor = CreateDIBitmap(hDC, - bitmapInfoHeader, CBM_INIT, - windowIcon->iconInfo->bitsColor, - &bitmapInfo, DIB_RGB_COLORS); + iconInfo.hbmMask = CreateDIBitmap(hDC, bitmapInfoHeader, CBM_INIT, + windowIcon->iconInfo->bitsMask, &bitmapInfo, DIB_RGB_COLORS); + iconInfo.hbmColor = + CreateDIBitmap(hDC, bitmapInfoHeader, CBM_INIT, windowIcon->iconInfo->bitsColor, + &bitmapInfo, DIB_RGB_COLORS); hIcon = CreateIconIndirect(&iconInfo); if (hIcon) { WPARAM wParam; LPARAM lParam; - wParam = (WPARAM) bigIcon ? ICON_BIG : ICON_SMALL; - lParam = (LPARAM) hIcon; + wParam = (WPARAM)bigIcon ? ICON_BIG : ICON_SMALL; + lParam = (LPARAM)hIcon; SendMessage(railWindow->hWnd, WM_SETICON, wParam, lParam); } @@ -737,15 +732,15 @@ static BOOL wf_rail_window_icon(rdpContext* context, return TRUE; } -static BOOL wf_rail_window_cached_icon(rdpContext* context, - WINDOW_ORDER_INFO* orderInfo, WINDOW_CACHED_ICON_ORDER* windowCachedIcon) +static BOOL wf_rail_window_cached_icon(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo, + const WINDOW_CACHED_ICON_ORDER* windowCachedIcon) { WLog_DBG(TAG, "RailWindowCachedIcon"); return TRUE; } -static void wf_rail_notify_icon_common(rdpContext* context, - WINDOW_ORDER_INFO* orderInfo, NOTIFY_ICON_STATE_ORDER* notifyIconState) +static void wf_rail_notify_icon_common(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo, + const NOTIFY_ICON_STATE_ORDER* notifyIconState) { if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_VERSION) { @@ -765,7 +760,7 @@ static void wf_rail_notify_icon_common(rdpContext* context, if (orderInfo->fieldFlags & WINDOW_ORDER_ICON) { - ICON_INFO* iconInfo = &(notifyIconState->icon); + const ICON_INFO* iconInfo = &(notifyIconState->icon); PrintRailIconInfo(orderInfo, iconInfo); } @@ -774,48 +769,46 @@ static void wf_rail_notify_icon_common(rdpContext* context, } } -static BOOL wf_rail_notify_icon_create(rdpContext* context, - WINDOW_ORDER_INFO* orderInfo, NOTIFY_ICON_STATE_ORDER* notifyIconState) +static BOOL wf_rail_notify_icon_create(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo, + const NOTIFY_ICON_STATE_ORDER* notifyIconState) { - wfContext* wfc = (wfContext*) context; + wfContext* wfc = (wfContext*)context; RailClientContext* rail = wfc->rail; WLog_DBG(TAG, "RailNotifyIconCreate"); wf_rail_notify_icon_common(context, orderInfo, notifyIconState); return TRUE; } -static BOOL wf_rail_notify_icon_update(rdpContext* context, - WINDOW_ORDER_INFO* orderInfo, NOTIFY_ICON_STATE_ORDER* notifyIconState) +static BOOL wf_rail_notify_icon_update(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo, + const NOTIFY_ICON_STATE_ORDER* notifyIconState) { - wfContext* wfc = (wfContext*) context; + wfContext* wfc = (wfContext*)context; RailClientContext* rail = wfc->rail; WLog_DBG(TAG, "RailNotifyIconUpdate"); wf_rail_notify_icon_common(context, orderInfo, notifyIconState); return TRUE; } -static BOOL wf_rail_notify_icon_delete(rdpContext* context, - WINDOW_ORDER_INFO* orderInfo) +static BOOL wf_rail_notify_icon_delete(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo) { - wfContext* wfc = (wfContext*) context; + wfContext* wfc = (wfContext*)context; RailClientContext* rail = wfc->rail; WLog_DBG(TAG, "RailNotifyIconDelete"); return TRUE; } -static BOOL wf_rail_monitored_desktop(rdpContext* context, - WINDOW_ORDER_INFO* orderInfo, MONITORED_DESKTOP_ORDER* monitoredDesktop) +static BOOL wf_rail_monitored_desktop(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo, + const MONITORED_DESKTOP_ORDER* monitoredDesktop) { - wfContext* wfc = (wfContext*) context; + wfContext* wfc = (wfContext*)context; RailClientContext* rail = wfc->rail; WLog_DBG(TAG, "RailMonitorDesktop"); return TRUE; } -static BOOL wf_rail_non_monitored_desktop(rdpContext* context, - WINDOW_ORDER_INFO* orderInfo) +static BOOL wf_rail_non_monitored_desktop(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo) { - wfContext* wfc = (wfContext*) context; + wfContext* wfc = (wfContext*)context; RailClientContext* rail = wfc->rail; WLog_DBG(TAG, "RailNonMonitorDesktop"); return TRUE; @@ -844,7 +837,7 @@ void wf_rail_register_update_callbacks(rdpUpdate* update) * @return 0 on success, otherwise a Win32 error code */ static UINT wf_rail_server_execute_result(RailClientContext* context, - RAIL_EXEC_RESULT_ORDER* execResult) + const RAIL_EXEC_RESULT_ORDER* execResult) { WLog_DBG(TAG, "RailServerExecuteResult: 0x%08X", execResult->rawResult); return CHANNEL_RC_OK; @@ -856,7 +849,7 @@ static UINT wf_rail_server_execute_result(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT wf_rail_server_system_param(RailClientContext* context, - RAIL_SYSPARAM_ORDER* sysparam) + const RAIL_SYSPARAM_ORDER* sysparam) { return CHANNEL_RC_OK; } @@ -867,13 +860,13 @@ static UINT wf_rail_server_system_param(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT wf_rail_server_handshake(RailClientContext* context, - RAIL_HANDSHAKE_ORDER* handshake) + const RAIL_HANDSHAKE_ORDER* handshake) { RAIL_EXEC_ORDER exec; RAIL_SYSPARAM_ORDER sysparam; RAIL_HANDSHAKE_ORDER clientHandshake; RAIL_CLIENT_STATUS_ORDER clientStatus; - wfContext* wfc = (wfContext*) context->custom; + wfContext* wfc = (wfContext*)context->custom; rdpSettings* settings = wfc->context.settings; clientHandshake.buildNumber = 0x00001DB0; context->ClientHandshake(context, &clientHandshake); @@ -923,7 +916,7 @@ static UINT wf_rail_server_handshake(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT wf_rail_server_handshake_ex(RailClientContext* context, - RAIL_HANDSHAKE_EX_ORDER* handshakeEx) + const RAIL_HANDSHAKE_EX_ORDER* handshakeEx) { return CHANNEL_RC_OK; } @@ -934,7 +927,7 @@ static UINT wf_rail_server_handshake_ex(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT wf_rail_server_local_move_size(RailClientContext* context, - RAIL_LOCALMOVESIZE_ORDER* localMoveSize) + const RAIL_LOCALMOVESIZE_ORDER* localMoveSize) { return CHANNEL_RC_OK; } @@ -945,7 +938,7 @@ static UINT wf_rail_server_local_move_size(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT wf_rail_server_min_max_info(RailClientContext* context, - RAIL_MINMAXINFO_ORDER* minMaxInfo) + const RAIL_MINMAXINFO_ORDER* minMaxInfo) { return CHANNEL_RC_OK; } @@ -956,7 +949,7 @@ static UINT wf_rail_server_min_max_info(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT wf_rail_server_language_bar_info(RailClientContext* context, - RAIL_LANGBAR_INFO_ORDER* langBarInfo) + const RAIL_LANGBAR_INFO_ORDER* langBarInfo) { return CHANNEL_RC_OK; } @@ -967,7 +960,7 @@ static UINT wf_rail_server_language_bar_info(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT wf_rail_server_get_appid_response(RailClientContext* context, - RAIL_GET_APPID_RESP_ORDER* getAppIdResp) + const RAIL_GET_APPID_RESP_ORDER* getAppIdResp) { return CHANNEL_RC_OK; } @@ -987,8 +980,7 @@ void wf_rail_invalidate_region(wfContext* wfc, REGION16* invalidRegion) for (index = 0; index < count; index++) { - railWindow = (wfRailWindow*) HashTable_GetItemValue(wfc->railWindows, - (void*) pKeys[index]); + railWindow = (wfRailWindow*)HashTable_GetItemValue(wfc->railWindows, (void*)pKeys[index]); if (railWindow) { @@ -1016,9 +1008,9 @@ void wf_rail_invalidate_region(wfContext* wfc, REGION16* invalidRegion) BOOL wf_rail_init(wfContext* wfc, RailClientContext* rail) { - rdpContext* context = (rdpContext*) wfc; + rdpContext* context = (rdpContext*)wfc; wfc->rail = rail; - rail->custom = (void*) wfc; + rail->custom = (void*)wfc; rail->ServerExecuteResult = wf_rail_server_execute_result; rail->ServerSystemParam = wf_rail_server_system_param; rail->ServerHandshake = wf_rail_server_handshake; diff --git a/client/Windows/wfreerdp.rc b/client/Windows/wfreerdp.rc index 135f641..e5bfc9c 100644 Binary files a/client/Windows/wfreerdp.rc and b/client/Windows/wfreerdp.rc differ diff --git a/client/X11/CMakeLists.txt b/client/X11/CMakeLists.txt index 48e5af9..869652c 100644 --- a/client/X11/CMakeLists.txt +++ b/client/X11/CMakeLists.txt @@ -29,9 +29,7 @@ set(${MODULE_PREFIX}_SRCS xf_gfx.c xf_gfx.h xf_rail.c - xf_rail.h - xf_tsmf.c - xf_tsmf.h + xf_rail.h xf_input.c xf_input.h xf_event.c @@ -59,6 +57,12 @@ set(${MODULE_PREFIX}_SRCS xf_client.c xf_client.h) +if (CHANNEL_TSMF_CLIENT) + set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} + xf_tsmf.c + xf_tsmf.h) +endif() + if(WITH_CLIENT_INTERFACE) if(CLIENT_INTERFACE_SHARED) add_library(${MODULE_NAME} SHARED ${${MODULE_PREFIX}_SRCS}) diff --git a/client/X11/cli/xfreerdp.c b/client/X11/cli/xfreerdp.c index 663d49b..c8a77f3 100644 --- a/client/X11/cli/xfreerdp.c +++ b/client/X11/cli/xfreerdp.c @@ -53,7 +53,7 @@ int main(int argc, char* argv[]) return 1; settings = context->settings; - xfc = (xfContext*) context; + xfc = (xfContext*)context; status = freerdp_client_settings_parse_command_line(context->settings, argc, argv, FALSE); @@ -61,11 +61,14 @@ int main(int argc, char* argv[]) if (status) { - if (settings->ListMonitors) + BOOL list = settings->ListMonitors; + if (list) xf_list_monitors(xfc); freerdp_client_context_free(context); - return 0; + if (list) + return 0; + return status; } freerdp_client_start(context); diff --git a/client/X11/generate_argument_docbook.c b/client/X11/generate_argument_docbook.c index b700539..78de2f9 100644 --- a/client/X11/generate_argument_docbook.c +++ b/client/X11/generate_argument_docbook.c @@ -9,6 +9,7 @@ LPSTR tr_esc_str(LPCSTR arg, bool format) { LPSTR tmp = NULL; + LPSTR tmp2 = NULL; size_t cs = 0, x, ds, len; size_t s; @@ -24,12 +25,17 @@ LPSTR tr_esc_str(LPCSTR arg, bool format) /* Prepare a initial buffer with the size of the result string. */ ds = s + 1; - if (s) - tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR)); + if (ds) + { + tmp2 = (LPSTR)realloc(tmp, ds * sizeof(CHAR)); + if (!tmp2) + free(tmp); + tmp = tmp2; + } if (NULL == tmp) { - fprintf(stderr, "Could not allocate string buffer.\n"); + fprintf(stderr, "Could not allocate string buffer.\n"); exit(-2); } @@ -43,11 +49,14 @@ LPSTR tr_esc_str(LPCSTR arg, bool format) case '<': len = format ? 13 : 4; ds += len - 1; - tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR)); + tmp2 = (LPSTR)realloc(tmp, ds * sizeof(CHAR)); + if (!tmp2) + free(tmp); + tmp = tmp2; if (NULL == tmp) { - fprintf(stderr, "Could not reallocate string buffer.\n"); + fprintf(stderr, "Could not reallocate string buffer.\n"); exit(-3); } @@ -64,11 +73,14 @@ LPSTR tr_esc_str(LPCSTR arg, bool format) case '>': len = format ? 14 : 4; ds += len - 1; - tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR)); + tmp2 = (LPSTR)realloc(tmp, ds * sizeof(CHAR)); + if (!tmp2) + free(tmp); + tmp = tmp2; if (NULL == tmp) { - fprintf(stderr, "Could not reallocate string buffer.\n"); + fprintf(stderr, "Could not reallocate string buffer.\n"); exit(-4); } @@ -77,18 +89,21 @@ LPSTR tr_esc_str(LPCSTR arg, bool format) strncpy(&tmp[cs], "", len); else /* coverity[buffer_size] */ - strncpy(&tmp[cs], "<", len); + strncpy(&tmp[cs], ">", len); cs += len; break; case '\'': ds += 5; - tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR)); + tmp2 = (LPSTR)realloc(tmp, ds * sizeof(CHAR)); + if (!tmp2) + free(tmp); + tmp = tmp2; if (NULL == tmp) { - fprintf(stderr, "Could not reallocate string buffer.\n"); + fprintf(stderr, "Could not reallocate string buffer.\n"); exit(-5); } @@ -102,11 +117,14 @@ LPSTR tr_esc_str(LPCSTR arg, bool format) case '"': ds += 5; - tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR)); + tmp2 = (LPSTR)realloc(tmp, ds * sizeof(CHAR)); + if (!tmp2) + free(tmp); + tmp = tmp2; if (NULL == tmp) { - fprintf(stderr, "Could not reallocate string buffer.\n"); + fprintf(stderr, "Could not reallocate string buffer.\n"); exit(-6); } @@ -120,11 +138,14 @@ LPSTR tr_esc_str(LPCSTR arg, bool format) case '&': ds += 4; - tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR)); + tmp2 = (LPSTR)realloc(tmp, ds * sizeof(CHAR)); + if (!tmp2) + free(tmp); + tmp = tmp2; if (NULL == tmp) { - fprintf(stderr, "Could not reallocate string buffer.\n"); + fprintf(stderr, "Could not reallocate string buffer.\n"); exit(-7); } @@ -158,7 +179,7 @@ int main(int argc, char* argv[]) if (NULL == fp) { - fprintf(stderr, "Could not open '%s' for writing.\n", fname); + fprintf(stderr, "Could not open '%s' for writing.\n", fname); return -1; } @@ -171,17 +192,17 @@ int main(int argc, char* argv[]) * compatible XML */ if (elements < 2) { - fprintf(stderr, "The argument array 'args' is empty, writing an empty file.\n"); + fprintf(stderr, "The argument array 'args' is empty, writing an empty file.\n"); elements = 1; } for (x = 0; x < elements - 1; x++) { const COMMAND_LINE_ARGUMENT_A* arg = &args[x]; - char* name = tr_esc_str((LPSTR) arg->Name, FALSE); - char* alias = tr_esc_str((LPSTR) arg->Alias, FALSE); + char* name = tr_esc_str((LPSTR)arg->Name, FALSE); + char* alias = tr_esc_str((LPSTR)arg->Alias, FALSE); char* format = tr_esc_str(arg->Format, TRUE); - char* text = tr_esc_str((LPSTR) arg->Text, FALSE); + char* text = tr_esc_str((LPSTR)arg->Text, FALSE); fprintf(fp, "\t\t\t\n"); do @@ -213,8 +234,7 @@ int main(int argc, char* argv[]) free(name); name = alias; - } - while (alias); + } while (alias); if (text) { @@ -228,7 +248,7 @@ int main(int argc, char* argv[]) fprintf(fp, " (default:%s)", arg->Default ? "on" : "off"); else if (arg->Default) { - char* value = tr_esc_str((LPSTR) arg->Default, FALSE); + char* value = tr_esc_str((LPSTR)arg->Default, FALSE); fprintf(fp, " (default:%s)", value); free(value); } @@ -248,4 +268,3 @@ int main(int argc, char* argv[]) fclose(fp); return 0; } - diff --git a/client/X11/xf_channels.c b/client/X11/xf_channels.c index ef91504..8090b9b 100644 --- a/client/X11/xf_channels.c +++ b/client/X11/xf_channels.c @@ -28,7 +28,9 @@ #include "xfreerdp.h" #include "xf_gfx.h" +#if defined(CHANNEL_TSMF_CLIENT) #include "xf_tsmf.h" +#endif #include "xf_rail.h" #include "xf_cliprdr.h" #include "xf_disp.h" @@ -36,35 +38,33 @@ void xf_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e) { - xfContext* xfc = (xfContext*) context; - rdpSettings* settings = xfc->context.settings; + xfContext* xfc = (xfContext*)context; if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) { - xfc->rdpei = (RdpeiClientContext*) e->pInterface; + xfc->rdpei = (RdpeiClientContext*)e->pInterface; } +#if defined(CHANNEL_TSMF_CLIENT) else if (strcmp(e->name, TSMF_DVC_CHANNEL_NAME) == 0) { - xf_tsmf_init(xfc, (TsmfClientContext*) e->pInterface); + xf_tsmf_init(xfc, (TsmfClientContext*)e->pInterface); } +#endif else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) { - if (settings->SoftwareGdi) - gdi_graphics_pipeline_init(xfc->context.gdi, (RdpgfxClientContext*) e->pInterface); - else - xf_graphics_pipeline_init(xfc, (RdpgfxClientContext*) e->pInterface); + xf_graphics_pipeline_init(xfc, (RdpgfxClientContext*)e->pInterface); } else if (strcmp(e->name, RAIL_SVC_CHANNEL_NAME) == 0) { - xf_rail_init(xfc, (RailClientContext*) e->pInterface); + xf_rail_init(xfc, (RailClientContext*)e->pInterface); } else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) { - xf_cliprdr_init(xfc, (CliprdrClientContext*) e->pInterface); + xf_cliprdr_init(xfc, (CliprdrClientContext*)e->pInterface); } else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0) { - xf_encomsp_init(xfc, (EncomspClientContext*) e->pInterface); + xf_encomsp_init(xfc, (EncomspClientContext*)e->pInterface); } else if (strcmp(e->name, DISP_DVC_CHANNEL_NAME) == 0) { @@ -76,10 +76,7 @@ void xf_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* } else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0) { - if (settings->SoftwareGdi) - gdi_video_control_init(xfc->context.gdi, (VideoClientContext*)e->pInterface); - else - xf_video_control_init(xfc, (VideoClientContext*)e->pInterface); + xf_video_control_init(xfc, (VideoClientContext*)e->pInterface); } else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0) { @@ -89,7 +86,7 @@ void xf_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* void xf_OnChannelDisconnectedEventHandler(void* context, ChannelDisconnectedEventArgs* e) { - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; rdpSettings* settings = xfc->context.settings; if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) @@ -100,28 +97,27 @@ void xf_OnChannelDisconnectedEventHandler(void* context, ChannelDisconnectedEven { xf_disp_uninit(xfc->xfDisp, (DispClientContext*)e->pInterface); } +#if defined(CHANNEL_TSMF_CLIENT) else if (strcmp(e->name, TSMF_DVC_CHANNEL_NAME) == 0) { - xf_tsmf_uninit(xfc, (TsmfClientContext*) e->pInterface); + xf_tsmf_uninit(xfc, (TsmfClientContext*)e->pInterface); } +#endif else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) { - if (settings->SoftwareGdi) - gdi_graphics_pipeline_uninit(xfc->context.gdi, (RdpgfxClientContext*) e->pInterface); - else - xf_graphics_pipeline_uninit(xfc, (RdpgfxClientContext*) e->pInterface); + xf_graphics_pipeline_uninit(xfc, (RdpgfxClientContext*)e->pInterface); } else if (strcmp(e->name, RAIL_SVC_CHANNEL_NAME) == 0) { - xf_rail_uninit(xfc, (RailClientContext*) e->pInterface); + xf_rail_uninit(xfc, (RailClientContext*)e->pInterface); } else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) { - xf_cliprdr_uninit(xfc, (CliprdrClientContext*) e->pInterface); + xf_cliprdr_uninit(xfc, (CliprdrClientContext*)e->pInterface); } else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0) { - xf_encomsp_uninit(xfc, (EncomspClientContext*) e->pInterface); + xf_encomsp_uninit(xfc, (EncomspClientContext*)e->pInterface); } else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0) { diff --git a/client/X11/xf_channels.h b/client/X11/xf_channels.h index 8a8c3b1..c12d823 100644 --- a/client/X11/xf_channels.h +++ b/client/X11/xf_channels.h @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c index 4a3e0d2..2a5569d 100644 --- a/client/X11/xf_client.c +++ b/client/X11/xf_client.c @@ -27,6 +27,7 @@ #endif #include +#include #include #include @@ -88,7 +89,9 @@ #include "xf_gdi.h" #include "xf_rail.h" +#if defined(CHANNEL_TSMF_CLIENT) #include "xf_tsmf.h" +#endif #include "xf_event.h" #include "xf_input.h" #include "xf_cliprdr.h" @@ -101,10 +104,11 @@ #include "xf_channels.h" #include "xfreerdp.h" - #include #define TAG CLIENT_TAG("x11") +#define MIN_PIXEL_DIFF 0.001 + static int (*_def_error_handler)(Display*, XErrorEvent*); static int _xf_error_handler(Display* d, XErrorEvent* ev); static void xf_check_extensions(xfContext* context); @@ -123,6 +127,7 @@ static void xf_draw_screen_scaled(xfContext* xfc, int x, int y, int w, int h) double yScalingFactor; int x2; int y2; + const char* filter; rdpSettings* settings = xfc->context.settings; if (xfc->scaledWidth <= 0 || xfc->scaledHeight <= 0) @@ -153,8 +158,8 @@ static void xf_draw_screen_scaled(xfContext* xfc, int x, int y, int w, int h) if (XSubtractRegion(reg1, reg2, reg1) && !XEmptyRegion(reg1)) { XSetRegion(xfc->display, xfc->gc, reg1); - XFillRectangle(xfc->display, xfc->window->handle, xfc->gc, 0, 0, - xfc->window->width, xfc->window->height); + XFillRectangle(xfc->display, xfc->window->handle, xfc->gc, 0, 0, xfc->window->width, + xfc->window->height); XSetClipMask(xfc->display, xfc->gc, None); } @@ -163,11 +168,23 @@ static void xf_draw_screen_scaled(xfContext* xfc, int x, int y, int w, int h) } picFormat = XRenderFindVisualFormat(xfc->display, xfc->visual); pa.subwindow_mode = IncludeInferiors; - primaryPicture = XRenderCreatePicture(xfc->display, xfc->primary, picFormat, - CPSubwindowMode, &pa); - windowPicture = XRenderCreatePicture(xfc->display, xfc->window->handle, - picFormat, CPSubwindowMode, &pa); - XRenderSetPictureFilter(xfc->display, primaryPicture, FilterBilinear, 0, 0); + primaryPicture = + XRenderCreatePicture(xfc->display, xfc->primary, picFormat, CPSubwindowMode, &pa); + windowPicture = + XRenderCreatePicture(xfc->display, xfc->window->handle, picFormat, CPSubwindowMode, &pa); + /* avoid blurry filter when scaling factor is 2x, 3x, etc + * useful when the client has high-dpi monitor */ + filter = FilterBilinear; + if (fabs(xScalingFactor - yScalingFactor) < MIN_PIXEL_DIFF) + { + const double inverseX = 1.0 / xScalingFactor; + const double inverseRoundedX = round(inverseX); + const double absInverse = fabs(inverseX - inverseRoundedX); + + if (absInverse < MIN_PIXEL_DIFF) + filter = FilterNearest; + } + XRenderSetPictureFilter(xfc->display, primaryPicture, filter, 0, 0); transform.matrix[0][0] = XDoubleToFixed(xScalingFactor); transform.matrix[0][1] = XDoubleToFixed(0.0); transform.matrix[0][2] = XDoubleToFixed(0.0); @@ -185,8 +202,8 @@ static void xf_draw_screen_scaled(xfContext* xfc, int x, int y, int w, int h) w = ceil(x2 / xScalingFactor) + 1 - x; h = ceil(y2 / yScalingFactor) + 1 - y; XRenderSetPictureTransform(xfc->display, primaryPicture, &transform); - XRenderComposite(xfc->display, PictOpSrc, primaryPicture, 0, windowPicture, x, - y, 0, 0, xfc->offset_x + x, xfc->offset_y + y, w, h); + XRenderComposite(xfc->display, PictOpSrc, primaryPicture, 0, windowPicture, x, y, 0, 0, + xfc->offset_x + x, xfc->offset_y + y, w, h); XRenderFreePicture(xfc->display, primaryPicture); XRenderFreePicture(xfc->display, windowPicture); } @@ -195,9 +212,9 @@ BOOL xf_picture_transform_required(xfContext* xfc) { rdpSettings* settings = xfc->context.settings; - if (xfc->offset_x || xfc->offset_y || - xfc->scaledWidth != settings->DesktopWidth || - xfc->scaledHeight != settings->DesktopHeight) + if ((xfc->offset_x != 0) || (xfc->offset_y != 0) || + (xfc->scaledWidth != (INT64)settings->DesktopWidth) || + (xfc->scaledHeight != (INT64)settings->DesktopHeight)) { return TRUE; } @@ -206,8 +223,15 @@ BOOL xf_picture_transform_required(xfContext* xfc) } #endif /* WITH_XRENDER defined */ -void xf_draw_screen(xfContext* xfc, int x, int y, int w, int h) +void xf_draw_screen_(xfContext* xfc, int x, int y, int w, int h, const char* fkt, const char* file, + int line) { + if (!xfc) + { + WLog_DBG(TAG, "[%s] called from [%s] xfc=%p", __FUNCTION__, fkt, xfc); + return; + } + if (w == 0 || h == 0) { WLog_WARN(TAG, "invalid width and/or height specified: w=%d h=%d", w, h); @@ -229,7 +253,7 @@ void xf_draw_screen(xfContext* xfc, int x, int y, int w, int h) static BOOL xf_desktop_resize(rdpContext* context) { rdpSettings* settings; - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; settings = context->settings; if (xfc->primary) @@ -237,10 +261,8 @@ static BOOL xf_desktop_resize(rdpContext* context) BOOL same = (xfc->primary == xfc->drawing) ? TRUE : FALSE; XFreePixmap(xfc->display, xfc->primary); - if (!(xfc->primary = XCreatePixmap( - xfc->display, xfc->drawable, - settings->DesktopWidth, - settings->DesktopHeight, xfc->depth))) + if (!(xfc->primary = XCreatePixmap(xfc->display, xfc->drawable, settings->DesktopWidth, + settings->DesktopHeight, xfc->depth))) return FALSE; if (same) @@ -291,7 +313,7 @@ static BOOL xf_sw_end_paint(rdpContext* context) UINT32 w, h; int ninvalid; HGDI_RGN cinvalid; - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; rdpGdi* gdi = context->gdi; if (gdi->suppressOutput) @@ -311,18 +333,17 @@ static BOOL xf_sw_end_paint(rdpContext* context) if (gdi->primary->hdc->hwnd->invalid->null) return TRUE; - xf_lock_x11(xfc, FALSE); - XPutImage(xfc->display, xfc->primary, xfc->gc, xfc->image, - x, y, x, y, w, h); + xf_lock_x11(xfc); + XPutImage(xfc->display, xfc->primary, xfc->gc, xfc->image, x, y, x, y, w, h); xf_draw_screen(xfc, x, y, w, h); - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); } else { if (gdi->primary->hdc->hwnd->ninvalid < 1) return TRUE; - xf_lock_x11(xfc, FALSE); + xf_lock_x11(xfc); for (i = 0; i < ninvalid; i++) { @@ -330,13 +351,12 @@ static BOOL xf_sw_end_paint(rdpContext* context) y = cinvalid[i].y; w = cinvalid[i].w; h = cinvalid[i].h; - XPutImage(xfc->display, xfc->primary, xfc->gc, - xfc->image, x, y, x, y, w, h); + XPutImage(xfc->display, xfc->primary, xfc->gc, xfc->image, x, y, x, y, w, h); xf_draw_screen(xfc, x, y, w, h); } XFlush(xfc->display); - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); } } else @@ -344,9 +364,9 @@ static BOOL xf_sw_end_paint(rdpContext* context) if (gdi->primary->hdc->hwnd->invalid->null) return TRUE; - xf_lock_x11(xfc, FALSE); + xf_lock_x11(xfc); xf_rail_paint(xfc, x, y, x + w, y + h); - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); } gdi->primary->hdc->hwnd->invalid->null = TRUE; @@ -357,10 +377,10 @@ static BOOL xf_sw_end_paint(rdpContext* context) static BOOL xf_sw_desktop_resize(rdpContext* context) { rdpGdi* gdi = context->gdi; - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; rdpSettings* settings = context->settings; BOOL ret = FALSE; - xf_lock_x11(xfc, TRUE); + xf_lock_x11(xfc); if (!gdi_resize(gdi, settings->DesktopWidth, settings->DesktopHeight)) goto out; @@ -371,9 +391,9 @@ static BOOL xf_sw_desktop_resize(rdpContext* context) XDestroyImage(xfc->image); } - if (!(xfc->image = XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, - 0, (char*)gdi->primary_buffer, gdi->width, - gdi->height, xfc->scanline_pad, gdi->stride))) + if (!(xfc->image = XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0, + (char*)gdi->primary_buffer, gdi->width, gdi->height, + xfc->scanline_pad, gdi->stride))) { goto out; } @@ -382,7 +402,7 @@ static BOOL xf_sw_desktop_resize(rdpContext* context) xfc->image->bitmap_bit_order = LSBFirst; ret = xf_desktop_resize(context); out: - xf_unlock_x11(xfc, TRUE); + xf_unlock_x11(xfc); return ret; } @@ -390,7 +410,7 @@ static BOOL xf_hw_end_paint(rdpContext* context) { INT32 x, y; UINT32 w, h; - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; if (xfc->context.gdi->suppressOutput) return TRUE; @@ -406,9 +426,9 @@ static BOOL xf_hw_end_paint(rdpContext* context) y = xfc->hdc->hwnd->invalid->y; w = xfc->hdc->hwnd->invalid->w; h = xfc->hdc->hwnd->invalid->h; - xf_lock_x11(xfc, FALSE); + xf_lock_x11(xfc); xf_draw_screen(xfc, x, y, w, h); - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); } else { @@ -421,7 +441,7 @@ static BOOL xf_hw_end_paint(rdpContext* context) ninvalid = xfc->hdc->hwnd->ninvalid; cinvalid = xfc->hdc->hwnd->cinvalid; - xf_lock_x11(xfc, FALSE); + xf_lock_x11(xfc); for (i = 0; i < ninvalid; i++) { @@ -433,7 +453,7 @@ static BOOL xf_hw_end_paint(rdpContext* context) } XFlush(xfc->display); - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); } } else @@ -445,9 +465,9 @@ static BOOL xf_hw_end_paint(rdpContext* context) y = xfc->hdc->hwnd->invalid->y; w = xfc->hdc->hwnd->invalid->w; h = xfc->hdc->hwnd->invalid->h; - xf_lock_x11(xfc, FALSE); + xf_lock_x11(xfc); xf_rail_paint(xfc, x, y, x + w, y + h); - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); } xfc->hdc->hwnd->invalid->null = TRUE; @@ -458,17 +478,17 @@ static BOOL xf_hw_end_paint(rdpContext* context) static BOOL xf_hw_desktop_resize(rdpContext* context) { rdpGdi* gdi = context->gdi; - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; rdpSettings* settings = context->settings; BOOL ret = FALSE; - xf_lock_x11(xfc, TRUE); + xf_lock_x11(xfc); if (!gdi_resize(gdi, settings->DesktopWidth, settings->DesktopHeight)) goto out; ret = xf_desktop_resize(context); out: - xf_unlock_x11(xfc, TRUE); + xf_unlock_x11(xfc); return ret; } @@ -477,30 +497,61 @@ static BOOL xf_process_x_events(freerdp* instance) BOOL status; XEvent xevent; int pending_status; - xfContext* xfc = (xfContext*) instance->context; + xfContext* xfc = (xfContext*)instance->context; status = TRUE; pending_status = TRUE; while (pending_status) { - xf_lock_x11(xfc, FALSE); + xf_lock_x11(xfc); pending_status = XPending(xfc->display); - xf_unlock_x11(xfc, FALSE); if (pending_status) { ZeroMemory(&xevent, sizeof(xevent)); XNextEvent(xfc->display, &xevent); status = xf_event_process(instance, &xevent); - - if (!status) - return status; } + xf_unlock_x11(xfc); + if (!status) + break; } 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); + /* Just assume a window title is never longer than a filename... */ + size = strnlen(name, MAX_PATH) + 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 +583,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 @@ -605,8 +629,7 @@ BOOL xf_create_window(xfContext* xfc) xfc->gc = XCreateGC(xfc->display, xfc->drawable, GCGraphicsExposures, &gcv); if (!xfc->primary) - xfc->primary = XCreatePixmap(xfc->display, xfc->drawable, - settings->DesktopWidth, + xfc->primary = XCreatePixmap(xfc->display, xfc->drawable, settings->DesktopWidth, settings->DesktopHeight, xfc->depth); xfc->drawing = xfc->primary; @@ -615,25 +638,21 @@ BOOL xf_create_window(xfContext* xfc) xfc->bitmap_mono = XCreatePixmap(xfc->display, xfc->drawable, 8, 8, 1); if (!xfc->gc_mono) - xfc->gc_mono = XCreateGC(xfc->display, xfc->bitmap_mono, GCGraphicsExposures, - &gcv); + xfc->gc_mono = XCreateGC(xfc->display, xfc->bitmap_mono, GCGraphicsExposures, &gcv); XSetFunction(xfc->display, xfc->gc, GXcopy); XSetFillStyle(xfc->display, xfc->gc, FillSolid); XSetForeground(xfc->display, xfc->gc, BlackPixelOfScreen(xfc->screen)); - XFillRectangle(xfc->display, xfc->primary, xfc->gc, 0, 0, - settings->DesktopWidth, + XFillRectangle(xfc->display, xfc->primary, xfc->gc, 0, 0, settings->DesktopWidth, settings->DesktopHeight); XFlush(xfc->display); if (!xfc->image) { rdpGdi* gdi = xfc->context.gdi; - xfc->image = XCreateImage(xfc->display, xfc->visual, - xfc->depth, - ZPixmap, 0, (char*) gdi->primary_buffer, - settings->DesktopWidth, settings->DesktopHeight, - xfc->scanline_pad, gdi->stride); + xfc->image = XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0, + (char*)gdi->primary_buffer, settings->DesktopWidth, + settings->DesktopHeight, xfc->scanline_pad, gdi->stride); xfc->image->byte_order = LSBFirst; xfc->image->bitmap_bit_order = LSBFirst; } @@ -655,11 +674,13 @@ static void xf_window_free(xfContext* xfc) xfc->hdc = NULL; } +#if defined(CHANNEL_TSMF_CLIENT) if (xfc->xv_context) { xf_tsmf_uninit(xfc, NULL); xfc->xv_context = NULL; } +#endif if (xfc->image) { @@ -702,7 +723,7 @@ static void xf_window_free(xfContext* xfc) void xf_toggle_fullscreen(xfContext* xfc) { WindowStateChangeEventArgs e; - rdpContext* context = (rdpContext*) xfc; + rdpContext* context = (rdpContext*)xfc; rdpSettings* settings = context->settings; /* @@ -722,14 +743,14 @@ void xf_toggle_fullscreen(xfContext* xfc) PubSub_OnWindowStateChange(context->pubSub, context, &e); } -void xf_toggle_control(xfContext* xfc) +BOOL xf_toggle_control(xfContext* xfc) { EncomspClientContext* encomsp; ENCOMSP_CHANGE_PARTICIPANT_CONTROL_LEVEL_PDU pdu; encomsp = xfc->encomsp; if (!encomsp) - return; + return FALSE; pdu.ParticipantId = 0; pdu.Flags = ENCOMSP_REQUEST_VIEW; @@ -739,6 +760,7 @@ void xf_toggle_control(xfContext* xfc) encomsp->ChangeParticipantControlLevel(encomsp, &pdu); xfc->controlToggle = !xfc->controlToggle; + return TRUE; } /** @@ -746,48 +768,69 @@ void xf_toggle_control(xfContext* xfc) * * @return 0 on success, otherwise a Win32 error code */ -static UINT xf_encomsp_participant_created(EncomspClientContext* context, - ENCOMSP_PARTICIPANT_CREATED_PDU* participantCreated) +static UINT +xf_encomsp_participant_created(EncomspClientContext* context, + const ENCOMSP_PARTICIPANT_CREATED_PDU* participantCreated) { + xfContext* xfc; + rdpSettings* settings; + BOOL request; + + if (!context || !context->custom || !participantCreated) + return ERROR_INVALID_PARAMETER; + + xfc = context->custom; + settings = xfc->context.settings; + + if (!settings) + return ERROR_INVALID_PARAMETER; + + request = freerdp_settings_get_bool(settings, FreeRDP_RemoteAssistanceRequestControl); + if (request && (participantCreated->Flags & ENCOMSP_MAY_VIEW) && + !(participantCreated->Flags & ENCOMSP_MAY_INTERACT)) + xf_toggle_control(xfc); + return CHANNEL_RC_OK; } void xf_encomsp_init(xfContext* xfc, EncomspClientContext* encomsp) { xfc->encomsp = encomsp; - encomsp->custom = (void*) xfc; + encomsp->custom = (void*)xfc; encomsp->ParticipantCreated = xf_encomsp_participant_created; } void xf_encomsp_uninit(xfContext* xfc, EncomspClientContext* encomsp) { + WINPR_UNUSED(encomsp); xfc->encomsp = NULL; } -void xf_lock_x11(xfContext* xfc, BOOL display) +void xf_lock_x11_(xfContext* xfc, const char* fkt) { + if (!xfc->UseXThreads) - { WaitForSingleObject(xfc->mutex, INFINITE); - } else - { - if (display) - XLockDisplay(xfc->display); - } + XLockDisplay(xfc->display); + + if (xfc->locked) + WLog_WARN(TAG, "%s:\t[%" PRIu32 "] recursive lock from %s", __FUNCTION__, xfc->locked, fkt); + xfc->locked++; + WLog_VRB(TAG, "%s:\t[%" PRIu32 "] from %s", __FUNCTION__, xfc->locked, fkt); } -void xf_unlock_x11(xfContext* xfc, BOOL display) +void xf_unlock_x11_(xfContext* xfc, const char* fkt) { + if (xfc->locked == 0) + WLog_WARN(TAG, "X11: trying to unlock although not locked!"); + + WLog_VRB(TAG, "%s:\t[%" PRIu32 "] from %s", __FUNCTION__, xfc->locked - 1, fkt); if (!xfc->UseXThreads) - { ReleaseMutex(xfc->mutex); - } else - { - if (display) - XUnlockDisplay(xfc->display); - } + XUnlockDisplay(xfc->display); + xfc->locked--; } static BOOL xf_get_pixmap_info(xfContext* xfc) @@ -826,15 +869,14 @@ static BOOL xf_get_pixmap_info(xfContext* xfc) tpl.class = TrueColor; tpl.screen = xfc->screen_number; - if (XGetWindowAttributes(xfc->display, RootWindowOfScreen(xfc->screen), - &window_attributes) == 0) + if (XGetWindowAttributes(xfc->display, RootWindowOfScreen(xfc->screen), &window_attributes) == + 0) { WLog_ERR(TAG, "XGetWindowAttributes failed"); return FALSE; } - vis = XGetVisualInfo(xfc->display, VisualClassMask | VisualScreenMask, - &tpl, &vi_count); + vis = XGetVisualInfo(xfc->display, VisualClassMask | VisualScreenMask, &tpl, &vi_count); if (!vis) { @@ -902,10 +944,10 @@ static int _xf_error_handler(Display* d, XErrorEvent* ev) return xf_error_handler(d, ev); } -static BOOL xf_play_sound(rdpContext* context, - const PLAY_SOUND_UPDATE* play_sound) +static BOOL xf_play_sound(rdpContext* context, const PLAY_SOUND_UPDATE* play_sound) { - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; + WINPR_UNUSED(play_sound); XkbBell(xfc->display, None, 100, 0); return TRUE; } @@ -916,9 +958,9 @@ static void xf_check_extensions(xfContext* context) int xkb_major = XkbMajorVersion; int xkb_minor = XkbMinorVersion; - if (XkbLibraryVersion(&xkb_major, &xkb_minor) - && XkbQueryExtension(context->display, &xkb_opcode, &xkb_event, - &xkb_error, &xkb_major, &xkb_minor)) + if (XkbLibraryVersion(&xkb_major, &xkb_minor) && + XkbQueryExtension(context->display, &xkb_opcode, &xkb_event, &xkb_error, &xkb_major, + &xkb_minor)) { context->xkbAvailable = TRUE; } @@ -928,8 +970,7 @@ static void xf_check_extensions(xfContext* context) int xrender_event_base; int xrender_error_base; - if (XRenderQueryExtension(context->display, &xrender_event_base, - &xrender_error_base)) + if (XRenderQueryExtension(context->display, &xrender_event_base, &xrender_error_base)) { context->xrenderAvailable = TRUE; } @@ -940,18 +981,14 @@ static void xf_check_extensions(xfContext* context) #ifdef WITH_XI /* Input device which does NOT have the correct mapping. We must disregard */ /* this device when trying to find the input device which is the pointer. */ -static const char TEST_PTR_STR [] = "Virtual core XTEST pointer"; +static const char TEST_PTR_STR[] = "Virtual core XTEST pointer"; static const size_t TEST_PTR_LEN = sizeof(TEST_PTR_STR) / sizeof(char); - -/* Invalid device identifier which indicate failure. */ -static const int INVALID_XID = -1; #endif /* WITH_XI */ static void xf_get_x11_button_map(xfContext* xfc, unsigned char* x11_map) { #ifdef WITH_XI int opcode, event, error; - int xid; XDevice* ptr_dev; XExtensionVersion* version; XDeviceInfo* devices1; @@ -961,7 +998,7 @@ static void xf_get_x11_button_map(xfContext* xfc, unsigned char* x11_map) if (XQueryExtension(xfc->display, "XInputExtension", &opcode, &event, &error)) { WLog_DBG(TAG, "Searching for XInput pointer device"); - xid = INVALID_XID; + ptr_dev = NULL; /* loop through every device, looking for a pointer */ version = XGetExtensionVersion(xfc->display, INAME); @@ -977,8 +1014,9 @@ static void xf_get_x11_button_map(xfContext* xfc, unsigned char* x11_map) if ((devices2[i].use == XISlavePointer) && (strncmp(devices2[i].name, TEST_PTR_STR, TEST_PTR_LEN) != 0)) { - xid = devices2[i].deviceid; - break; + ptr_dev = XOpenDevice(xfc->display, devices2[i].deviceid); + if (ptr_dev) + break; } } @@ -997,8 +1035,9 @@ static void xf_get_x11_button_map(xfContext* xfc, unsigned char* x11_map) if ((devices1[i].use == IsXExtensionPointer) && (strncmp(devices1[i].name, TEST_PTR_STR, TEST_PTR_LEN) != 0)) { - xid = devices1[i].id; - break; + ptr_dev = XOpenDevice(xfc->display, devices1[i].id); + if (ptr_dev) + break; } } @@ -1010,10 +1049,9 @@ static void xf_get_x11_button_map(xfContext* xfc, unsigned char* x11_map) /* get button mapping from input extension if there is a pointer device; */ /* otherwise leave unchanged. */ - if (xid != INVALID_XID) + if (ptr_dev) { - WLog_DBG(TAG, "Pointer device: %d", xid); - ptr_dev = XOpenDevice(xfc->display, xid); + WLog_DBG(TAG, "Pointer device: %d", ptr_dev->device_id); XGetDeviceButtonMapping(xfc->display, ptr_dev, x11_map, NUM_BUTTONS_MAPPED); XCloseDevice(xfc->display, ptr_dev); } @@ -1032,29 +1070,57 @@ 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] = -{ - PTR_FLAGS_BUTTON1, - PTR_FLAGS_BUTTON3, - PTR_FLAGS_BUTTON2 +static const button_map xf_button_flags[NUM_BUTTONS_MAPPED] = { + { 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) + if (xfc->context.settings->UnmapButtons) { xf_get_x11_button_map(xfc, x11_map); } @@ -1062,71 +1128,51 @@ 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 = logical; + map->flags = get_flags_for_button(physical + Button1); + } } } } /** -* Callback given to freerdp_connect() to process the pre-connect operations. -* It will fill the rdp_freerdp structure (instance) with the appropriate options to use for the connection. -* -* @param instance - pointer to the rdp_freerdp structure that contains the connection's parameters, and will -* be filled with the appropriate informations. -* -* @return TRUE if successful. FALSE otherwise. -* Can exit with error code XF_EXIT_PARSE_ARGUMENTS if there is an error in the parameters. -*/ + * Callback given to freerdp_connect() to process the pre-connect operations. + * It will fill the rdp_freerdp structure (instance) with the appropriate options to use for the + * connection. + * + * @param instance - pointer to the rdp_freerdp structure that contains the connection's parameters, + * and will be filled with the appropriate informations. + * + * @return TRUE if successful. FALSE otherwise. + * Can exit with error code XF_EXIT_PARSE_ARGUMENTS if there is an error in the parameters. + */ static BOOL xf_pre_connect(freerdp* instance) { rdpChannels* channels; rdpSettings* settings; rdpContext* context = instance->context; - xfContext* xfc = (xfContext*) instance->context; + xfContext* xfc = (xfContext*)instance->context; UINT32 maxWidth = 0; UINT32 maxHeight = 0; settings = instance->settings; 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_SubscribeChannelConnected(instance->context->pubSub, xf_OnChannelConnectedEventHandler); PubSub_SubscribeChannelDisconnected(instance->context->pubSub, xf_OnChannelDisconnectedEventHandler); @@ -1135,9 +1181,16 @@ static BOOL xf_pre_connect(freerdp* instance) if (!settings->Username && !settings->CredentialsFromStdin && !settings->SmartcardLogon) { - char* login_name = getlogin(); + int rc; + char login_name[MAX_PATH] = { 0 }; - if (login_name) +#ifdef HAVE_GETLOGIN_R + rc = getlogin_r(login_name, sizeof(login_name)); +#else + strncpy(login_name, getlogin(), sizeof(login_name)); + rc = 0; +#endif + if (rc == 0) { settings->Username = _strdup(login_name); @@ -1177,8 +1230,8 @@ static BOOL xf_pre_connect(freerdp* instance) * If /f is specified in combination with /smart-sizing:widthxheight then * we run the session in the /smart-sizing dimensions scaled to full screen */ - if (settings->Fullscreen && settings->SmartSizing && - settings->SmartSizingWidth && settings->SmartSizingHeight) + if (settings->Fullscreen && settings->SmartSizing && settings->SmartSizingWidth && + settings->SmartSizingHeight) { settings->DesktopWidth = settings->SmartSizingWidth; settings->DesktopHeight = settings->SmartSizingHeight; @@ -1189,23 +1242,22 @@ 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; } /** -* Callback given to freerdp_connect() to perform post-connection operations. -* It will be called only if the connection was initialized properly, and will continue the initialization based on the -* newly created connection. -*/ + * Callback given to freerdp_connect() to perform post-connection operations. + * It will be called only if the connection was initialized properly, and will continue the + * initialization based on the newly created connection. + */ static BOOL xf_post_connect(freerdp* instance) { rdpUpdate* update; rdpContext* context; rdpSettings* settings; ResizeWindowEventArgs e; - xfContext* xfc = (xfContext*) instance->context; + xfContext* xfc = (xfContext*)instance->context; context = instance->context; settings = instance->settings; update = context->update; @@ -1303,7 +1355,7 @@ static void xf_post_disconnect(freerdp* instance) return; context = instance->context; - xfc = (xfContext*) context; + xfc = (xfContext*)context; PubSub_UnsubscribeChannelConnected(instance->context->pubSub, xf_OnChannelConnectedEventHandler); PubSub_UnsubscribeChannelDisconnected(instance->context->pubSub, @@ -1333,7 +1385,7 @@ static void xf_post_disconnect(freerdp* instance) static int xf_logon_error_info(freerdp* instance, UINT32 data, UINT32 type) { - xfContext* xfc = (xfContext*) instance->context; + xfContext* xfc = (xfContext*)instance->context; const char* str_data = freerdp_get_logon_error_info_data(data); const char* str_type = freerdp_get_logon_error_info_type(type); WLog_INFO(TAG, "Logon Error Info %s [%s]", str_data, str_type); @@ -1352,8 +1404,8 @@ static DWORD WINAPI xf_input_thread(LPVOID arg) wMessageQueue* queue; int pending_status = 1; int process_status = 1; - freerdp* instance = (freerdp*) arg; - xfContext* xfc = (xfContext*) instance->context; + freerdp* instance = (freerdp*)arg; + xfContext* xfc = (xfContext*)instance->context; queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE); nCount = 0; events[nCount++] = MessageQueue_Event(queue); @@ -1382,23 +1434,22 @@ static DWORD WINAPI xf_input_thread(LPVOID arg) { do { - xf_lock_x11(xfc, FALSE); + xf_lock_x11(xfc); pending_status = XPending(xfc->display); - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); if (pending_status) { - xf_lock_x11(xfc, FALSE); + xf_lock_x11(xfc); ZeroMemory(&xevent, sizeof(xevent)); XNextEvent(xfc->display, &xevent); process_status = xf_event_process(instance, &xevent); - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); if (!process_status) break; } - } - while (pending_status); + } while (pending_status); if (!process_status) { @@ -1445,12 +1496,12 @@ static BOOL handle_window_events(freerdp* instance) } /** Main loop for the rdp connection. -* It will be run from the thread's entry point (thread_func()). -* It initiates the connection, and will continue to run until the session ends, -* processing events as they are received. -* @param instance - pointer to the rdp_freerdp structure that contains the session's settings -* @return A code from the enum XF_EXIT_CODE (0 if successful) -*/ + * It will be run from the thread's entry point (thread_func()). + * It initiates the connection, and will continue to run until the session ends, + * processing events as they are received. + * @param instance - pointer to the rdp_freerdp structure that contains the session's settings + * @return A code from the enum XF_EXIT_CODE (0 if successful) + */ static DWORD WINAPI xf_client_thread(LPVOID param) { BOOL status; @@ -1468,17 +1519,17 @@ static DWORD WINAPI xf_client_thread(LPVOID param) rdpSettings* settings; TimerEventArgs timerEvent; EventArgsInit(&timerEvent, "xfreerdp"); - instance = (freerdp*) param; + instance = (freerdp*)param; context = instance->context; status = freerdp_connect(instance); - xfc = (xfContext*) instance->context; + xfc = (xfContext*)instance->context; if (!status) { - if (freerdp_get_last_error(instance->context) == - FREERDP_ERROR_AUTHENTICATION_FAILED) + if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_AUTHENTICATION_FAILED) exit_code = XF_EXIT_AUTH_FAILURE; - else if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED) + else if (freerdp_get_last_error(instance->context) == + FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED) exit_code = XF_EXIT_NEGO_FAILURE; else exit_code = XF_EXIT_CONN_FAILED; @@ -1492,17 +1543,16 @@ static DWORD WINAPI xf_client_thread(LPVOID param) /* --authonly ? */ if (instance->settings->AuthenticationOnly) { - WLog_ERR(TAG, "Authentication only, exit status %"PRId32"", !status); + WLog_ERR(TAG, "Authentication only, exit status %" PRId32 "", !status); goto disconnect; } if (!status) { - WLog_ERR(TAG, "Freerdp connect error exit status %"PRId32"", !status); + WLog_ERR(TAG, "Freerdp connect error exit status %" PRId32 "", !status); exit_code = freerdp_error_info(instance); - if (freerdp_get_last_error(instance->context) == - FREERDP_ERROR_AUTHENTICATION_FAILED) + if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_AUTHENTICATION_FAILED) exit_code = XF_EXIT_AUTH_FAILURE; else if (exit_code == ERRINFO_SUCCESS) exit_code = XF_EXIT_CONN_FAILED; @@ -1560,7 +1610,8 @@ static DWORD WINAPI xf_client_thread(LPVOID param) } { - DWORD tmp = freerdp_get_event_handles(context, &handles[nCount], ARRAYSIZE(handles) - nCount); + DWORD tmp = + freerdp_get_event_handles(context, &handles[nCount], ARRAYSIZE(handles) - nCount); if (tmp == 0) { @@ -1571,8 +1622,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); @@ -1625,8 +1676,8 @@ static DWORD WINAPI xf_client_thread(LPVOID param) freerdp_get_disconnect_ultimatum(context) == Disconnect_Ultimatum_user_requested) { /* This situation might be limited to Windows XP. */ - WLog_INFO(TAG, - "Error info says user did not initiate but disconnect ultimatum says they did; treat this as a user logoff"); + WLog_INFO(TAG, "Error info says user did not initiate but disconnect ultimatum says " + "they did; treat this as a user logoff"); exit_code = XF_EXIT_LOGOFF; } } @@ -1644,8 +1695,7 @@ end: DWORD xf_exit_code_from_disconnect_reason(DWORD reason) { - if (reason == 0 || (reason >= XF_EXIT_PARSE_ARGUMENTS - && reason <= XF_EXIT_NEGO_FAILURE)) + if (reason == 0 || (reason >= XF_EXIT_PARSE_ARGUMENTS && reason <= XF_EXIT_NEGO_FAILURE)) return reason; /* License error set */ else if (reason >= 0x100 && reason <= 0x10A) @@ -1663,14 +1713,14 @@ DWORD xf_exit_code_from_disconnect_reason(DWORD reason) static void xf_TerminateEventHandler(void* context, TerminateEventArgs* e) { rdpContext* ctx = (rdpContext*)context; + WINPR_UNUSED(e); freerdp_abort_connect(ctx->instance); } #ifdef WITH_XRENDER -static void xf_ZoomingChangeEventHandler(void* context, - ZoomingChangeEventArgs* e) +static void xf_ZoomingChangeEventHandler(void* context, ZoomingChangeEventArgs* e) { - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; rdpSettings* settings = xfc->context.settings; int w = xfc->scaledWidth + e->dx; int h = xfc->scaledHeight + e->dy; @@ -1692,10 +1742,9 @@ static void xf_ZoomingChangeEventHandler(void* context, xf_draw_screen(xfc, 0, 0, settings->DesktopWidth, settings->DesktopHeight); } -static void xf_PanningChangeEventHandler(void* context, - PanningChangeEventArgs* e) +static void xf_PanningChangeEventHandler(void* context, PanningChangeEventArgs* e) { - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; rdpSettings* settings = xfc->context.settings; if (e->dx == 0 && e->dy == 0) @@ -1708,8 +1757,8 @@ static void xf_PanningChangeEventHandler(void* context, #endif /** -* Client Interface -*/ + * Client Interface + */ static BOOL xfreerdp_client_global_init() { @@ -1727,18 +1776,16 @@ static void xfreerdp_client_global_uninit() static int xfreerdp_client_start(rdpContext* context) { - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; rdpSettings* settings = context->settings; if (!settings->ServerHostname) { - WLog_ERR(TAG, - "error: server hostname was not specified with /v:[:port]"); + WLog_ERR(TAG, "error: server hostname was not specified with /v:[:port]"); return -1; } - if (!(xfc->thread = CreateThread(NULL, 0, xf_client_thread, - context->instance, 0, NULL))) + if (!(xfc->thread = CreateThread(NULL, 0, xf_client_thread, context->instance, 0, NULL))) { WLog_ERR(TAG, "failed to create client thread"); return -1; @@ -1749,7 +1796,7 @@ static int xfreerdp_client_start(rdpContext* context) static int xfreerdp_client_stop(rdpContext* context) { - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; freerdp_abort_connect(context->instance); if (xfc->thread) @@ -1767,7 +1814,7 @@ static Atom get_supported_atom(xfContext* xfc, const char* atomName) unsigned long i; const Atom atom = XInternAtom(xfc->display, atomName, False); - for (i = 0; i < xfc->supportedAtomCount; i++) + for (i = 0; i < xfc->supportedAtomCount; i++) { if (xfc->supportedAtoms[i] == atom) return atom; @@ -1777,7 +1824,7 @@ static Atom get_supported_atom(xfContext* xfc, const char* atomName) } static BOOL xfreerdp_client_new(freerdp* instance, rdpContext* context) { - xfContext* xfc = (xfContext*) instance->context; + xfContext* xfc = (xfContext*)instance->context; assert(context); assert(xfc); assert(!xfc->display); @@ -1788,16 +1835,13 @@ 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); + PubSub_SubscribeTerminate(context->pubSub, xf_TerminateEventHandler); #ifdef WITH_XRENDER - PubSub_SubscribeZoomingChange(context->pubSub, - xf_ZoomingChangeEventHandler); - PubSub_SubscribePanningChange(context->pubSub, - xf_PanningChangeEventHandler); + PubSub_SubscribeZoomingChange(context->pubSub, xf_ZoomingChangeEventHandler); + PubSub_SubscribePanningChange(context->pubSub, xf_PanningChangeEventHandler); #endif xfc->UseXThreads = TRUE; /* uncomment below if debugging to prevent keyboard grap */ @@ -1817,8 +1861,7 @@ static BOOL xfreerdp_client_new(freerdp* instance, rdpContext* context) if (!xfc->display) { WLog_ERR(TAG, "failed to open display: %s", XDisplayName(NULL)); - WLog_ERR(TAG, - "Please check that the $DISPLAY environment variable is properly set."); + WLog_ERR(TAG, "Please check that the $DISPLAY environment variable is properly set."); goto fail_open_display; } @@ -1847,8 +1890,8 @@ static BOOL xfreerdp_client_new(freerdp* instance, rdpContext* context) unsigned long nitems, after; unsigned char* data = NULL; int status = XGetWindowProperty(xfc->display, RootWindowOfScreen(xfc->screen), - xfc->_NET_SUPPORTED, 0, 1024, False, XA_ATOM, - &actual_type, &actual_format, &nitems, &after, &data); + xfc->_NET_SUPPORTED, 0, 1024, False, XA_ATOM, &actual_type, + &actual_format, &nitems, &after, &data); if ((status == Success) && (actual_type == XA_ATOM) && (actual_format == 32)) { @@ -1863,46 +1906,39 @@ static BOOL xfreerdp_client_new(freerdp* instance, rdpContext* context) xfc->_NET_WM_ICON = XInternAtom(xfc->display, "_NET_WM_ICON", False); xfc->_MOTIF_WM_HINTS = XInternAtom(xfc->display, "_MOTIF_WM_HINTS", False); - xfc->_NET_CURRENT_DESKTOP = XInternAtom(xfc->display, "_NET_CURRENT_DESKTOP", - False); + xfc->_NET_CURRENT_DESKTOP = XInternAtom(xfc->display, "_NET_CURRENT_DESKTOP", False); xfc->_NET_WORKAREA = XInternAtom(xfc->display, "_NET_WORKAREA", False); xfc->_NET_WM_STATE = get_supported_atom(xfc, "_NET_WM_STATE"); xfc->_NET_WM_STATE_FULLSCREEN = get_supported_atom(xfc, "_NET_WM_STATE_FULLSCREEN"); - xfc->_NET_WM_STATE_MAXIMIZED_HORZ = XInternAtom(xfc->display, - "_NET_WM_STATE_MAXIMIZED_HORZ", False); - xfc->_NET_WM_STATE_MAXIMIZED_VERT = XInternAtom(xfc->display, - "_NET_WM_STATE_MAXIMIZED_VERT", False); + xfc->_NET_WM_STATE_MAXIMIZED_HORZ = + XInternAtom(xfc->display, "_NET_WM_STATE_MAXIMIZED_HORZ", False); + xfc->_NET_WM_STATE_MAXIMIZED_VERT = + XInternAtom(xfc->display, "_NET_WM_STATE_MAXIMIZED_VERT", False); xfc->_NET_WM_FULLSCREEN_MONITORS = get_supported_atom(xfc, "_NET_WM_FULLSCREEN_MONITORS"); xfc->_NET_WM_NAME = XInternAtom(xfc->display, "_NET_WM_NAME", False); xfc->_NET_WM_PID = XInternAtom(xfc->display, "_NET_WM_PID", False); - xfc->_NET_WM_WINDOW_TYPE = XInternAtom(xfc->display, "_NET_WM_WINDOW_TYPE", - False); - xfc->_NET_WM_WINDOW_TYPE_NORMAL = XInternAtom(xfc->display, - "_NET_WM_WINDOW_TYPE_NORMAL", False); - xfc->_NET_WM_WINDOW_TYPE_DIALOG = XInternAtom(xfc->display, - "_NET_WM_WINDOW_TYPE_DIALOG", False); - 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); - 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, - "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", False); - xfc->_NET_WM_STATE_SKIP_TASKBAR = XInternAtom(xfc->display, - "_NET_WM_STATE_SKIP_TASKBAR", False); - xfc->_NET_WM_STATE_SKIP_PAGER = XInternAtom(xfc->display, - "_NET_WM_STATE_SKIP_PAGER", False); - xfc->_NET_WM_MOVERESIZE = XInternAtom(xfc->display, "_NET_WM_MOVERESIZE", - False); - xfc->_NET_MOVERESIZE_WINDOW = XInternAtom(xfc->display, - "_NET_MOVERESIZE_WINDOW", False); + xfc->_NET_WM_WINDOW_TYPE = XInternAtom(xfc->display, "_NET_WM_WINDOW_TYPE", False); + xfc->_NET_WM_WINDOW_TYPE_NORMAL = + XInternAtom(xfc->display, "_NET_WM_WINDOW_TYPE_NORMAL", False); + xfc->_NET_WM_WINDOW_TYPE_DIALOG = + XInternAtom(xfc->display, "_NET_WM_WINDOW_TYPE_DIALOG", False); + 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); + 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, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", False); + xfc->_NET_WM_STATE_SKIP_TASKBAR = + XInternAtom(xfc->display, "_NET_WM_STATE_SKIP_TASKBAR", False); + xfc->_NET_WM_STATE_SKIP_PAGER = XInternAtom(xfc->display, "_NET_WM_STATE_SKIP_PAGER", False); + xfc->_NET_WM_MOVERESIZE = XInternAtom(xfc->display, "_NET_WM_MOVERESIZE", False); + xfc->_NET_MOVERESIZE_WINDOW = XInternAtom(xfc->display, "_NET_MOVERESIZE_WINDOW", False); xfc->UTF8_STRING = XInternAtom(xfc->display, "UTF8_STRING", FALSE); xfc->WM_PROTOCOLS = XInternAtom(xfc->display, "WM_PROTOCOLS", False); xfc->WM_DELETE_WINDOW = XInternAtom(xfc->display, "WM_DELETE_WINDOW", False); xfc->WM_STATE = XInternAtom(xfc->display, "WM_STATE", False); - xfc->x11event = CreateFileDescriptorEvent(NULL, FALSE, FALSE, xfc->xfds, - WINPR_FD_READ); + xfc->x11event = CreateFileDescriptorEvent(NULL, FALSE, FALSE, xfc->xfds, WINPR_FD_READ); if (!xfc->x11event) { @@ -1949,18 +1985,15 @@ fail_open_display: static void xfreerdp_client_free(freerdp* instance, rdpContext* context) { - xfContext* xfc = (xfContext*) instance->context; + xfContext* xfc = (xfContext*)instance->context; if (!context) return; - PubSub_UnsubscribeTerminate(context->pubSub, - xf_TerminateEventHandler); + PubSub_UnsubscribeTerminate(context->pubSub, xf_TerminateEventHandler); #ifdef WITH_XRENDER - PubSub_UnsubscribeZoomingChange(context->pubSub, - xf_ZoomingChangeEventHandler); - PubSub_UnsubscribePanningChange(context->pubSub, - xf_PanningChangeEventHandler); + PubSub_UnsubscribeZoomingChange(context->pubSub, xf_ZoomingChangeEventHandler); + PubSub_UnsubscribePanningChange(context->pubSub, xf_PanningChangeEventHandler); #endif if (xfc->display) diff --git a/client/X11/xf_client.h b/client/X11/xf_client.h index 34535a1..e3b00bf 100644 --- a/client/X11/xf_client.h +++ b/client/X11/xf_client.h @@ -36,15 +36,15 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -/** - * Client Interface - */ - + /** + * Client Interface + */ -FREERDP_API int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints); + FREERDP_API int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints); #ifdef __cplusplus } diff --git a/client/X11/xf_cliprdr.c b/client/X11/xf_cliprdr.c index 1c86031..21017db 100644 --- a/client/X11/xf_cliprdr.c +++ b/client/X11/xf_cliprdr.c @@ -45,7 +45,7 @@ #define TAG CLIENT_TAG("x11") -#define MAX_CLIPBOARD_FORMATS 255 +#define MAX_CLIPBOARD_FORMATS 255 struct xf_cliprdr_format { @@ -89,7 +89,7 @@ struct xf_clipboard const char* data_format_name; int data_length; int data_raw_length; - XEvent* respond; + XSelectionEvent* respond; Window owner; BOOL sync; @@ -132,17 +132,15 @@ static void xf_cliprdr_check_owner(xfClipboard* clipboard) static BOOL xf_cliprdr_is_self_owned(xfClipboard* clipboard) { xfContext* xfc = clipboard->xfc; - return XGetSelectionOwner(xfc->display, - clipboard->clipboard_atom) == xfc->drawable; + return XGetSelectionOwner(xfc->display, clipboard->clipboard_atom) == xfc->drawable; } -static void xf_cliprdr_set_raw_transfer_enabled(xfClipboard* clipboard, - BOOL enabled) +static void xf_cliprdr_set_raw_transfer_enabled(xfClipboard* clipboard, BOOL enabled) { UINT32 data = enabled; xfContext* xfc = clipboard->xfc; - XChangeProperty(xfc->display, xfc->drawable, clipboard->raw_transfer_atom, - XA_INTEGER, 32, PropModeReplace, (BYTE*) &data, 1); + XChangeProperty(xfc->display, xfc->drawable, clipboard->raw_transfer_atom, XA_INTEGER, 32, + PropModeReplace, (BYTE*)&data, 1); } static BOOL xf_cliprdr_is_raw_transfer_available(xfClipboard* clipboard) @@ -160,9 +158,9 @@ static BOOL xf_cliprdr_is_raw_transfer_available(xfClipboard* clipboard) if (owner != None) { - result = XGetWindowProperty(xfc->display, owner, - clipboard->raw_transfer_atom, 0, 4, 0, XA_INTEGER, - &type, &format, &length, &bytes_left, (BYTE**) &data); + result = + XGetWindowProperty(xfc->display, owner, clipboard->raw_transfer_atom, 0, 4, 0, + XA_INTEGER, &type, &format, &length, &bytes_left, (BYTE**)&data); } if (data) @@ -180,14 +178,12 @@ static BOOL xf_cliprdr_is_raw_transfer_available(xfClipboard* clipboard) return is_enabled ? TRUE : FALSE; } -static BOOL xf_cliprdr_formats_equal(const CLIPRDR_FORMAT* server, - const xfCliprdrFormat* client) +static BOOL xf_cliprdr_formats_equal(const CLIPRDR_FORMAT* server, const xfCliprdrFormat* client) { if (server->formatName && client->formatName) { /* The server may be using short format names while we store them in full form. */ - return (0 == strncmp(server->formatName, client->formatName, - strlen(server->formatName))); + return (0 == strncmp(server->formatName, client->formatName, strlen(server->formatName))); } if (!server->formatName && !client->formatName) @@ -198,8 +194,7 @@ static BOOL xf_cliprdr_formats_equal(const CLIPRDR_FORMAT* server, return FALSE; } -static xfCliprdrFormat* xf_cliprdr_get_client_format_by_id( - xfClipboard* clipboard, UINT32 formatId) +static xfCliprdrFormat* xf_cliprdr_get_client_format_by_id(xfClipboard* clipboard, UINT32 formatId) { int index; xfCliprdrFormat* format; @@ -215,8 +210,7 @@ static xfCliprdrFormat* xf_cliprdr_get_client_format_by_id( return NULL; } -static xfCliprdrFormat* xf_cliprdr_get_client_format_by_atom( - xfClipboard* clipboard, Atom atom) +static xfCliprdrFormat* xf_cliprdr_get_client_format_by_atom(xfClipboard* clipboard, Atom atom) { int i; xfCliprdrFormat* format; @@ -232,8 +226,7 @@ static xfCliprdrFormat* xf_cliprdr_get_client_format_by_atom( return NULL; } -static CLIPRDR_FORMAT* xf_cliprdr_get_server_format_by_atom( - xfClipboard* clipboard, Atom atom) +static CLIPRDR_FORMAT* xf_cliprdr_get_server_format_by_atom(xfClipboard* clipboard, Atom atom) { int i, j; xfCliprdrFormat* client_format; @@ -263,14 +256,11 @@ static CLIPRDR_FORMAT* xf_cliprdr_get_server_format_by_atom( * * @return 0 on success, otherwise a Win32 error code */ -static UINT xf_cliprdr_send_data_request(xfClipboard* clipboard, - UINT32 formatId) +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); + return clipboard->context->ClientFormatDataRequest(clipboard->context, &request); } /** @@ -278,16 +268,13 @@ static UINT xf_cliprdr_send_data_request(xfClipboard* clipboard, * * @return 0 on success, otherwise a Win32 error code */ -static UINT xf_cliprdr_send_data_response(xfClipboard* clipboard, BYTE* data, - int size) +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; - return clipboard->context->ClientFormatDataResponse(clipboard->context, - &response); + return clipboard->context->ClientFormatDataResponse(clipboard->context, &response); } static wStream* xf_cliprdr_serialize_server_format_list(xfClipboard* clipboard) @@ -304,8 +291,7 @@ static wStream* xf_cliprdr_serialize_server_format_list(xfClipboard* clipboard) } /* If present, the last format is always synthetic CF_RAW. Do not include it. */ - formatCount = (clipboard->numServerFormats > 0) ? clipboard->numServerFormats - - 1 : 0; + formatCount = (clipboard->numServerFormats > 0) ? clipboard->numServerFormats - 1 : 0; Stream_Write_UINT32(s, formatCount); for (i = 0; i < formatCount; i++) @@ -334,8 +320,8 @@ error: return NULL; } -static CLIPRDR_FORMAT* xf_cliprdr_parse_server_format_list(BYTE* data, - size_t length, UINT32* numFormats) +static CLIPRDR_FORMAT* xf_cliprdr_parse_server_format_list(BYTE* data, size_t length, + UINT32* numFormats) { UINT32 i; wStream* s = NULL; @@ -357,11 +343,11 @@ static CLIPRDR_FORMAT* xf_cliprdr_parse_server_format_list(BYTE* data, if (*numFormats > MAX_CLIPBOARD_FORMATS) { - WLog_ERR(TAG, "unexpectedly large number of formats: %"PRIu32"", *numFormats); + WLog_ERR(TAG, "unexpectedly large number of formats: %" PRIu32 "", *numFormats); goto error; } - if (!(formats = (CLIPRDR_FORMAT*) calloc(*numFormats, sizeof(CLIPRDR_FORMAT)))) + if (!(formats = (CLIPRDR_FORMAT*)calloc(*numFormats, sizeof(CLIPRDR_FORMAT)))) { WLog_ERR(TAG, "failed to allocate format list"); goto error; @@ -379,12 +365,12 @@ static CLIPRDR_FORMAT* xf_cliprdr_parse_server_format_list(BYTE* data, } Stream_Read_UINT32(s, formats[i].formatId); - formatName = (const char*) Stream_Pointer(s); + formatName = (const char*)Stream_Pointer(s); formatNameLength = strnlen(formatName, Stream_GetRemainingLength(s)); if (formatNameLength == Stream_GetRemainingLength(s)) { - WLog_ERR(TAG, "missing terminating null byte, %"PRIuz" bytes left to read", + WLog_ERR(TAG, "missing terminating null byte, %" PRIuz " bytes left to read", formatNameLength); goto error; } @@ -414,8 +400,7 @@ static void xf_cliprdr_free_formats(CLIPRDR_FORMAT* formats, UINT32 numFormats) free(formats); } -static CLIPRDR_FORMAT* xf_cliprdr_get_raw_server_formats(xfClipboard* clipboard, - UINT32* numFormats) +static CLIPRDR_FORMAT* xf_cliprdr_get_raw_server_formats(xfClipboard* clipboard, UINT32* numFormats) { Atom type = None; int format = 0; @@ -425,22 +410,21 @@ static CLIPRDR_FORMAT* xf_cliprdr_get_raw_server_formats(xfClipboard* clipboard, CLIPRDR_FORMAT* formats = NULL; xfContext* xfc = clipboard->xfc; *numFormats = 0; - XGetWindowProperty(xfc->display, clipboard->owner, - clipboard->raw_format_list_atom, - 0, 4096, False, clipboard->raw_format_list_atom, &type, &format, - &length, &remaining, &data); + XGetWindowProperty(xfc->display, clipboard->owner, clipboard->raw_format_list_atom, 0, 4096, + False, clipboard->raw_format_list_atom, &type, &format, &length, &remaining, + &data); - if (data && length > 0 && format == 8 - && type == clipboard->raw_format_list_atom) + if (data && length > 0 && format == 8 && type == clipboard->raw_format_list_atom) { formats = xf_cliprdr_parse_server_format_list(data, length, numFormats); } else { WLog_ERR(TAG, - "failed to retrieve raw format list: data=%p, length=%lu, format=%d, type=%lu (expected=%lu)", - (void*) data, length, format, (unsigned long) type, - (unsigned long) clipboard->raw_format_list_atom); + "failed to retrieve raw format list: data=%p, length=%lu, format=%d, type=%lu " + "(expected=%lu)", + (void*)data, length, format, (unsigned long)type, + (unsigned long)clipboard->raw_format_list_atom); } if (data) @@ -449,10 +433,10 @@ static CLIPRDR_FORMAT* xf_cliprdr_get_raw_server_formats(xfClipboard* clipboard, return formats; } -static CLIPRDR_FORMAT* xf_cliprdr_get_formats_from_targets( - xfClipboard* clipboard, UINT32* numFormats) +static CLIPRDR_FORMAT* xf_cliprdr_get_formats_from_targets(xfClipboard* clipboard, + UINT32* numFormats) { - int i; + unsigned long i; Atom atom; BYTE* data = NULL; int format_property; @@ -462,8 +446,8 @@ static CLIPRDR_FORMAT* xf_cliprdr_get_formats_from_targets( CLIPRDR_FORMAT* formats = NULL; xfContext* xfc = clipboard->xfc; *numFormats = 0; - XGetWindowProperty(xfc->display, xfc->drawable, clipboard->property_atom, - 0, 200, 0, XA_ATOM, &atom, &format_property, &length, &bytes_left, &data); + XGetWindowProperty(xfc->display, xfc->drawable, clipboard->property_atom, 0, 200, 0, XA_ATOM, + &atom, &format_property, &length, &bytes_left, &data); if (length > 0) { @@ -473,7 +457,7 @@ static CLIPRDR_FORMAT* xf_cliprdr_get_formats_from_targets( goto out; } - if (!(formats = (CLIPRDR_FORMAT*) calloc(length, sizeof(CLIPRDR_FORMAT)))) + if (!(formats = (CLIPRDR_FORMAT*)calloc(length, sizeof(CLIPRDR_FORMAT)))) { WLog_ERR(TAG, "failed to allocate %lu CLIPRDR_FORMAT structs", length); goto out; @@ -482,7 +466,7 @@ static CLIPRDR_FORMAT* xf_cliprdr_get_formats_from_targets( for (i = 0; i < length; i++) { - atom = ((Atom*) data)[i]; + atom = ((Atom*)data)[i]; format = xf_cliprdr_get_client_format_by_atom(clipboard, atom); if (format) @@ -501,8 +485,7 @@ out: return formats; } -static CLIPRDR_FORMAT* xf_cliprdr_get_client_formats(xfClipboard* clipboard, - UINT32* numFormats) +static CLIPRDR_FORMAT* xf_cliprdr_get_client_formats(xfClipboard* clipboard, UINT32* numFormats) { CLIPRDR_FORMAT* formats = NULL; *numFormats = 0; @@ -530,8 +513,8 @@ static void xf_cliprdr_provide_server_format_list(xfClipboard* clipboard) if (formats) { XChangeProperty(xfc->display, xfc->drawable, clipboard->raw_format_list_atom, - clipboard->raw_format_list_atom, 8, PropModeReplace, - Stream_Buffer(formats), Stream_Length(formats)); + clipboard->raw_format_list_atom, 8, PropModeReplace, Stream_Buffer(formats), + Stream_Length(formats)); } else { @@ -545,18 +528,18 @@ 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; + formatList.msgType = CB_FORMAT_LIST; clipboard->context->ClientFormatList(clipboard->context, &formatList); xf_cliprdr_free_formats(formats, numFormats); } -static void xf_cliprdr_process_requested_data(xfClipboard* clipboard, - BOOL hasData, BYTE* data, int size) +static void xf_cliprdr_process_requested_data(xfClipboard* clipboard, BOOL hasData, BYTE* data, + int size) { BOOL bSuccess; UINT32 SrcSize; @@ -569,8 +552,7 @@ static void xf_cliprdr_process_requested_data(xfClipboard* clipboard, if (clipboard->incr_starts && hasData) return; - format = xf_cliprdr_get_client_format_by_id(clipboard, - clipboard->requestedFormatId); + format = xf_cliprdr_get_client_format_by_id(clipboard, clipboard->requestedFormatId); if (!hasData || !data || !format) { @@ -589,7 +571,7 @@ static void xf_cliprdr_process_requested_data(xfClipboard* clipboard, case CF_TEXT: case CF_OEMTEXT: case CF_UNICODETEXT: - size = strlen((char*) data) + 1; + size = strlen((char*)data) + 1; srcFormatId = ClipboardGetFormatId(clipboard->system, "UTF8_STRING"); break; @@ -606,7 +588,7 @@ static void xf_cliprdr_process_requested_data(xfClipboard* clipboard, break; } - SrcSize = (UINT32) size; + SrcSize = (UINT32)size; bSuccess = ClipboardSetData(clipboard->system, srcFormatId, data, SrcSize); if (format->formatName) @@ -617,7 +599,7 @@ static void xf_cliprdr_process_requested_data(xfClipboard* clipboard, if (bSuccess) { DstSize = 0; - pDstData = (BYTE*) ClipboardGetData(clipboard->system, dstFormatId, &DstSize); + pDstData = (BYTE*)ClipboardGetData(clipboard->system, dstFormatId, &DstSize); } if (!pDstData) @@ -637,7 +619,7 @@ static void xf_cliprdr_process_requested_data(xfClipboard* clipboard, (dstFormatId == ClipboardGetFormatId(clipboard->system, "FileGroupDescriptorW"))) { UINT error = NO_ERROR; - FILEDESCRIPTOR* file_array = (FILEDESCRIPTOR*) pDstData; + FILEDESCRIPTOR* file_array = (FILEDESCRIPTOR*)pDstData; UINT32 file_count = DstSize / sizeof(FILEDESCRIPTOR); pDstData = NULL; DstSize = 0; @@ -649,7 +631,7 @@ static void xf_cliprdr_process_requested_data(xfClipboard* clipboard, free(file_array); } - xf_cliprdr_send_data_response(clipboard, pDstData, (int) DstSize); + xf_cliprdr_send_data_response(clipboard, pDstData, (int)DstSize); free(pDstData); } @@ -664,8 +646,7 @@ static BOOL xf_cliprdr_get_requested_data(xfClipboard* clipboard, Atom target) unsigned long bytes_left; xfCliprdrFormat* format; xfContext* xfc = clipboard->xfc; - format = xf_cliprdr_get_client_format_by_id(clipboard, - clipboard->requestedFormatId); + format = xf_cliprdr_get_client_format_by_id(clipboard, clipboard->requestedFormatId); if (!format || (format->atom != target)) { @@ -673,8 +654,7 @@ static BOOL xf_cliprdr_get_requested_data(xfClipboard* clipboard, Atom target) return FALSE; } - XGetWindowProperty(xfc->display, xfc->drawable, - clipboard->property_atom, 0, 0, 0, target, + XGetWindowProperty(xfc->display, xfc->drawable, clipboard->property_atom, 0, 0, 0, target, &type, &format_property, &length, &bytes_left, &data); if (data) @@ -711,23 +691,22 @@ static BOOL xf_cliprdr_get_requested_data(xfClipboard* clipboard, Atom target) clipboard->incr_starts = 0; has_data = TRUE; } - else if (XGetWindowProperty(xfc->display, xfc->drawable, - clipboard->property_atom, 0, bytes_left, 0, target, - &type, &format_property, &length, &dummy, &data) == Success) + else if (XGetWindowProperty(xfc->display, xfc->drawable, clipboard->property_atom, 0, + bytes_left, 0, target, &type, &format_property, &length, &dummy, + &data) == Success) { if (clipboard->incr_starts) { BYTE* new_data; bytes_left = length * format_property / 8; - new_data = (BYTE*) realloc(clipboard->incr_data, - clipboard->incr_data_length + bytes_left); + new_data = + (BYTE*)realloc(clipboard->incr_data, clipboard->incr_data_length + bytes_left); if (!new_data) return FALSE; clipboard->incr_data = new_data; - CopyMemory(clipboard->incr_data + clipboard->incr_data_length, data, - bytes_left); + CopyMemory(clipboard->incr_data + clipboard->incr_data_length, data, bytes_left); clipboard->incr_data_length += bytes_left; XFree(data); data = NULL; @@ -741,7 +720,7 @@ static BOOL xf_cliprdr_get_requested_data(xfClipboard* clipboard, Atom target) } XDeleteProperty(xfc->display, xfc->drawable, clipboard->property_atom); - xf_cliprdr_process_requested_data(clipboard, has_data, data, (int) bytes_left); + xf_cliprdr_process_requested_data(clipboard, has_data, data, (int)bytes_left); if (data) XFree(data); @@ -753,7 +732,10 @@ static void xf_cliprdr_append_target(xfClipboard* clipboard, Atom target) { int i; - if (clipboard->numTargets >= ARRAYSIZE(clipboard->targets)) + if (clipboard->numTargets < 0) + return; + + if ((size_t)clipboard->numTargets >= ARRAYSIZE(clipboard->targets)) return; for (i = 0; i < clipboard->numTargets; i++) @@ -765,37 +747,35 @@ static void xf_cliprdr_append_target(xfClipboard* clipboard, Atom target) clipboard->targets[clipboard->numTargets++] = target; } -static void xf_cliprdr_provide_targets(xfClipboard* clipboard, XEvent* respond) +static void xf_cliprdr_provide_targets(xfClipboard* clipboard, const XSelectionEvent* respond) { xfContext* xfc = clipboard->xfc; - if (respond->xselection.property != None) + if (respond->property != None) { - XChangeProperty(xfc->display, respond->xselection.requestor, - respond->xselection.property, XA_ATOM, 32, PropModeReplace, - (BYTE*) clipboard->targets, clipboard->numTargets); + XChangeProperty(xfc->display, respond->requestor, respond->property, XA_ATOM, 32, + PropModeReplace, (BYTE*)clipboard->targets, clipboard->numTargets); } } -static void xf_cliprdr_provide_data(xfClipboard* clipboard, XEvent* respond, - BYTE* data, UINT32 size) +static void xf_cliprdr_provide_data(xfClipboard* clipboard, const XSelectionEvent* respond, + const BYTE* data, UINT32 size) { xfContext* xfc = clipboard->xfc; - if (respond->xselection.property != None) + if (respond->property != None) { - XChangeProperty(xfc->display, respond->xselection.requestor, - respond->xselection.property, respond->xselection.target, - 8, PropModeReplace, data, size); + XChangeProperty(xfc->display, respond->requestor, respond->property, respond->target, 8, + PropModeReplace, data, size); } } static BOOL xf_cliprdr_process_selection_notify(xfClipboard* clipboard, - XEvent* xevent) + const XSelectionEvent* xevent) { - if (xevent->xselection.target == clipboard->targets[1]) + if (xevent->target == clipboard->targets[1]) { - if (xevent->xselection.property == None) + if (xevent->property == None) { xf_cliprdr_send_client_format_list(clipboard); } @@ -808,7 +788,7 @@ static BOOL xf_cliprdr_process_selection_notify(xfClipboard* clipboard, } else { - return xf_cliprdr_get_requested_data(clipboard, xevent->xselection.target); + return xf_cliprdr_get_requested_data(clipboard, xevent->target); } } @@ -832,13 +812,13 @@ static void xf_cliprdr_clear_cached_data(xfClipboard* clipboard) } static BOOL xf_cliprdr_process_selection_request(xfClipboard* clipboard, - XEvent* xevent) + const XSelectionRequestEvent* xevent) { int fmt; Atom type; UINT32 formatId; const char* formatName; - XEvent* respond; + XSelectionEvent* respond; BYTE* data = NULL; BOOL delayRespond; BOOL rawTransfer; @@ -848,42 +828,40 @@ static BOOL xf_cliprdr_process_selection_request(xfClipboard* clipboard, CLIPRDR_FORMAT* format; xfContext* xfc = clipboard->xfc; - if (xevent->xselectionrequest.owner != xfc->drawable) + if (xevent->owner != xfc->drawable) return FALSE; delayRespond = FALSE; - if (!(respond = (XEvent*) calloc(1, sizeof(XEvent)))) + if (!(respond = (XSelectionEvent*)calloc(1, sizeof(XSelectionEvent)))) { WLog_ERR(TAG, "failed to allocate XEvent data"); return FALSE; } - respond->xselection.property = None; - respond->xselection.type = SelectionNotify; - respond->xselection.display = xevent->xselectionrequest.display; - respond->xselection.requestor = xevent->xselectionrequest.requestor; - respond->xselection.selection = xevent->xselectionrequest.selection; - respond->xselection.target = xevent->xselectionrequest.target; - respond->xselection.time = xevent->xselectionrequest.time; + respond->property = None; + respond->type = SelectionNotify; + respond->display = xevent->display; + respond->requestor = xevent->requestor; + respond->selection = xevent->selection; + respond->target = xevent->target; + respond->time = xevent->time; - if (xevent->xselectionrequest.target == clipboard->targets[0]) /* TIMESTAMP */ + if (xevent->target == clipboard->targets[0]) /* TIMESTAMP */ { /* TODO */ } - else if (xevent->xselectionrequest.target == - clipboard->targets[1]) /* TARGETS */ + else if (xevent->target == clipboard->targets[1]) /* TARGETS */ { /* Someone else requests our available formats */ - respond->xselection.property = xevent->xselectionrequest.property; + respond->property = xevent->property; xf_cliprdr_provide_targets(clipboard, respond); } else { - format = xf_cliprdr_get_server_format_by_atom(clipboard, - xevent->xselectionrequest.target); + format = xf_cliprdr_get_server_format_by_atom(clipboard, xevent->target); - if (format && (xevent->xselectionrequest.requestor != xfc->drawable)) + if (format && (xevent->requestor != xfc->drawable)) { formatId = format->formatId; formatName = format->formatName; @@ -891,9 +869,9 @@ static BOOL xf_cliprdr_process_selection_request(xfClipboard* clipboard, if (formatId == CF_RAW) { - if (XGetWindowProperty(xfc->display, xevent->xselectionrequest.requestor, - clipboard->property_atom, 0, 4, 0, XA_INTEGER, - &type, &fmt, &length, &bytes_left, &data) != Success) + if (XGetWindowProperty(xfc->display, xevent->requestor, clipboard->property_atom, 0, + 4, 0, XA_INTEGER, &type, &fmt, &length, &bytes_left, + &data) != Success) { } @@ -907,21 +885,22 @@ static BOOL xf_cliprdr_process_selection_request(xfClipboard* clipboard, /* We can compare format names by pointer value here as they are both * taken from the same clipboard->serverFormats array */ - matchingFormat = (formatId == clipboard->data_format_id) - && (formatName == clipboard->data_format_name); + matchingFormat = (formatId == clipboard->data_format_id) && + (formatName == clipboard->data_format_name); if (matchingFormat && (clipboard->data != 0) && !rawTransfer) { /* Cached converted clipboard data available. Send it now */ - respond->xselection.property = xevent->xselectionrequest.property; + respond->property = xevent->property; xf_cliprdr_provide_data(clipboard, respond, clipboard->data, clipboard->data_length); } else if (matchingFormat && (clipboard->data_raw != 0) && rawTransfer) { /* Cached raw clipboard data available. Send it now */ - respond->xselection.property = xevent->xselectionrequest.property; - xf_cliprdr_provide_data(clipboard, respond, clipboard->data_raw, clipboard->data_raw_length); + respond->property = xevent->property; + xf_cliprdr_provide_data(clipboard, respond, clipboard->data_raw, + clipboard->data_raw_length); } else if (clipboard->respond) { @@ -934,7 +913,7 @@ static BOOL xf_cliprdr_process_selection_request(xfClipboard* clipboard, * Response will be postponed after receiving the data */ xf_cliprdr_clear_cached_data(clipboard); - respond->xselection.property = xevent->xselectionrequest.property; + respond->property = xevent->property; clipboard->respond = respond; clipboard->data_format_id = formatId; clipboard->data_format_name = formatName; @@ -947,7 +926,13 @@ static BOOL xf_cliprdr_process_selection_request(xfClipboard* clipboard, if (!delayRespond) { - XSendEvent(xfc->display, xevent->xselectionrequest.requestor, 0, 0, respond); + union { + XEvent* ev; + XSelectionEvent* sev; + } conv; + + conv.sev = respond; + XSendEvent(xfc->display, xevent->requestor, 0, 0, conv.ev); XFlush(xfc->display); free(respond); } @@ -956,10 +941,12 @@ static BOOL xf_cliprdr_process_selection_request(xfClipboard* clipboard, } static BOOL xf_cliprdr_process_selection_clear(xfClipboard* clipboard, - XEvent* xevent) + const XSelectionClearEvent* xevent) { xfContext* xfc = clipboard->xfc; + WINPR_UNUSED(xevent); + if (xf_cliprdr_is_self_owned(clipboard)) return FALSE; @@ -967,8 +954,7 @@ static BOOL xf_cliprdr_process_selection_clear(xfClipboard* clipboard, return TRUE; } -static BOOL xf_cliprdr_process_property_notify(xfClipboard* clipboard, - XEvent* xevent) +static BOOL xf_cliprdr_process_property_notify(xfClipboard* clipboard, const XPropertyEvent* xevent) { xfCliprdrFormat* format; xfContext* xfc = NULL; @@ -978,18 +964,17 @@ static BOOL xf_cliprdr_process_property_notify(xfClipboard* clipboard, xfc = clipboard->xfc; - if (xevent->xproperty.atom != clipboard->property_atom) + if (xevent->atom != clipboard->property_atom) return FALSE; /* Not cliprdr-related */ - if (xevent->xproperty.window == clipboard->root_window) + if (xevent->window == clipboard->root_window) { xf_cliprdr_send_client_format_list(clipboard); } - else if ((xevent->xproperty.window == xfc->drawable) && - (xevent->xproperty.state == PropertyNewValue) && clipboard->incr_starts) + else if ((xevent->window == xfc->drawable) && (xevent->state == PropertyNewValue) && + clipboard->incr_starts) { - format = xf_cliprdr_get_client_format_by_id(clipboard, - clipboard->requestedFormatId); + format = xf_cliprdr_get_client_format_by_id(clipboard, clipboard->requestedFormatId); if (format) xf_cliprdr_get_requested_data(clipboard, format->atom); @@ -998,7 +983,7 @@ static BOOL xf_cliprdr_process_property_notify(xfClipboard* clipboard, return TRUE; } -void xf_cliprdr_handle_xevent(xfContext* xfc, XEvent* event) +void xf_cliprdr_handle_xevent(xfContext* xfc, const XEvent* event) { xfClipboard* clipboard; @@ -1012,10 +997,10 @@ void xf_cliprdr_handle_xevent(xfContext* xfc, XEvent* event) #ifdef WITH_XFIXES - if (clipboard->xfixes_supported - && event->type == XFixesSelectionNotify + clipboard->xfixes_event_base) + if (clipboard->xfixes_supported && + event->type == XFixesSelectionNotify + clipboard->xfixes_event_base) { - XFixesSelectionNotifyEvent* se = (XFixesSelectionNotifyEvent*) event; + XFixesSelectionNotifyEvent* se = (XFixesSelectionNotifyEvent*)event; if (se->subtype == XFixesSetSelectionOwnerNotify) { @@ -1037,19 +1022,19 @@ void xf_cliprdr_handle_xevent(xfContext* xfc, XEvent* event) switch (event->type) { case SelectionNotify: - xf_cliprdr_process_selection_notify(clipboard, event); + xf_cliprdr_process_selection_notify(clipboard, &event->xselection); break; case SelectionRequest: - xf_cliprdr_process_selection_request(clipboard, event); + xf_cliprdr_process_selection_request(clipboard, &event->xselectionrequest); break; case SelectionClear: - xf_cliprdr_process_selection_clear(clipboard, event); + xf_cliprdr_process_selection_clear(clipboard, &event->xselectionclear); break; case PropertyNotify: - xf_cliprdr_process_property_notify(clipboard, event); + xf_cliprdr_process_property_notify(clipboard, &event->xproperty); break; case FocusIn: @@ -1072,19 +1057,16 @@ static UINT xf_cliprdr_send_client_capabilities(xfClipboard* clipboard) CLIPRDR_CAPABILITIES capabilities; CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet; capabilities.cCapabilitiesSets = 1; - capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*) & - (generalCapabilitySet); + 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; + generalCapabilitySet.generalFlags |= CB_STREAM_FILECLIP_ENABLED | CB_FILECLIP_NO_FILE_PATHS; - return clipboard->context->ClientCapabilities(clipboard->context, - &capabilities); + return clipboard->context->ClientCapabilities(clipboard->context, &capabilities); } /** @@ -1096,17 +1078,16 @@ 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) { - if (!(formats = (CLIPRDR_FORMAT*) calloc(numFormats, sizeof(CLIPRDR_FORMAT)))) + if (!(formats = (CLIPRDR_FORMAT*)calloc(numFormats, sizeof(CLIPRDR_FORMAT)))) { - WLog_ERR(TAG, "failed to allocate %"PRIu32" CLIPRDR_FORMAT structs", numFormats); + WLog_ERR(TAG, "failed to allocate %" PRIu32 " CLIPRDR_FORMAT structs", numFormats); return CHANNEL_RC_NO_MEMORY; } } @@ -1120,14 +1101,15 @@ static UINT xf_cliprdr_send_client_format_list(xfClipboard* clipboard) formatList.msgFlags = CB_RESPONSE_OK; formatList.numFormats = numFormats; formatList.formats = formats; + formatList.msgType = CB_FORMAT_LIST; ret = clipboard->context->ClientFormatList(clipboard->context, &formatList); free(formats); if (clipboard->owner && clipboard->owner != xfc->drawable) { /* Request the owner for TARGETS, and wait for SelectionNotify event */ - XConvertSelection(xfc->display, clipboard->clipboard_atom, - clipboard->targets[1], clipboard->property_atom, xfc->drawable, CurrentTime); + XConvertSelection(xfc->display, clipboard->clipboard_atom, clipboard->targets[1], + clipboard->property_atom, xfc->drawable, CurrentTime); } return ret; @@ -1138,15 +1120,13 @@ static UINT xf_cliprdr_send_client_format_list(xfClipboard* clipboard) * * @return 0 on success, otherwise a Win32 error code */ -static UINT xf_cliprdr_send_client_format_list_response(xfClipboard* clipboard, - BOOL status) +static UINT xf_cliprdr_send_client_format_list_response(xfClipboard* 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); + return clipboard->context->ClientFormatListResponse(clipboard->context, &formatListResponse); } /** @@ -1155,11 +1135,13 @@ 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; + xfClipboard* clipboard = (xfClipboard*)context->custom; UINT ret; + WINPR_UNUSED(monitorReady); + if ((ret = xf_cliprdr_send_client_capabilities(clipboard)) != CHANNEL_RC_OK) return ret; @@ -1176,22 +1158,22 @@ 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; const CLIPRDR_GENERAL_CAPABILITY_SET* generalCaps; - const BYTE* capsPtr = (const BYTE*) capabilities->capabilitySets; - xfClipboard* clipboard = (xfClipboard*) context->custom; + const BYTE* capsPtr = (const BYTE*)capabilities->capabilitySets; + xfClipboard* clipboard = (xfClipboard*)context->custom; clipboard->streams_supported = FALSE; for (i = 0; i < capabilities->cCapabilitiesSets; i++) { - caps = (const CLIPRDR_CAPABILITY_SET*) capsPtr; + caps = (const CLIPRDR_CAPABILITY_SET*)capsPtr; if (caps->capabilitySetType == CB_CAPSTYPE_GENERAL) { - generalCaps = (const CLIPRDR_GENERAL_CAPABILITY_SET*) caps; + generalCaps = (const CLIPRDR_GENERAL_CAPABILITY_SET*)caps; if (generalCaps->generalFlags & CB_STREAM_FILECLIP_ENABLED) { @@ -1211,11 +1193,11 @@ 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; - xfClipboard* clipboard = (xfClipboard*) context->custom; + xfClipboard* clipboard = (xfClipboard*)context->custom; xfContext* xfc = clipboard->xfc; UINT ret; xf_cliprdr_clear_cached_data(clipboard); @@ -1234,11 +1216,10 @@ static UINT xf_cliprdr_server_format_list(CliprdrClientContext* context, clipboard->numServerFormats = formatList->numFormats + 1; /* +1 for CF_RAW */ - if (!(clipboard->serverFormats = (CLIPRDR_FORMAT*) calloc( - clipboard->numServerFormats, sizeof(CLIPRDR_FORMAT)))) + if (!(clipboard->serverFormats = + (CLIPRDR_FORMAT*)calloc(clipboard->numServerFormats, sizeof(CLIPRDR_FORMAT)))) { - WLog_ERR(TAG, "failed to allocate %d CLIPRDR_FORMAT structs", - clipboard->numServerFormats); + WLog_ERR(TAG, "failed to allocate %d CLIPRDR_FORMAT structs", clipboard->numServerFormats); return CHANNEL_RC_NO_MEMORY; } @@ -1289,8 +1270,7 @@ static UINT xf_cliprdr_server_format_list(CliprdrClientContext* context, } ret = xf_cliprdr_send_client_format_list_response(clipboard, TRUE); - XSetSelectionOwner(xfc->display, clipboard->clipboard_atom, xfc->drawable, - CurrentTime); + XSetSelectionOwner(xfc->display, clipboard->clipboard_atom, xfc->drawable, CurrentTime); XFlush(xfc->display); return ret; } @@ -1300,10 +1280,11 @@ 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) +static UINT +xf_cliprdr_server_format_list_response(CliprdrClientContext* context, + const CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse) { - //xfClipboard* clipboard = (xfClipboard*) context->custom; + // xfClipboard* clipboard = (xfClipboard*) context->custom; return CHANNEL_RC_OK; } @@ -1312,21 +1293,22 @@ 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) +static UINT +xf_cliprdr_server_format_data_request(CliprdrClientContext* context, + const CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest) { BOOL rawTransfer; xfCliprdrFormat* format = NULL; UINT32 formatId = formatDataRequest->requestedFormatId; - xfClipboard* clipboard = (xfClipboard*) context->custom; + xfClipboard* clipboard = (xfClipboard*)context->custom; xfContext* xfc = clipboard->xfc; rawTransfer = xf_cliprdr_is_raw_transfer_available(clipboard); if (rawTransfer) { format = xf_cliprdr_get_client_format_by_id(clipboard, CF_RAW); - XChangeProperty(xfc->display, xfc->drawable, clipboard->property_atom, - XA_INTEGER, 32, PropModeReplace, (BYTE*) &formatId, 1); + XChangeProperty(xfc->display, xfc->drawable, clipboard->property_atom, XA_INTEGER, 32, + PropModeReplace, (BYTE*)&formatId, 1); } else format = xf_cliprdr_get_client_format_by_id(clipboard, formatId); @@ -1335,8 +1317,8 @@ static UINT xf_cliprdr_server_format_data_request(CliprdrClientContext* context, return xf_cliprdr_send_data_response(clipboard, NULL, 0); clipboard->requestedFormatId = rawTransfer ? CF_RAW : formatId; - XConvertSelection(xfc->display, clipboard->clipboard_atom, - format->atom, clipboard->property_atom, xfc->drawable, CurrentTime); + XConvertSelection(xfc->display, clipboard->clipboard_atom, format->atom, + clipboard->property_atom, xfc->drawable, CurrentTime); XFlush(xfc->display); /* After this point, we expect a SelectionNotify event from the clipboard owner. */ return CHANNEL_RC_OK; @@ -1347,8 +1329,9 @@ 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) +static UINT +xf_cliprdr_server_format_data_response(CliprdrClientContext* context, + const CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse) { BOOL bSuccess; BYTE* pDstData; @@ -1359,7 +1342,7 @@ static UINT xf_cliprdr_server_format_data_response(CliprdrClientContext* BOOL nullTerminated = FALSE; UINT32 size = formatDataResponse->dataLen; const BYTE* data = formatDataResponse->requestedFormatData; - xfClipboard* clipboard = (xfClipboard*) context->custom; + xfClipboard* clipboard = (xfClipboard*)context->custom; xfContext* xfc = clipboard->xfc; if (!clipboard->respond) @@ -1384,6 +1367,13 @@ static UINT xf_cliprdr_server_format_data_response(CliprdrClientContext* dstFormatId = ClipboardGetFormatId(clipboard->system, "text/html"); nullTerminated = TRUE; } + + if (strcmp(clipboard->data_format_name, "FileGroupDescriptorW") == 0) + { + srcFormatId = ClipboardGetFormatId(clipboard->system, "FileGroupDescriptorW"); + dstFormatId = ClipboardGetFormatId(clipboard->system, "text/uri-list"); + nullTerminated = FALSE; + } } else { @@ -1417,7 +1407,7 @@ static UINT xf_cliprdr_server_format_data_response(CliprdrClientContext* } } - SrcSize = (UINT32) size; + SrcSize = (UINT32)size; bSuccess = ClipboardSetData(clipboard->system, srcFormatId, data, SrcSize); if (bSuccess) @@ -1425,24 +1415,25 @@ static UINT xf_cliprdr_server_format_data_response(CliprdrClientContext* if (SrcSize == 0) { WLog_INFO(TAG, "skipping, empty data detected!!!"); + free(clipboard->respond); + clipboard->respond = NULL; return CHANNEL_RC_OK; } - DstSize = 0; - pDstData = (BYTE*) ClipboardGetData(clipboard->system, dstFormatId, &DstSize); + pDstData = (BYTE*)ClipboardGetData(clipboard->system, dstFormatId, &DstSize); if (!pDstData) { - WLog_ERR(TAG, "failed to get clipboard data in format %s [source format %s]", - ClipboardGetFormatName(clipboard->system, dstFormatId), - ClipboardGetFormatName(clipboard->system, srcFormatId)); - return ERROR_INTERNAL_ERROR; + WLog_WARN(TAG, "failed to get clipboard data in format %s [source format %s]", + ClipboardGetFormatName(clipboard->system, dstFormatId), + ClipboardGetFormatName(clipboard->system, srcFormatId)); } - if (nullTerminated) + if (nullTerminated && pDstData) { - while (DstSize > 0 && pDstData[DstSize - 1] == '\0') - DstSize--; + BYTE* nullTerminator = memchr(pDstData, '\0', DstSize); + if (nullTerminator) + DstSize = nullTerminator - pDstData; } } @@ -1453,7 +1444,7 @@ static UINT xf_cliprdr_server_format_data_response(CliprdrClientContext* /* We have to copy the original data again, as pSrcData is now owned * by clipboard->system. Memory allocation failure is not fatal here * as this is only a cached value. */ - clipboard->data_raw = (BYTE*) malloc(size); + clipboard->data_raw = (BYTE*)malloc(size); if (clipboard->data_raw) { @@ -1462,40 +1453,49 @@ static UINT xf_cliprdr_server_format_data_response(CliprdrClientContext* } else { - WLog_WARN(TAG, "failed to allocate %"PRIu32" bytes for a copy of raw clipboard data", size); + WLog_WARN(TAG, "failed to allocate %" PRIu32 " bytes for a copy of raw clipboard data", + size); } xf_cliprdr_provide_data(clipboard, clipboard->respond, pDstData, DstSize); - XSendEvent(xfc->display, clipboard->respond->xselection.requestor, 0, 0, - clipboard->respond); - XFlush(xfc->display); + { + union { + XEvent* ev; + XSelectionEvent* sev; + } conv; + + conv.sev = clipboard->respond; + + XSendEvent(xfc->display, clipboard->respond->requestor, 0, 0, conv.ev); + XFlush(xfc->display); + } free(clipboard->respond); clipboard->respond = NULL; return CHANNEL_RC_OK; } -static UINT xf_cliprdr_server_file_size_request(xfClipboard* clipboard, - const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) +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; if (fileContentsRequest->cbRequested != sizeof(UINT64)) { - WLog_WARN(TAG, "unexpected FILECONTENTS_SIZE request: %"PRIu32" bytes", + WLog_WARN(TAG, "unexpected FILECONTENTS_SIZE request: %" PRIu32 " bytes", fileContentsRequest->cbRequested); } return clipboard->delegate->ClientRequestFileSize(clipboard->delegate, &request); } -static UINT xf_cliprdr_server_file_range_request(xfClipboard* clipboard, - const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) +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; @@ -1504,19 +1504,19 @@ static UINT xf_cliprdr_server_file_range_request(xfClipboard* clipboard, return clipboard->delegate->ClientRequestFileRange(clipboard->delegate, &request); } -static UINT xf_cliprdr_send_file_contents_failure(CliprdrClientContext* context, - const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) +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; return context->ClientFileContentsResponse(context, &response); } -static UINT xf_cliprdr_server_file_contents_request(CliprdrClientContext* context, - CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) +static UINT +xf_cliprdr_server_file_contents_request(CliprdrClientContext* context, + const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) { UINT error = NO_ERROR; xfClipboard* clipboard = context->custom; @@ -1548,54 +1548,54 @@ 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) + 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; response.cbRequested = sizeof(UINT64); - response.requestedData = (BYTE*) &fileSize; + response.requestedData = (BYTE*)&fileSize; return clipboard->context->ClientFileContentsResponse(clipboard->context, &response); } static UINT xf_cliprdr_clipboard_file_size_failure(wClipboardDelegate* delegate, - const wClipboardFileSizeRequest* request, UINT errorCode) + const wClipboardFileSizeRequest* request, + UINT errorCode) { - CLIPRDR_FILE_CONTENTS_RESPONSE response; + CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 }; xfClipboard* clipboard = delegate->custom; - ZeroMemory(&response, sizeof(response)); + 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 xf_cliprdr_clipboard_file_range_success(wClipboardDelegate* delegate, - const wClipboardFileRangeRequest* request, const BYTE* data, UINT32 size) + 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; response.cbRequested = size; - response.requestedData = (BYTE*) data; + response.requestedData = (BYTE*)data; return clipboard->context->ClientFileContentsResponse(clipboard->context, &response); } static UINT xf_cliprdr_clipboard_file_range_failure(wClipboardDelegate* delegate, - const wClipboardFileRangeRequest* request, UINT errorCode) + const wClipboardFileRangeRequest* request, + UINT errorCode) { - CLIPRDR_FILE_CONTENTS_RESPONSE response; + CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 }; xfClipboard* clipboard = delegate->custom; - ZeroMemory(&response, sizeof(response)); + WINPR_UNUSED(errorCode); + response.msgFlags = CB_RESPONSE_FAIL; response.streamId = request->streamId; - response.dwFlags = FILECONTENTS_RANGE; return clipboard->context->ClientFileContentsResponse(clipboard->context, &response); } @@ -1605,7 +1605,7 @@ xfClipboard* xf_clipboard_new(xfContext* xfc) rdpChannels* channels; xfClipboard* clipboard; - if (!(clipboard = (xfClipboard*) calloc(1, sizeof(xfClipboard)))) + if (!(clipboard = (xfClipboard*)calloc(1, sizeof(xfClipboard)))) { WLog_ERR(TAG, "failed to allocate xfClipboard data"); return NULL; @@ -1613,7 +1613,7 @@ xfClipboard* xf_clipboard_new(xfContext* xfc) xfc->clipboard = clipboard; clipboard->xfc = xfc; - channels = ((rdpContext*) xfc)->channels; + channels = ((rdpContext*)xfc)->channels; clipboard->channels = channels; clipboard->system = ClipboardCreate(); clipboard->requestedFormatId = -1; @@ -1628,8 +1628,7 @@ xfClipboard* xf_clipboard_new(xfContext* xfc) clipboard->property_atom = XInternAtom(xfc->display, "_FREERDP_CLIPRDR", FALSE); clipboard->raw_transfer_atom = XInternAtom(xfc->display, "_FREERDP_CLIPRDR_RAW", FALSE); - clipboard->raw_format_list_atom = - XInternAtom(xfc->display, "_FREERDP_CLIPRDR_FORMATS", FALSE); + clipboard->raw_format_list_atom = XInternAtom(xfc->display, "_FREERDP_CLIPRDR_FORMATS", FALSE); xf_cliprdr_set_raw_transfer_enabled(clipboard, TRUE); XSelectInput(xfc->display, clipboard->root_window, PropertyChangeMask); #ifdef WITH_XFIXES @@ -1642,7 +1641,8 @@ xfClipboard* xf_clipboard_new(xfContext* xfc) if (XFixesQueryVersion(xfc->display, &xfmajor, &xfminor)) { XFixesSelectSelectionInput(xfc->display, clipboard->root_window, - clipboard->clipboard_atom, XFixesSetSelectionOwnerNotifyMask); + clipboard->clipboard_atom, + XFixesSetSelectionOwnerNotifyMask); clipboard->xfixes_supported = TRUE; } else @@ -1656,8 +1656,9 @@ xfClipboard* xf_clipboard_new(xfContext* xfc) } #else - WLog_ERR(TAG, - "Warning: Using clipboard redirection without XFIXES extension is strongly discouraged!"); + WLog_ERR( + TAG, + "Warning: Using clipboard redirection without XFIXES extension is strongly discouraged!"); #endif clipboard->clientFormats[n].atom = XInternAtom(xfc->display, "_FREERDP_RAW", False); clipboard->clientFormats[n].formatId = CF_RAW; @@ -1715,6 +1716,8 @@ xfClipboard* xf_clipboard_new(xfContext* xfc) clipboard->incr_atom = XInternAtom(xfc->display, "INCR", FALSE); clipboard->delegate = ClipboardGetDelegate(clipboard->system); clipboard->delegate->custom = clipboard; + /* TODO: set up a filesystem base path for local URI */ + /* clipboard->delegate->basePath = "file:///tmp/foo/bar/gaga"; */ clipboard->delegate->ClipboardFileSizeSuccess = xf_cliprdr_clipboard_file_size_success; clipboard->delegate->ClipboardFileSizeFailure = xf_cliprdr_clipboard_file_size_failure; clipboard->delegate->ClipboardFileRangeSuccess = xf_cliprdr_clipboard_file_range_success; @@ -1764,7 +1767,7 @@ void xf_cliprdr_init(xfContext* xfc, CliprdrClientContext* cliprdr) { xfc->cliprdr = cliprdr; xfc->clipboard->context = cliprdr; - cliprdr->custom = (void*) xfc->clipboard; + cliprdr->custom = (void*)xfc->clipboard; cliprdr->MonitorReady = xf_cliprdr_monitor_ready; cliprdr->ServerCapabilities = xf_cliprdr_server_capabilities; cliprdr->ServerFormatList = xf_cliprdr_server_format_list; diff --git a/client/X11/xf_cliprdr.h b/client/X11/xf_cliprdr.h index f9c3583..f2262f7 100644 --- a/client/X11/xf_cliprdr.h +++ b/client/X11/xf_cliprdr.h @@ -31,6 +31,6 @@ void xf_clipboard_free(xfClipboard* clipboard); void xf_cliprdr_init(xfContext* xfc, CliprdrClientContext* cliprdr); void xf_cliprdr_uninit(xfContext* xfc, CliprdrClientContext* cliprdr); -void xf_cliprdr_handle_xevent(xfContext* xfc, XEvent* event); +void xf_cliprdr_handle_xevent(xfContext* xfc, const XEvent* event); #endif /* FREERDP_CLIENT_X11_CLIPRDR_H */ diff --git a/client/X11/xf_disp.c b/client/X11/xf_disp.c index 1b30976..a9d2ee8 100644 --- a/client/X11/xf_disp.c +++ b/client/X11/xf_disp.c @@ -25,7 +25,7 @@ #include #if (RANDR_MAJOR * 100 + RANDR_MINOR) >= 105 -# define USABLE_XRANDR +#define USABLE_XRANDR #endif #endif @@ -33,7 +33,6 @@ #include "xf_disp.h" #include "xf_monitor.h" - #define TAG CLIENT_TAG("x11disp") #define RESIZE_MIN_DELAY 200 /* minimum delay in ms between two resizes */ @@ -121,8 +120,8 @@ static BOOL xf_disp_sendResize(xfDispContext* xfDisp) if (xfc->fullscreen && (settings->MonitorCount > 0)) { - if (xf_disp_sendLayout(xfDisp->disp, settings->MonitorDefArray, - settings->MonitorCount) != CHANNEL_RC_OK) + if (xf_disp_sendLayout(xfDisp->disp, settings->MonitorDefArray, settings->MonitorCount) != + CHANNEL_RC_OK) return FALSE; } else @@ -215,6 +214,8 @@ static void xf_disp_OnGraphicsReset(void* context, GraphicsResetEventArgs* e) xfDispContext* xfDisp; rdpSettings* settings; + WINPR_UNUSED(e); + if (!xf_disp_check_context(context, &xfc, &xfDisp, &settings)) return; @@ -233,6 +234,8 @@ static void xf_disp_OnTimer(void* context, TimerEventArgs* e) xfDispContext* xfDisp; rdpSettings* settings; + WINPR_UNUSED(e); + if (!xf_disp_check_context(context, &xfc, &xfDisp, &settings)) return; @@ -345,7 +348,7 @@ UINT xf_disp_sendLayout(DispClientContext* disp, rdpMonitor* monitors, int nmoni return ret; } -BOOL xf_disp_handle_xevent(xfContext* xfc, XEvent* event) +BOOL xf_disp_handle_xevent(xfContext* xfc, const XEvent* event) { xfDispContext* xfDisp; rdpSettings* settings; @@ -374,8 +377,8 @@ BOOL xf_disp_handle_xevent(xfContext* xfc, XEvent* event) #endif xf_detect_monitors(xfc, &maxWidth, &maxHeight); - return xf_disp_sendLayout(xfDisp->disp, settings->MonitorDefArray, - settings->MonitorCount) == CHANNEL_RC_OK; + return xf_disp_sendLayout(xfDisp->disp, settings->MonitorDefArray, settings->MonitorCount) == + CHANNEL_RC_OK; } BOOL xf_disp_handle_configureNotify(xfContext* xfc, int width, int height) @@ -402,14 +405,15 @@ static UINT xf_DisplayControlCaps(DispClientContext* disp, UINT32 maxNumMonitors xfDispContext* xfDisp = (xfDispContext*)disp->custom; rdpSettings* settings = xfDisp->xfc->context.settings; WLog_DBG(TAG, - "DisplayControlCapsPdu: MaxNumMonitors: %"PRIu32" MaxMonitorAreaFactorA: %"PRIu32" MaxMonitorAreaFactorB: %"PRIu32"", + "DisplayControlCapsPdu: MaxNumMonitors: %" PRIu32 " MaxMonitorAreaFactorA: %" PRIu32 + " MaxMonitorAreaFactorB: %" PRIu32 "", maxNumMonitors, maxMonitorAreaFactorA, maxMonitorAreaFactorB); xfDisp->activated = TRUE; 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; } @@ -426,7 +430,7 @@ BOOL xf_disp_init(xfDispContext* xfDisp, DispClientContext* disp) return FALSE; xfDisp->disp = disp; - disp->custom = (void*) xfDisp; + disp->custom = (void*)xfDisp; if (settings->DynamicResolutionUpdate) { diff --git a/client/X11/xf_disp.h b/client/X11/xf_disp.h index 6e2db41..9062501 100644 --- a/client/X11/xf_disp.h +++ b/client/X11/xf_disp.h @@ -30,7 +30,7 @@ FREERDP_API BOOL xf_disp_uninit(xfDispContext* xfDisp, DispClientContext* disp); xfDispContext* xf_disp_new(xfContext* xfc); void xf_disp_free(xfDispContext* disp); -BOOL xf_disp_handle_xevent(xfContext* xfc, XEvent* event); +BOOL xf_disp_handle_xevent(xfContext* xfc, const XEvent* event); BOOL xf_disp_handle_configureNotify(xfContext* xfc, int width, int height); void xf_disp_resized(xfDispContext* disp); diff --git a/client/X11/xf_event.c b/client/X11/xf_event.c index 70c3aee..3f7d872 100644 --- a/client/X11/xf_event.c +++ b/client/X11/xf_event.c @@ -39,7 +39,11 @@ #define TAG CLIENT_TAG("x11") -#define CLAMP_COORDINATES(x, y) if (x < 0) x = 0; if (y < 0) y = 0 +#define CLAMP_COORDINATES(x, y) \ + if (x < 0) \ + x = 0; \ + if (y < 0) \ + y = 0 static const char* x11_event_string(int event) { @@ -155,7 +159,10 @@ static const char* x11_event_string(int event) #ifdef WITH_DEBUG_X11 #define DEBUG_X11(...) WLog_DBG(TAG, __VA_ARGS__) #else -#define DEBUG_X11(...) do { } while (0) +#define DEBUG_X11(...) \ + do \ + { \ + } while (0) #endif BOOL xf_event_action_script_init(xfContext* xfc) @@ -178,7 +185,8 @@ BOOL xf_event_action_script_init(xfContext* xfc) while (fgets(buffer, sizeof(buffer), actionScript)) { - strtok(buffer, "\n"); + char* context = NULL; + strtok_s(buffer, "\n", &context); xevent = _strdup(buffer); if (!xevent || ArrayList_Add(xfc->xevents, xevent) < 0) @@ -202,7 +210,8 @@ void xf_event_action_script_free(xfContext* xfc) xfc->xevents = NULL; } } -static BOOL xf_event_execute_action_script(xfContext* xfc, XEvent* event) + +static BOOL xf_event_execute_action_script(xfContext* xfc, const XEvent* event) { int index; int count; @@ -213,7 +222,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) @@ -224,7 +233,7 @@ static BOOL xf_event_execute_action_script(xfContext* xfc, XEvent* event) for (index = 0; index < count; index++) { - name = (char*) ArrayList_GetItem(xfc->xevents, index); + name = (char*)ArrayList_GetItem(xfc->xevents, index); if (_stricmp(name, xeventName) == 0) { @@ -236,8 +245,8 @@ static BOOL xf_event_execute_action_script(xfContext* xfc, XEvent* event) if (!match) return FALSE; - sprintf_s(command, sizeof(command), "%s xevent %s %lu", - xfc->context.settings->ActionScript, xeventName, (unsigned long) xfc->window->handle); + sprintf_s(command, sizeof(command), "%s xevent %s %lu", xfc->context.settings->ActionScript, + xeventName, (unsigned long)xfc->window->handle); actionScript = popen(command, "r"); if (!actionScript) @@ -245,12 +254,14 @@ static BOOL xf_event_execute_action_script(xfContext* xfc, XEvent* event) while (fgets(buffer, sizeof(buffer), actionScript)) { - strtok(buffer, "\n"); + char* context = NULL; + strtok_s(buffer, "\n", &context); } pclose(actionScript); return TRUE; } + void xf_event_adjust_coordinates(xfContext* xfc, int* x, int* y) { rdpSettings* settings; @@ -277,7 +288,7 @@ void xf_event_adjust_coordinates(xfContext* xfc, int* x, int* y) CLAMP_COORDINATES(*x, *y); } -static BOOL xf_event_Expose(xfContext* xfc, XEvent* event, BOOL app) +static BOOL xf_event_Expose(xfContext* xfc, const XExposeEvent* event, BOOL app) { int x, y; int w, h; @@ -292,26 +303,25 @@ static BOOL xf_event_Expose(xfContext* xfc, XEvent* event, BOOL app) } else { - x = event->xexpose.x; - y = event->xexpose.y; - w = event->xexpose.width; - h = event->xexpose.height; - } - - if (xfc->context.gdi->gfx) - { - xf_OutputExpose(xfc, x, y, w, h); - return TRUE; + x = event->x; + y = event->y; + w = event->width; + h = event->height; } if (!app) { + if (xfc->context.gdi->gfx) + { + xf_OutputExpose(xfc, x, y, w, h); + return TRUE; + } xf_draw_screen(xfc, x, y, w, h); } else { xfAppWindow* appWindow; - appWindow = xf_AppWindowFromX11Window(xfc, event->xany.window); + appWindow = xf_AppWindowFromX11Window(xfc, event->window); if (appWindow) { @@ -321,13 +331,15 @@ static BOOL xf_event_Expose(xfContext* xfc, XEvent* event, BOOL app) return TRUE; } -static BOOL xf_event_VisibilityNotify(xfContext* xfc, XEvent* event, BOOL app) + +static BOOL xf_event_VisibilityNotify(xfContext* xfc, const XVisibilityEvent* event, BOOL app) { - xfc->unobscured = event->xvisibility.state == VisibilityUnobscured; + WINPR_UNUSED(app); + xfc->unobscured = event->state == VisibilityUnobscured; return TRUE; } -BOOL xf_generic_MotionNotify(xfContext* xfc, int x, int y, int state, - Window window, BOOL app) + +BOOL xf_generic_MotionNotify(xfContext* xfc, int x, int y, int state, Window window, BOOL app) { rdpInput* input; Window childWindow; @@ -346,9 +358,8 @@ BOOL xf_generic_MotionNotify(xfContext* xfc, int x, int y, int state, return TRUE; /* Translate to desktop coordinates */ - XTranslateCoordinates(xfc->display, window, - RootWindowOfScreen(xfc->screen), - x, y, &x, &y, &childWindow); + XTranslateCoordinates(xfc->display, window, RootWindowOfScreen(xfc->screen), x, y, &x, &y, + &childWindow); } xf_event_adjust_coordinates(xfc, &x, &y); @@ -356,90 +367,67 @@ BOOL xf_generic_MotionNotify(xfContext* xfc, int x, int y, int state, if (xfc->fullscreen && !app) { - XSetInputFocus(xfc->display, xfc->window->handle, RevertToPointerRoot, - CurrentTime); + XSetInputFocus(xfc->display, xfc->window->handle, RevertToPointerRoot, CurrentTime); } return TRUE; } -static BOOL xf_event_MotionNotify(xfContext* xfc, XEvent* event, BOOL app) +static BOOL xf_event_MotionNotify(xfContext* xfc, const XMotionEvent* event, BOOL app) { + if (xfc->window) + xf_floatbar_set_root_y(xfc->window->floatbar, event->y); + if (xfc->use_xinput) return TRUE; - if(xfc->floatbar && !(app)) - xf_floatbar_set_root_y(xfc, event->xmotion.y); - - return xf_generic_MotionNotify(xfc, event->xmotion.x, event->xmotion.y, - event->xmotion.state, event->xmotion.window, app); + return xf_generic_MotionNotify(xfc, event->x, event->y, event->state, event->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; - - 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; + const button_map* cur = &xfc->button_map[i]; - 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 */ @@ -447,9 +435,8 @@ BOOL xf_generic_ButtonPress(xfContext* xfc, int x, int y, int button, return TRUE; /* Translate to desktop coordinates */ - XTranslateCoordinates(xfc->display, window, - RootWindowOfScreen(xfc->screen), - x, y, &x, &y, &childWindow); + XTranslateCoordinates(xfc->display, window, RootWindowOfScreen(xfc->screen), x, y, + &x, &y, &childWindow); } xf_event_adjust_coordinates(xfc, &x, &y); @@ -463,120 +450,67 @@ BOOL xf_generic_ButtonPress(xfContext* xfc, int x, int y, int button, return TRUE; } -static BOOL xf_event_ButtonPress(xfContext* xfc, XEvent* event, BOOL app) +static BOOL xf_event_ButtonPress(xfContext* xfc, const XButtonEvent* 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->x, event->y, event->button, event->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) +static BOOL xf_event_ButtonRelease(xfContext* xfc, const XButtonEvent* 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->x, event->y, event->button, event->window, app, + FALSE); } -static BOOL xf_event_KeyPress(xfContext* xfc, XEvent* event, BOOL app) + +static BOOL xf_event_KeyPress(xfContext* xfc, const XKeyEvent* event, BOOL app) { KeySym keysym; char str[256]; - XLookupString((XKeyEvent*) event, str, sizeof(str), &keysym, NULL); - xf_keyboard_key_press(xfc, event->xkey.keycode, keysym); + WINPR_UNUSED(app); + XLookupString((XKeyEvent*)event, str, sizeof(str), &keysym, NULL); + xf_keyboard_key_press(xfc, event->keycode, keysym); return TRUE; } -static BOOL xf_event_KeyRelease(xfContext* xfc, XEvent* event, BOOL app) + +static BOOL xf_event_KeyRelease(xfContext* xfc, const XKeyEvent* event, BOOL app) { KeySym keysym; char str[256]; - XLookupString((XKeyEvent*) event, str, sizeof(str), &keysym, NULL); - xf_keyboard_key_release(xfc, event->xkey.keycode, keysym); + WINPR_UNUSED(app); + XLookupString((XKeyEvent*)event, str, sizeof(str), &keysym, NULL); + xf_keyboard_key_release(xfc, event->keycode, keysym); return TRUE; } -static BOOL xf_event_FocusIn(xfContext* xfc, XEvent* event, BOOL app) + +static BOOL xf_event_FocusIn(xfContext* xfc, const XFocusInEvent* event, BOOL app) { - if (event->xfocus.mode == NotifyGrab) + if (event->mode == NotifyGrab) return TRUE; xfc->focused = TRUE; if (xfc->mouse_active && !app) - XGrabKeyboard(xfc->display, xfc->window->handle, TRUE, GrabModeAsync, - GrabModeAsync, CurrentTime); + { + if (!xfc->window) + return FALSE; + + XGrabKeyboard(xfc->display, xfc->window->handle, TRUE, GrabModeAsync, GrabModeAsync, + CurrentTime); + } if (app) { xfAppWindow* appWindow; - xf_rail_send_activate(xfc, event->xany.window, TRUE); - appWindow = xf_AppWindowFromX11Window(xfc, event->xany.window); + xf_rail_send_activate(xfc, event->window, TRUE); + appWindow = xf_AppWindowFromX11Window(xfc, event->window); - /* Update the server with any window changes that occurred while the window was not focused. */ + /* Update the server with any window changes that occurred while the window was not focused. + */ if (appWindow) { xf_rail_adjust_position(xfc, appWindow); @@ -586,27 +520,31 @@ static BOOL xf_event_FocusIn(xfContext* xfc, XEvent* event, BOOL app) xf_keyboard_focus_in(xfc); return TRUE; } -static BOOL xf_event_FocusOut(xfContext* xfc, XEvent* event, BOOL app) + +static BOOL xf_event_FocusOut(xfContext* xfc, const XFocusOutEvent* event, BOOL app) { - if (event->xfocus.mode == NotifyUngrab) + if (event->mode == NotifyUngrab) return TRUE; xfc->focused = FALSE; - if (event->xfocus.mode == NotifyWhileGrabbed) + if (event->mode == NotifyWhileGrabbed) XUngrabKeyboard(xfc->display, CurrentTime); xf_keyboard_release_all_keypress(xfc); xf_keyboard_clear(xfc); if (app) - xf_rail_send_activate(xfc, event->xany.window, FALSE); + xf_rail_send_activate(xfc, event->window, FALSE); return TRUE; } -static BOOL xf_event_MappingNotify(xfContext* xfc, XEvent* event, BOOL app) + +static BOOL xf_event_MappingNotify(xfContext* xfc, const XMappingEvent* event, BOOL app) { - if (event->xmapping.request == MappingModifier) + WINPR_UNUSED(app); + + if (event->request == MappingModifier) { if (xfc->modifierMap) XFreeModifiermap(xfc->modifierMap); @@ -616,15 +554,16 @@ static BOOL xf_event_MappingNotify(xfContext* xfc, XEvent* event, BOOL app) return TRUE; } -static BOOL xf_event_ClientMessage(xfContext* xfc, XEvent* event, BOOL app) + +static BOOL xf_event_ClientMessage(xfContext* xfc, const XClientMessageEvent* event, BOOL app) { - if ((event->xclient.message_type == xfc->WM_PROTOCOLS) - && ((Atom) event->xclient.data.l[0] == xfc->WM_DELETE_WINDOW)) + if ((event->message_type == xfc->WM_PROTOCOLS) && + ((Atom)event->data.l[0] == xfc->WM_DELETE_WINDOW)) { if (app) { xfAppWindow* appWindow; - appWindow = xf_AppWindowFromX11Window(xfc, event->xany.window); + appWindow = xf_AppWindowFromX11Window(xfc, event->window); if (appWindow) { @@ -642,24 +581,27 @@ static BOOL xf_event_ClientMessage(xfContext* xfc, XEvent* event, BOOL app) return TRUE; } -static BOOL xf_event_EnterNotify(xfContext* xfc, XEvent* event, BOOL app) + +static BOOL xf_event_EnterNotify(xfContext* xfc, const XEnterWindowEvent* event, BOOL app) { if (!app) { + if (!xfc->window) + return FALSE; + xfc->mouse_active = TRUE; if (xfc->fullscreen) - XSetInputFocus(xfc->display, xfc->window->handle, RevertToPointerRoot, - CurrentTime); + XSetInputFocus(xfc->display, xfc->window->handle, RevertToPointerRoot, CurrentTime); if (xfc->focused) - XGrabKeyboard(xfc->display, xfc->window->handle, TRUE, GrabModeAsync, - GrabModeAsync, CurrentTime); + XGrabKeyboard(xfc->display, xfc->window->handle, TRUE, GrabModeAsync, GrabModeAsync, + CurrentTime); } else { xfAppWindow* appWindow; - appWindow = xf_AppWindowFromX11Window(xfc, event->xany.window); + appWindow = xf_AppWindowFromX11Window(xfc, event->window); /* keep track of which window has focus so that we can apply pointer updates */ @@ -671,8 +613,11 @@ static BOOL xf_event_EnterNotify(xfContext* xfc, XEvent* event, BOOL app) return TRUE; } -static BOOL xf_event_LeaveNotify(xfContext* xfc, XEvent* event, BOOL app) + +static BOOL xf_event_LeaveNotify(xfContext* xfc, const XLeaveWindowEvent* event, BOOL app) { + WINPR_UNUSED(event); + if (!app) { xfc->mouse_active = FALSE; @@ -681,31 +626,34 @@ static BOOL xf_event_LeaveNotify(xfContext* xfc, XEvent* event, BOOL app) return TRUE; } -static BOOL xf_event_ConfigureNotify(xfContext* xfc, XEvent* event, BOOL app) + +static BOOL xf_event_ConfigureNotify(xfContext* xfc, const XConfigureEvent* event, BOOL app) { Window childWindow; xfAppWindow* appWindow; - rdpSettings* settings = xfc->context.settings; + rdpSettings* settings; + settings = xfc->context.settings; if (!app) { - if (xfc->window->left != event->xconfigure.x) - xfc->window->left = event->xconfigure.x; + if (!xfc->window) + return FALSE; + + if (xfc->window->left != event->x) + xfc->window->left = event->x; - if (xfc->window->top != event->xconfigure.y) - xfc->window->top = event->xconfigure.y; + if (xfc->window->top != event->y) + xfc->window->top = event->y; - if (xfc->window->width != event->xconfigure.width || - xfc->window->height != event->xconfigure.height) + if (xfc->window->width != event->width || xfc->window->height != event->height) { - xfc->window->width = event->xconfigure.width; - xfc->window->height = event->xconfigure.height; + xfc->window->width = event->width; + xfc->window->height = event->height; #ifdef WITH_XRENDER xfc->offset_x = 0; xfc->offset_y = 0; - if (xfc->context.settings->SmartSizing - || xfc->context.settings->MultiTouchGestures) + if (xfc->context.settings->SmartSizing || xfc->context.settings->MultiTouchGestures) { xfc->scaledWidth = xfc->window->width; xfc->scaledHeight = xfc->window->height; @@ -732,7 +680,7 @@ static BOOL xf_event_ConfigureNotify(xfContext* xfc, XEvent* event, BOOL app) return TRUE; } - appWindow = xf_AppWindowFromX11Window(xfc, event->xany.window); + appWindow = xf_AppWindowFromX11Window(xfc, event->window); if (appWindow) { @@ -740,11 +688,10 @@ static BOOL xf_event_ConfigureNotify(xfContext* xfc, XEvent* event, BOOL app) * ConfigureNotify coordinates are expressed relative to the window parent. * Translate these to root window coordinates. */ - XTranslateCoordinates(xfc->display, appWindow->handle, - RootWindowOfScreen(xfc->screen), - 0, 0, &appWindow->x, &appWindow->y, &childWindow); - appWindow->width = event->xconfigure.width; - appWindow->height = event->xconfigure.height; + XTranslateCoordinates(xfc->display, appWindow->handle, RootWindowOfScreen(xfc->screen), 0, + 0, &appWindow->x, &appWindow->y, &childWindow); + appWindow->width = event->width; + appWindow->height = event->height; /* * Additional checks for not in a local move and not ignoring configure to send @@ -759,16 +706,16 @@ static BOOL xf_event_ConfigureNotify(xfContext* xfc, XEvent* event, BOOL app) } else { - if ((!event->xconfigure.send_event - || appWindow->local_move.state == LMS_NOT_ACTIVE) - && !appWindow->rail_ignore_configure && xfc->focused) + if ((!event->send_event || appWindow->local_move.state == LMS_NOT_ACTIVE) && + !appWindow->rail_ignore_configure && xfc->focused) xf_rail_adjust_position(xfc, appWindow); } } return TRUE; } -static BOOL xf_event_MapNotify(xfContext* xfc, XEvent* event, BOOL app) + +static BOOL xf_event_MapNotify(xfContext* xfc, const XMapEvent* event, BOOL app) { xfAppWindow* appWindow; @@ -776,7 +723,7 @@ static BOOL xf_event_MapNotify(xfContext* xfc, XEvent* event, BOOL app) gdi_send_suppress_output(xfc->context.gdi, FALSE); else { - appWindow = xf_AppWindowFromX11Window(xfc, event->xany.window); + appWindow = xf_AppWindowFromX11Window(xfc, event->window); if (appWindow) { @@ -785,14 +732,15 @@ static BOOL xf_event_MapNotify(xfContext* xfc, XEvent* event, BOOL app) * Doing this here would inhibit the ability to restore a maximized window * that is minimized back to the maximized state */ - //xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_RESTORE); + xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_RESTORE); appWindow->is_mapped = TRUE; } } return TRUE; } -static BOOL xf_event_UnmapNotify(xfContext* xfc, XEvent* event, BOOL app) + +static BOOL xf_event_UnmapNotify(xfContext* xfc, const XUnmapEvent* event, BOOL app) { xfAppWindow* appWindow; xf_keyboard_release_all_keypress(xfc); @@ -801,7 +749,7 @@ static BOOL xf_event_UnmapNotify(xfContext* xfc, XEvent* event, BOOL app) gdi_send_suppress_output(xfc->context.gdi, TRUE); else { - appWindow = xf_AppWindowFromX11Window(xfc, event->xany.window); + appWindow = xf_AppWindowFromX11Window(xfc, event->window); if (appWindow) { @@ -811,19 +759,18 @@ static BOOL xf_event_UnmapNotify(xfContext* xfc, XEvent* event, BOOL app) return TRUE; } -static BOOL xf_event_PropertyNotify(xfContext* xfc, XEvent* event, BOOL app) + +static BOOL xf_event_PropertyNotify(xfContext* xfc, const XPropertyEvent* event, BOOL app) { /* * This section handles sending the appropriate commands to the rail server * when the window has been minimized, maximized, restored locally * ie. not using the buttons on the rail window itself */ - if ((((Atom) event->xproperty.atom == xfc->_NET_WM_STATE) - && (event->xproperty.state != PropertyDelete)) || - (((Atom) event->xproperty.atom == xfc->WM_STATE) - && (event->xproperty.state != PropertyDelete))) + if ((((Atom)event->atom == xfc->_NET_WM_STATE) && (event->state != PropertyDelete)) || + (((Atom)event->atom == xfc->WM_STATE) && (event->state != PropertyDelete))) { - int i; + unsigned long i; BOOL status; BOOL maxVert = FALSE; BOOL maxHorz = FALSE; @@ -836,29 +783,29 @@ static BOOL xf_event_PropertyNotify(xfContext* xfc, XEvent* event, BOOL app) if (app) { - appWindow = xf_AppWindowFromX11Window(xfc, event->xany.window); + appWindow = xf_AppWindowFromX11Window(xfc, event->window); if (!appWindow) return TRUE; } - if ((Atom) event->xproperty.atom == xfc->_NET_WM_STATE) + if ((Atom)event->atom == xfc->_NET_WM_STATE) { - status = xf_GetWindowProperty(xfc, event->xproperty.window, - xfc->_NET_WM_STATE, 12, &nitems, &bytes, &prop); + status = xf_GetWindowProperty(xfc, event->window, xfc->_NET_WM_STATE, 12, &nitems, + &bytes, &prop); if (status) { for (i = 0; i < nitems; i++) { - if ((Atom)((UINT16**) prop)[i] == XInternAtom(xfc->display, - "_NET_WM_STATE_MAXIMIZED_VERT", False)) + if ((Atom)((UINT16**)prop)[i] == + XInternAtom(xfc->display, "_NET_WM_STATE_MAXIMIZED_VERT", False)) { maxVert = TRUE; } - if ((Atom)((UINT16**) prop)[i] == XInternAtom(xfc->display, - "_NET_WM_STATE_MAXIMIZED_HORZ", False)) + if ((Atom)((UINT16**)prop)[i] == + XInternAtom(xfc->display, "_NET_WM_STATE_MAXIMIZED_HORZ", False)) { maxHorz = TRUE; } @@ -868,15 +815,15 @@ static BOOL xf_event_PropertyNotify(xfContext* xfc, XEvent* event, BOOL app) } } - if ((Atom) event->xproperty.atom == xfc->WM_STATE) + if ((Atom)event->atom == xfc->WM_STATE) { - status = xf_GetWindowProperty(xfc, event->xproperty.window, - xfc->WM_STATE, 1, &nitems, &bytes, &prop); + status = + xf_GetWindowProperty(xfc, event->window, xfc->WM_STATE, 1, &nitems, &bytes, &prop); if (status) { /* If the window is in the iconic state */ - if (((UINT32) *prop == 3)) + if (((UINT32)*prop == 3)) minimized = TRUE; else minimized = FALSE; @@ -888,8 +835,8 @@ static BOOL xf_event_PropertyNotify(xfContext* xfc, XEvent* event, BOOL app) if (app) { - if (maxVert && maxHorz && !minimized - && (appWindow->rail_state != WINDOW_SHOW_MAXIMIZED)) + if (maxVert && maxHorz && !minimized && + (appWindow->rail_state != WINDOW_SHOW_MAXIMIZED)) { appWindow->rail_state = WINDOW_SHOW_MAXIMIZED; xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_MAXIMIZE); @@ -899,8 +846,8 @@ static BOOL xf_event_PropertyNotify(xfContext* xfc, XEvent* event, BOOL app) appWindow->rail_state = WINDOW_SHOW_MINIMIZED; xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_MINIMIZE); } - else if (!minimized && !maxVert && !maxHorz - && (appWindow->rail_state != WINDOW_SHOW)) + else if (!minimized && !maxVert && !maxHorz && (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); @@ -912,8 +859,8 @@ static BOOL xf_event_PropertyNotify(xfContext* xfc, XEvent* event, BOOL app) return TRUE; } -static BOOL xf_event_suppress_events(xfContext* xfc, xfAppWindow* appWindow, - XEvent* event) + +static BOOL xf_event_suppress_events(xfContext* xfc, xfAppWindow* appWindow, const XEvent* event) { if (!xfc->remote_app) return FALSE; @@ -924,7 +871,8 @@ static BOOL xf_event_suppress_events(xfContext* xfc, xfAppWindow* appWindow, /* No local move in progress, nothing to do */ - /* Prevent Configure from happening during indeterminant state of Horz or Vert Max only */ + /* Prevent Configure from happening during indeterminant state of Horz or Vert Max only + */ if ((event->type == ConfigureNotify) && appWindow->rail_ignore_configure) { appWindow->rail_ignore_configure = FALSE; @@ -935,13 +883,16 @@ static BOOL xf_event_suppress_events(xfContext* xfc, xfAppWindow* appWindow, case LMS_STARTING: - /* Local move initiated by RDP server, but we have not yet seen any updates from the X server */ + /* Local move initiated by RDP server, but we have not yet seen any updates from the X + * server */ switch (event->type) { case ConfigureNotify: - /* Starting to see move events from the X server. Local move is now in progress. */ + /* Starting to see move events from the X server. Local move is now in progress. + */ appWindow->local_move.state = LMS_ACTIVE; - /* Allow these events to be processed during move to keep our state up to date. */ + /* Allow these events to be processed during move to keep our state up to date. + */ break; case ButtonPress: @@ -997,11 +948,12 @@ static BOOL xf_event_suppress_events(xfContext* xfc, xfAppWindow* appWindow, return FALSE; } -BOOL xf_event_process(freerdp* instance, XEvent* event) + +BOOL xf_event_process(freerdp* instance, const XEvent* event) { BOOL status = TRUE; xfAppWindow* appWindow; - xfContext* xfc = (xfContext*) instance->context; + xfContext* xfc = (xfContext*)instance->context; rdpSettings* settings = xfc->context.settings; if (xfc->remote_app) @@ -1018,64 +970,67 @@ 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); if (event->type != MotionNotify) { - DEBUG_X11("%s Event(%d): wnd=0x%08lX", x11_event_string(event->type), - event->type, (unsigned long) event->xany.window); + DEBUG_X11("%s Event(%d): wnd=0x%08lX", x11_event_string(event->type), event->type, + (unsigned long)event->xany.window); } switch (event->type) { case Expose: - status = xf_event_Expose(xfc, event, xfc->remote_app); + status = xf_event_Expose(xfc, &event->xexpose, xfc->remote_app); break; case VisibilityNotify: - status = xf_event_VisibilityNotify(xfc, event, xfc->remote_app); + status = xf_event_VisibilityNotify(xfc, &event->xvisibility, xfc->remote_app); break; case MotionNotify: - status = xf_event_MotionNotify(xfc, event, xfc->remote_app); + status = xf_event_MotionNotify(xfc, &event->xmotion, xfc->remote_app); break; case ButtonPress: - status = xf_event_ButtonPress(xfc, event, xfc->remote_app); + status = xf_event_ButtonPress(xfc, &event->xbutton, xfc->remote_app); break; case ButtonRelease: - status = xf_event_ButtonRelease(xfc, event, xfc->remote_app); + status = xf_event_ButtonRelease(xfc, &event->xbutton, xfc->remote_app); break; case KeyPress: - status = xf_event_KeyPress(xfc, event, xfc->remote_app); + status = xf_event_KeyPress(xfc, &event->xkey, xfc->remote_app); break; case KeyRelease: - status = xf_event_KeyRelease(xfc, event, xfc->remote_app); + status = xf_event_KeyRelease(xfc, &event->xkey, xfc->remote_app); break; case FocusIn: - status = xf_event_FocusIn(xfc, event, xfc->remote_app); + status = xf_event_FocusIn(xfc, &event->xfocus, xfc->remote_app); break; case FocusOut: - status = xf_event_FocusOut(xfc, event, xfc->remote_app); + status = xf_event_FocusOut(xfc, &event->xfocus, xfc->remote_app); break; case EnterNotify: - status = xf_event_EnterNotify(xfc, event, xfc->remote_app); + status = xf_event_EnterNotify(xfc, &event->xcrossing, xfc->remote_app); break; case LeaveNotify: - status = xf_event_LeaveNotify(xfc, event, xfc->remote_app); + status = xf_event_LeaveNotify(xfc, &event->xcrossing, xfc->remote_app); break; case NoExpose: @@ -1085,30 +1040,30 @@ BOOL xf_event_process(freerdp* instance, XEvent* event) break; case ConfigureNotify: - status = xf_event_ConfigureNotify(xfc, event, xfc->remote_app); + status = xf_event_ConfigureNotify(xfc, &event->xconfigure, xfc->remote_app); break; case MapNotify: - status = xf_event_MapNotify(xfc, event, xfc->remote_app); + status = xf_event_MapNotify(xfc, &event->xmap, xfc->remote_app); break; case UnmapNotify: - status = xf_event_UnmapNotify(xfc, event, xfc->remote_app); + status = xf_event_UnmapNotify(xfc, &event->xunmap, xfc->remote_app); break; case ReparentNotify: break; case MappingNotify: - status = xf_event_MappingNotify(xfc, event, xfc->remote_app); + status = xf_event_MappingNotify(xfc, &event->xmapping, xfc->remote_app); break; case ClientMessage: - status = xf_event_ClientMessage(xfc, event, xfc->remote_app); + status = xf_event_ClientMessage(xfc, &event->xclient, xfc->remote_app); break; case PropertyNotify: - status = xf_event_PropertyNotify(xfc, event, xfc->remote_app); + status = xf_event_PropertyNotify(xfc, &event->xproperty, xfc->remote_app); break; default: diff --git a/client/X11/xf_event.h b/client/X11/xf_event.h index 4e880aa..185c83c 100644 --- a/client/X11/xf_event.h +++ b/client/X11/xf_event.h @@ -28,13 +28,15 @@ 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, ...); +BOOL xf_event_process(freerdp* instance, const XEvent* event); +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..0966ff5 100644 --- a/client/X11/xf_floatbar.c +++ b/client/X11/xf_floatbar.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include "xf_floatbar.h" @@ -31,31 +30,35 @@ #define TAG CLIENT_TAG("x11") -#define FLOATBAR_HEIGHT 26 -#define FLOATBAR_DEFAULT_WIDTH 576 -#define FLOATBAR_MIN_WIDTH 200 -#define FLOATBAR_BORDER 24 -#define FLOATBAR_BUTTON_WIDTH 24 -#define FLOATBAR_COLOR_BACKGROUND "RGB:31/6c/a9" -#define FLOATBAR_COLOR_BORDER "RGB:75/9a/c8" -#define FLOATBAR_COLOR_FOREGROUND "RGB:FF/FF/FF" +#define FLOATBAR_HEIGHT 26 +#define FLOATBAR_DEFAULT_WIDTH 576 +#define FLOATBAR_MIN_WIDTH 200 +#define FLOATBAR_BORDER 24 +#define FLOATBAR_BUTTON_WIDTH 24 +#define FLOATBAR_COLOR_BACKGROUND "RGB:31/6c/a9" +#define FLOATBAR_COLOR_BORDER "RGB:75/9a/c8" +#define FLOATBAR_COLOR_FOREGROUND "RGB:FF/FF/FF" #ifdef WITH_DEBUG_X11 #define DEBUG_X11(...) WLog_DBG(TAG, __VA_ARGS__) #else -#define DEBUG_X11(...) do { } while (0) +#define DEBUG_X11(...) \ + do \ + { \ + } while (0) #endif -#define XF_FLOATBAR_MODE_NONE 0 -#define XF_FLOATBAR_MODE_DRAGGING 1 -#define XF_FLOATBAR_MODE_RESIZE_LEFT 2 -#define XF_FLOATBAR_MODE_RESIZE_RIGHT 3 +#define XF_FLOATBAR_MODE_NONE 0 +#define XF_FLOATBAR_MODE_DRAGGING 1 +#define XF_FLOATBAR_MODE_RESIZE_LEFT 2 +#define XF_FLOATBAR_MODE_RESIZE_RIGHT 3 - -#define XF_FLOATBAR_BUTTON_CLOSE 1 -#define XF_FLOATBAR_BUTTON_RESTORE 2 +#define XF_FLOATBAR_BUTTON_CLOSE 1 +#define XF_FLOATBAR_BUTTON_RESTORE 2 #define XF_FLOATBAR_BUTTON_MINIMIZE 3 -#define XF_FLOATBAR_BUTTON_LOCKED 4 +#define XF_FLOATBAR_BUTTON_LOCKED 4 + +typedef BOOL (*OnClick)(xfFloatbar*); typedef struct xf_floatbar_button xfFloatbarButton; @@ -71,6 +74,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 +93,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 +168,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,18 +239,26 @@ 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)); + button = (xfFloatbarButton*)calloc(1, sizeof(xfFloatbarButton)); button->type = type; switch (type) @@ -191,74 +289,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, - FLOATBAR_BUTTON_WIDTH, 0, CopyFromParent, InputOutput, CopyFromParent, 0, NULL); - XSelectInput(xfc->display, button->handle, ExposureMask | ButtonPressMask | ButtonReleaseMask | - FocusChangeMask | LeaveWindowMask | EnterWindowMask | StructureNotifyMask); + button->handle = XCreateWindow(floatbar->xfc->display, floatbar->handle, button->x, 0, + FLOATBAR_BUTTON_WIDTH, FLOATBAR_BUTTON_WIDTH, 0, CopyFromParent, + InputOutput, CopyFromParent, 0, NULL); + 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; - floatbar = (xfFloatbar*) calloc(1, sizeof(xfFloatbar)); - floatbar->locked = TRUE; - XGetWindowAttributes(xfc->display, window, &attr); + /* Force disable with remote app */ + if (xfc->remote_app) + return NULL; - 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; - } - } + floatbar = (xfFloatbar*)calloc(1, sizeof(xfFloatbar)); - 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); + if (!floatbar) + return NULL; + + 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); return color.pixel; } -static void xf_floatbar_event_expose(xfContext* xfc, XEvent* event) +static void xf_floatbar_event_expose(xfFloatbar* floatbar) { 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,38 +380,35 @@ 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, - floatbar->height); + 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); - /* 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); + 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 (limit to maximum file name) */ + len = strnlen(floatbar->title, MAX_PATH); + 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, Window window) { - xfFloatbar* floatbar; int i, size; size = ARRAYSIZE(floatbar->buttons); - floatbar = xfc->window->floatbar; for (i = 0; i < size; i++) { - if (floatbar->buttons[i]->handle == event->xany.window) + if (floatbar->buttons[i]->handle == window) { return floatbar->buttons[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) { - 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++) @@ -337,15 +431,18 @@ static void xf_floatbar_button_update_positon(xfContext* xfc, XEvent* event) switch (button->type) { case XF_FLOATBAR_BUTTON_CLOSE: - button->x = floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * button->type; + button->x = + floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * button->type; break; case XF_FLOATBAR_BUTTON_RESTORE: - button->x = floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * button->type; + button->x = + floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * button->type; break; case XF_FLOATBAR_BUTTON_MINIMIZE: - button->x = floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * button->type; + button->x = + floatbar->width - FLOATBAR_BORDER - FLOATBAR_BUTTON_WIDTH * button->type; break; default: @@ -353,18 +450,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); } } -static void xf_floatbar_button_event_expose(xfContext* xfc, XEvent* event) +static void xf_floatbar_button_event_expose(xfFloatbar* floatbar, Window window) { - xfFloatbar* floatbar; - xfFloatbarButton* button; + xfFloatbarButton* button = xf_floatbar_get_button(floatbar, window); static unsigned char* bits; GC gc; Pixmap pattern; - button = xf_floatbar_get_button(xfc, event); + xfContext* xfc = floatbar->xfc; if (!button) return; @@ -402,49 +498,47 @@ 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, const XButtonEvent* event) { - xfFloatbarButton* button; - button = xf_floatbar_get_button(xfc, event); + xfFloatbarButton* button = xf_floatbar_get_button(floatbar, event->window); 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, const XButtonEvent* event) { xfFloatbarButton* button; - button = xf_floatbar_get_button(xfc, event); + button = xf_floatbar_get_button(floatbar, event->window); if (button) { if (button->clicked) - button->onclick(xfc); + button->onclick(floatbar); + button->clicked = FALSE; } } -static void xf_floatbar_event_buttonpress(xfContext* xfc, XEvent* event) +static void xf_floatbar_event_buttonpress(xfFloatbar* floatbar, const XButtonEvent* event) { - xfFloatbar* floatbar; - floatbar = xfc->window->floatbar; - - switch (event->xbutton.button) + switch (event->button) { case Button1: - if (event->xmotion.x <= FLOATBAR_BORDER) + if (event->x <= FLOATBAR_BORDER) floatbar->mode = XF_FLOATBAR_MODE_RESIZE_LEFT; - else if (event->xmotion.x >= (floatbar->width - FLOATBAR_BORDER)) + else if (event->x >= (floatbar->width - FLOATBAR_BORDER)) floatbar->mode = XF_FLOATBAR_MODE_RESIZE_RIGHT; else floatbar->mode = XF_FLOATBAR_MODE_DRAGGING; @@ -456,12 +550,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, const XButtonEvent* event) { - switch (event->xbutton.button) + switch (event->button) { case Button1: - xfc->window->floatbar->mode = XF_FLOATBAR_MODE_NONE; + floatbar->mode = XF_FLOATBAR_MODE_NONE; break; default: @@ -469,13 +563,12 @@ 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, const XMotionEvent* 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; + movement = event->x_root - floatbar->last_motion_x_root; /* set x and width depending if movement happens on the left or right */ if (floatbar->mode == XF_FLOATBAR_MODE_RESIZE_LEFT) @@ -498,13 +591,12 @@ 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, const XMotionEvent* 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; + movement = event->x_root - floatbar->last_motion_x_root; x = floatbar->x + movement; /* do nothing if floatbar would be moved out of the window */ @@ -518,78 +610,77 @@ 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, const XMotionEvent* 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)) + if ((event->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)) + else if ((event->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) + if (event->x <= FLOATBAR_BORDER || event->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->x_root; } -static void xf_floatbar_button_event_focusin(xfContext* xfc, XEvent* event) +static void xf_floatbar_button_event_focusin(xfFloatbar* floatbar, const XAnyEvent* event) { xfFloatbarButton* button; - button = xf_floatbar_get_button(xfc, event); + button = xf_floatbar_get_button(floatbar, event->window); if (button) { button->focus = TRUE; - xf_floatbar_button_event_expose(xfc, event); + xf_floatbar_button_event_expose(floatbar, event->window); } } -static void xf_floatbar_button_event_focusout(xfContext* xfc, XEvent* event) +static void xf_floatbar_button_event_focusout(xfFloatbar* floatbar, const XAnyEvent* event) { xfFloatbarButton* button; - button = xf_floatbar_get_button(xfc, event); + button = xf_floatbar_get_button(floatbar, event->window); if (button) { button->focus = FALSE; - button->clicked = FALSE; - xf_floatbar_button_event_expose(xfc, event); + xf_floatbar_button_event_expose(floatbar, event->window); } } -static void xf_floatbar_event_focusout(xfContext* xfc, XEvent* event) +static void xf_floatbar_event_focusout(xfFloatbar* floatbar) { - 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, const XEvent* event) { - xfFloatbar* floatbar; xfFloatbarButton* button; size_t i, size; - if (!xfc || !event || !xfc->window) + if (!floatbar || !floatbar->xfc || !event) return FALSE; - floatbar = xfc->window->floatbar; + if (!floatbar->created) + return FALSE; 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, const 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); + if (event->xexpose.window == floatbar->handle) + xf_floatbar_event_expose(floatbar); else - xf_floatbar_button_event_expose(xfc, event); + xf_floatbar_button_event_expose(floatbar, event->xexpose.window); break; case MotionNotify: - xf_floatbar_event_motionnotify(xfc, event); + xf_floatbar_event_motionnotify(floatbar, &event->xmotion); break; case ButtonPress: if (event->xany.window == floatbar->handle) - xf_floatbar_event_buttonpress(xfc, event); + xf_floatbar_event_buttonpress(floatbar, &event->xbutton); else - xf_floatbar_button_event_buttonpress(xfc, event); + xf_floatbar_button_event_buttonpress(floatbar, &event->xbutton); break; case ButtonRelease: if (event->xany.window == floatbar->handle) - xf_floatbar_event_buttonrelease(xfc, event); + xf_floatbar_event_buttonrelease(floatbar, &event->xbutton); else - xf_floatbar_button_event_buttonrelease(xfc, event); + xf_floatbar_button_event_buttonrelease(floatbar, &event->xbutton); 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->xany); break; case LeaveNotify: case FocusOut: if (event->xany.window == floatbar->handle) - xf_floatbar_event_focusout(xfc, event); + xf_floatbar_event_focusout(floatbar); else - xf_floatbar_button_event_focusout(xfc, event); + xf_floatbar_button_event_focusout(floatbar, &event->xany); break; case ConfigureNotify: if (event->xany.window == floatbar->handle) - xf_floatbar_button_update_positon(xfc, event); + xf_floatbar_button_update_positon(floatbar); break; case PropertyNotify: if (event->xany.window == floatbar->handle) - xf_floatbar_button_update_positon(xfc, event); + xf_floatbar_button_update_positon(floatbar); 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..145514b 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, const XEvent* event); +BOOL xf_floatbar_check_event(xfFloatbar* floatbar, const 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_gdi.c b/client/X11/xf_gdi.c index 8b31d74..949e62d 100644 --- a/client/X11/xf_gdi.c +++ b/client/X11/xf_gdi.c @@ -39,18 +39,16 @@ #include #define TAG CLIENT_TAG("x11") -static const UINT8 GDI_BS_HATCHED_PATTERNS[] = -{ +static const UINT8 GDI_BS_HATCHED_PATTERNS[] = { 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, /* HS_HORIZONTAL */ 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, /* HS_VERTICAL */ 0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F, /* HS_FDIAGONAL */ 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0xFE, /* HS_BDIAGONAL */ 0xF7, 0xF7, 0xF7, 0x00, 0xF7, 0xF7, 0xF7, 0xF7, /* HS_CROSS */ - 0x7E, 0xBD, 0xDB, 0xE7, 0xE7, 0xDB, 0xBD, 0x7E /* HS_DIACROSS */ + 0x7E, 0xBD, 0xDB, 0xE7, 0xE7, 0xDB, 0xBD, 0x7E /* HS_DIACROSS */ }; -static const BYTE xf_rop2_table[] = -{ +static const BYTE xf_rop2_table[] = { 0, GXclear, /* 0 */ GXnor, /* DPon */ @@ -74,7 +72,7 @@ static BOOL xf_set_rop2(xfContext* xfc, int rop2) { if ((rop2 < 0x01) || (rop2 > 0x10)) { - WLog_ERR(TAG, "Unsupported ROP2: %d", rop2); + WLog_ERR(TAG, "Unsupported ROP2: %d", rop2); return FALSE; } @@ -210,7 +208,7 @@ static BOOL xf_set_rop3(xfContext* xfc, UINT32 rop3) if (function < 0) { - WLog_ERR(TAG, "Unsupported ROP3: 0x%08"PRIX32"", rop3); + WLog_ERR(TAG, "Unsupported ROP3: 0x%08" PRIX32 "", rop3); XSetFunction(xfc->display, xfc->gc, GXclear); return FALSE; } @@ -219,9 +217,7 @@ static BOOL xf_set_rop3(xfContext* xfc, UINT32 rop3) return TRUE; } -static Pixmap xf_brush_new(xfContext* xfc, UINT32 width, UINT32 height, - UINT32 bpp, - BYTE* data) +static Pixmap xf_brush_new(xfContext* xfc, UINT32 width, UINT32 height, UINT32 bpp, BYTE* data) { GC gc; Pixmap bitmap; @@ -235,12 +231,11 @@ static Pixmap xf_brush_new(xfContext* xfc, UINT32 width, UINT32 height, if (data) { brushFormat = gdi_get_pixel_format(bpp); - cdata = (BYTE*) _aligned_malloc(width * height * 4, 16); - freerdp_image_copy(cdata, gdi->dstFormat, 0, 0, 0, - width, height, data, brushFormat, 0, 0, 0, - &xfc->context.gdi->palette, FREERDP_FLIP_NONE); - image = XCreateImage(xfc->display, xfc->visual, xfc->depth, - ZPixmap, 0, (char*) cdata, width, height, xfc->scanline_pad, 0); + cdata = (BYTE*)_aligned_malloc(width * height * 4, 16); + freerdp_image_copy(cdata, gdi->dstFormat, 0, 0, 0, width, height, data, brushFormat, 0, 0, + 0, &xfc->context.gdi->palette, FREERDP_FLIP_NONE); + image = XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0, (char*)cdata, width, + height, xfc->scanline_pad, 0); image->byte_order = LSBFirst; image->bitmap_bit_order = LSBFirst; gc = XCreateGC(xfc->display, xfc->drawable, 0, NULL); @@ -257,16 +252,15 @@ static Pixmap xf_brush_new(xfContext* xfc, UINT32 width, UINT32 height, return bitmap; } -static Pixmap xf_mono_bitmap_new(xfContext* xfc, int width, int height, - const BYTE* data) +static Pixmap xf_mono_bitmap_new(xfContext* xfc, int width, int height, const BYTE* data) { int scanline; XImage* image; Pixmap bitmap; scanline = (width + 7) / 8; bitmap = XCreatePixmap(xfc->display, xfc->drawable, width, height, 1); - image = XCreateImage(xfc->display, xfc->visual, 1, - ZPixmap, 0, (char*) data, width, height, 8, scanline); + image = XCreateImage(xfc->display, xfc->visual, 1, ZPixmap, 0, (char*)data, width, height, 8, + scanline); image->byte_order = LSBFirst; image->bitmap_bit_order = LSBFirst; XPutImage(xfc->display, bitmap, xfc->gc_mono, image, 0, 0, 0, 0, width, height); @@ -275,12 +269,11 @@ static Pixmap xf_mono_bitmap_new(xfContext* xfc, int width, int height, return bitmap; } -static BOOL xf_gdi_set_bounds(rdpContext* context, - const rdpBounds* bounds) +static BOOL xf_gdi_set_bounds(rdpContext* context, const rdpBounds* bounds) { XRectangle clip; - xfContext* xfc = (xfContext*) context; - xf_lock_x11(xfc, FALSE); + xfContext* xfc = (xfContext*)context; + xf_lock_x11(xfc); if (bounds) { @@ -295,39 +288,38 @@ static BOOL xf_gdi_set_bounds(rdpContext* context, XSetClipMask(xfc->display, xfc->gc, None); } - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); return TRUE; } static BOOL xf_gdi_dstblt(rdpContext* context, const DSTBLT_ORDER* dstblt) { - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; BOOL ret = FALSE; - xf_lock_x11(xfc, FALSE); + xf_lock_x11(xfc); if (!xf_set_rop3(xfc, gdi_rop3_code(dstblt->bRop))) goto fail; XSetFillStyle(xfc->display, xfc->gc, FillSolid); - XFillRectangle(xfc->display, xfc->drawing, xfc->gc, - dstblt->nLeftRect, dstblt->nTopRect, + XFillRectangle(xfc->display, xfc->drawing, xfc->gc, dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth, dstblt->nHeight); ret = TRUE; if (xfc->drawing == xfc->primary) - ret = gdi_InvalidateRegion(xfc->hdc, dstblt->nLeftRect, dstblt->nTopRect, - dstblt->nWidth, dstblt->nHeight); + ret = gdi_InvalidateRegion(xfc->hdc, dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth, + dstblt->nHeight); fail: XSetFunction(xfc->display, xfc->gc, GXcopy); - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); return ret; } static BOOL xf_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt) { const rdpBrush* brush; - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; BOOL ret = FALSE; XColor xfg, xbg; @@ -337,7 +329,7 @@ static BOOL xf_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt) if (!xf_decode_color(xfc, patblt->backColor, &xbg)) return FALSE; - xf_lock_x11(xfc, FALSE); + xf_lock_x11(xfc); brush = &patblt->brush; if (!xf_set_rop3(xfc, gdi_rop3_code(patblt->bRop))) @@ -349,24 +341,24 @@ static BOOL xf_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt) XSetFillStyle(xfc->display, xfc->gc, FillSolid); XSetBackground(xfc->display, xfc->gc, xbg.pixel); XSetForeground(xfc->display, xfc->gc, xfg.pixel); - XFillRectangle(xfc->display, xfc->drawing, xfc->gc, - patblt->nLeftRect, patblt->nTopRect, patblt->nWidth, patblt->nHeight); + XFillRectangle(xfc->display, xfc->drawing, xfc->gc, patblt->nLeftRect, patblt->nTopRect, + patblt->nWidth, patblt->nHeight); break; case GDI_BS_HATCHED: - { - Pixmap pattern = xf_mono_bitmap_new(xfc, 8, 8, - &GDI_BS_HATCHED_PATTERNS[8 * brush->hatch]); - XSetBackground(xfc->display, xfc->gc, xbg.pixel); - XSetForeground(xfc->display, xfc->gc, xfg.pixel); - XSetFillStyle(xfc->display, xfc->gc, FillOpaqueStippled); - XSetStipple(xfc->display, xfc->gc, pattern); - XSetTSOrigin(xfc->display, xfc->gc, brush->x, brush->y); - XFillRectangle(xfc->display, xfc->drawing, xfc->gc, - patblt->nLeftRect, patblt->nTopRect, patblt->nWidth, patblt->nHeight); - XFreePixmap(xfc->display, pattern); - } - break; + { + Pixmap pattern = + xf_mono_bitmap_new(xfc, 8, 8, &GDI_BS_HATCHED_PATTERNS[8 * brush->hatch]); + XSetBackground(xfc->display, xfc->gc, xbg.pixel); + XSetForeground(xfc->display, xfc->gc, xfg.pixel); + XSetFillStyle(xfc->display, xfc->gc, FillOpaqueStippled); + XSetStipple(xfc->display, xfc->gc, pattern); + XSetTSOrigin(xfc->display, xfc->gc, brush->x, brush->y); + XFillRectangle(xfc->display, xfc->drawing, xfc->gc, patblt->nLeftRect, patblt->nTopRect, + patblt->nWidth, patblt->nHeight); + XFreePixmap(xfc->display, pattern); + } + break; case GDI_BS_PATTERN: if (brush->bpp > 1) @@ -380,8 +372,8 @@ static BOOL xf_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt) XSetFillStyle(xfc->display, xfc->gc, FillTiled); XSetTile(xfc->display, xfc->gc, pattern); XSetTSOrigin(xfc->display, xfc->gc, brush->x, brush->y); - XFillRectangle(xfc->display, xfc->drawing, xfc->gc, - patblt->nLeftRect, patblt->nTopRect, patblt->nWidth, patblt->nHeight); + XFillRectangle(xfc->display, xfc->drawing, xfc->gc, patblt->nLeftRect, + patblt->nTopRect, patblt->nWidth, patblt->nHeight); XSetTile(xfc->display, xfc->gc, xfc->primary); XFreePixmap(xfc->display, pattern); } @@ -393,82 +385,78 @@ static BOOL xf_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt) XSetFillStyle(xfc->display, xfc->gc, FillOpaqueStippled); XSetStipple(xfc->display, xfc->gc, pattern); XSetTSOrigin(xfc->display, xfc->gc, brush->x, brush->y); - XFillRectangle(xfc->display, xfc->drawing, xfc->gc, - patblt->nLeftRect, patblt->nTopRect, patblt->nWidth, patblt->nHeight); + XFillRectangle(xfc->display, xfc->drawing, xfc->gc, patblt->nLeftRect, + patblt->nTopRect, patblt->nWidth, patblt->nHeight); XFreePixmap(xfc->display, pattern); } break; default: - WLog_ERR(TAG, "unimplemented brush style:%"PRIu32"", brush->style); + WLog_ERR(TAG, "unimplemented brush style:%" PRIu32 "", brush->style); goto fail; } ret = TRUE; if (xfc->drawing == xfc->primary) - ret = gdi_InvalidateRegion(xfc->hdc, patblt->nLeftRect, patblt->nTopRect, - patblt->nWidth, patblt->nHeight); + ret = gdi_InvalidateRegion(xfc->hdc, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth, + patblt->nHeight); fail: XSetFunction(xfc->display, xfc->gc, GXcopy); - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); return ret; } static BOOL xf_gdi_scrblt(rdpContext* context, const SCRBLT_ORDER* scrblt) { - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; BOOL ret = FALSE; if (!xfc->display || !xfc->drawing) return FALSE; - xf_lock_x11(xfc, FALSE); + xf_lock_x11(xfc); if (!xf_set_rop3(xfc, gdi_rop3_code(scrblt->bRop))) goto fail; - XCopyArea(xfc->display, xfc->primary, xfc->drawing, xfc->gc, scrblt->nXSrc, - scrblt->nYSrc, + XCopyArea(xfc->display, xfc->primary, xfc->drawing, xfc->gc, scrblt->nXSrc, scrblt->nYSrc, scrblt->nWidth, scrblt->nHeight, scrblt->nLeftRect, scrblt->nTopRect); ret = TRUE; if (xfc->drawing == xfc->primary) - ret = gdi_InvalidateRegion(xfc->hdc, scrblt->nLeftRect, scrblt->nTopRect, - scrblt->nWidth, scrblt->nHeight); + ret = gdi_InvalidateRegion(xfc->hdc, scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth, + scrblt->nHeight); XSetFunction(xfc->display, xfc->gc, GXcopy); fail: - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); return ret; } -static BOOL xf_gdi_opaque_rect(rdpContext* context, - const OPAQUE_RECT_ORDER* opaque_rect) +static BOOL xf_gdi_opaque_rect(rdpContext* context, const OPAQUE_RECT_ORDER* opaque_rect) { XColor color; - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; BOOL ret = TRUE; if (!xf_decode_color(xfc, opaque_rect->color, &color)) return FALSE; - xf_lock_x11(xfc, FALSE); + xf_lock_x11(xfc); XSetFunction(xfc->display, xfc->gc, GXcopy); XSetFillStyle(xfc->display, xfc->gc, FillSolid); XSetForeground(xfc->display, xfc->gc, color.pixel); - XFillRectangle(xfc->display, xfc->drawing, xfc->gc, - opaque_rect->nLeftRect, opaque_rect->nTopRect, - opaque_rect->nWidth, opaque_rect->nHeight); + XFillRectangle(xfc->display, xfc->drawing, xfc->gc, opaque_rect->nLeftRect, + opaque_rect->nTopRect, opaque_rect->nWidth, opaque_rect->nHeight); if (xfc->drawing == xfc->primary) - ret = gdi_InvalidateRegion(xfc->hdc, opaque_rect->nLeftRect, - opaque_rect->nTopRect, + ret = gdi_InvalidateRegion(xfc->hdc, opaque_rect->nLeftRect, opaque_rect->nTopRect, opaque_rect->nWidth, opaque_rect->nHeight); - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); return ret; } @@ -476,14 +464,14 @@ static BOOL xf_gdi_multi_opaque_rect(rdpContext* context, const MULTI_OPAQUE_RECT_ORDER* multi_opaque_rect) { UINT32 i; - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; BOOL ret = TRUE; XColor color; if (!xf_decode_color(xfc, multi_opaque_rect->color, &color)) return FALSE; - xf_lock_x11(xfc, FALSE); + xf_lock_x11(xfc); XSetFunction(xfc->display, xfc->gc, GXcopy); XSetFillStyle(xfc->display, xfc->gc, FillSolid); XSetForeground(xfc->display, xfc->gc, color.pixel); @@ -491,8 +479,7 @@ static BOOL xf_gdi_multi_opaque_rect(rdpContext* context, for (i = 0; i < multi_opaque_rect->numRectangles; i++) { const DELTA_RECT* rectangle = &multi_opaque_rect->rectangles[i]; - XFillRectangle(xfc->display, xfc->drawing, xfc->gc, - rectangle->left, rectangle->top, + XFillRectangle(xfc->display, xfc->drawing, xfc->gc, rectangle->left, rectangle->top, rectangle->width, rectangle->height); if (xfc->drawing == xfc->primary) @@ -503,25 +490,25 @@ static BOOL xf_gdi_multi_opaque_rect(rdpContext* context, } } - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); return ret; } static BOOL xf_gdi_line_to(rdpContext* context, const LINE_TO_ORDER* line_to) { XColor color; - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; BOOL ret = TRUE; if (!xf_decode_color(xfc, line_to->penColor, &color)) return FALSE; - xf_lock_x11(xfc, FALSE); + xf_lock_x11(xfc); xf_set_rop2(xfc, line_to->bRop2); XSetFillStyle(xfc->display, xfc->gc, FillSolid); XSetForeground(xfc->display, xfc->gc, color.pixel); - XDrawLine(xfc->display, xfc->drawing, xfc->gc, - line_to->nXStart, line_to->nYStart, line_to->nXEnd, line_to->nYEnd); + XDrawLine(xfc->display, xfc->drawing, xfc->gc, line_to->nXStart, line_to->nYStart, + line_to->nXEnd, line_to->nYEnd); if (xfc->drawing == xfc->primary) { @@ -534,12 +521,11 @@ static BOOL xf_gdi_line_to(rdpContext* context, const LINE_TO_ORDER* line_to) } XSetFunction(xfc->display, xfc->gc, GXcopy); - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); return ret; } -static BOOL xf_gdi_invalidate_poly_region(xfContext* xfc, XPoint* points, - int npoints) +static BOOL xf_gdi_invalidate_poly_region(xfContext* xfc, XPoint* points, int npoints) { int x, y, x1, y1, x2, y2; @@ -573,20 +559,19 @@ static BOOL xf_gdi_invalidate_poly_region(xfContext* xfc, XPoint* points, return gdi_InvalidateRegion(xfc->hdc, x1, y1, x2 - x1, y2 - y1); } -static BOOL xf_gdi_polyline(rdpContext* context, - const POLYLINE_ORDER* polyline) +static BOOL xf_gdi_polyline(rdpContext* context, const POLYLINE_ORDER* polyline) { UINT32 i; int npoints; XColor color; XPoint* points; - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; BOOL ret = TRUE; if (!xf_decode_color(xfc, polyline->penColor, &color)) return FALSE; - xf_lock_x11(xfc, FALSE); + xf_lock_x11(xfc); xf_set_rop2(xfc, polyline->bRop2); XSetFillStyle(xfc->display, xfc->gc, FillSolid); XSetForeground(xfc->display, xfc->gc, color.pixel); @@ -595,7 +580,7 @@ static BOOL xf_gdi_polyline(rdpContext* context, if (!points) { - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); return FALSE; } @@ -608,8 +593,7 @@ static BOOL xf_gdi_polyline(rdpContext* context, points[i + 1].y = polyline->points[i].y; } - XDrawLines(xfc->display, xfc->drawing, xfc->gc, points, npoints, - CoordModePrevious); + XDrawLines(xfc->display, xfc->drawing, xfc->gc, points, npoints, CoordModePrevious); if (xfc->drawing == xfc->primary) { @@ -619,7 +603,7 @@ static BOOL xf_gdi_polyline(rdpContext* context, XSetFunction(xfc->display, xfc->gc, GXcopy); free(points); - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); return ret; } @@ -632,28 +616,26 @@ static BOOL xf_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt) if (!context || !memblt) return FALSE; - bitmap = (xfBitmap*) memblt->bitmap; - xfc = (xfContext*) context; + bitmap = (xfBitmap*)memblt->bitmap; + xfc = (xfContext*)context; if (!bitmap || !xfc || !xfc->display || !xfc->drawing) return FALSE; - xf_lock_x11(xfc, FALSE); + xf_lock_x11(xfc); if (xf_set_rop3(xfc, gdi_rop3_code(memblt->bRop))) { - XCopyArea(xfc->display, bitmap->pixmap, xfc->drawing, xfc->gc, - memblt->nXSrc, memblt->nYSrc, memblt->nWidth, memblt->nHeight, - memblt->nLeftRect, memblt->nTopRect); + XCopyArea(xfc->display, bitmap->pixmap, xfc->drawing, xfc->gc, memblt->nXSrc, memblt->nYSrc, + memblt->nWidth, memblt->nHeight, memblt->nLeftRect, memblt->nTopRect); if (xfc->drawing == xfc->primary) - ret = gdi_InvalidateRegion(xfc->hdc, memblt->nLeftRect, - memblt->nTopRect, memblt->nWidth, - memblt->nHeight); + ret = gdi_InvalidateRegion(xfc->hdc, memblt->nLeftRect, memblt->nTopRect, + memblt->nWidth, memblt->nHeight); } XSetFunction(xfc->display, xfc->gc, GXcopy); - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); return ret; } @@ -664,7 +646,7 @@ static BOOL xf_gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt) XColor foreColor; XColor backColor; Pixmap pattern = 0; - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; BOOL ret = FALSE; if (!xfc->display || !xfc->drawing) @@ -676,9 +658,9 @@ static BOOL xf_gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt) if (!xf_decode_color(xfc, mem3blt->backColor, &backColor)) return FALSE; - xf_lock_x11(xfc, FALSE); + xf_lock_x11(xfc); brush = &mem3blt->brush; - bitmap = (xfBitmap*) mem3blt->bitmap; + bitmap = (xfBitmap*)mem3blt->bitmap; if (!xf_set_rop3(xfc, gdi_rop3_code(mem3blt->bRop))) goto fail; @@ -718,18 +700,17 @@ static BOOL xf_gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt) break; default: - WLog_ERR(TAG, "Mem3Blt unimplemented brush style:%"PRIu32"", brush->style); + WLog_ERR(TAG, "Mem3Blt unimplemented brush style:%" PRIu32 "", brush->style); goto fail; } - XCopyArea(xfc->display, bitmap->pixmap, xfc->drawing, xfc->gc, - mem3blt->nXSrc, mem3blt->nYSrc, mem3blt->nWidth, mem3blt->nHeight, - mem3blt->nLeftRect, mem3blt->nTopRect); + XCopyArea(xfc->display, bitmap->pixmap, xfc->drawing, xfc->gc, mem3blt->nXSrc, mem3blt->nYSrc, + mem3blt->nWidth, mem3blt->nHeight, mem3blt->nLeftRect, mem3blt->nTopRect); ret = TRUE; if (xfc->drawing == xfc->primary) - ret = gdi_InvalidateRegion(xfc->hdc, mem3blt->nLeftRect, mem3blt->nTopRect, - mem3blt->nWidth, mem3blt->nHeight); + ret = gdi_InvalidateRegion(xfc->hdc, mem3blt->nLeftRect, mem3blt->nTopRect, mem3blt->nWidth, + mem3blt->nHeight); XSetFillStyle(xfc->display, xfc->gc, FillSolid); XSetTSOrigin(xfc->display, xfc->gc, 0, 0); @@ -739,31 +720,30 @@ static BOOL xf_gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt) fail: XSetFunction(xfc->display, xfc->gc, GXcopy); - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); return ret; } - -static BOOL xf_gdi_polygon_sc(rdpContext* context, - const POLYGON_SC_ORDER* polygon_sc) +static BOOL xf_gdi_polygon_sc(rdpContext* context, const POLYGON_SC_ORDER* polygon_sc) { - int i, npoints; + UINT32 i; + int npoints; XPoint* points; XColor brush_color; - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; BOOL ret = TRUE; if (!xf_decode_color(xfc, polygon_sc->brushColor, &brush_color)) return FALSE; - xf_lock_x11(xfc, FALSE); + xf_lock_x11(xfc); xf_set_rop2(xfc, polygon_sc->bRop2); npoints = polygon_sc->numPoints + 1; points = calloc(npoints, sizeof(XPoint)); if (!points) { - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); return FALSE; } @@ -787,14 +767,13 @@ static BOOL xf_gdi_polygon_sc(rdpContext* context, break; default: - WLog_ERR(TAG, "PolygonSC unknown fillMode: %"PRIu32"", polygon_sc->fillMode); + WLog_ERR(TAG, "PolygonSC unknown fillMode: %" PRIu32 "", polygon_sc->fillMode); break; } XSetFillStyle(xfc->display, xfc->gc, FillSolid); XSetForeground(xfc->display, xfc->gc, brush_color.pixel); - XFillPolygon(xfc->display, xfc->drawing, xfc->gc, - points, npoints, Complex, CoordModePrevious); + XFillPolygon(xfc->display, xfc->drawing, xfc->gc, points, npoints, Complex, CoordModePrevious); if (xfc->drawing == xfc->primary) { @@ -804,20 +783,20 @@ static BOOL xf_gdi_polygon_sc(rdpContext* context, XSetFunction(xfc->display, xfc->gc, GXcopy); free(points); - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); return ret; } -static BOOL xf_gdi_polygon_cb(rdpContext* context, - POLYGON_CB_ORDER* polygon_cb) +static BOOL xf_gdi_polygon_cb(rdpContext* context, POLYGON_CB_ORDER* polygon_cb) { - int i, npoints; + UINT32 i; + int npoints; XPoint* points; Pixmap pattern; const rdpBrush* brush; XColor foreColor; XColor backColor; - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; BOOL ret = TRUE; if (!xf_decode_color(xfc, polygon_cb->foreColor, &foreColor)) @@ -826,7 +805,7 @@ static BOOL xf_gdi_polygon_cb(rdpContext* context, if (!xf_decode_color(xfc, polygon_cb->backColor, &backColor)) return FALSE; - xf_lock_x11(xfc, FALSE); + xf_lock_x11(xfc); brush = &(polygon_cb->brush); xf_set_rop2(xfc, polygon_cb->bRop2); npoints = polygon_cb->numPoints + 1; @@ -834,7 +813,7 @@ static BOOL xf_gdi_polygon_cb(rdpContext* context, if (!points) { - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); return FALSE; } @@ -858,7 +837,7 @@ static BOOL xf_gdi_polygon_cb(rdpContext* context, break; default: - WLog_ERR(TAG, "PolygonCB unknown fillMode: %"PRIu32"", polygon_cb->fillMode); + WLog_ERR(TAG, "PolygonCB unknown fillMode: %" PRIu32 "", polygon_cb->fillMode); break; } @@ -890,8 +869,8 @@ static BOOL xf_gdi_polygon_cb(rdpContext* context, } XSetTSOrigin(xfc->display, xfc->gc, brush->x, brush->y); - XFillPolygon(xfc->display, xfc->drawing, xfc->gc, - points, npoints, Complex, CoordModePrevious); + XFillPolygon(xfc->display, xfc->drawing, xfc->gc, points, npoints, Complex, + CoordModePrevious); XSetFillStyle(xfc->display, xfc->gc, FillSolid); XSetTSOrigin(xfc->display, xfc->gc, 0, 0); XFreePixmap(xfc->display, pattern); @@ -904,12 +883,12 @@ static BOOL xf_gdi_polygon_cb(rdpContext* context, } else { - WLog_ERR(TAG, "PolygonCB unimplemented brush style:%"PRIu32"", brush->style); + WLog_ERR(TAG, "PolygonCB unimplemented brush style:%" PRIu32 "", brush->style); } XSetFunction(xfc->display, xfc->gc, GXcopy); free(points); - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); return ret; } @@ -917,10 +896,10 @@ static BOOL xf_gdi_surface_frame_marker(rdpContext* context, const SURFACE_FRAME_MARKER* surface_frame_marker) { rdpSettings* settings; - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; BOOL ret = TRUE; settings = xfc->context.settings; - xf_lock_x11(xfc, FALSE); + xf_lock_x11(xfc); switch (surface_frame_marker->frameAction) { @@ -937,7 +916,8 @@ static BOOL xf_gdi_surface_frame_marker(rdpContext* context, if ((xfc->frame_x2 > xfc->frame_x1) && (xfc->frame_y2 > xfc->frame_y1)) ret = gdi_InvalidateRegion(xfc->hdc, xfc->frame_x1, xfc->frame_y1, - xfc->frame_x2 - xfc->frame_x1, xfc->frame_y2 - xfc->frame_y1); + xfc->frame_x2 - xfc->frame_x1, + xfc->frame_y2 - xfc->frame_y1); if (settings->FrameAcknowledge > 0) { @@ -948,12 +928,12 @@ static BOOL xf_gdi_surface_frame_marker(rdpContext* context, break; } - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); return ret; } -static BOOL xf_gdi_surface_update_frame(xfContext* xfc, UINT16 tx, UINT16 ty, - UINT16 width, UINT16 height) +static BOOL xf_gdi_surface_update_frame(xfContext* xfc, UINT16 tx, UINT16 ty, UINT16 width, + UINT16 height) { BOOL ret = TRUE; @@ -989,8 +969,8 @@ static BOOL xf_gdi_surface_update_frame(xfContext* xfc, UINT16 tx, UINT16 ty, return ret; } -static BOOL xf_gdi_update_screen(xfContext* xfc, const BYTE* pSrcData, - UINT32 scanline, const REGION16* pRegion) +static BOOL xf_gdi_update_screen(xfContext* xfc, const BYTE* pSrcData, UINT32 scanline, + const REGION16* pRegion) { BOOL ret = FALSE; XImage* image; @@ -1021,8 +1001,8 @@ static BOOL xf_gdi_update_screen(xfContext* xfc, const BYTE* pSrcData, UINT32 width = rects[i].right - rects[i].left; UINT32 height = rects[i].bottom - rects[i].top; const BYTE* src = pSrcData + top * scanline + bpp * left; - image = XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0, - (char*) src, width, height, xfc->scanline_pad, scanline); + image = XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0, (char*)src, width, + height, xfc->scanline_pad, scanline); if (!image) break; @@ -1039,14 +1019,14 @@ static BOOL xf_gdi_update_screen(xfContext* xfc, const BYTE* pSrcData, return ret; } -static BOOL xf_gdi_surface_bits(rdpContext* context, - const SURFACE_BITS_COMMAND* cmd) +static BOOL xf_gdi_surface_bits(rdpContext* context, const SURFACE_BITS_COMMAND* cmd) { BYTE* pSrcData; - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; BOOL ret = FALSE; DWORD format; rdpGdi* gdi; + size_t size; REGION16 region; RECTANGLE_16 cmdRect; @@ -1059,24 +1039,25 @@ static BOOL xf_gdi_surface_bits(rdpContext* context, cmdRect.right = cmdRect.left + cmd->bmp.width; cmdRect.bottom = cmdRect.top + cmd->bmp.height; gdi = context->gdi; - xf_lock_x11(xfc, FALSE); + xf_lock_x11(xfc); switch (cmd->bmp.codecID) { case RDP_CODEC_ID_REMOTEFX: if (!rfx_process_message(context->codecs->rfx, cmd->bmp.bitmapData, cmd->bmp.bitmapDataLength, cmd->destLeft, cmd->destTop, - gdi->primary_buffer, gdi->dstFormat, gdi->stride, - gdi->height, ®ion)) + gdi->primary_buffer, gdi->dstFormat, gdi->stride, gdi->height, + ®ion)) goto fail; break; case RDP_CODEC_ID_NSCODEC: if (!nsc_process_message(context->codecs->nsc, cmd->bmp.bpp, cmd->bmp.width, - cmd->bmp.height, cmd->bmp.bitmapData, cmd->bmp.bitmapDataLength, - gdi->primary_buffer, gdi->dstFormat, gdi->stride, - 0, 0, cmd->bmp.width, cmd->bmp.height, FREERDP_FLIP_VERTICAL)) + cmd->bmp.height, cmd->bmp.bitmapData, + cmd->bmp.bitmapDataLength, gdi->primary_buffer, gdi->dstFormat, + gdi->stride, 0, 0, cmd->bmp.width, cmd->bmp.height, + FREERDP_FLIP_VERTICAL)) goto fail; region16_union_rect(®ion, ®ion, &cmdRect); @@ -1085,26 +1066,31 @@ static BOOL xf_gdi_surface_bits(rdpContext* context, case RDP_CODEC_ID_NONE: pSrcData = cmd->bmp.bitmapData; format = gdi_get_pixel_format(cmd->bmp.bpp); + size = cmd->bmp.width * cmd->bmp.height * GetBytesPerPixel(format); + if (size > cmd->bmp.bitmapDataLength) + { + WLog_ERR(TAG, "Short nocodec message: got %" PRIu32 " bytes, require %" PRIuz, + cmd->bmp.bitmapDataLength, size); + goto fail; + } - if (!freerdp_image_copy(gdi->primary_buffer, gdi->dstFormat, gdi->stride, - cmd->destLeft, cmd->destTop, cmd->bmp.width, cmd->bmp.height, - pSrcData, format, 0, 0, 0, - &xfc->context.gdi->palette, FREERDP_FLIP_VERTICAL)) + if (!freerdp_image_copy(gdi->primary_buffer, gdi->dstFormat, gdi->stride, cmd->destLeft, + cmd->destTop, cmd->bmp.width, cmd->bmp.height, pSrcData, format, + 0, 0, 0, &xfc->context.gdi->palette, FREERDP_FLIP_VERTICAL)) goto fail; region16_union_rect(®ion, ®ion, &cmdRect); break; default: - WLog_ERR(TAG, "Unsupported codecID %"PRIu16"", cmd->bmp.codecID); - ret = TRUE; + WLog_ERR(TAG, "Unsupported codecID %" PRIu16 "", cmd->bmp.codecID); goto fail; } ret = xf_gdi_update_screen(xfc, gdi->primary_buffer, gdi->stride, ®ion); fail: region16_uninit(®ion); - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); return ret; } @@ -1126,4 +1112,3 @@ void xf_gdi_register_update_callbacks(rdpUpdate* update) update->SurfaceBits = xf_gdi_surface_bits; update->SurfaceFrameMarker = xf_gdi_surface_frame_marker; } - diff --git a/client/X11/xf_gfx.c b/client/X11/xf_gfx.c index b68a297..cb3423e 100644 --- a/client/X11/xf_gfx.c +++ b/client/X11/xf_gfx.c @@ -38,19 +38,22 @@ static UINT xf_OutputUpdate(xfContext* xfc, xfGfxSurface* surface) RECTANGLE_16 surfaceRect; rdpGdi* gdi; UINT32 nbRects, x; + double sx, sy; const RECTANGLE_16* rects; gdi = xfc->context.gdi; surfaceX = surface->gdi.outputOriginX; surfaceY = surface->gdi.outputOriginY; surfaceRect.left = 0; surfaceRect.top = 0; - surfaceRect.right = surface->gdi.width; - surfaceRect.bottom = surface->gdi.height; + surfaceRect.right = surface->gdi.mappedWidth; + surfaceRect.bottom = surface->gdi.mappedHeight; XSetClipMask(xfc->display, xfc->gc, None); XSetFunction(xfc->display, xfc->gc, GXcopy); XSetFillStyle(xfc->display, xfc->gc, FillSolid); - region16_intersect_rect(&(surface->gdi.invalidRegion), - &(surface->gdi.invalidRegion), &surfaceRect); + region16_intersect_rect(&(surface->gdi.invalidRegion), &(surface->gdi.invalidRegion), + &surfaceRect); + sx = surface->gdi.outputTargetWidth / (double)surface->gdi.mappedWidth; + sy = surface->gdi.outputTargetHeight / (double)surface->gdi.mappedHeight; if (!(rects = region16_rects(&surface->gdi.invalidRegion, &nbRects))) return CHANNEL_RC_OK; @@ -59,47 +62,43 @@ static UINT xf_OutputUpdate(xfContext* xfc, xfGfxSurface* surface) { const UINT32 nXSrc = rects[x].left; const UINT32 nYSrc = rects[x].top; - const UINT32 width = rects[x].right - nXSrc; - const UINT32 height = rects[x].bottom - nYSrc; - const UINT32 nXDst = surfaceX + nXSrc; - const UINT32 nYDst = surfaceY + nYSrc; + const UINT32 swidth = rects[x].right - nXSrc; + const UINT32 sheight = rects[x].bottom - nYSrc; + const UINT32 nXDst = surfaceX + nXSrc * sx; + const UINT32 nYDst = surfaceY + nYSrc * sy; + const UINT32 dwidth = swidth * sx; + const UINT32 dheight = sheight * sy; if (surface->stage) { - if (!freerdp_image_copy(surface->stage, gdi->dstFormat, - surface->stageScanline, nXSrc, nYSrc, - width, height, - surface->gdi.data, surface->gdi.format, - surface->gdi.scanline, nXSrc, nYSrc, - NULL, FREERDP_FLIP_NONE)) + if (!freerdp_image_scale(surface->stage, gdi->dstFormat, surface->stageScanline, nXSrc, + nYSrc, dwidth, dheight, surface->gdi.data, surface->gdi.format, + surface->gdi.scanline, nXSrc, nYSrc, swidth, sheight)) goto fail; } if (xfc->remote_app) { - XPutImage(xfc->display, xfc->primary, xfc->gc, - surface->image, nXSrc, nYSrc, - nXDst, nYDst, width, height); - xf_lock_x11(xfc, FALSE); - xf_rail_paint(xfc, nXDst, nYDst, nXDst + width, nYDst + height); - xf_unlock_x11(xfc, FALSE); + XPutImage(xfc->display, xfc->primary, xfc->gc, surface->image, nXSrc, nYSrc, nXDst, + nYDst, dwidth, dheight); + xf_lock_x11(xfc); + xf_rail_paint(xfc, nXDst, nYDst, nXDst + dwidth, nYDst + dheight); + xf_unlock_x11(xfc); } else #ifdef WITH_XRENDER - if (xfc->context.settings->SmartSizing - || xfc->context.settings->MultiTouchGestures) - { - XPutImage(xfc->display, xfc->primary, xfc->gc, surface->image, - nXSrc, nYSrc, nXDst, nYDst, width, height); - xf_draw_screen(xfc, nXDst, nYDst, width, height); - } - else + if (xfc->context.settings->SmartSizing || xfc->context.settings->MultiTouchGestures) + { + XPutImage(xfc->display, xfc->primary, xfc->gc, surface->image, nXSrc, nYSrc, nXDst, + nYDst, dwidth, dheight); + xf_draw_screen(xfc, nXDst, nYDst, dwidth, dheight); + } + else #endif - { - XPutImage(xfc->display, xfc->drawable, xfc->gc, - surface->image, nXSrc, nYSrc, - nXDst, nYDst, width, height); - } + { + XPutImage(xfc->display, xfc->drawable, xfc->gc, surface->image, nXSrc, nYSrc, nXDst, + nYDst, dwidth, dheight); + } } rc = CHANNEL_RC_OK; @@ -115,45 +114,53 @@ static UINT xf_UpdateSurfaces(RdpgfxClientContext* context) UINT16 count; UINT32 index; UINT status = CHANNEL_RC_OK; - xfGfxSurface* surface; UINT16* pSurfaceIds = NULL; rdpGdi* gdi = (rdpGdi*)context->custom; - xfContext* xfc = (xfContext*) gdi->context; + xfContext* xfc; if (!gdi) return status; - if (!gdi->graphicsReset) - return status; - if (gdi->suppressOutput) return CHANNEL_RC_OK; + xfc = (xfContext*)gdi->context; + EnterCriticalSection(&context->mux); context->GetSurfaceIds(context, &pSurfaceIds, &count); for (index = 0; index < count; index++) { - surface = (xfGfxSurface*) context->GetSurfaceData(context, pSurfaceIds[index]); + xfGfxSurface* surface = (xfGfxSurface*)context->GetSurfaceData(context, pSurfaceIds[index]); - if (!surface || !surface->gdi.outputMapped) + if (!surface) continue; - status = xf_OutputUpdate(xfc, surface); + /* If UpdateSurfaceArea callback is available, the output has already been updated. */ + if (context->UpdateSurfaceArea) + { + if (surface->gdi.windowId != 0) + continue; + } + + status = ERROR_INTERNAL_ERROR; + + if (surface->gdi.outputMapped) + status = xf_OutputUpdate(xfc, surface); if (status != 0) break; } free(pSurfaceIds); + LeaveCriticalSection(&context->mux); return status; } -UINT xf_OutputExpose(xfContext* xfc, UINT32 x, UINT32 y, - UINT32 width, UINT32 height) +UINT xf_OutputExpose(xfContext* xfc, UINT32 x, UINT32 y, UINT32 width, UINT32 height) { UINT16 count; UINT32 index; - UINT status = CHANNEL_RC_OK; + UINT status = ERROR_INTERNAL_ERROR; xfGfxSurface* surface; RECTANGLE_16 invalidRect; RECTANGLE_16 surfaceRect; @@ -164,19 +171,27 @@ 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; + + if (!TryEnterCriticalSection(&context->mux)) + { + free(pSurfaceIds); + return CHANNEL_RC_OK; + } for (index = 0; index < count; index++) { - surface = (xfGfxSurface*) context->GetSurfaceData(context, pSurfaceIds[index]); + surface = (xfGfxSurface*)context->GetSurfaceData(context, pSurfaceIds[index]); if (!surface || !surface->gdi.outputMapped) continue; surfaceRect.left = surface->gdi.outputOriginX; surfaceRect.top = surface->gdi.outputOriginY; - surfaceRect.right = surface->gdi.outputOriginX + surface->gdi.width; - surfaceRect.bottom = surface->gdi.outputOriginY + surface->gdi.height; + surfaceRect.right = surface->gdi.outputOriginX + surface->gdi.outputTargetWidth; + surfaceRect.bottom = surface->gdi.outputOriginY + surface->gdi.outputTargetHeight; if (rectangles_intersection(&invalidRect, &surfaceRect, &intersection)) { @@ -185,14 +200,19 @@ UINT xf_OutputExpose(xfContext* xfc, UINT32 x, UINT32 y, intersection.top -= surfaceRect.top; intersection.right -= surfaceRect.left; intersection.bottom -= surfaceRect.top; - region16_union_rect(&surface->gdi.invalidRegion, - &surface->gdi.invalidRegion, + region16_union_rect(&surface->gdi.invalidRegion, &surface->gdi.invalidRegion, &intersection); } } free(pSurfaceIds); + LeaveCriticalSection(&context->mux); IFCALLRET(context->UpdateSurfaces, status, context); + + if (status != CHANNEL_RC_OK) + goto fail; + +fail: return status; } @@ -215,7 +235,6 @@ UINT32 x11_pad_scanline(UINT32 scanline, UINT32 inPad) return scanline; } - /** * Function description * @@ -228,8 +247,8 @@ static UINT xf_CreateSurface(RdpgfxClientContext* context, size_t size; xfGfxSurface* surface; rdpGdi* gdi = (rdpGdi*)context->custom; - xfContext* xfc = (xfContext*) gdi->context; - surface = (xfGfxSurface*) calloc(1, sizeof(xfGfxSurface)); + xfContext* xfc = (xfContext*)gdi->context; + surface = (xfGfxSurface*)calloc(1, sizeof(xfGfxSurface)); if (!surface) return CHANNEL_RC_NO_MEMORY; @@ -243,8 +262,12 @@ static UINT xf_CreateSurface(RdpgfxClientContext* context, } surface->gdi.surfaceId = createSurface->surfaceId; - surface->gdi.width = (UINT32) createSurface->width; - surface->gdi.height = (UINT32) createSurface->height; + surface->gdi.width = x11_pad_scanline(createSurface->width, 0); + surface->gdi.height = x11_pad_scanline(createSurface->height, 0); + surface->gdi.mappedWidth = createSurface->width; + surface->gdi.mappedHeight = createSurface->height; + surface->gdi.outputTargetWidth = createSurface->width; + surface->gdi.outputTargetHeight = createSurface->height; switch (createSurface->pixelFormat) { @@ -257,7 +280,8 @@ static UINT xf_CreateSurface(RdpgfxClientContext* context, break; default: - WLog_ERR(TAG, "%s: unknown pixelFormat 0x%"PRIx32"", __FUNCTION__, createSurface->pixelFormat); + WLog_ERR(TAG, "%s: unknown pixelFormat 0x%" PRIx32 "", __FUNCTION__, + createSurface->pixelFormat); ret = ERROR_INTERNAL_ERROR; goto out_free; } @@ -277,9 +301,10 @@ static UINT xf_CreateSurface(RdpgfxClientContext* context, if (AreColorFormatsEqualNoAlpha(gdi->dstFormat, surface->gdi.format)) { - surface->image = XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0, - (char*) surface->gdi.data, surface->gdi.width, surface->gdi.height, - xfc->scanline_pad, surface->gdi.scanline); + surface->image = + XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0, + (char*)surface->gdi.data, surface->gdi.mappedWidth, + surface->gdi.mappedHeight, xfc->scanline_pad, surface->gdi.scanline); } else { @@ -288,7 +313,7 @@ static UINT xf_CreateSurface(RdpgfxClientContext* context, surface->stageScanline = width * bytes; surface->stageScanline = x11_pad_scanline(surface->stageScanline, xfc->scanline_pad); size = surface->stageScanline * surface->gdi.height; - surface->stage = (BYTE*) _aligned_malloc(size, 16); + surface->stage = (BYTE*)_aligned_malloc(size, 16); if (!surface->stage) { @@ -297,10 +322,10 @@ static UINT xf_CreateSurface(RdpgfxClientContext* context, } ZeroMemory(surface->stage, size); - surface->image = XCreateImage(xfc->display, xfc->visual, xfc->depth, - ZPixmap, 0, (char*) surface->stage, - surface->gdi.width, surface->gdi.height, - xfc->scanline_pad, surface->stageScanline); + surface->image = + XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0, (char*)surface->stage, + surface->gdi.mappedWidth, surface->gdi.mappedHeight, xfc->scanline_pad, + surface->stageScanline); } if (!surface->image) @@ -314,7 +339,7 @@ static UINT xf_CreateSurface(RdpgfxClientContext* context, surface->gdi.outputMapped = FALSE; region16_init(&surface->gdi.invalidRegion); - if (context->SetSurfaceData(context, surface->gdi.surfaceId, (void*) surface) != CHANNEL_RC_OK) + if (context->SetSurfaceData(context, surface->gdi.surfaceId, (void*)surface) != CHANNEL_RC_OK) { WLog_ERR(TAG, "%s: an error occurred during SetSurfaceData", __FUNCTION__); goto error_set_surface_data; @@ -343,11 +368,15 @@ static UINT xf_DeleteSurface(RdpgfxClientContext* context, { rdpCodecs* codecs = NULL; xfGfxSurface* surface = NULL; - surface = (xfGfxSurface*) context->GetSurfaceData(context, - deleteSurface->surfaceId); + UINT status; + EnterCriticalSection(&context->mux); + surface = (xfGfxSurface*)context->GetSurfaceData(context, deleteSurface->surfaceId); if (surface) { + if (surface->gdi.windowId > 0) + IFCALL(context->UnmapWindowForSurface, context, surface->gdi.windowId); + #ifdef WITH_GFX_H264 h264_context_free(surface->gdi.h264); #endif @@ -360,22 +389,26 @@ 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); + 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) { rdpGdi* gdi = xfc->context.gdi; gdi_graphics_pipeline_init(gdi, gfx); - gfx->UpdateSurfaces = xf_UpdateSurfaces; - gfx->CreateSurface = xf_CreateSurface; - gfx->DeleteSurface = xf_DeleteSurface; + + if (!xfc->context.settings->SoftwareGdi) + { + gfx->UpdateSurfaces = xf_UpdateSurfaces; + gfx->CreateSurface = xf_CreateSurface; + gfx->DeleteSurface = xf_DeleteSurface; + } } void xf_graphics_pipeline_uninit(xfContext* xfc, RdpgfxClientContext* gfx) diff --git a/client/X11/xf_gfx.h b/client/X11/xf_gfx.h index 11c1720..934e85a 100644 --- a/client/X11/xf_gfx.h +++ b/client/X11/xf_gfx.h @@ -36,21 +36,10 @@ struct xf_gfx_surface }; typedef struct xf_gfx_surface xfGfxSurface; -struct xf_gfx_cache_entry -{ - UINT64 cacheKey; - UINT32 width; - UINT32 height; - BYTE* data; - UINT32 scanline; - UINT32 format; -}; -typedef struct xf_gfx_cache_entry xfGfxCacheEntry; - -UINT xf_OutputExpose(xfContext* xfc, UINT32 x, UINT32 y, - UINT32 width, UINT32 height); +UINT xf_OutputExpose(xfContext* xfc, UINT32 x, UINT32 y, UINT32 width, UINT32 height); void xf_graphics_pipeline_init(xfContext* xfc, RdpgfxClientContext* gfx); + void xf_graphics_pipeline_uninit(xfContext* xfc, RdpgfxClientContext* gfx); #endif /* FREERDP_CLIENT_X11_GFX_H */ diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c index 5efc3f8..b63b20e 100644 --- a/client/X11/xf_graphics.c +++ b/client/X11/xf_graphics.c @@ -104,16 +104,16 @@ static BOOL xf_Bitmap_New(rdpContext* context, rdpBitmap* bitmap) BYTE* data; rdpGdi* gdi; xfBitmap* xbitmap = (xfBitmap*)bitmap; - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; if (!context || !bitmap || !context->gdi) return FALSE; gdi = context->gdi; - xf_lock_x11(xfc, FALSE); + xf_lock_x11(xfc); depth = GetBitsPerPixel(bitmap->format); - xbitmap->pixmap = XCreatePixmap(xfc->display, xfc->drawable, bitmap->width, - bitmap->height, xfc->depth); + xbitmap->pixmap = + XCreatePixmap(xfc->display, xfc->drawable, bitmap->width, bitmap->height, xfc->depth); if (!xbitmap->pixmap) goto unlock; @@ -122,15 +122,14 @@ static BOOL xf_Bitmap_New(rdpContext* context, rdpBitmap* bitmap) { XSetFunction(xfc->display, xfc->gc, GXcopy); - if (depth != xfc->depth) + if ((INT64)depth != xfc->depth) { if (!(data = _aligned_malloc(bitmap->width * bitmap->height * 4, 16))) goto unlock; - if (!freerdp_image_copy(data, gdi->dstFormat, 0, 0, 0, - bitmap->width, bitmap->height, - bitmap->data, bitmap->format, - 0, 0, 0, &context->gdi->palette, FREERDP_FLIP_NONE)) + if (!freerdp_image_copy(data, gdi->dstFormat, 0, 0, 0, bitmap->width, bitmap->height, + bitmap->data, bitmap->format, 0, 0, 0, &context->gdi->palette, + FREERDP_FLIP_NONE)) { _aligned_free(data); goto unlock; @@ -141,9 +140,9 @@ static BOOL xf_Bitmap_New(rdpContext* context, rdpBitmap* bitmap) bitmap->format = gdi->dstFormat; } - xbitmap->image = XCreateImage(xfc->display, xfc->visual, xfc->depth, - ZPixmap, 0, (char*) bitmap->data, bitmap->width, bitmap->height, - xfc->scanline_pad, 0); + xbitmap->image = + XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0, (char*)bitmap->data, + bitmap->width, bitmap->height, xfc->scanline_pad, 0); if (!xbitmap->image) goto unlock; @@ -156,19 +155,19 @@ static BOOL xf_Bitmap_New(rdpContext* context, rdpBitmap* bitmap) rc = TRUE; unlock: - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); return rc; } static void xf_Bitmap_Free(rdpContext* context, rdpBitmap* bitmap) { - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; xfBitmap* xbitmap = (xfBitmap*)bitmap; if (!xfc || !xbitmap) return; - xf_lock_x11(xfc, FALSE); + xf_lock_x11(xfc); if (xbitmap->pixmap != 0) { @@ -183,7 +182,7 @@ static void xf_Bitmap_Free(rdpContext* context, rdpBitmap* bitmap) xbitmap->image = NULL; } - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); _aligned_free(bitmap->data); free(xbitmap); } @@ -191,7 +190,7 @@ static void xf_Bitmap_Free(rdpContext* context, rdpBitmap* bitmap) static BOOL xf_Bitmap_Paint(rdpContext* context, rdpBitmap* bitmap) { int width, height; - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; xfBitmap* xbitmap = (xfBitmap*)bitmap; BOOL ret; @@ -200,31 +199,30 @@ static BOOL xf_Bitmap_Paint(rdpContext* context, rdpBitmap* bitmap) width = bitmap->right - bitmap->left + 1; height = bitmap->bottom - bitmap->top + 1; - xf_lock_x11(xfc, FALSE); + xf_lock_x11(xfc); XSetFunction(xfc->display, xfc->gc, GXcopy); - XPutImage(xfc->display, xfc->primary, xfc->gc, - xbitmap->image, 0, 0, bitmap->left, bitmap->top, width, height); + XPutImage(xfc->display, xfc->primary, xfc->gc, xbitmap->image, 0, 0, bitmap->left, bitmap->top, + width, height); ret = gdi_InvalidateRegion(xfc->hdc, bitmap->left, bitmap->top, width, height); - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); return ret; } -static BOOL xf_Bitmap_SetSurface(rdpContext* context, rdpBitmap* bitmap, - BOOL primary) +static BOOL xf_Bitmap_SetSurface(rdpContext* context, rdpBitmap* bitmap, BOOL primary) { - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; if (!context || (!bitmap && !primary)) return FALSE; - xf_lock_x11(xfc, FALSE); + xf_lock_x11(xfc); if (primary) xfc->drawing = xfc->primary; else - xfc->drawing = ((xfBitmap*) bitmap)->pixmap; + xfc->drawing = ((xfBitmap*)bitmap)->pixmap; - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); return TRUE; } @@ -235,7 +233,7 @@ static BOOL xf_Pointer_New(rdpContext* context, rdpPointer* pointer) UINT32 CursorFormat; size_t size; XcursorImage ci; - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; xfPointer* xpointer = (xfPointer*)pointer; if (!context || !pointer || !context->gdi) @@ -246,7 +244,7 @@ static BOOL xf_Pointer_New(rdpContext* context, rdpPointer* pointer) else CursorFormat = (!xfc->big_endian) ? PIXEL_FORMAT_BGRA32 : PIXEL_FORMAT_ARGB32; - xf_lock_x11(xfc, FALSE); + xf_lock_x11(xfc); ZeroMemory(&ci, sizeof(ci)); ci.version = XCURSOR_IMAGE_VERSION; ci.size = sizeof(ci); @@ -256,27 +254,25 @@ static BOOL xf_Pointer_New(rdpContext* context, rdpPointer* pointer) ci.yhot = pointer->yPos; size = ci.height * ci.width * GetBytesPerPixel(CursorFormat); - if (!(ci.pixels = (XcursorPixel*) _aligned_malloc(size, 16))) + if (!(ci.pixels = (XcursorPixel*)_aligned_malloc(size, 16))) { - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); return FALSE; } if (!freerdp_image_copy_from_pointer_data( - (BYTE*) ci.pixels, CursorFormat, - 0, 0, 0, pointer->width, pointer->height, - pointer->xorMaskData, pointer->lengthXorMask, - pointer->andMaskData, pointer->lengthAndMask, - pointer->xorBpp, &context->gdi->palette)) + (BYTE*)ci.pixels, CursorFormat, 0, 0, 0, pointer->width, pointer->height, + pointer->xorMaskData, pointer->lengthXorMask, pointer->andMaskData, + pointer->lengthAndMask, pointer->xorBpp, &context->gdi->palette)) { _aligned_free(ci.pixels); - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); return FALSE; } xpointer->cursor = XcursorImageLoadCursor(xfc->display, &ci); _aligned_free(ci.pixels); - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); #endif return TRUE; } @@ -284,30 +280,29 @@ static BOOL xf_Pointer_New(rdpContext* context, rdpPointer* pointer) static void xf_Pointer_Free(rdpContext* context, rdpPointer* pointer) { #ifdef WITH_XCURSOR - xfContext* xfc = (xfContext*) context; - xf_lock_x11(xfc, FALSE); + xfContext* xfc = (xfContext*)context; + xf_lock_x11(xfc); - if (((xfPointer*) pointer)->cursor) - XFreeCursor(xfc->display, ((xfPointer*) pointer)->cursor); + if (((xfPointer*)pointer)->cursor) + XFreeCursor(xfc->display, ((xfPointer*)pointer)->cursor); - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); #endif } -static BOOL xf_Pointer_Set(rdpContext* context, - const rdpPointer* pointer) +static BOOL xf_Pointer_Set(rdpContext* context, const rdpPointer* pointer) { #ifdef WITH_XCURSOR - xfContext* xfc = (xfContext*) context; - xf_lock_x11(xfc, FALSE); - xfc->pointer = (xfPointer*) pointer; + xfContext* xfc = (xfContext*)context; + xf_lock_x11(xfc); + xfc->pointer = (xfPointer*)pointer; /* in RemoteApp mode, window can be null if none has had focus */ if (xfc->window) XDefineCursor(xfc->display, xfc->window->handle, xfc->pointer->cursor); - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); #endif return TRUE; } @@ -315,9 +310,9 @@ static BOOL xf_Pointer_Set(rdpContext* context, static BOOL xf_Pointer_SetNull(rdpContext* context) { #ifdef WITH_XCURSOR - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; static Cursor nullcursor = None; - xf_lock_x11(xfc, FALSE); + xf_lock_x11(xfc); if (nullcursor == None) { @@ -337,7 +332,7 @@ static BOOL xf_Pointer_SetNull(rdpContext* context) if ((xfc->window) && (nullcursor != None)) XDefineCursor(xfc->display, xfc->window->handle, nullcursor); - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); #endif return TRUE; } @@ -345,21 +340,21 @@ static BOOL xf_Pointer_SetNull(rdpContext* context) static BOOL xf_Pointer_SetDefault(rdpContext* context) { #ifdef WITH_XCURSOR - xfContext* xfc = (xfContext*) context; - xf_lock_x11(xfc, FALSE); + xfContext* xfc = (xfContext*)context; + xf_lock_x11(xfc); xfc->pointer = NULL; if (xfc->window) XUndefineCursor(xfc->display, xfc->window->handle); - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); #endif return TRUE; } static BOOL xf_Pointer_SetPosition(rdpContext* context, UINT32 x, UINT32 y) { - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; XWindowAttributes current; XSetWindowAttributes tmp; BOOL ret = FALSE; @@ -367,15 +362,14 @@ static BOOL xf_Pointer_SetPosition(rdpContext* context, UINT32 x, UINT32 y) if (!xfc->focused || !xfc->window) return TRUE; - xf_lock_x11(xfc, FALSE); + xf_lock_x11(xfc); if (XGetWindowAttributes(xfc->display, xfc->window->handle, ¤t) == 0) goto out; tmp.event_mask = (current.your_event_mask & ~(PointerMotionMask)); - if (XChangeWindowAttributes(xfc->display, xfc->window->handle, CWEventMask, - &tmp) == 0) + if (XChangeWindowAttributes(xfc->display, xfc->window->handle, CWEventMask, &tmp) == 0) goto out; XWarpPointer(xfc->display, None, xfc->window->handle, 0, 0, 0, 0, x, y); @@ -383,7 +377,7 @@ static BOOL xf_Pointer_SetPosition(rdpContext* context, UINT32 x, UINT32 y) XChangeWindowAttributes(xfc->display, xfc->window->handle, CWEventMask, &tmp); ret = TRUE; out: - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); return ret; } @@ -393,46 +387,44 @@ static BOOL xf_Glyph_New(rdpContext* context, const rdpGlyph* glyph) int scanline; XImage* image; xfGlyph* xf_glyph; - xf_glyph = (xfGlyph*) glyph; - xfContext* xfc = (xfContext*) context; - xf_lock_x11(xfc, FALSE); + xf_glyph = (xfGlyph*)glyph; + xfContext* xfc = (xfContext*)context; + xf_lock_x11(xfc); scanline = (glyph->cx + 7) / 8; - xf_glyph->pixmap = XCreatePixmap(xfc->display, xfc->drawing, glyph->cx, - glyph->cy, 1); - image = XCreateImage(xfc->display, xfc->visual, 1, - ZPixmap, 0, (char*) glyph->aj, glyph->cx, glyph->cy, 8, scanline); + xf_glyph->pixmap = XCreatePixmap(xfc->display, xfc->drawing, glyph->cx, glyph->cy, 1); + image = XCreateImage(xfc->display, xfc->visual, 1, ZPixmap, 0, (char*)glyph->aj, glyph->cx, + glyph->cy, 8, scanline); image->byte_order = MSBFirst; image->bitmap_bit_order = MSBFirst; XInitImage(image); - XPutImage(xfc->display, xf_glyph->pixmap, xfc->gc_mono, image, 0, 0, 0, 0, - glyph->cx, glyph->cy); + XPutImage(xfc->display, xf_glyph->pixmap, xfc->gc_mono, image, 0, 0, 0, 0, glyph->cx, + glyph->cy); image->data = NULL; XDestroyImage(image); - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); return TRUE; } static void xf_Glyph_Free(rdpContext* context, rdpGlyph* glyph) { - xfContext* xfc = (xfContext*) context; - xf_lock_x11(xfc, FALSE); + xfContext* xfc = (xfContext*)context; + xf_lock_x11(xfc); - if (((xfGlyph*) glyph)->pixmap != 0) - XFreePixmap(xfc->display, ((xfGlyph*) glyph)->pixmap); + if (((xfGlyph*)glyph)->pixmap != 0) + XFreePixmap(xfc->display, ((xfGlyph*)glyph)->pixmap); - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); free(glyph->aj); free(glyph); } -static BOOL xf_Glyph_Draw(rdpContext* context, const rdpGlyph* glyph, INT32 x, - INT32 y, INT32 w, INT32 h, INT32 sx, INT32 sy, - BOOL fOpRedundant) +static BOOL xf_Glyph_Draw(rdpContext* context, const rdpGlyph* glyph, INT32 x, INT32 y, INT32 w, + INT32 h, INT32 sx, INT32 sy, BOOL fOpRedundant) { xfGlyph* xf_glyph; - xfContext* xfc = (xfContext*) context; - xf_glyph = (xfGlyph*) glyph; - xf_lock_x11(xfc, FALSE); + xfContext* xfc = (xfContext*)context; + xf_glyph = (xfGlyph*)glyph; + xf_lock_x11(xfc); if (!fOpRedundant) { @@ -446,18 +438,17 @@ static BOOL xf_Glyph_Draw(rdpContext* context, const rdpGlyph* glyph, INT32 x, if (sx || sy) WLog_ERR(TAG, ""); - //XSetClipOrigin(xfc->display, xfc->gc, sx, sy); + // XSetClipOrigin(xfc->display, xfc->gc, sx, sy); XSetTSOrigin(xfc->display, xfc->gc, x, y); XFillRectangle(xfc->display, xfc->drawing, xfc->gc, x, y, w, h); - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); return TRUE; } -static BOOL xf_Glyph_BeginDraw(rdpContext* context, INT32 x, INT32 y, - INT32 width, INT32 height, UINT32 bgcolor, - UINT32 fgcolor, BOOL fOpRedundant) +static BOOL xf_Glyph_BeginDraw(rdpContext* context, INT32 x, INT32 y, INT32 width, INT32 height, + UINT32 bgcolor, UINT32 fgcolor, BOOL fOpRedundant) { - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; XRectangle rect; XColor xbgcolor, xfgcolor; @@ -471,7 +462,7 @@ static BOOL xf_Glyph_BeginDraw(rdpContext* context, INT32 x, INT32 y, rect.y = y; rect.width = width; rect.height = height; - xf_lock_x11(xfc, FALSE); + xf_lock_x11(xfc); if (!fOpRedundant) { @@ -483,15 +474,14 @@ static BOOL xf_Glyph_BeginDraw(rdpContext* context, INT32 x, INT32 y, XSetForeground(xfc->display, xfc->gc, xbgcolor.pixel); XSetBackground(xfc->display, xfc->gc, xfgcolor.pixel); - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); return TRUE; } -static BOOL xf_Glyph_EndDraw(rdpContext* context, INT32 x, INT32 y, - INT32 width, INT32 height, +static BOOL xf_Glyph_EndDraw(rdpContext* context, INT32 x, INT32 y, INT32 width, INT32 height, UINT32 bgcolor, UINT32 fgcolor) { - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; BOOL ret = TRUE; XColor xfgcolor, xbgcolor; @@ -512,7 +502,7 @@ BOOL xf_register_pointer(rdpGraphics* graphics) { rdpPointer* pointer = NULL; - if (!(pointer = (rdpPointer*) calloc(1, sizeof(rdpPointer)))) + if (!(pointer = (rdpPointer*)calloc(1, sizeof(rdpPointer)))) return FALSE; pointer->size = sizeof(xfPointer); diff --git a/client/X11/xf_input.c b/client/X11/xf_input.c index 0bed66c..b35c8ce 100644 --- a/client/X11/xf_input.c +++ b/client/X11/xf_input.c @@ -88,7 +88,6 @@ const char* xf_input_get_class_string(int class) return "XIUnknownClass"; } - int xf_input_init(xfContext* xfc, Window window) { int i, j; @@ -137,7 +136,7 @@ int xf_input_init(xfContext* xfc, Window window) for (j = 0; j < dev->num_classes; j++) { XIAnyClassInfo* class = dev->classes[j]; - XITouchClassInfo* t = (XITouchClassInfo*) class; + XITouchClassInfo* t = (XITouchClassInfo*)class; if ((class->type == XITouchClass) && (t->mode == XIDirectTouch) && (strcmp(dev->name, "Virtual core pointer") != 0)) @@ -149,12 +148,11 @@ int xf_input_init(xfContext* xfc, Window window) for (j = 0; j < dev->num_classes; j++) { XIAnyClassInfo* class = dev->classes[j]; - XITouchClassInfo* t = (XITouchClassInfo*) class; + XITouchClassInfo* t = (XITouchClassInfo*)class; if (xfc->context.settings->MultiTouchInput) { - WLog_INFO(TAG, "%s (%d) \"%s\" id: %d", - xf_input_get_class_string(class->type), + WLog_INFO(TAG, "%s (%d) \"%s\" id: %d", xf_input_get_class_string(class->type), class->type, dev->name, dev->deviceid); } @@ -181,12 +179,11 @@ int xf_input_init(xfContext* xfc, Window window) if (xfc->use_xinput) { - if (!touch && (class->type == XIButtonClass) - && strcmp(dev->name, "Virtual core pointer")) + if (!touch && (class->type == XIButtonClass) && + strcmp(dev->name, "Virtual core pointer")) { - WLog_INFO(TAG, "%s button device (id: %d, mode: %d)", - dev->name, - dev->deviceid, t->mode); + WLog_INFO(TAG, "%s button device (id: %d, mode: %d)", dev->name, dev->deviceid, + t->mode); XISetMask(masks[nmasks], XI_ButtonPress); XISetMask(masks[nmasks], XI_ButtonRelease); XISetMask(masks[nmasks], XI_Motion); @@ -204,15 +201,13 @@ int xf_input_init(xfContext* xfc, Window window) return 0; } -static BOOL xf_input_is_duplicate(XGenericEventCookie* cookie) +static BOOL xf_input_is_duplicate(const XGenericEventCookie* cookie) { - XIDeviceEvent* event; + const XIDeviceEvent* event; event = cookie->data; - if ((lastEvent.time == event->time) && - (lastEvType == cookie->evtype) && - (lastEvent.detail == event->detail) && - (lastEvent.event_x == event->event_x) && + if ((lastEvent.time == event->time) && (lastEvType == cookie->evtype) && + (lastEvent.detail == event->detail) && (lastEvent.event_x == event->event_x) && (lastEvent.event_y == event->event_y)) { return TRUE; @@ -221,9 +216,9 @@ static BOOL xf_input_is_duplicate(XGenericEventCookie* cookie) return FALSE; } -static void xf_input_save_last_event(XGenericEventCookie* cookie) +static void xf_input_save_last_event(const XGenericEventCookie* cookie) { - XIDeviceEvent* event; + const XIDeviceEvent* event; event = cookie->data; lastEvType = cookie->evtype; lastEvent.time = event->time; @@ -385,6 +380,7 @@ static void xf_input_touch_begin(xfContext* xfc, XIDeviceEvent* event) { int i; + WINPR_UNUSED(xfc); for (i = 0; i < MAX_CONTACTS; i++) { if (contacts[i].id == 0) @@ -423,6 +419,7 @@ static void xf_input_touch_end(xfContext* xfc, XIDeviceEvent* event) { int i; + WINPR_UNUSED(xfc); for (i = 0; i < MAX_CONTACTS; i++) { if (contacts[i].id == event->detail) @@ -435,43 +432,47 @@ static void xf_input_touch_end(xfContext* xfc, XIDeviceEvent* event) } } -static int xf_input_handle_event_local(xfContext* xfc, XEvent* event) +static int xf_input_handle_event_local(xfContext* xfc, const XEvent* event) { - XGenericEventCookie* cookie = &event->xcookie; - XGetEventData(xfc->display, cookie); - - if ((cookie->type == GenericEvent) && (cookie->extension == xfc->XInputOpcode)) + union { + const XGenericEventCookie* cc; + XGenericEventCookie* vc; + } cookie; + cookie.cc = &event->xcookie; + XGetEventData(xfc->display, cookie.vc); + + if ((cookie.cc->type == GenericEvent) && (cookie.cc->extension == xfc->XInputOpcode)) { - switch (cookie->evtype) + switch (cookie.cc->evtype) { case XI_TouchBegin: - if (xf_input_is_duplicate(cookie) == FALSE) - xf_input_touch_begin(xfc, cookie->data); + if (xf_input_is_duplicate(cookie.cc) == FALSE) + xf_input_touch_begin(xfc, cookie.cc->data); - xf_input_save_last_event(cookie); + xf_input_save_last_event(cookie.cc); break; case XI_TouchUpdate: - if (xf_input_is_duplicate(cookie) == FALSE) - xf_input_touch_update(xfc, cookie->data); + if (xf_input_is_duplicate(cookie.cc) == FALSE) + xf_input_touch_update(xfc, cookie.cc->data); - xf_input_save_last_event(cookie); + xf_input_save_last_event(cookie.cc); break; case XI_TouchEnd: - if (xf_input_is_duplicate(cookie) == FALSE) - xf_input_touch_end(xfc, cookie->data); + if (xf_input_is_duplicate(cookie.cc) == FALSE) + xf_input_touch_end(xfc, cookie.cc->data); - xf_input_save_last_event(cookie); + xf_input_save_last_event(cookie.cc); break; default: - WLog_ERR(TAG, "unhandled xi type= %d", cookie->evtype); + WLog_ERR(TAG, "unhandled xi type= %d", cookie.cc->evtype); break; } } - XFreeEventData(xfc->display, cookie); + XFreeEventData(xfc->display, cookie.vc); return 0; } @@ -498,7 +499,7 @@ static void xf_input_hide_cursor(xfContext* xfc) XcursorImage ci; XcursorPixel xp = 0; static Cursor nullcursor = None; - xf_lock_x11(xfc, FALSE); + xf_lock_x11(xfc); ZeroMemory(&ci, sizeof(ci)); ci.version = XCURSOR_IMAGE_VERSION; ci.size = sizeof(ci); @@ -511,7 +512,7 @@ static void xf_input_hide_cursor(xfContext* xfc) XDefineCursor(xfc->display, xfc->window->handle, nullcursor); xfc->cursorHidden = TRUE; - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); } #endif @@ -520,7 +521,7 @@ static void xf_input_hide_cursor(xfContext* xfc) static void xf_input_show_cursor(xfContext* xfc) { #ifdef WITH_XCURSOR - xf_lock_x11(xfc, FALSE); + xf_lock_x11(xfc); if (xfc->cursorHidden) { @@ -535,7 +536,7 @@ static void xf_input_show_cursor(xfContext* xfc) xfc->cursorHidden = FALSE; } - xf_unlock_x11(xfc, FALSE); + xf_unlock_x11(xfc); #endif } @@ -551,8 +552,8 @@ static int xf_input_touch_remote(xfContext* xfc, XIDeviceEvent* event, int evtyp xf_input_hide_cursor(xfc); touchId = event->detail; - x = (int) event->event_x; - y = (int) event->event_y; + x = (int)event->event_x; + y = (int)event->event_y; xf_event_adjust_coordinates(xfc, &x, &y); if (evtype == XI_TouchBegin) @@ -581,52 +582,56 @@ 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: - xf_generic_MotionNotify(xfc, (int) event->event_x, (int) event->event_y, - event->detail, event->event, xfc->remote_app); + xf_generic_MotionNotify(xfc, (int)event->event_x, (int)event->event_y, event->detail, + event->event, xfc->remote_app); break; } return 0; } -static int xf_input_handle_event_remote(xfContext* xfc, XEvent* event) +static int xf_input_handle_event_remote(xfContext* xfc, const XEvent* event) { - XGenericEventCookie* cookie = &event->xcookie; - XGetEventData(xfc->display, cookie); - - if ((cookie->type == GenericEvent) && (cookie->extension == xfc->XInputOpcode)) + union { + const XGenericEventCookie* cc; + XGenericEventCookie* vc; + } cookie; + cookie.cc = &event->xcookie; + XGetEventData(xfc->display, cookie.vc); + + if ((cookie.cc->type == GenericEvent) && (cookie.cc->extension == xfc->XInputOpcode)) { - switch (cookie->evtype) + switch (cookie.cc->evtype) { case XI_TouchBegin: - xf_input_touch_remote(xfc, cookie->data, XI_TouchBegin); + xf_input_touch_remote(xfc, cookie.cc->data, XI_TouchBegin); break; case XI_TouchUpdate: - xf_input_touch_remote(xfc, cookie->data, XI_TouchUpdate); + xf_input_touch_remote(xfc, cookie.cc->data, XI_TouchUpdate); break; case XI_TouchEnd: - xf_input_touch_remote(xfc, cookie->data, XI_TouchEnd); + xf_input_touch_remote(xfc, cookie.cc->data, XI_TouchEnd); break; default: - xf_input_event(xfc, cookie->data, cookie->evtype); + xf_input_event(xfc, cookie.cc->data, cookie.cc->evtype); break; } } - XFreeEventData(xfc->display, cookie); + XFreeEventData(xfc->display, cookie.vc); return 0; } @@ -639,7 +644,7 @@ int xf_input_init(xfContext* xfc, Window window) #endif -int xf_input_handle_event(xfContext* xfc, XEvent* event) +int xf_input_handle_event(xfContext* xfc, const XEvent* event) { #ifdef WITH_XI diff --git a/client/X11/xf_input.h b/client/X11/xf_input.h index c08fea0..a961512 100644 --- a/client/X11/xf_input.h +++ b/client/X11/xf_input.h @@ -28,6 +28,6 @@ #endif int xf_input_init(xfContext* xfc, Window window); -int xf_input_handle_event(xfContext* xfc, XEvent* event); +int xf_input_handle_event(xfContext* xfc, const XEvent* event); #endif /* FREERDP_CLIENT_X11_INPUT_H */ diff --git a/client/X11/xf_keyboard.c b/client/X11/xf_keyboard.c index 61bf89f..794acea 100644 --- a/client/X11/xf_keyboard.c +++ b/client/X11/xf_keyboard.c @@ -74,7 +74,8 @@ static BOOL xf_keyboard_action_script_init(xfContext* xfc) while (fgets(buffer, sizeof(buffer), keyScript) != NULL) { - strtok(buffer, "\n"); + char* context = NULL; + strtok_s(buffer, "\n", &context); keyCombination = _strdup(buffer); if (!keyCombination || ArrayList_Add(xfc->keyCombinations, keyCombination) < 0) @@ -172,8 +173,7 @@ void xf_keyboard_release_all_keypress(xfContext* xfc) // release tab before releasing the windows key. // this stops the start menu from opening on unfocus event. if (rdp_scancode == RDP_SCANCODE_LWIN) - freerdp_input_send_keyboard_event_ex(xfc->context.input, FALSE, - RDP_SCANCODE_TAB); + freerdp_input_send_keyboard_event_ex(xfc->context.input, FALSE, RDP_SCANCODE_TAB); freerdp_input_send_keyboard_event_ex(xfc->context.input, FALSE, rdp_scancode); xfc->KeyboardState[keycode] = FALSE; @@ -196,11 +196,10 @@ void xf_keyboard_send_key(xfContext* xfc, BOOL down, BYTE keycode) if (rdp_scancode == RDP_SCANCODE_UNKNOWN) { - WLog_ERR(TAG, "Unknown key with X keycode 0x%02"PRIx8"", keycode); + WLog_ERR(TAG, "Unknown key with X keycode 0x%02" PRIx8 "", keycode); } - else if (rdp_scancode == RDP_SCANCODE_PAUSE && - !xf_keyboard_key_pressed(xfc, XK_Control_L) - && !xf_keyboard_key_pressed(xfc, XK_Control_R)) + else if (rdp_scancode == RDP_SCANCODE_PAUSE && !xf_keyboard_key_pressed(xfc, XK_Control_L) && + !xf_keyboard_key_pressed(xfc, XK_Control_R)) { /* Pause without Ctrl has to be sent as a series of keycodes * in a single input PDU. Pause only happens on "press"; @@ -232,13 +231,13 @@ int xf_keyboard_read_keyboard_state(xfContext* xfc) if (!xfc->remote_app) { - XQueryPointer(xfc->display, xfc->window->handle, - &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state); + XQueryPointer(xfc->display, xfc->window->handle, &wdummy, &wdummy, &dummy, &dummy, &dummy, + &dummy, &state); } else { - XQueryPointer(xfc->display, DefaultRootWindow(xfc->display), - &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state); + XQueryPointer(xfc->display, DefaultRootWindow(xfc->display), &wdummy, &wdummy, &dummy, + &dummy, &dummy, &dummy, &state); } return state; @@ -292,8 +291,7 @@ static BOOL xf_keyboard_set_key_state(xfContext* xfc, BOOL on, int keysym) return FALSE; } - return XkbLockModifiers(xfc->display, XkbUseCoreKbd, keysymMask, - on ? keysymMask : 0); + return XkbLockModifiers(xfc->display, XkbUseCoreKbd, keysymMask, on ? keysymMask : 0); } UINT32 xf_keyboard_get_toggle_keys_state(xfContext* xfc) @@ -322,9 +320,11 @@ static void xk_keyboard_update_modifier_keys(xfContext* xfc) int state; size_t i; KeyCode keycode; - int keysyms[] = {XK_Shift_L, XK_Shift_R, XK_Alt_L, XK_Alt_R, - XK_Control_L, XK_Control_R, XK_Super_L, XK_Super_R - }; + int keysyms[] = { XK_Shift_L, XK_Shift_R, XK_Alt_L, XK_Alt_R, + XK_Control_L, XK_Control_R, XK_Super_L, XK_Super_R }; + + xf_keyboard_clear(xfc); + state = xf_keyboard_read_keyboard_state(xfc); for (i = 0; i < ARRAYSIZE(keysyms); i++) @@ -357,8 +357,7 @@ void xf_keyboard_focus_in(xfContext* xfc) if (xfc->remote_app) return; - if (XQueryPointer(xfc->display, xfc->window->handle, &w, &w, &d, &d, &x, &y, - &state)) + if (XQueryPointer(xfc->display, xfc->window->handle, &w, &w, &d, &d, &x, &y, &state)) { if (x >= 0 && x < xfc->window->width && y >= 0 && y < xfc->window->height) { @@ -368,9 +367,7 @@ void xf_keyboard_focus_in(xfContext* xfc) } } -static int xf_keyboard_execute_action_script(xfContext* xfc, - XF_MODIFIER_KEYS* mod, - KeySym keysym) +static int xf_keyboard_execute_action_script(xfContext* xfc, XF_MODIFIER_KEYS* mod, KeySym keysym) { int index; int count; @@ -386,9 +383,8 @@ static int xf_keyboard_execute_action_script(xfContext* xfc, if (!xfc->actionScriptExists) return 1; - if ((keysym == XK_Shift_L) || (keysym == XK_Shift_R) || - (keysym == XK_Alt_L) || (keysym == XK_Alt_R) || - (keysym == XK_Control_L) || (keysym == XK_Control_R)) + if ((keysym == XK_Shift_L) || (keysym == XK_Shift_R) || (keysym == XK_Alt_L) || + (keysym == XK_Alt_R) || (keysym == XK_Control_L) || (keysym == XK_Control_R)) { return 1; } @@ -417,7 +413,7 @@ static int xf_keyboard_execute_action_script(xfContext* xfc, for (index = 0; index < count; index++) { - keyCombination = (char*) ArrayList_GetItem(xfc->keyCombinations, index); + keyCombination = (char*)ArrayList_GetItem(xfc->keyCombinations, index); if (_stricmp(keyCombination, combination) == 0) { @@ -429,8 +425,8 @@ static int xf_keyboard_execute_action_script(xfContext* xfc, if (!match) return 1; - sprintf_s(command, sizeof(command), "%s key %s", - xfc->context.settings->ActionScript, combination); + sprintf_s(command, sizeof(command), "%s key %s", xfc->context.settings->ActionScript, + combination); keyScript = popen(command, "r"); if (!keyScript) @@ -438,7 +434,8 @@ static int xf_keyboard_execute_action_script(xfContext* xfc, while (fgets(buffer, sizeof(buffer), keyScript) != NULL) { - strtok(buffer, "\n"); + char* context = NULL; + strtok_s(buffer, "\n", &context); if (strcmp(buffer, "key-local") == 0) status = 0; @@ -513,8 +510,8 @@ BOOL xf_keyboard_handle_special_keys(xfContext* xfc, KeySym keysym) if (mod.Ctrl && mod.Alt) { /* Ctrl-Alt-C: toggle control */ - xf_toggle_control(xfc); - return TRUE; + if (xf_toggle_control(xfc)) + return TRUE; } } @@ -632,9 +629,8 @@ void xf_keyboard_handle_special_keys_release(xfContext* xfc, KeySym keysym) BOOL xf_keyboard_set_indicators(rdpContext* context, UINT16 led_flags) { - xfContext* xfc = (xfContext*) context; - xf_keyboard_set_key_state(xfc, led_flags & KBD_SYNC_SCROLL_LOCK, - XK_Scroll_Lock); + xfContext* xfc = (xfContext*)context; + xf_keyboard_set_key_state(xfc, led_flags & KBD_SYNC_SCROLL_LOCK, XK_Scroll_Lock); xf_keyboard_set_key_state(xfc, led_flags & KBD_SYNC_NUM_LOCK, XK_Num_Lock); xf_keyboard_set_key_state(xfc, led_flags & KBD_SYNC_CAPS_LOCK, XK_Caps_Lock); xf_keyboard_set_key_state(xfc, led_flags & KBD_SYNC_KANA_LOCK, XK_Kana_Lock); @@ -648,7 +644,8 @@ BOOL xf_keyboard_set_ime_status(rdpContext* context, UINT16 imeId, UINT32 imeSta return FALSE; WLog_WARN(TAG, - "KeyboardSetImeStatus(unitId=%04"PRIx16", imeState=%08"PRIx32", imeConvMode=%08"PRIx32") ignored", + "KeyboardSetImeStatus(unitId=%04" PRIx16 ", imeState=%08" PRIx32 + ", imeConvMode=%08" PRIx32 ") ignored", imeId, imeState, imeConvMode); return TRUE; } diff --git a/client/X11/xf_keyboard.h b/client/X11/xf_keyboard.h index c7e601b..2f7dfb7 100644 --- a/client/X11/xf_keyboard.h +++ b/client/X11/xf_keyboard.h @@ -57,6 +57,7 @@ void xf_keyboard_focus_in(xfContext* xfc); BOOL xf_keyboard_handle_special_keys(xfContext* xfc, KeySym keysym); void xf_keyboard_handle_special_keys_release(xfContext* xfc, KeySym keysym); BOOL xf_keyboard_set_indicators(rdpContext* context, UINT16 led_flags); -BOOL xf_keyboard_set_ime_status(rdpContext* context, UINT16 imeId, UINT32 imeState, UINT32 imeConvMode); +BOOL xf_keyboard_set_ime_status(rdpContext* context, UINT16 imeId, UINT32 imeState, + UINT32 imeConvMode); #endif /* FREERDP_CLIENT_X11_XF_KEYBOARD_H */ diff --git a/client/X11/xf_monitor.c b/client/X11/xf_monitor.c index 9eb854e..72a3dbe 100644 --- a/client/X11/xf_monitor.c +++ b/client/X11/xf_monitor.c @@ -44,14 +44,15 @@ #include #if (RANDR_MAJOR * 100 + RANDR_MINOR) >= 105 -# define USABLE_XRANDR +#define USABLE_XRANDR #endif #endif #include "xf_monitor.h" -/* See MSDN Section on Multiple Display Monitors: http://msdn.microsoft.com/en-us/library/dd145071 */ +/* See MSDN Section on Multiple Display Monitors: http://msdn.microsoft.com/en-us/library/dd145071 + */ int xf_list_monitors(xfContext* xfc) { @@ -69,18 +70,15 @@ int xf_list_monitors(xfContext* xfc) #if defined(USABLE_XRANDR) if (XRRQueryExtension(xfc->display, &major, &minor) && - (XRRQueryVersion(xfc->display, &major, &minor) == True) && - (major * 100 + minor >= 105)) + (XRRQueryVersion(xfc->display, &major, &minor) == True) && (major * 100 + minor >= 105)) { - XRRMonitorInfo* monitors = XRRGetMonitors(xfc->display, DefaultRootWindow(xfc->display), 1, - &nmonitors); + XRRMonitorInfo* monitors = + XRRGetMonitors(xfc->display, DefaultRootWindow(xfc->display), 1, &nmonitors); for (i = 0; i < nmonitors; i++) { - printf(" %s [%d] %dx%d\t+%d+%d\n", - monitors[i].primary ? "*" : " ", i, - monitors[i].width, monitors[i].height, - monitors[i].x, monitors[i].y); + printf(" %s [%d] %dx%d\t+%d+%d\n", monitors[i].primary ? "*" : " ", i, + monitors[i].width, monitors[i].height, monitors[i].x, monitors[i].y); } XRRFreeMonitors(monitors); @@ -88,24 +86,22 @@ int xf_list_monitors(xfContext* xfc) else #endif #ifdef WITH_XINERAMA - if (XineramaQueryExtension(display, &major, &minor)) + if (XineramaQueryExtension(display, &major, &minor)) + { + if (XineramaIsActive(display)) { - if (XineramaIsActive(display)) - { - XineramaScreenInfo* screen = XineramaQueryScreens(display, &nmonitors); - - for (i = 0; i < nmonitors; i++) - { - printf(" %s [%d] %hdx%hd\t+%hd+%hd\n", - (i == 0) ? "*" : " ", i, - screen[i].width, screen[i].height, - screen[i].x_org, screen[i].y_org); - } + XineramaScreenInfo* screen = XineramaQueryScreens(display, &nmonitors); - XFree(screen); + for (i = 0; i < nmonitors; i++) + { + printf(" %s [%d] %hdx%hd\t+%hd+%hd\n", (i == 0) ? "*" : " ", i, + screen[i].width, screen[i].height, screen[i].x_org, screen[i].y_org); } + + XFree(screen); } - else + } + else #else { Screen* screen = ScreenOfDisplay(display, DefaultScreen(display)); @@ -113,13 +109,13 @@ int xf_list_monitors(xfContext* xfc) } #endif - XCloseDisplay(display); + XCloseDisplay(display); return 0; } static BOOL xf_is_monitor_id_active(xfContext* xfc, UINT32 id) { - int index; + UINT32 index; rdpSettings* settings = xfc->context.settings; if (!settings->NumMonitorIds) @@ -136,12 +132,11 @@ static BOOL xf_is_monitor_id_active(xfContext* xfc, UINT32 id) BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) { - UINT32 i; int nmonitors = 0; 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,30 +149,35 @@ 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; /* get mouse location */ - if (!XQueryPointer(xfc->display, DefaultRootWindow(xfc->display), - &_dummy_w, &_dummy_w, &mouse_x, &mouse_y, - &_dummy_i, &_dummy_i, (void*) &_dummy_i)) + if (!XQueryPointer(xfc->display, DefaultRootWindow(xfc->display), &_dummy_w, &_dummy_w, + &mouse_x, &mouse_y, &_dummy_i, &_dummy_i, (void*)&_dummy_i)) mouse_x = mouse_y = 0; #if defined(USABLE_XRANDR) if (XRRQueryExtension(xfc->display, &major, &minor) && - (XRRQueryVersion(xfc->display, &major, &minor) == True) && - (major * 100 + minor >= 105)) + (XRRQueryVersion(xfc->display, &major, &minor) == True) && (major * 100 + minor >= 105)) { - XRRMonitorInfo* rrmonitors = XRRGetMonitors(xfc->display, DefaultRootWindow(xfc->display), 1, - &vscreen->nmonitors); + XRRMonitorInfo* rrmonitors = + XRRGetMonitors(xfc->display, DefaultRootWindow(xfc->display), 1, &vscreen->nmonitors); if (vscreen->nmonitors > 16) vscreen->nmonitors = 0; if (vscreen->nmonitors) { + int i; + for (i = 0; i < vscreen->nmonitors; i++) { vscreen->monitors[i].area.left = rrmonitors[i].x; @@ -194,34 +194,38 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) else #endif #ifdef WITH_XINERAMA - if (XineramaQueryExtension(xfc->display, &major, &minor) && XineramaIsActive(xfc->display)) - { - XineramaScreenInfo* screenInfo = XineramaQueryScreens(xfc->display, &vscreen->nmonitors); + if (XineramaQueryExtension(xfc->display, &major, &minor) && XineramaIsActive(xfc->display)) + { + XineramaScreenInfo* screenInfo = XineramaQueryScreens(xfc->display, &vscreen->nmonitors); + + if (vscreen->nmonitors > 16) + vscreen->nmonitors = 0; - if (vscreen->nmonitors > 16) - vscreen->nmonitors = 0; + if (vscreen->nmonitors) + { + int i; - if (vscreen->nmonitors) + for (i = 0; i < vscreen->nmonitors; i++) { - for (i = 0; i < vscreen->nmonitors; i++) - { - vscreen->monitors[i].area.left = screenInfo[i].x_org; - vscreen->monitors[i].area.top = screenInfo[i].y_org; - vscreen->monitors[i].area.right = screenInfo[i].x_org + screenInfo[i].width - 1; - vscreen->monitors[i].area.bottom = screenInfo[i].y_org + screenInfo[i].height - 1; - } + vscreen->monitors[i].area.left = screenInfo[i].x_org; + vscreen->monitors[i].area.top = screenInfo[i].y_org; + vscreen->monitors[i].area.right = screenInfo[i].x_org + screenInfo[i].width - 1; + vscreen->monitors[i].area.bottom = screenInfo[i].y_org + screenInfo[i].height - 1; } - - XFree(screenInfo); } + XFree(screenInfo); + } + #endif - xfc->fullscreenMonitors.top = xfc->fullscreenMonitors.bottom = - xfc->fullscreenMonitors.left = xfc->fullscreenMonitors.right = 0; + xfc->fullscreenMonitors.top = xfc->fullscreenMonitors.bottom = xfc->fullscreenMonitors.left = + xfc->fullscreenMonitors.right = 0; /* Determine which monitor that the mouse cursor is on */ if (vscreen->monitors) { + int i; + for (i = 0; i < vscreen->nmonitors; i++) { if ((mouse_x >= vscreen->monitors[i].area.left) && @@ -246,7 +250,8 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) if ((!settings->UseMultimon && !settings->SpanMonitors) || (settings->Workarea && !settings->RemoteApplicationMode)) { - /* If no monitors were specified on the command-line then set the current monitor as active */ + /* If no monitors were specified on the command-line then set the current monitor as active + */ if (!settings->NumMonitorIds) { settings->MonitorIds[0] = current_monitor; @@ -271,9 +276,13 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) this is required in case of a screen composed of more than one monitor but user did not enable multimonitor */ - if (settings->NumMonitorIds == 1) + if ((settings->NumMonitorIds == 1) && (vscreen->nmonitors > current_monitor)) { 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 +314,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 - @@ -312,12 +324,14 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) if (settings->PercentScreenUseWidth) *pMaxWidth = ((vscreen->monitors[current_monitor].area.right - - vscreen->monitors[current_monitor].area.left + 1) * settings->PercentScreen) / + vscreen->monitors[current_monitor].area.left + 1) * + settings->PercentScreen) / 100; if (settings->PercentScreenUseHeight) *pMaxHeight = ((vscreen->monitors[current_monitor].area.bottom - - vscreen->monitors[current_monitor].area.top + 1) * settings->PercentScreen) / + vscreen->monitors[current_monitor].area.top + 1) * + settings->PercentScreen) / 100; } else @@ -338,57 +352,81 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) *pMaxHeight = settings->DesktopHeight; } - /* Create array of all active monitors by taking into account monitors requested on the command-line */ - for (i = 0; i < vscreen->nmonitors; i++) + /* Create array of all active monitors by taking into account monitors requested on the + * command-line */ { - MONITOR_ATTRIBUTES* attrs; - - if (!xf_is_monitor_id_active(xfc, i)) - continue; - - 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); - settings->MonitorDefArray[nmonitors].height = - MIN(vscreen->monitors[i].area.bottom - vscreen->monitors[i].area.top + 1, *pMaxHeight); - settings->MonitorDefArray[nmonitors].orig_screen = i; -#ifdef USABLE_XRANDR + int i; - if (useXRandr && rrmonitors) + for (i = 0; i < vscreen->nmonitors; i++) { - Rotation rot, ret; - attrs = &settings->MonitorDefArray[nmonitors].attributes; - attrs->physicalWidth = rrmonitors[i].mwidth; - attrs->physicalHeight = rrmonitors[i].mheight; - ret = XRRRotations(xfc->display, i, &rot); - attrs->orientation = rot; - } + MONITOR_ATTRIBUTES* attrs; + + if (!xf_is_monitor_id_active(xfc, (UINT32)i)) + continue; + + if (!vscreen->monitors) + return FALSE; + + settings->MonitorDefArray[nmonitors].x = + (vscreen->monitors[i].area.left * + (settings->PercentScreenUseWidth ? settings->PercentScreen : 100)) / + 100; + settings->MonitorDefArray[nmonitors].y = + (vscreen->monitors[i].area.top * + (settings->PercentScreenUseHeight ? settings->PercentScreen : 100)) / + 100; + settings->MonitorDefArray[nmonitors].width = + ((vscreen->monitors[i].area.right - vscreen->monitors[i].area.left + 1) * + (settings->PercentScreenUseWidth ? settings->PercentScreen : 100)) / + 100; + settings->MonitorDefArray[nmonitors].height = + ((vscreen->monitors[i].area.bottom - vscreen->monitors[i].area.top + 1) * + (settings->PercentScreenUseWidth ? settings->PercentScreen : 100)) / + 100; + settings->MonitorDefArray[nmonitors].orig_screen = i; +#ifdef USABLE_XRANDR + + if (useXRandr && rrmonitors) + { + Rotation rot, ret; + attrs = &settings->MonitorDefArray[nmonitors].attributes; + attrs->physicalWidth = rrmonitors[i].mwidth; + attrs->physicalHeight = rrmonitors[i].mheight; + ret = XRRRotations(xfc->display, i, &rot); + attrs->orientation = rot; + } #endif - if (i == settings->MonitorIds[0]) - { - settings->MonitorDefArray[nmonitors].is_primary = TRUE; - settings->MonitorLocalShiftX = settings->MonitorDefArray[nmonitors].x; - settings->MonitorLocalShiftY = settings->MonitorDefArray[nmonitors].y; - primaryMonitorFound = TRUE; - } + if ((UINT32)i == settings->MonitorIds[0]) + { + settings->MonitorDefArray[nmonitors].is_primary = TRUE; + settings->MonitorLocalShiftX = settings->MonitorDefArray[nmonitors].x; + settings->MonitorLocalShiftY = settings->MonitorDefArray[nmonitors].y; + primaryMonitorFound = TRUE; + } - nmonitors++; + nmonitors++; + } } - /* If no monitor is active(bogus command-line monitor specification) - then lets try to fallback to go fullscreen on the current monitor only */ + /* 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) { + INT32 width, height; + if (!vscreen->monitors) + return FALSE; + + width = vscreen->monitors[current_monitor].area.right - + vscreen->monitors[current_monitor].area.left + 1L; + height = vscreen->monitors[current_monitor].area.bottom - + vscreen->monitors[current_monitor].area.top + 1L; + 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( - vscreen->monitors[current_monitor].area.right - - vscreen->monitors[current_monitor].area.left + 1, *pMaxWidth); - settings->MonitorDefArray[0].height = MIN( - vscreen->monitors[current_monitor].area.bottom - - vscreen->monitors[current_monitor].area.top + 1, *pMaxHeight); + settings->MonitorDefArray[0].width = MIN(width, (INT64)(*pMaxWidth)); + settings->MonitorDefArray[0].height = MIN(height, (INT64)(*pMaxHeight)); settings->MonitorDefArray[0].orig_screen = current_monitor; nmonitors = 1; } @@ -398,14 +436,15 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) /* If we have specific monitor information */ if (settings->MonitorCount) { + UINT32 i; /* Initialize bounding rectangle for all monitors */ int vX = settings->MonitorDefArray[0].x; int vY = settings->MonitorDefArray[0].y; int vR = vX + settings->MonitorDefArray[0].width; int vB = vY + settings->MonitorDefArray[0].height; xfc->fullscreenMonitors.top = xfc->fullscreenMonitors.bottom = - xfc->fullscreenMonitors.left = xfc->fullscreenMonitors.right = - settings->MonitorDefArray[0].orig_screen; + xfc->fullscreenMonitors.left = xfc->fullscreenMonitors.right = + settings->MonitorDefArray[0].orig_screen; /* Calculate bounding rectangle around all monitors to be used AND * also set the Xinerama indices which define left/top/right/bottom monitors. @@ -415,10 +454,10 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) /* does the same as gdk_rectangle_union */ int destX = MIN(vX, settings->MonitorDefArray[i].x); int destY = MIN(vY, settings->MonitorDefArray[i].y); - int destR = MAX(vR, settings->MonitorDefArray[i].x + - settings->MonitorDefArray[i].width); - int destB = MAX(vB, settings->MonitorDefArray[i].y + - settings->MonitorDefArray[i].height); + int destR = + MAX(vR, settings->MonitorDefArray[i].x + settings->MonitorDefArray[i].width); + int destB = + MAX(vB, settings->MonitorDefArray[i].y + settings->MonitorDefArray[i].height); if (vX != destX) xfc->fullscreenMonitors.left = settings->MonitorDefArray[i].orig_screen; @@ -432,10 +471,12 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) if (vB != destB) xfc->fullscreenMonitors.bottom = settings->MonitorDefArray[i].orig_screen; - vX = destX; - vY = destY; - vR = destR; - vB = destB; + vX = destX / ((settings->PercentScreenUseWidth ? settings->PercentScreen : 100) / 100.); + vY = + destY / ((settings->PercentScreenUseHeight ? settings->PercentScreen : 100) / 100.); + vR = destR / ((settings->PercentScreenUseWidth ? settings->PercentScreen : 100) / 100.); + vB = + destB / ((settings->PercentScreenUseHeight ? settings->PercentScreen : 100) / 100.); } vscreen->area.left = 0; @@ -455,7 +496,7 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) if (settings->NumMonitorIds) { /* The first monitor is the first in the setting which should be used */ - monitor_index = settings->MonitorIds[0]; + monitor_index = settings->MonitorIds[0]; } else { @@ -479,11 +520,12 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) } else { - /* Lets try to see if there is a monitor with a 0,0 coordinate and use it as a fallback*/ + /* Lets try to see if there is a monitor with a 0,0 coordinate and use it as a + * fallback*/ for (i = 0; i < settings->MonitorCount; i++) { - if (!primaryMonitorFound && settings->MonitorDefArray[i].x == 0 - && settings->MonitorDefArray[i].y == 0) + if (!primaryMonitorFound && settings->MonitorDefArray[i].x == 0 && + settings->MonitorDefArray[i].y == 0) { settings->MonitorDefArray[i].is_primary = TRUE; settings->MonitorLocalShiftX = settings->MonitorDefArray[i].x; @@ -495,22 +537,24 @@ BOOL xf_detect_monitors(xfContext* xfc, UINT32* pMaxWidth, UINT32* pMaxHeight) } /* Subtract monitor shift from monitor variables for server-side use. - * We maintain monitor shift value as Window requires the primary monitor to have a coordinate of 0,0 - * In some X configurations, no monitor may have a coordinate of 0,0. This can also be happen if the user - * requests specific monitors from the command-line as well. So, we make sure to translate our primary monitor's - * upper-left corner to 0,0 on the server. + * We maintain monitor shift value as Window requires the primary monitor to have a + * coordinate of 0,0 In some X configurations, no monitor may have a coordinate of 0,0. This + * can also be happen if the user requests specific monitors from the command-line as well. + * So, we make sure to translate our primary monitor's upper-left corner to 0,0 on the + * server. */ for (i = 0; i < settings->MonitorCount; i++) { - settings->MonitorDefArray[i].x = settings->MonitorDefArray[i].x - - settings->MonitorLocalShiftX; - settings->MonitorDefArray[i].y = settings->MonitorDefArray[i].y - - settings->MonitorLocalShiftY; + settings->MonitorDefArray[i].x = + settings->MonitorDefArray[i].x - settings->MonitorLocalShiftX; + settings->MonitorDefArray[i].y = + settings->MonitorDefArray[i].y - settings->MonitorLocalShiftY; } - /* 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; + /* Set the desktop width and height according to the bounding rectangle around the active + * monitors */ + *pMaxWidth = MIN(*pMaxWidth, (UINT32)vscreen->area.right - vscreen->area.left + 1); + *pMaxHeight = MIN(*pMaxHeight, (UINT32)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..d712604 100644 --- a/client/X11/xf_rail.c +++ b/client/X11/xf_rail.c @@ -33,32 +33,20 @@ #define TAG CLIENT_TAG("x11") -static const char* error_code_names[] = -{ - "RAIL_EXEC_S_OK", - "RAIL_EXEC_E_HOOK_NOT_LOADED", - "RAIL_EXEC_E_DECODE_FAILED", - "RAIL_EXEC_E_NOT_IN_ALLOWLIST", - "RAIL_EXEC_E_FILE_NOT_FOUND", - "RAIL_EXEC_E_FAIL", - "RAIL_EXEC_E_SESSION_LOCKED" -}; +static const char* error_code_names[] = { "RAIL_EXEC_S_OK", + "RAIL_EXEC_E_HOOK_NOT_LOADED", + "RAIL_EXEC_E_DECODE_FAILED", + "RAIL_EXEC_E_NOT_IN_ALLOWLIST", + "RAIL_EXEC_E_FILE_NOT_FOUND", + "RAIL_EXEC_E_FAIL", + "RAIL_EXEC_E_SESSION_LOCKED" }; #ifdef WITH_DEBUG_RAIL -static const char* movetype_names[] = -{ - "(invalid)", - "RAIL_WMSZ_LEFT", - "RAIL_WMSZ_RIGHT", - "RAIL_WMSZ_TOP", - "RAIL_WMSZ_TOPLEFT", - "RAIL_WMSZ_TOPRIGHT", - "RAIL_WMSZ_BOTTOM", - "RAIL_WMSZ_BOTTOMLEFT", - "RAIL_WMSZ_BOTTOMRIGHT", - "RAIL_WMSZ_MOVE", - "RAIL_WMSZ_KEYMOVE", - "RAIL_WMSZ_KEYSIZE" +static const char* movetype_names[] = { + "(invalid)", "RAIL_WMSZ_LEFT", "RAIL_WMSZ_RIGHT", + "RAIL_WMSZ_TOP", "RAIL_WMSZ_TOPLEFT", "RAIL_WMSZ_TOPRIGHT", + "RAIL_WMSZ_BOTTOM", "RAIL_WMSZ_BOTTOMLEFT", "RAIL_WMSZ_BOTTOMRIGHT", + "RAIL_WMSZ_MOVE", "RAIL_WMSZ_KEYMOVE", "RAIL_WMSZ_KEYSIZE" }; #endif @@ -76,7 +64,6 @@ struct xf_rail_icon_cache UINT32 numCacheEntries; xfRailIcon scratch; }; -typedef struct xf_rail_icon_cache xfRailIconCache; void xf_rail_enable_remoteapp_mode(xfContext* xfc) { @@ -118,8 +105,7 @@ void xf_rail_send_activate(xfContext* xfc, Window xwindow, BOOL enabled) xfc->rail->ClientActivate(xfc->rail, &activate); } -void xf_rail_send_client_system_command(xfContext* xfc, UINT32 windowId, - UINT16 command) +void xf_rail_send_client_system_command(xfContext* xfc, UINT32 windowId, UINT16 command) { RAIL_SYSCOMMAND_ORDER syscommand; syscommand.windowId = windowId; @@ -141,14 +127,14 @@ void xf_rail_adjust_position(xfContext* xfc, xfAppWindow* appWindow) return; /* If current window position disagrees with RDP window position, send update to RDP server */ - if (appWindow->x != appWindow->windowOffsetX || - appWindow->y != appWindow->windowOffsetY || - appWindow->width != appWindow->windowWidth || - appWindow->height != appWindow->windowHeight) + if (appWindow->x != appWindow->windowOffsetX || appWindow->y != appWindow->windowOffsetY || + appWindow->width != (INT64)appWindow->windowWidth || + appWindow->height != (INT64)appWindow->windowHeight) { windowMove.windowId = appWindow->windowId; /* - * Calculate new size/position for the rail window(new values for windowOffsetX/windowOffsetY/windowWidth/windowHeight) on the server + * Calculate new size/position for the rail window(new values for + * windowOffsetX/windowOffsetY/windowWidth/windowHeight) on the server */ windowMove.left = appWindow->x; windowMove.top = appWindow->y; @@ -173,20 +159,22 @@ void xf_rail_end_local_move(xfContext* xfc, xfAppWindow* appWindow) */ windowMove.windowId = appWindow->windowId; /* - * Calculate new size/position for the rail window(new values for windowOffsetX/windowOffsetY/windowWidth/windowHeight) on the server + * Calculate new size/position for the rail window(new values for + * windowOffsetX/windowOffsetY/windowWidth/windowHeight) on the server * */ windowMove.left = appWindow->x; windowMove.top = appWindow->y; - windowMove.right = windowMove.left + - appWindow->width; /* In the update to RDP the position is one past the window */ + windowMove.right = + windowMove.left + + appWindow->width; /* In the update to RDP the position is one past the window */ windowMove.bottom = windowMove.top + appWindow->height; xfc->rail->ClientWindowMove(xfc->rail, &windowMove); /* * Simulate button up at new position to end the local move (per RDP spec) */ - XQueryPointer(xfc->display, appWindow->handle, - &root_window, &child_window, &x, &y, &child_x, &child_y, &mask); + XQueryPointer(xfc->display, appWindow->handle, &root_window, &child_window, &x, &y, &child_x, + &child_y, &mask); /* only send the mouse coordinates if not a keyboard move or size */ if ((appWindow->local_move.direction != _NET_WM_MOVERESIZE_MOVE_KEYBOARD) && @@ -210,7 +198,7 @@ void xf_rail_end_local_move(xfContext* xfc, xfAppWindow* appWindow) static void xf_rail_invalidate_region(xfContext* xfc, REGION16* invalidRegion) { int index; - int count; + int count = 0; RECTANGLE_16 updateRect; RECTANGLE_16 windowRect; ULONG_PTR* pKeys = NULL; @@ -218,12 +206,12 @@ static void xf_rail_invalidate_region(xfContext* xfc, REGION16* invalidRegion) const RECTANGLE_16* extents; REGION16 windowInvalidRegion; region16_init(&windowInvalidRegion); - count = HashTable_GetKeys(xfc->railWindows, &pKeys); + if (xfc->railWindows) + count = HashTable_GetKeys(xfc->railWindows, &pKeys); for (index = 0; index < count; index++) { - appWindow = (xfAppWindow*) HashTable_GetItemValue(xfc->railWindows, - (void*) pKeys[index]); + appWindow = xf_rail_get_window(xfc, *(UINT64*)pKeys[index]); if (appWindow) { @@ -252,8 +240,7 @@ static void xf_rail_invalidate_region(xfContext* xfc, REGION16* invalidRegion) region16_uninit(&windowInvalidRegion); } -void xf_rail_paint(xfContext* xfc, INT32 uleft, INT32 utop, UINT32 uright, - UINT32 ubottom) +void xf_rail_paint(xfContext* xfc, INT32 uleft, INT32 utop, UINT32 uright, UINT32 ubottom) { REGION16 invalidRegion; RECTANGLE_16 invalidRect; @@ -269,29 +256,27 @@ void xf_rail_paint(xfContext* xfc, INT32 uleft, INT32 utop, UINT32 uright, /* RemoteApp Core Protocol Extension */ -static BOOL xf_rail_window_common(rdpContext* context, - WINDOW_ORDER_INFO* orderInfo, WINDOW_STATE_ORDER* windowState) +static BOOL xf_rail_window_common(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo, + const WINDOW_STATE_ORDER* windowState) { xfAppWindow* appWindow = NULL; - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; UINT32 fieldFlags = orderInfo->fieldFlags; BOOL position_or_size_updated = FALSE; + appWindow = xf_rail_get_window(xfc, orderInfo->windowId); if (fieldFlags & WINDOW_ORDER_STATE_NEW) { - appWindow = (xfAppWindow*) calloc(1, sizeof(xfAppWindow)); + if (!appWindow) + appWindow = xf_rail_add_window(xfc, orderInfo->windowId, windowState->windowOffsetX, + windowState->windowOffsetY, windowState->windowWidth, + windowState->windowHeight, 0xFFFFFFFF); if (!appWindow) return FALSE; - appWindow->xfc = xfc; - appWindow->windowId = orderInfo->windowId; appWindow->dwStyle = windowState->style; appWindow->dwExStyle = windowState->extendedStyle; - appWindow->x = appWindow->windowOffsetX = windowState->windowOffsetX; - appWindow->y = appWindow->windowOffsetY = windowState->windowOffsetY; - appWindow->width = appWindow->windowWidth = windowState->windowWidth; - appWindow->height = appWindow->windowHeight = windowState->windowHeight; /* Ensure window always gets a window title */ if (fieldFlags & WINDOW_ORDER_FIELD_TITLE) @@ -306,8 +291,9 @@ static BOOL xf_rail_window_common(rdpContext* context, /* error handled below */ } } - else if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) windowState->titleInfo.string, - windowState->titleInfo.length / 2, &title, 0, NULL, NULL) < 1) + else if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*)windowState->titleInfo.string, + windowState->titleInfo.length / 2, &title, 0, NULL, + NULL) < 1) { WLog_ERR(TAG, "failed to convert window title"); /* error handled below */ @@ -327,22 +313,15 @@ static BOOL xf_rail_window_common(rdpContext* context, return FALSE; } - HashTable_Add(xfc->railWindows, (void*)(UINT_PTR) orderInfo->windowId, - (void*) appWindow); xf_AppWindowInit(xfc, appWindow); } - else - { - appWindow = (xfAppWindow*) HashTable_GetItemValue(xfc->railWindows, - (void*)(UINT_PTR) orderInfo->windowId); - } if (!appWindow) return FALSE; /* Keep track of any position/size update so that we can force a refresh of the window */ if ((fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) || - (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE) || + (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE) || (fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET) || (fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE) || (fieldFlags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA) || @@ -394,7 +373,7 @@ static BOOL xf_rail_window_common(rdpContext* context, return FALSE; } } - else if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) windowState->titleInfo.string, + else if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*)windowState->titleInfo.string, windowState->titleInfo.length / 2, &title, 0, NULL, NULL) < 1) { WLog_ERR(TAG, "failed to convert window title"); @@ -435,8 +414,8 @@ static BOOL xf_rail_window_common(rdpContext* context, if (appWindow->numWindowRects) { - appWindow->windowRects = (RECTANGLE_16*) calloc(appWindow->numWindowRects, - sizeof(RECTANGLE_16)); + appWindow->windowRects = + (RECTANGLE_16*)calloc(appWindow->numWindowRects, sizeof(RECTANGLE_16)); if (!appWindow->windowRects) return FALSE; @@ -464,8 +443,8 @@ static BOOL xf_rail_window_common(rdpContext* context, if (appWindow->numVisibilityRects) { - appWindow->visibilityRects = (RECTANGLE_16*) calloc( - appWindow->numVisibilityRects, sizeof(RECTANGLE_16)); + appWindow->visibilityRects = + (RECTANGLE_16*)calloc(appWindow->numVisibilityRects, sizeof(RECTANGLE_16)); if (!appWindow->visibilityRects) return FALSE; @@ -494,31 +473,32 @@ static BOOL xf_rail_window_common(rdpContext* context, if (position_or_size_updated) { - UINT32 visibilityRectsOffsetX = (appWindow->visibleOffsetX - - (appWindow->clientOffsetX - appWindow->windowClientDeltaX)); - UINT32 visibilityRectsOffsetY = (appWindow->visibleOffsetY - - (appWindow->clientOffsetY - appWindow->windowClientDeltaY)); + UINT32 visibilityRectsOffsetX = + (appWindow->visibleOffsetX - + (appWindow->clientOffsetX - appWindow->windowClientDeltaX)); + UINT32 visibilityRectsOffsetY = + (appWindow->visibleOffsetY - + (appWindow->clientOffsetY - appWindow->windowClientDeltaY)); /* - * The rail server like to set the window to a small size when it is minimized even though it is hidden - * in some cases this can cause the window not to restore back to its original size. Therefore we don't - * update our local window when that rail window state is minimized + * The rail server like to set the window to a small size when it is minimized even though + * it is hidden in some cases this can cause the window not to restore back to its original + * size. Therefore we don't update our local window when that rail window state is minimized */ if (appWindow->rail_state != WINDOW_SHOW_MINIMIZED) { /* Redraw window area if already in the correct position */ - if (appWindow->x == appWindow->windowOffsetX && - appWindow->y == appWindow->windowOffsetY && - appWindow->width == appWindow->windowWidth && - appWindow->height == appWindow->windowHeight) + if (appWindow->x == (INT64)appWindow->windowOffsetX && + appWindow->y == (INT64)appWindow->windowOffsetY && + appWindow->width == (INT64)appWindow->windowWidth && + appWindow->height == (INT64)appWindow->windowHeight) { xf_UpdateWindowArea(xfc, appWindow, 0, 0, appWindow->windowWidth, appWindow->windowHeight); } else { - xf_MoveWindow(xfc, appWindow, appWindow->windowOffsetX, - appWindow->windowOffsetY, + xf_MoveWindow(xfc, appWindow, appWindow->windowOffsetX, appWindow->windowOffsetY, appWindow->windowWidth, appWindow->windowHeight); } @@ -531,21 +511,15 @@ static BOOL xf_rail_window_common(rdpContext* context, /* We should only be using the visibility rects for shaping the window */ /*if (fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS) { - xf_SetWindowRects(xfc, appWindow, appWindow->windowRects, appWindow->numWindowRects); + xf_SetWindowRects(xfc, appWindow, appWindow->windowRects, appWindow->numWindowRects); }*/ return TRUE; } -static BOOL xf_rail_window_delete(rdpContext* context, - WINDOW_ORDER_INFO* orderInfo) +static BOOL xf_rail_window_delete(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo) { - xfContext* xfc = (xfContext*) context; - - if (!xfc) - return FALSE; - - HashTable_Remove(xfc->railWindows, (void*)(UINT_PTR) orderInfo->windowId); - return TRUE; + xfContext* xfc = (xfContext*)context; + return xf_rail_del_window(xfc, orderInfo->windowId); } static xfRailIconCache* RailIconCache_New(rdpSettings* settings) @@ -558,13 +532,12 @@ static xfRailIconCache* RailIconCache_New(rdpSettings* settings) cache->numCaches = settings->RemoteAppNumIconCaches; cache->numCacheEntries = settings->RemoteAppNumIconCacheEntries; - cache->entries = calloc(cache->numCaches * cache->numCacheEntries, - sizeof(xfRailIcon)); + cache->entries = calloc(cache->numCaches * cache->numCacheEntries, sizeof(xfRailIcon)); if (!cache->entries) { - WLog_ERR(TAG, "failed to allocate icon cache %d x %d entries", - cache->numCaches, cache->numCacheEntries); + WLog_ERR(TAG, "failed to allocate icon cache %d x %d entries", cache->numCaches, + cache->numCacheEntries); free(cache); return NULL; } @@ -589,8 +562,7 @@ static void RailIconCache_Free(xfRailIconCache* cache) } } -static xfRailIcon* RailIconCache_Lookup(xfRailIconCache* cache, - UINT8 cacheId, UINT16 cacheEntry) +static xfRailIcon* RailIconCache_Lookup(xfRailIconCache* cache, UINT8 cacheId, UINT16 cacheEntry) { /* * MS-RDPERP 2.2.1.2.3 Icon Info (TS_ICON_INFO) @@ -614,139 +586,6 @@ static xfRailIcon* RailIconCache_Lookup(xfRailIconCache* cache, } /* - * DIB color palettes are arrays of RGBQUAD structs with colors in BGRX format. - * They are used only by 1, 2, 4, and 8-bit bitmaps. - */ -static void fill_gdi_palette_for_icon(ICON_INFO* iconInfo, gdiPalette* palette) -{ - UINT32 i; - palette->format = PIXEL_FORMAT_BGRX32; - ZeroMemory(palette->palette, sizeof(palette->palette)); - - if (!iconInfo->cbColorTable) - return; - - if ((iconInfo->cbColorTable % 4 != 0) || (iconInfo->cbColorTable / 4 > 256)) - { - WLog_WARN(TAG, "weird palette size: %u", iconInfo->cbColorTable); - return; - } - - for (i = 0; i < iconInfo->cbColorTable / 4; i++) - { - palette->palette[i] = ReadColor(&iconInfo->colorTable[4 * i], palette->format); - } -} - -static BOOL convert_icon_color_to_argb(ICON_INFO* iconInfo, BYTE* argbPixels) -{ - DWORD format; - gdiPalette palette; - - /* - * Color formats used by icons are DIB bitmap formats (2-bit format - * is not used by MS-RDPERP). Note that 16-bit is RGB555, not RGB565, - * and that 32-bit format uses BGRA order. - */ - switch (iconInfo->bpp) - { - case 1: - case 4: - /* - * These formats are not supported by freerdp_image_copy(). - * PIXEL_FORMAT_MONO and PIXEL_FORMAT_A4 are *not* correct - * color formats for this. Please fix freerdp_image_copy() - * if you came here to fix a broken icon of some weird app - * that still uses 1 or 4bpp format in the 21st century. - */ - WLog_WARN(TAG, "1bpp and 4bpp icons are not supported"); - return FALSE; - - case 8: - format = PIXEL_FORMAT_RGB8; - break; - - case 16: - format = PIXEL_FORMAT_RGB15; - break; - - case 24: - format = PIXEL_FORMAT_RGB24; - break; - - case 32: - format = PIXEL_FORMAT_BGRA32; - break; - - default: - WLog_WARN(TAG, "invalid icon bpp: %d", iconInfo->bpp); - return FALSE; - } - - fill_gdi_palette_for_icon(iconInfo, &palette); - return freerdp_image_copy( - argbPixels, - PIXEL_FORMAT_ARGB32, - 0, 0, 0, - iconInfo->width, - iconInfo->height, - iconInfo->bitsColor, - format, - 0, 0, 0, - &palette, - FREERDP_FLIP_VERTICAL - ); -} - -static inline UINT32 div_ceil(UINT32 a, UINT32 b) -{ - return (a + (b - 1)) / b; -} - -static inline UINT32 round_up(UINT32 a, UINT32 b) -{ - return b * div_ceil(a, b); -} - -static void apply_icon_alpha_mask(ICON_INFO* iconInfo, BYTE* argbPixels) -{ - BYTE nextBit; - BYTE* maskByte; - UINT32 x, y; - UINT32 stride; - - if (!iconInfo->cbBitsMask) - return; - - /* - * Each byte encodes 8 adjacent pixels (with LSB padding as needed). - * And due to hysterical raisins, stride of DIB bitmaps must be - * a multiple of 4 bytes. - */ - stride = round_up(div_ceil(iconInfo->width, 8), 4); - - for (y = 0; y < iconInfo->height; y++) - { - /* ɐᴉlɐɹʇsn∀ uᴉ ǝɹ,ǝʍ ʇɐɥʇ ʇǝƃɹoɟ ʇ,uop */ - maskByte = &iconInfo->bitsMask[stride * (iconInfo->height - 1 - y)]; - nextBit = 0x80; - - for (x = 0; x < iconInfo->width; x++) - { - BYTE alpha = (*maskByte & nextBit) ? 0x00 : 0xFF; - argbPixels[4 * (x + y * iconInfo->width)] &= alpha; - nextBit >>= 1; - - if (!nextBit) - { - nextBit = 0x80; - maskByte++; - } - } - } -} - -/* * _NET_WM_ICON format is defined as "array of CARDINAL" values which for * Xlib must be represented with an array of C's "long" values. Note that * "long" != "INT32" on 64-bit systems. Therefore we can't simply cast @@ -758,7 +597,7 @@ static void apply_icon_alpha_mask(ICON_INFO* iconInfo, BYTE* argbPixels) */ static BOOL convert_rail_icon(ICON_INFO* iconInfo, xfRailIcon* railIcon) { - BYTE* argbPixels; + BYTE* argbPixels = NULL; BYTE* nextPixel; long* pixels; int i; @@ -768,10 +607,12 @@ static BOOL convert_rail_icon(ICON_INFO* iconInfo, xfRailIcon* railIcon) if (!argbPixels) goto error; - if (!convert_icon_color_to_argb(iconInfo, argbPixels)) + if (!freerdp_image_copy_from_icon_data( + argbPixels, PIXEL_FORMAT_ARGB32, 0, 0, 0, iconInfo->width, iconInfo->height, + iconInfo->bitsColor, iconInfo->cbBitsColor, iconInfo->bitsMask, iconInfo->cbBitsMask, + iconInfo->colorTable, iconInfo->cbColorTable, iconInfo->bpp)) goto error; - apply_icon_alpha_mask(iconInfo, argbPixels); nelements = 2 + iconInfo->width * iconInfo->height; pixels = realloc(railIcon->data, nelements * sizeof(long)); @@ -797,42 +638,33 @@ error: return FALSE; } -static void xf_rail_set_window_icon(xfContext* xfc, - xfAppWindow* railWindow, xfRailIcon* icon, +static void xf_rail_set_window_icon(xfContext* xfc, xfAppWindow* railWindow, xfRailIcon* icon, BOOL replace) { - XChangeProperty(xfc->display, railWindow->handle, xfc->_NET_WM_ICON, - XA_CARDINAL, 32, replace ? PropModeReplace : PropModeAppend, - (unsigned char*) icon->data, icon->length); + XChangeProperty(xfc->display, railWindow->handle, xfc->_NET_WM_ICON, XA_CARDINAL, 32, + replace ? PropModeReplace : PropModeAppend, (unsigned char*)icon->data, + icon->length); XFlush(xfc->display); } -static xfAppWindow* xf_rail_get_window_by_id(xfContext* xfc, UINT32 windowId) +static BOOL xf_rail_window_icon(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo, + const WINDOW_ICON_ORDER* windowIcon) { - return (xfAppWindow*) HashTable_GetItemValue(xfc->railWindows, - (void*)(UINT_PTR) windowId); -} - -static BOOL xf_rail_window_icon(rdpContext* context, - WINDOW_ORDER_INFO* orderInfo, WINDOW_ICON_ORDER* windowIcon) -{ - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; xfAppWindow* railWindow; xfRailIcon* icon; BOOL replaceIcon; - railWindow = xf_rail_get_window_by_id(xfc, orderInfo->windowId); + railWindow = xf_rail_get_window(xfc, orderInfo->windowId); if (!railWindow) return TRUE; - icon = RailIconCache_Lookup(xfc->railIconCache, - windowIcon->iconInfo->cacheId, + icon = RailIconCache_Lookup(xfc->railIconCache, windowIcon->iconInfo->cacheId, windowIcon->iconInfo->cacheEntry); if (!icon) { - WLog_WARN(TAG, "failed to get icon from cache %02X:%04X", - windowIcon->iconInfo->cacheId, + WLog_WARN(TAG, "failed to get icon from cache %02X:%04X", windowIcon->iconInfo->cacheId, windowIcon->iconInfo->cacheEntry); return FALSE; } @@ -848,27 +680,25 @@ static BOOL xf_rail_window_icon(rdpContext* context, return TRUE; } -static BOOL xf_rail_window_cached_icon(rdpContext* context, - WINDOW_ORDER_INFO* orderInfo, WINDOW_CACHED_ICON_ORDER* windowCachedIcon) +static BOOL xf_rail_window_cached_icon(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo, + const WINDOW_CACHED_ICON_ORDER* windowCachedIcon) { - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; xfAppWindow* railWindow; xfRailIcon* icon; BOOL replaceIcon; - railWindow = xf_rail_get_window_by_id(xfc, orderInfo->windowId); + railWindow = xf_rail_get_window(xfc, orderInfo->windowId); if (!railWindow) return TRUE; - icon = RailIconCache_Lookup(xfc->railIconCache, - windowCachedIcon->cachedIcon.cacheId, + icon = RailIconCache_Lookup(xfc->railIconCache, windowCachedIcon->cachedIcon.cacheId, windowCachedIcon->cachedIcon.cacheEntry); if (!icon) { WLog_WARN(TAG, "failed to get icon from cache %02X:%04X", - windowCachedIcon->cachedIcon.cacheId, - windowCachedIcon->cachedIcon.cacheEntry); + windowCachedIcon->cachedIcon.cacheId, windowCachedIcon->cachedIcon.cacheEntry); return FALSE; } @@ -877,8 +707,8 @@ static BOOL xf_rail_window_cached_icon(rdpContext* context, return TRUE; } -static BOOL xf_rail_notify_icon_common(rdpContext* context, - WINDOW_ORDER_INFO* orderInfo, NOTIFY_ICON_STATE_ORDER* notifyIconState) +static BOOL xf_rail_notify_icon_common(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo, + const NOTIFY_ICON_STATE_ORDER* notifyIconState) { if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_VERSION) { @@ -907,34 +737,32 @@ static BOOL xf_rail_notify_icon_common(rdpContext* context, return TRUE; } -static BOOL xf_rail_notify_icon_create(rdpContext* context, - WINDOW_ORDER_INFO* orderInfo, NOTIFY_ICON_STATE_ORDER* notifyIconState) +static BOOL xf_rail_notify_icon_create(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo, + const NOTIFY_ICON_STATE_ORDER* notifyIconState) { return xf_rail_notify_icon_common(context, orderInfo, notifyIconState); } -static BOOL xf_rail_notify_icon_update(rdpContext* context, - WINDOW_ORDER_INFO* orderInfo, NOTIFY_ICON_STATE_ORDER* notifyIconState) +static BOOL xf_rail_notify_icon_update(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo, + const NOTIFY_ICON_STATE_ORDER* notifyIconState) { return xf_rail_notify_icon_common(context, orderInfo, notifyIconState); } -static BOOL xf_rail_notify_icon_delete(rdpContext* context, - WINDOW_ORDER_INFO* orderInfo) +static BOOL xf_rail_notify_icon_delete(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo) { return TRUE; } -static BOOL xf_rail_monitored_desktop(rdpContext* context, - WINDOW_ORDER_INFO* orderInfo, MONITORED_DESKTOP_ORDER* monitoredDesktop) +static BOOL xf_rail_monitored_desktop(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo, + const MONITORED_DESKTOP_ORDER* monitoredDesktop) { return TRUE; } -static BOOL xf_rail_non_monitored_desktop(rdpContext* context, - WINDOW_ORDER_INFO* orderInfo) +static BOOL xf_rail_non_monitored_desktop(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo) { - xfContext* xfc = (xfContext*) context; + xfContext* xfc = (xfContext*)context; xf_rail_disable_remoteapp_mode(xfc); return TRUE; } @@ -962,9 +790,9 @@ static void xf_rail_register_update_callbacks(rdpUpdate* update) * @return 0 on success, otherwise a Win32 error code */ static UINT xf_rail_server_execute_result(RailClientContext* context, - const RAIL_EXEC_RESULT_ORDER* execResult) + const RAIL_EXEC_RESULT_ORDER* execResult) { - xfContext* xfc = (xfContext*) context->custom; + xfContext* xfc = (xfContext*)context->custom; if (execResult->execResult != RAIL_EXEC_S_OK) { @@ -988,37 +816,50 @@ static UINT xf_rail_server_execute_result(RailClientContext* context, static UINT xf_rail_server_system_param(RailClientContext* context, const RAIL_SYSPARAM_ORDER* sysparam) { + // TODO: Actually apply param return CHANNEL_RC_OK; } -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT xf_rail_server_handshake(RailClientContext* context, - const RAIL_HANDSHAKE_ORDER* handshake) +static UINT xf_rail_server_start_cmd(RailClientContext* context) { - RAIL_EXEC_ORDER exec; - RAIL_SYSPARAM_ORDER sysparam; - RAIL_HANDSHAKE_ORDER clientHandshake; - RAIL_CLIENT_STATUS_ORDER clientStatus; - xfContext* xfc = (xfContext*) context->custom; + UINT status; + RAIL_EXEC_ORDER exec = { 0 }; + RAIL_SYSPARAM_ORDER sysparam = { 0 }; + 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)); - clientStatus.flags = RAIL_CLIENTSTATUS_ALLOWLOCALMOVESIZE; - context->ClientInformation(context, &clientStatus); + clientStatus.flags = TS_RAIL_CLIENTSTATUS_ALLOWLOCALMOVESIZE; + + if (settings->AutoReconnectionEnabled) + clientStatus.flags |= TS_RAIL_CLIENTSTATUS_AUTORECONNECT; + + clientStatus.flags |= TS_RAIL_CLIENTSTATUS_ZORDER_SYNC; + clientStatus.flags |= TS_RAIL_CLIENTSTATUS_WINDOW_RESIZE_MARGIN_SUPPORTED; + clientStatus.flags |= TS_RAIL_CLIENTSTATUS_APPBAR_REMOTING_SUPPORTED; + clientStatus.flags |= TS_RAIL_CLIENTSTATUS_POWER_DISPLAY_REQUEST_SUPPORTED; + clientStatus.flags |= TS_RAIL_CLIENTSTATUS_BIDIRECTIONAL_CLOAK_SUPPORTED; + status = context->ClientInformation(context, &clientStatus); + + if (status != CHANNEL_RC_OK) + return status; if (settings->RemoteAppLanguageBarSupported) { RAIL_LANGBAR_INFO_ORDER langBarInfo; langBarInfo.languageBarStatus = 0x00000008; /* TF_SFT_HIDDEN */ - context->ClientLanguageBarInfo(context, &langBarInfo); + status = context->ClientLanguageBarInfo(context, &langBarInfo); + + /* We want the language bar, but the server might not support it. */ + switch (status) + { + case CHANNEL_RC_OK: + case ERROR_BAD_CONFIGURATION: + break; + default: + return status; + } } - ZeroMemory(&sysparam, sizeof(RAIL_SYSPARAM_ORDER)); sysparam.params = 0; sysparam.params |= SPI_MASK_SET_HIGH_CONTRAST; sysparam.highContrast.colorScheme.string = NULL; @@ -1038,13 +879,25 @@ 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); +} +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT xf_rail_server_handshake(RailClientContext* context, + const RAIL_HANDSHAKE_ORDER* handshake) +{ + return xf_rail_server_start_cmd(context); } /** @@ -1055,7 +908,7 @@ static UINT xf_rail_server_handshake(RailClientContext* context, static UINT xf_rail_server_handshake_ex(RailClientContext* context, const RAIL_HANDSHAKE_EX_ORDER* handshakeEx) { - return CHANNEL_RC_OK; + return xf_rail_server_start_cmd(context); } /** @@ -1064,15 +917,13 @@ static UINT xf_rail_server_handshake_ex(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT xf_rail_server_local_move_size(RailClientContext* context, - const RAIL_LOCALMOVESIZE_ORDER* localMoveSize) + const RAIL_LOCALMOVESIZE_ORDER* localMoveSize) { int x = 0, y = 0; int direction = 0; Window child_window; - xfAppWindow* appWindow = NULL; - xfContext* xfc = (xfContext*) context->custom; - appWindow = (xfAppWindow*) HashTable_GetItemValue(xfc->railWindows, - (void*)(UINT_PTR) localMoveSize->windowId); + xfContext* xfc = (xfContext*)context->custom; + xfAppWindow* appWindow = xf_rail_get_window(xfc, localMoveSize->windowId); if (!appWindow) return ERROR_INTERNAL_ERROR; @@ -1129,8 +980,7 @@ static UINT xf_rail_server_local_move_size(RailClientContext* context, case RAIL_WMSZ_MOVE: direction = _NET_WM_MOVERESIZE_MOVE; - XTranslateCoordinates(xfc->display, appWindow->handle, - RootWindowOfScreen(xfc->screen), + XTranslateCoordinates(xfc->display, appWindow->handle, RootWindowOfScreen(xfc->screen), localMoveSize->posX, localMoveSize->posY, &x, &y, &child_window); break; @@ -1165,18 +1015,15 @@ static UINT xf_rail_server_local_move_size(RailClientContext* context, static UINT xf_rail_server_min_max_info(RailClientContext* context, const RAIL_MINMAXINFO_ORDER* minMaxInfo) { - xfAppWindow* appWindow = NULL; - xfContext* xfc = (xfContext*) context->custom; - appWindow = (xfAppWindow*) HashTable_GetItemValue(xfc->railWindows, - (void*)(UINT_PTR) minMaxInfo->windowId); + xfContext* xfc = (xfContext*)context->custom; + xfAppWindow* appWindow = xf_rail_get_window(xfc, minMaxInfo->windowId); if (appWindow) { - xf_SetWindowMinMaxInfo(xfc, appWindow, - minMaxInfo->maxWidth, minMaxInfo->maxHeight, - minMaxInfo->maxPosX, minMaxInfo->maxPosY, - minMaxInfo->minTrackWidth, minMaxInfo->minTrackHeight, - minMaxInfo->maxTrackWidth, minMaxInfo->maxTrackHeight); + xf_SetWindowMinMaxInfo(xfc, appWindow, minMaxInfo->maxWidth, minMaxInfo->maxHeight, + minMaxInfo->maxPosX, minMaxInfo->maxPosY, minMaxInfo->minTrackWidth, + minMaxInfo->minTrackHeight, minMaxInfo->maxTrackWidth, + minMaxInfo->maxTrackHeight); } return CHANNEL_RC_OK; @@ -1188,7 +1035,7 @@ static UINT xf_rail_server_min_max_info(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT xf_rail_server_language_bar_info(RailClientContext* context, - const RAIL_LANGBAR_INFO_ORDER* langBarInfo) + const RAIL_LANGBAR_INFO_ORDER* langBarInfo) { return CHANNEL_RC_OK; } @@ -1199,14 +1046,31 @@ static UINT xf_rail_server_language_bar_info(RailClientContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT xf_rail_server_get_appid_response(RailClientContext* context, - const RAIL_GET_APPID_RESP_ORDER* getAppIdResp) + const RAIL_GET_APPID_RESP_ORDER* getAppIdResp) { return CHANNEL_RC_OK; } +static BOOL rail_window_key_equals(void* key1, void* key2) +{ + const UINT64* k1 = (const UINT64*)key1; + const UINT64* k2 = (const UINT64*)key2; + + if (!k1 || !k2) + return FALSE; + + return *k1 == *k2; +} + +static UINT32 rail_window_key_hash(void* key) +{ + const UINT64* k1 = (const UINT64*)key; + return (UINT32)*k1; +} + static void rail_window_free(void* value) { - xfAppWindow* appWindow = (xfAppWindow*) value; + xfAppWindow* appWindow = (xfAppWindow*)value; if (!appWindow) return; @@ -1216,14 +1080,14 @@ static void rail_window_free(void* value) int xf_rail_init(xfContext* xfc, RailClientContext* rail) { - rdpContext* context = (rdpContext*) xfc; + rdpContext* context = (rdpContext*)xfc; if (!xfc || !rail) return 0; xfc->rail = rail; xf_rail_register_update_callbacks(context->update); - rail->custom = (void*) xfc; + rail->custom = (void*)xfc; rail->ServerExecuteResult = xf_rail_server_execute_result; rail->ServerSystemParam = xf_rail_server_system_param; rail->ServerHandshake = xf_rail_server_handshake; @@ -1237,6 +1101,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); @@ -1251,6 +1117,8 @@ int xf_rail_init(xfContext* xfc, RailClientContext* rail) int xf_rail_uninit(xfContext* xfc, RailClientContext* rail) { + WINPR_UNUSED(rail); + if (xfc->rail) { xfc->rail->custom = NULL; @@ -1271,3 +1139,50 @@ int xf_rail_uninit(xfContext* xfc, RailClientContext* rail) return 1; } + +xfAppWindow* xf_rail_add_window(xfContext* xfc, UINT64 id, UINT32 x, UINT32 y, UINT32 width, + UINT32 height, UINT32 surfaceId) +{ + xfAppWindow* appWindow; + + if (!xfc) + return NULL; + + appWindow = (xfAppWindow*)calloc(1, sizeof(xfAppWindow)); + + if (!appWindow) + return NULL; + + appWindow->xfc = xfc; + appWindow->windowId = id; + appWindow->surfaceId = surfaceId; + appWindow->x = x; + appWindow->y = y; + appWindow->width = width; + appWindow->height = height; + xf_AppWindowCreate(xfc, appWindow); + HashTable_Add(xfc->railWindows, &appWindow->windowId, (void*)appWindow); + return appWindow; +} + +BOOL xf_rail_del_window(xfContext* xfc, UINT64 id) +{ + if (!xfc) + return FALSE; + + if (!xfc->railWindows) + return FALSE; + + return HashTable_Remove(xfc->railWindows, &id); +} + +xfAppWindow* xf_rail_get_window(xfContext* xfc, UINT64 id) +{ + if (!xfc) + return NULL; + + if (!xfc->railWindows) + return FALSE; + + return HashTable_GetItemValue(xfc->railWindows, &id); +} diff --git a/client/X11/xf_rail.h b/client/X11/xf_rail.h index 2e1ea53..c99ed70 100644 --- a/client/X11/xf_rail.h +++ b/client/X11/xf_rail.h @@ -33,6 +33,16 @@ void xf_rail_end_local_move(xfContext* xfc, xfAppWindow* appWindow); void xf_rail_enable_remoteapp_mode(xfContext* xfc); void xf_rail_disable_remoteapp_mode(xfContext* xfc); +xfAppWindow* xf_rail_add_window(xfContext* xfc, UINT64 id, UINT32 x, UINT32 y, UINT32 width, + UINT32 height, UINT32 surfaceId); +xfAppWindow* xf_rail_get_window(xfContext* xfc, UINT64 id); + +BOOL xf_rail_del_window(xfContext* xfc, UINT64 id); + +BOOL xf_rail_draw_window(xfContext* xfc, xfAppWindow* window, const char* data, UINT32 scanline, + UINT32 width, UINT32 height, const RECTANGLE_16* src, + const RECTANGLE_16* dst); + int xf_rail_init(xfContext* xfc, RailClientContext* rail); int xf_rail_uninit(xfContext* xfc, RailClientContext* rail); diff --git a/client/X11/xf_tsmf.c b/client/X11/xf_tsmf.c index 58fa794..87f1047 100644 --- a/client/X11/xf_tsmf.c +++ b/client/X11/xf_tsmf.c @@ -72,7 +72,7 @@ static BOOL xf_tsmf_is_format_supported(xfXvContext* xv, UINT32 pixfmt) return FALSE; } -int xf_tsmf_xv_video_frame_event(TsmfClientContext* tsmf, TSMF_VIDEO_FRAME_EVENT* event) +static int xf_tsmf_xv_video_frame_event(TsmfClientContext* tsmf, TSMF_VIDEO_FRAME_EVENT* event) { int i; int x, y; @@ -87,19 +87,19 @@ int xf_tsmf_xv_video_frame_event(TsmfClientContext* tsmf, TSMF_VIDEO_FRAME_EVENT int numRects = 0; xfContext* xfc; xfXvContext* xv; - XRectangle* xrects; + XRectangle* xrects = NULL; XShmSegmentInfo shminfo; BOOL converti420yv12 = FALSE; if (!tsmf) return -1; - xfc = (xfContext*) tsmf->custom; + xfc = (xfContext*)tsmf->custom; if (!xfc) return -1; - xv = (xfXvContext*) xfc->xv_context; + xv = (xfXvContext*)xfc->xv_context; if (!xv) return -1; @@ -118,7 +118,7 @@ int xf_tsmf_xv_video_frame_event(TsmfClientContext* tsmf, TSMF_VIDEO_FRAME_EVENT if (numRects > 0) { - xrects = (XRectangle*) calloc(numRects, sizeof(XRectangle)); + xrects = (XRectangle*)calloc(numRects, sizeof(XRectangle)); if (!xrects) return -1; @@ -186,13 +186,13 @@ int xf_tsmf_xv_video_frame_event(TsmfClientContext* tsmf, TSMF_VIDEO_FRAME_EVENT } else { - WLog_DBG(TAG, "pixel format 0x%"PRIX32" not supported by hardware.", pixfmt); + WLog_DBG(TAG, "pixel format 0x%" PRIX32 " not supported by hardware.", pixfmt); free(xrects); return -1003; } - image = XvShmCreateImage(xfc->display, xv->xv_port, - xvpixfmt, 0, event->frameWidth, event->frameHeight, &shminfo); + image = XvShmCreateImage(xfc->display, xv->xv_port, xvpixfmt, 0, event->frameWidth, + event->frameHeight, &shminfo); if (xv->xv_image_size != image->data_size) { @@ -228,17 +228,15 @@ int xf_tsmf_xv_video_frame_event(TsmfClientContext* tsmf, TSMF_VIDEO_FRAME_EVENT /* Y */ if (image->pitches[0] == event->frameWidth) { - CopyMemory(image->data + image->offsets[0], - event->frameData, - event->frameWidth * event->frameHeight); + CopyMemory(image->data + image->offsets[0], event->frameData, + event->frameWidth * event->frameHeight); } else { for (i = 0; i < event->frameHeight; i++) { CopyMemory(image->data + image->offsets[0] + i * image->pitches[0], - event->frameData + i * event->frameWidth, - event->frameWidth); + event->frameData + i * event->frameWidth, event->frameWidth); } } /* UV */ @@ -247,48 +245,54 @@ int xf_tsmf_xv_video_frame_event(TsmfClientContext* tsmf, TSMF_VIDEO_FRAME_EVENT { data1 = event->frameData + event->frameWidth * event->frameHeight; data2 = event->frameData + event->frameWidth * event->frameHeight + - event->frameWidth * event->frameHeight / 4; + event->frameWidth * event->frameHeight / 4; } else { data2 = event->frameData + event->frameWidth * event->frameHeight; data1 = event->frameData + event->frameWidth * event->frameHeight + - event->frameWidth * event->frameHeight / 4; + event->frameWidth * event->frameHeight / 4; image->id = pixfmt == RDP_PIXFMT_I420 ? RDP_PIXFMT_YV12 : RDP_PIXFMT_I420; } if (image->pitches[1] * 2 == event->frameWidth) { - CopyMemory(image->data + image->offsets[1], - data1, - event->frameWidth * event->frameHeight / 4); - CopyMemory(image->data + image->offsets[2], - data2, - event->frameWidth * event->frameHeight / 4); + CopyMemory(image->data + image->offsets[1], data1, + event->frameWidth * event->frameHeight / 4); + CopyMemory(image->data + image->offsets[2], data2, + event->frameWidth * event->frameHeight / 4); } else { for (i = 0; i < event->frameHeight / 2; i++) { CopyMemory(image->data + image->offsets[1] + i * image->pitches[1], - data1 + i * event->frameWidth / 2, - event->frameWidth / 2); + data1 + i * event->frameWidth / 2, event->frameWidth / 2); CopyMemory(image->data + image->offsets[2] + i * image->pitches[2], - data2 + i * event->frameWidth / 2, - event->frameWidth / 2); + data2 + i * event->frameWidth / 2, event->frameWidth / 2); } } break; default: - CopyMemory(image->data, event->frameData, image->data_size <= event->frameSize ? - image->data_size : event->frameSize); + if (image->data_size < 0) + { + free(xrects); + return -2000; + } + else + { + const size_t size = ((UINT32)image->data_size <= event->frameSize) + ? (UINT32)image->data_size + : event->frameSize; + CopyMemory(image->data, event->frameData, size); + } break; } - XvShmPutImage(xfc->display, xv->xv_port, xfc->window->handle, xfc->gc, - image, 0, 0, image->width, image->height, - event->x, event->y, event->width, event->height, FALSE); + XvShmPutImage(xfc->display, xv->xv_port, xfc->window->handle, xfc->gc, image, 0, 0, + image->width, image->height, event->x, event->y, event->width, event->height, + FALSE); if (xv->xv_colorkey_atom == None) XSetClipMask(xfc->display, xfc->gc, None); @@ -321,7 +325,7 @@ int xf_tsmf_xv_init(xfContext* xfc, TsmfClientContext* tsmf) if (xfc->xv_context) return 1; /* context already created */ - xv = (xfXvContext*) calloc(1, sizeof(xfXvContext)); + xv = (xfXvContext*)calloc(1, sizeof(xfXvContext)); if (!xv) return -1; @@ -338,7 +342,8 @@ int xf_tsmf_xv_init(xfContext* xfc, TsmfClientContext* tsmf) return -1; } - ret = XvQueryExtension(xfc->display, &version, &release, &request_base, &event_base, &error_base); + ret = + XvQueryExtension(xfc->display, &version, &release, &request_base, &event_base, &error_base); if (ret != Success) { @@ -348,8 +353,7 @@ int xf_tsmf_xv_init(xfContext* xfc, TsmfClientContext* tsmf) WLog_DBG(TAG, "version %u release %u", version, release); - ret = XvQueryAdaptors(xfc->display, DefaultRootWindow(xfc->display), - &num_adaptors, &ai); + ret = XvQueryAdaptors(xfc->display, DefaultRootWindow(xfc->display), &num_adaptors, &ai); if (ret != Success) { @@ -360,7 +364,7 @@ int xf_tsmf_xv_init(xfContext* xfc, TsmfClientContext* tsmf) for (i = 0; i < num_adaptors; i++) { WLog_DBG(TAG, "adapter port %lu-%lu (%s)", ai[i].base_id, - ai[i].base_id + ai[i].num_ports - 1, ai[i].name); + ai[i].base_id + ai[i].num_ports - 1, ai[i].name); if (xv->xv_port == 0 && i == num_adaptors - 1) xv->xv_port = ai[i].base_id; @@ -383,7 +387,8 @@ int xf_tsmf_xv_init(xfContext* xfc, TsmfClientContext* tsmf) if (strcmp(attr[i].name, "XV_COLORKEY") == 0) { xv->xv_colorkey_atom = XInternAtom(xfc->display, "XV_COLORKEY", FALSE); - XvSetPortAttribute(xfc->display, xv->xv_port, xv->xv_colorkey_atom, attr[i].min_value + 1); + XvSetPortAttribute(xfc->display, xv->xv_port, xv->xv_colorkey_atom, + attr[i].min_value + 1); break; } } @@ -395,13 +400,14 @@ int xf_tsmf_xv_init(xfContext* xfc, TsmfClientContext* tsmf) if (ret > 0) { - xv->xv_pixfmts = (UINT32*) calloc((ret + 1), sizeof(UINT32)); + xv->xv_pixfmts = (UINT32*)calloc((ret + 1), sizeof(UINT32)); - for (i = 0; i < ret; i++) + for (i = 0; i < (unsigned int)ret; i++) { xv->xv_pixfmts[i] = fo[i].id; - WLog_DBG(TAG, "%c%c%c%c ", ((char*)(xv->xv_pixfmts + i))[0], ((char*)(xv->xv_pixfmts + i))[1], - ((char*)(xv->xv_pixfmts + i))[2], ((char*)(xv->xv_pixfmts + i))[3]); + WLog_DBG(TAG, "%c%c%c%c ", ((char*)(xv->xv_pixfmts + i))[0], + ((char*)(xv->xv_pixfmts + i))[1], ((char*)(xv->xv_pixfmts + i))[2], + ((char*)(xv->xv_pixfmts + i))[3]); } xv->xv_pixfmts[i] = 0; } @@ -410,7 +416,7 @@ int xf_tsmf_xv_init(xfContext* xfc, TsmfClientContext* tsmf) if (tsmf) { xfc->tsmf = tsmf; - tsmf->custom = (void*) xfc; + tsmf->custom = (void*)xfc; tsmf->FrameEvent = xf_tsmf_xv_video_frame_event; } @@ -420,8 +426,9 @@ int xf_tsmf_xv_init(xfContext* xfc, TsmfClientContext* tsmf) int xf_tsmf_xv_uninit(xfContext* xfc, TsmfClientContext* tsmf) { - xfXvContext* xv = (xfXvContext*) xfc->xv_context; + xfXvContext* xv = (xfXvContext*)xfc->xv_context; + WINPR_UNUSED(tsmf); if (xv) { if (xv->xv_image_size > 0) @@ -466,4 +473,3 @@ int xf_tsmf_uninit(xfContext* xfc, TsmfClientContext* tsmf) return 1; } - diff --git a/client/X11/xf_video.c b/client/X11/xf_video.c index 5fc8f2f..9520454 100644 --- a/client/X11/xf_video.c +++ b/client/X11/xf_video.c @@ -17,7 +17,6 @@ * limitations under the License. */ - #include #include #include @@ -33,7 +32,7 @@ typedef struct } xfVideoSurface; static VideoSurface* xfVideoCreateSurface(VideoClientContext* video, BYTE* data, UINT32 x, UINT32 y, - UINT32 width, UINT32 height) + UINT32 width, UINT32 height) { xfContext* xfc = (xfContext*)video->custom; xfVideoSurface* ret = calloc(1, sizeof(*ret)); @@ -46,8 +45,8 @@ static VideoSurface* xfVideoCreateSurface(VideoClientContext* video, BYTE* data, ret->base.y = y; ret->base.w = width; ret->base.h = height; - ret->image = XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0, - (char*)data, width, height, 8, width * 4); + ret->image = XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0, (char*)data, width, + height, 8, width * 4); if (!ret->image) { @@ -59,26 +58,23 @@ static VideoSurface* xfVideoCreateSurface(VideoClientContext* video, BYTE* data, return &ret->base; } - static BOOL xfVideoShowSurface(VideoClientContext* video, VideoSurface* surface) { xfVideoSurface* xfSurface = (xfVideoSurface*)surface; xfContext* xfc = video->custom; #ifdef WITH_XRENDER - if (xfc->context.settings->SmartSizing - || xfc->context.settings->MultiTouchGestures) + if (xfc->context.settings->SmartSizing || xfc->context.settings->MultiTouchGestures) { - XPutImage(xfc->display, xfc->primary, xfc->gc, xfSurface->image, - 0, 0, surface->x, surface->y, surface->w, surface->h); + XPutImage(xfc->display, xfc->primary, xfc->gc, xfSurface->image, 0, 0, surface->x, + surface->y, surface->w, surface->h); xf_draw_screen(xfc, surface->x, surface->y, surface->w, surface->h); } else #endif { - XPutImage(xfc->display, xfc->drawable, xfc->gc, xfSurface->image, - 0, 0, - surface->x, surface->y, surface->w, surface->h); + XPutImage(xfc->display, xfc->drawable, xfc->gc, xfSurface->image, 0, 0, surface->x, + surface->y, surface->w, surface->h); } return TRUE; @@ -88,6 +84,8 @@ static BOOL xfVideoDeleteSurface(VideoClientContext* video, VideoSurface* surfac { xfVideoSurface* xfSurface = (xfVideoSurface*)surface; + WINPR_UNUSED(video); + if (xfSurface) XFree(xfSurface->image); @@ -103,7 +101,6 @@ void xf_video_control_init(xfContext* xfc, VideoClientContext* video) video->deleteSurface = xfVideoDeleteSurface; } - void xf_video_control_uninit(xfContext* xfc, VideoClientContext* video) { gdi_video_control_uninit(xfc->context.gdi, video); diff --git a/client/X11/xf_video.h b/client/X11/xf_video.h index 47af49c..83708f0 100644 --- a/client/X11/xf_video.h +++ b/client/X11/xf_video.h @@ -30,5 +30,4 @@ void xf_video_control_uninit(xfContext* xfc, VideoClientContext* video); xfVideoContext* xf_video_new(xfContext* xfc); void xf_video_free(xfVideoContext* context); - #endif /* CLIENT_X11_XF_VIDEO_H_ */ diff --git a/client/X11/xf_window.c b/client/X11/xf_window.c index a86ad4c..819193e 100644 --- a/client/X11/xf_window.c +++ b/client/X11/xf_window.c @@ -60,7 +60,10 @@ #ifdef WITH_DEBUG_X11 #define DEBUG_X11(...) WLog_DBG(TAG, __VA_ARGS__) #else -#define DEBUG_X11(...) do { } while (0) +#define DEBUG_X11(...) \ + do \ + { \ + } while (0) #endif #include "FreeRDP_Icon_256px.h" @@ -71,29 +74,29 @@ /* Extended Window Manager Hints: http://standards.freedesktop.org/wm-spec/wm-spec-1.3.html */ /* bit definitions for MwmHints.flags */ -#define MWM_HINTS_FUNCTIONS (1L << 0) -#define MWM_HINTS_DECORATIONS (1L << 1) -#define MWM_HINTS_INPUT_MODE (1L << 2) -#define MWM_HINTS_STATUS (1L << 3) +#define MWM_HINTS_FUNCTIONS (1L << 0) +#define MWM_HINTS_DECORATIONS (1L << 1) +#define MWM_HINTS_INPUT_MODE (1L << 2) +#define MWM_HINTS_STATUS (1L << 3) /* bit definitions for MwmHints.functions */ -#define MWM_FUNC_ALL (1L << 0) -#define MWM_FUNC_RESIZE (1L << 1) -#define MWM_FUNC_MOVE (1L << 2) -#define MWM_FUNC_MINIMIZE (1L << 3) -#define MWM_FUNC_MAXIMIZE (1L << 4) -#define MWM_FUNC_CLOSE (1L << 5) +#define MWM_FUNC_ALL (1L << 0) +#define MWM_FUNC_RESIZE (1L << 1) +#define MWM_FUNC_MOVE (1L << 2) +#define MWM_FUNC_MINIMIZE (1L << 3) +#define MWM_FUNC_MAXIMIZE (1L << 4) +#define MWM_FUNC_CLOSE (1L << 5) /* bit definitions for MwmHints.decorations */ -#define MWM_DECOR_ALL (1L << 0) -#define MWM_DECOR_BORDER (1L << 1) -#define MWM_DECOR_RESIZEH (1L << 2) -#define MWM_DECOR_TITLE (1L << 3) -#define MWM_DECOR_MENU (1L << 4) -#define MWM_DECOR_MINIMIZE (1L << 5) -#define MWM_DECOR_MAXIMIZE (1L << 6) +#define MWM_DECOR_ALL (1L << 0) +#define MWM_DECOR_BORDER (1L << 1) +#define MWM_DECOR_RESIZEH (1L << 2) +#define MWM_DECOR_TITLE (1L << 3) +#define MWM_DECOR_MENU (1L << 4) +#define MWM_DECOR_MINIMIZE (1L << 5) +#define MWM_DECOR_MAXIMIZE (1L << 6) -#define PROP_MOTIF_WM_HINTS_ELEMENTS 5 +#define PROP_MOTIF_WM_HINTS_ELEMENTS 5 struct _PropMotifWmHints { @@ -107,19 +110,18 @@ typedef struct _PropMotifWmHints PropMotifWmHints; static void xf_SetWindowTitleText(xfContext* xfc, Window window, const char* name) { - const size_t i = strlen(name); + const size_t i = strnlen(name, MAX_PATH); XStoreName(xfc->display, window, name); Atom wm_Name = xfc->_NET_WM_NAME; Atom utf8Str = xfc->UTF8_STRING; - XChangeProperty(xfc->display, window, wm_Name, utf8Str, 8, - PropModeReplace, (const unsigned char*)name, (int)i); + XChangeProperty(xfc->display, window, wm_Name, utf8Str, 8, PropModeReplace, + (const unsigned char*)name, (int)i); } /** * Post an event from the client to the X server */ -void xf_SendClientEvent(xfContext* xfc, Window window, Atom atom, - unsigned int numArgs, ...) +void xf_SendClientEvent(xfContext* xfc, Window window, Atom atom, unsigned int numArgs, ...) { XEvent xevent; unsigned int i; @@ -139,7 +141,7 @@ void xf_SendClientEvent(xfContext* xfc, Window window, Atom atom, xevent.xclient.data.l[i] = va_arg(argp, int); } - DEBUG_X11("Send ClientMessage Event: wnd=0x%04lX", (unsigned long) xevent.xclient.window); + DEBUG_X11("Send ClientMessage Event: wnd=0x%04lX", (unsigned long)xevent.xclient.window); XSendEvent(xfc->display, RootWindowOfScreen(xfc->screen), False, SubstructureRedirectMask | SubstructureNotifyMask, &xevent); XSync(xfc->display, False); @@ -158,14 +160,13 @@ void xf_SetWindowFullscreen(xfContext* xfc, xfWindow* window, BOOL fullscreen) int startX, startY; UINT32 width = window->width; UINT32 height = window->height; - /* xfc->decorations is set by caller depending on settings and whether it is fullscreen or not */ + /* xfc->decorations is set by caller depending on settings and whether it is fullscreen or not + */ window->decorations = xfc->decorations; /* 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) { @@ -206,7 +207,8 @@ void xf_SetWindowFullscreen(xfContext* xfc, xfWindow* window, BOOL fullscreen) } /* - It is safe to proceed with simply toogling _NET_WM_STATE_FULLSCREEN window state on the following conditions: + It is safe to proceed with simply toogling _NET_WM_STATE_FULLSCREEN window state on the + following conditions: - The window manager supports multiple monitor full screen - The user requested to use a single monitor to render the remote desktop */ @@ -235,11 +237,8 @@ void xf_SetWindowFullscreen(xfContext* xfc, xfWindow* window, BOOL fullscreen) if (settings->MonitorCount > 1) { xf_SendClientEvent(xfc, window->handle, xfc->_NET_WM_FULLSCREEN_MONITORS, 5, - xfc->fullscreenMonitors.top, - xfc->fullscreenMonitors.bottom, - xfc->fullscreenMonitors.left, - xfc->fullscreenMonitors.right, - 1); + xfc->fullscreenMonitors.top, xfc->fullscreenMonitors.bottom, + xfc->fullscreenMonitors.left, xfc->fullscreenMonitors.right, 1); } } else @@ -250,8 +249,7 @@ void xf_SetWindowFullscreen(xfContext* xfc, xfWindow* window, BOOL fullscreen) if (xfc->fullscreenMonitors.top) { - xf_SendClientEvent(xfc, window->handle, xfc->_NET_WM_STATE, 4, - _NET_WM_STATE_ADD, + xf_SendClientEvent(xfc, window->handle, xfc->_NET_WM_STATE, 4, _NET_WM_STATE_ADD, xfc->fullscreenMonitors.top, 0, 0); } else @@ -272,16 +270,17 @@ void xf_SetWindowFullscreen(xfContext* xfc, xfWindow* window, BOOL fullscreen) unsigned long bytes; BYTE* prop; - if (xf_GetWindowProperty(xfc, window->handle, xfc->_NET_WM_STATE, 255, &nitems, &bytes, &prop)) + if (xf_GetWindowProperty(xfc, window->handle, xfc->_NET_WM_STATE, 255, &nitems, + &bytes, &prop)) { state = 0; while (nitems-- > 0) { - if (((Atom*) prop)[nitems] == xfc->_NET_WM_STATE_MAXIMIZED_VERT) + if (((Atom*)prop)[nitems] == xfc->_NET_WM_STATE_MAXIMIZED_VERT) state |= 0x01; - if (((Atom*) prop)[nitems] == xfc->_NET_WM_STATE_MAXIMIZED_HORZ) + if (((Atom*)prop)[nitems] == xfc->_NET_WM_STATE_MAXIMIZED_HORZ) state |= 0x02; } @@ -314,24 +313,21 @@ void xf_SetWindowFullscreen(xfContext* xfc, xfWindow* window, BOOL fullscreen) if (xfc->fullscreenMonitors.top) { - xf_SendClientEvent(xfc, window->handle, xfc->_NET_WM_STATE, 4, - _NET_WM_STATE_REMOVE, + xf_SendClientEvent(xfc, window->handle, xfc->_NET_WM_STATE, 4, _NET_WM_STATE_REMOVE, xfc->fullscreenMonitors.top, 0, 0); } /* restore maximized state, if the window was maximized before setting fullscreen */ if (xfc->savedMaximizedState & 0x01) { - xf_SendClientEvent(xfc, window->handle, xfc->_NET_WM_STATE, 4, - _NET_WM_STATE_ADD, xfc->_NET_WM_STATE_MAXIMIZED_VERT, - 0, 0); + xf_SendClientEvent(xfc, window->handle, xfc->_NET_WM_STATE, 4, _NET_WM_STATE_ADD, + xfc->_NET_WM_STATE_MAXIMIZED_VERT, 0, 0); } if (xfc->savedMaximizedState & 0x02) { - xf_SendClientEvent(xfc, window->handle, xfc->_NET_WM_STATE, 4, - _NET_WM_STATE_ADD, xfc->_NET_WM_STATE_MAXIMIZED_HORZ, - 0, 0); + xf_SendClientEvent(xfc, window->handle, xfc->_NET_WM_STATE, 4, _NET_WM_STATE_ADD, + xfc->_NET_WM_STATE_MAXIMIZED_HORZ, 0, 0); } xfc->savedMaximizedState = 0; @@ -341,8 +337,7 @@ void xf_SetWindowFullscreen(xfContext* xfc, xfWindow* window, BOOL fullscreen) /* http://tronche.com/gui/x/xlib/window-information/XGetWindowProperty.html */ -BOOL xf_GetWindowProperty(xfContext* xfc, Window window, Atom property, - int length, +BOOL xf_GetWindowProperty(xfContext* xfc, Window window, Atom property, int length, unsigned long* nitems, unsigned long* bytes, BYTE** prop) { int status; @@ -352,8 +347,7 @@ BOOL xf_GetWindowProperty(xfContext* xfc, Window window, Atom property, if (property == None) return FALSE; - status = XGetWindowProperty(xfc->display, window, - property, 0, length, False, AnyPropertyType, + status = XGetWindowProperty(xfc->display, window, property, 0, length, False, AnyPropertyType, &actual_type, &actual_format, nitems, bytes, prop); if (status != Success) @@ -361,7 +355,7 @@ BOOL xf_GetWindowProperty(xfContext* xfc, Window window, Atom property, if (actual_type == None) { - WLog_INFO(TAG, "Property %lu does not exist", (unsigned long) property); + WLog_INFO(TAG, "Property %lu does not exist", (unsigned long)property); return FALSE; } @@ -374,13 +368,13 @@ BOOL xf_GetCurrentDesktop(xfContext* xfc) unsigned long nitems; unsigned long bytes; unsigned char* prop; - status = xf_GetWindowProperty(xfc, DefaultRootWindow(xfc->display), - xfc->_NET_CURRENT_DESKTOP, 1, &nitems, &bytes, &prop); + status = xf_GetWindowProperty(xfc, DefaultRootWindow(xfc->display), xfc->_NET_CURRENT_DESKTOP, + 1, &nitems, &bytes, &prop); if (!status) return FALSE; - xfc->current_desktop = (int) * prop; + xfc->current_desktop = (int)*prop; free(prop); return TRUE; } @@ -397,19 +391,19 @@ BOOL xf_GetWorkArea(xfContext* xfc) if (!status) return FALSE; - status = xf_GetWindowProperty(xfc, DefaultRootWindow(xfc->display), - xfc->_NET_WORKAREA, 32 * 4, &nitems, &bytes, &prop); + status = xf_GetWindowProperty(xfc, DefaultRootWindow(xfc->display), xfc->_NET_WORKAREA, 32 * 4, + &nitems, &bytes, &prop); if (!status) return FALSE; - if ((xfc->current_desktop * 4 + 3) >= nitems) + if ((xfc->current_desktop * 4 + 3) >= (INT64)nitems) { free(prop); return FALSE; } - plong = (long*) prop; + plong = (long*)prop; xfc->workArea.x = plong[xfc->current_desktop * 4 + 0]; xfc->workArea.y = plong[xfc->current_desktop * 4 + 1]; xfc->workArea.width = plong[xfc->current_desktop * 4 + 2]; @@ -422,13 +416,12 @@ void xf_SetWindowDecorations(xfContext* xfc, Window window, BOOL show) { PropMotifWmHints hints; hints.decorations = (show) ? MWM_DECOR_ALL : 0; - hints.functions = MWM_FUNC_ALL ; + hints.functions = MWM_FUNC_ALL; hints.flags = MWM_HINTS_DECORATIONS | MWM_HINTS_FUNCTIONS; hints.inputMode = 0; hints.status = 0; - XChangeProperty(xfc->display, window, xfc->_MOTIF_WM_HINTS, - xfc->_MOTIF_WM_HINTS, 32, - PropModeReplace, (BYTE*) &hints, PROP_MOTIF_WM_HINTS_ELEMENTS); + XChangeProperty(xfc->display, window, xfc->_MOTIF_WM_HINTS, xfc->_MOTIF_WM_HINTS, 32, + PropModeReplace, (BYTE*)&hints, PROP_MOTIF_WM_HINTS_ELEMENTS); } void xf_SetWindowUnlisted(xfContext* xfc, Window window) @@ -436,8 +429,8 @@ void xf_SetWindowUnlisted(xfContext* xfc, Window window) Atom window_state[2]; window_state[0] = xfc->_NET_WM_STATE_SKIP_PAGER; window_state[1] = xfc->_NET_WM_STATE_SKIP_TASKBAR; - XChangeProperty(xfc->display, window, xfc->_NET_WM_STATE, - XA_ATOM, 32, PropModeReplace, (BYTE*) &window_state, 2); + XChangeProperty(xfc->display, window, xfc->_NET_WM_STATE, XA_ATOM, 32, PropModeReplace, + (BYTE*)&window_state, 2); } static void xf_SetWindowPID(xfContext* xfc, Window window, pid_t pid) @@ -448,22 +441,20 @@ static void xf_SetWindowPID(xfContext* xfc, Window window, pid_t pid) pid = getpid(); am_wm_pid = xfc->_NET_WM_PID; - XChangeProperty(xfc->display, window, am_wm_pid, XA_CARDINAL, - 32, PropModeReplace, (BYTE*) &pid, 1); + XChangeProperty(xfc->display, window, am_wm_pid, XA_CARDINAL, 32, PropModeReplace, (BYTE*)&pid, + 1); } static const char* get_shm_id(void) { static char shm_id[64]; - sprintf_s(shm_id, sizeof(shm_id), "/com.freerdp.xfreerdp.tsmf_%016X", - GetCurrentProcessId()); + sprintf_s(shm_id, sizeof(shm_id), "/com.freerdp.xfreerdp.tsmf_%016X", GetCurrentProcessId()); return shm_id; } Window xf_CreateDummyWindow(xfContext* xfc) { - return XCreateSimpleWindow(xfc->display, DefaultRootWindow(xfc->display), - 0, 0, 1, 1, 0, 0, 0); + return XCreateSimpleWindow(xfc->display, DefaultRootWindow(xfc->display), 0, 0, 1, 1, 0, 0, 0); } void xf_DestroyDummyWindow(xfContext* xfc, Window window) @@ -472,8 +463,7 @@ void xf_DestroyDummyWindow(xfContext* xfc, Window window) XDestroyWindow(xfc->display, window); } -xfWindow* xf_CreateDesktopWindow(xfContext* xfc, char* name, int width, - int height) +xfWindow* xf_CreateDesktopWindow(xfContext* xfc, char* name, int width, int height) { XEvent xevent; int input_mask; @@ -481,25 +471,25 @@ xfWindow* xf_CreateDesktopWindow(xfContext* xfc, char* name, int width, Window parentWindow; XClassHint* classHints; rdpSettings* settings; - window = (xfWindow*) calloc(1, sizeof(xfWindow)); + window = (xfWindow*)calloc(1, sizeof(xfWindow)); if (!window) return NULL; settings = xfc->context.settings; - parentWindow = (Window) xfc->context.settings->ParentWindowId; + parentWindow = (Window)xfc->context.settings->ParentWindowId; window->width = width; window->height = height; window->decorations = xfc->decorations; window->is_mapped = FALSE; window->is_transient = FALSE; - window->handle = XCreateWindow(xfc->display, RootWindowOfScreen(xfc->screen), - xfc->workArea.x, xfc->workArea.y, xfc->workArea.width, xfc->workArea.height, - 0, xfc->depth, InputOutput, xfc->visual, + window->handle = XCreateWindow(xfc->display, RootWindowOfScreen(xfc->screen), xfc->workArea.x, + xfc->workArea.y, xfc->workArea.width, xfc->workArea.height, 0, + xfc->depth, InputOutput, xfc->visual, CWBackPixel | CWBackingStore | CWOverrideRedirect | CWColormap | - CWBorderPixel | CWWinGravity | CWBitGravity, &xfc->attribs); - window->shmid = shm_open(get_shm_id(), (O_CREAT | O_RDWR), - (S_IREAD | S_IWRITE)); + CWBorderPixel | CWWinGravity | CWBitGravity, + &xfc->attribs); + window->shmid = shm_open(get_shm_id(), (O_CREAT | O_RDWR), (S_IREAD | S_IWRITE)); if (window->shmid < 0) { @@ -509,12 +499,12 @@ xfWindow* xf_CreateDesktopWindow(xfContext* xfc, char* name, int width, { void* mem; ftruncate(window->shmid, sizeof(window->handle)); - mem = mmap(0, sizeof(window->handle), PROT_READ | PROT_WRITE, MAP_SHARED, - window->shmid, 0); + mem = mmap(0, sizeof(window->handle), PROT_READ | PROT_WRITE, MAP_SHARED, window->shmid, 0); if (mem == MAP_FAILED) { - DEBUG_X11("xf_CreateDesktopWindow: failed to assign pointer to the memory address - shmat()\n"); + DEBUG_X11("xf_CreateDesktopWindow: failed to assign pointer to the memory address - " + "shmat()\n"); } else { @@ -541,17 +531,15 @@ xfWindow* xf_CreateDesktopWindow(xfContext* xfc, char* name, int width, xf_ResizeDesktopWindow(xfc, window, width, height); xf_SetWindowDecorations(xfc, window->handle, window->decorations); xf_SetWindowPID(xfc, window->handle, 0); - input_mask = - KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | - VisibilityChangeMask | FocusChangeMask | StructureNotifyMask | - PointerMotionMask | ExposureMask | PropertyChangeMask; + input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | + VisibilityChangeMask | FocusChangeMask | StructureNotifyMask | PointerMotionMask | + ExposureMask | PropertyChangeMask; if (xfc->grab_keyboard) input_mask |= EnterWindowMask | LeaveWindowMask; - XChangeProperty(xfc->display, window->handle, xfc->_NET_WM_ICON, XA_CARDINAL, - 32, - PropModeReplace, (BYTE*) xf_icon_prop, ARRAYSIZE(xf_icon_prop)); + XChangeProperty(xfc->display, window->handle, xfc->_NET_WM_ICON, XA_CARDINAL, 32, + PropModeReplace, (BYTE*)xf_icon_prop, ARRAYSIZE(xf_icon_prop)); if (parentWindow) XReparentWindow(xfc->display, window->handle, parentWindow, 0, 0); @@ -569,8 +557,7 @@ xfWindow* xf_CreateDesktopWindow(xfContext* xfc, char* name, int width, do { XMaskEvent(xfc->display, VisibilityChangeMask, &xevent); - } - while (xevent.type != VisibilityNotify); + } while (xevent.type != VisibilityNotify); /* * The XCreateWindow call will start the window in the upper-left corner of our current @@ -583,16 +570,14 @@ xfWindow* xf_CreateDesktopWindow(xfContext* xfc, char* name, int width, } else if (settings->DesktopPosX != UINT32_MAX && settings->DesktopPosY != UINT32_MAX) { - XMoveWindow(xfc->display, window->handle, settings->DesktopPosX, - settings->DesktopPosY); + XMoveWindow(xfc->display, window->handle, settings->DesktopPosX, settings->DesktopPosY); } - window->floatbar = xf_floatbar_new(xfc, window->handle); + window->floatbar = xf_floatbar_new(xfc, window->handle, name, settings->Floatbar); return window; } -void xf_ResizeDesktopWindow(xfContext* xfc, xfWindow* window, int width, - int height) +void xf_ResizeDesktopWindow(xfContext* xfc, xfWindow* window, int width, int height) { XSizeHints* size_hints; rdpSettings* settings = NULL; @@ -636,8 +621,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); @@ -655,13 +639,12 @@ void xf_DestroyDesktopWindow(xfContext* xfc, xfWindow* window) close(window->shmid); shm_unlink(get_shm_id()); - window->xfwin = (Window*) - 1; + window->xfwin = (Window*)-1; window->shmid = -1; free(window); } -void xf_SetWindowStyle(xfContext* xfc, xfAppWindow* appWindow, UINT32 style, - UINT32 ex_style) +void xf_SetWindowStyle(xfContext* xfc, xfAppWindow* appWindow, UINT32 style, UINT32 ex_style) { Atom window_type; BOOL redirect = FALSE; @@ -674,8 +657,8 @@ void xf_SetWindowStyle(xfContext* xfc, xfAppWindow* appWindow, UINT32 style, window_type = xfc->_NET_WM_WINDOW_TYPE_DROPDOWN_MENU; } /* - * TOPMOST window that is not a tool window is treated like a regular window (i.e. task manager). - * Want to do this here, since the window may have type WS_POPUP + * TOPMOST window that is not a tool window is treated like a regular window (i.e. task + * manager). Want to do this here, since the window may have type WS_POPUP */ else if (ex_style & WS_EX_TOPMOST) { @@ -705,12 +688,11 @@ void xf_SetWindowStyle(xfContext* xfc, xfAppWindow* appWindow, UINT32 style, */ XSetWindowAttributes attrs; attrs.override_redirect = redirect ? True : False; - XChangeWindowAttributes(xfc->display, appWindow->handle, CWOverrideRedirect, - &attrs); + XChangeWindowAttributes(xfc->display, appWindow->handle, CWOverrideRedirect, &attrs); } - XChangeProperty(xfc->display, appWindow->handle, xfc->_NET_WM_WINDOW_TYPE, - XA_ATOM, 32, PropModeReplace, (BYTE*) &window_type, 1); + XChangeProperty(xfc->display, appWindow->handle, xfc->_NET_WM_WINDOW_TYPE, XA_ATOM, 32, + PropModeReplace, (BYTE*)&window_type, 1); } void xf_SetWindowText(xfContext* xfc, xfAppWindow* appWindow, const char* name) @@ -718,8 +700,7 @@ void xf_SetWindowText(xfContext* xfc, xfAppWindow* appWindow, const char* name) xf_SetWindowTitleText(xfc, appWindow->handle, name); } -static void xf_FixWindowCoordinates(xfContext* xfc, int* x, int* y, int* width, - int* height) +static void xf_FixWindowCoordinates(xfContext* xfc, int* x, int* y, int* width, int* height) { int vscreen_width; int vscreen_height; @@ -761,6 +742,23 @@ static void xf_FixWindowCoordinates(xfContext* xfc, int* x, int* y, int* width, int xf_AppWindowInit(xfContext* xfc, xfAppWindow* appWindow) { + if (!xfc || !appWindow) + return -1; + + xf_SetWindowDecorations(xfc, appWindow->handle, appWindow->decorations); + xf_SetWindowStyle(xfc, appWindow, appWindow->dwStyle, appWindow->dwExStyle); + xf_SetWindowPID(xfc, appWindow->handle, 0); + xf_ShowWindow(xfc, appWindow, WINDOW_SHOW); + XClearWindow(xfc->display, appWindow->handle); + XMapWindow(xfc->display, appWindow->handle); + /* Move doesn't seem to work until window is mapped. */ + xf_MoveWindow(xfc, appWindow, appWindow->x, appWindow->y, appWindow->width, appWindow->height); + xf_SetWindowText(xfc, appWindow, appWindow->title); + return 1; +} + +int xf_AppWindowCreate(xfContext* xfc, xfAppWindow* appWindow) +{ XGCValues gcv; int input_mask; XWMHints* InputModeHint; @@ -774,16 +772,15 @@ int xf_AppWindowInit(xfContext* xfc, xfAppWindow* appWindow) appWindow->is_transient = FALSE; appWindow->rail_state = 0; appWindow->rail_ignore_configure = FALSE; - appWindow->handle = XCreateWindow(xfc->display, RootWindowOfScreen(xfc->screen), - appWindow->x, appWindow->y, appWindow->width, appWindow->height, - 0, xfc->depth, InputOutput, xfc->visual, 0, &xfc->attribs); + appWindow->handle = XCreateWindow(xfc->display, RootWindowOfScreen(xfc->screen), appWindow->x, + appWindow->y, appWindow->width, appWindow->height, 0, + xfc->depth, InputOutput, xfc->visual, 0, &xfc->attribs); if (!appWindow->handle) return -1; ZeroMemory(&gcv, sizeof(gcv)); - appWindow->gc = XCreateGC(xfc->display, appWindow->handle, GCGraphicsExposures, - &gcv); + appWindow->gc = XCreateGC(xfc->display, appWindow->handle, GCGraphicsExposures, &gcv); class_hints = XAllocClassHint(); if (class_hints) @@ -797,7 +794,7 @@ int xf_AppWindowInit(xfContext* xfc, xfAppWindow* appWindow) else { class = malloc(sizeof("RAIL:00000000")); - sprintf_s(class, sizeof("RAIL:00000000"), "RAIL:%08"PRIX32"", appWindow->windowId); + sprintf_s(class, sizeof("RAIL:00000000"), "RAIL:%08" PRIX64 "", appWindow->windowId); class_hints->res_class = class; } @@ -814,31 +811,20 @@ int xf_AppWindowInit(xfContext* xfc, xfAppWindow* appWindow) XSetWMHints(xfc->display, appWindow->handle, InputModeHint); XFree(InputModeHint); XSetWMProtocols(xfc->display, appWindow->handle, &(xfc->WM_DELETE_WINDOW), 1); - input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | - ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | - PointerMotionMask | Button1MotionMask | Button2MotionMask | - Button3MotionMask | Button4MotionMask | Button5MotionMask | - ButtonMotionMask | KeymapStateMask | ExposureMask | - VisibilityChangeMask | StructureNotifyMask | SubstructureNotifyMask | - SubstructureRedirectMask | FocusChangeMask | PropertyChangeMask | - ColormapChangeMask | OwnerGrabButtonMask; + input_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | + EnterWindowMask | LeaveWindowMask | PointerMotionMask | Button1MotionMask | + Button2MotionMask | Button3MotionMask | Button4MotionMask | Button5MotionMask | + ButtonMotionMask | KeymapStateMask | ExposureMask | VisibilityChangeMask | + StructureNotifyMask | SubstructureNotifyMask | SubstructureRedirectMask | + FocusChangeMask | PropertyChangeMask | ColormapChangeMask | OwnerGrabButtonMask; XSelectInput(xfc->display, appWindow->handle, input_mask); - xf_SetWindowDecorations(xfc, appWindow->handle, appWindow->decorations); - xf_SetWindowStyle(xfc, appWindow, appWindow->dwStyle, appWindow->dwExStyle); - xf_SetWindowPID(xfc, appWindow->handle, 0); - xf_ShowWindow(xfc, appWindow, WINDOW_SHOW); - XClearWindow(xfc->display, appWindow->handle); - XMapWindow(xfc->display, appWindow->handle); - /* Move doesn't seem to work until window is mapped. */ - xf_MoveWindow(xfc, appWindow, appWindow->x, appWindow->y, appWindow->width, - appWindow->height); - xf_SetWindowText(xfc, appWindow, appWindow->title); + return 1; } -void xf_SetWindowMinMaxInfo(xfContext* xfc, xfAppWindow* appWindow, - int maxWidth, int maxHeight, int maxPosX, int maxPosY, - int minTrackWidth, int minTrackHeight, int maxTrackWidth, int maxTrackHeight) +void xf_SetWindowMinMaxInfo(xfContext* xfc, xfAppWindow* appWindow, int maxWidth, int maxHeight, + int maxPosX, int maxPosY, int minTrackWidth, int minTrackHeight, + int maxTrackWidth, int maxTrackHeight) { XSizeHints* size_hints; size_hints = XAllocSizeHints(); @@ -846,9 +832,9 @@ void xf_SetWindowMinMaxInfo(xfContext* xfc, xfAppWindow* appWindow, if (size_hints) { size_hints->flags = PMinSize | PMaxSize | PResizeInc; - size_hints->min_width = minTrackWidth; + size_hints->min_width = minTrackWidth; size_hints->min_height = minTrackHeight; - size_hints->max_width = maxTrackWidth; + size_hints->max_width = maxTrackWidth; size_hints->max_height = maxTrackHeight; /* to speedup window drawing we need to select optimal value for sizing step. */ size_hints->width_inc = size_hints->height_inc = 1; @@ -857,29 +843,29 @@ void xf_SetWindowMinMaxInfo(xfContext* xfc, xfAppWindow* appWindow, } } -void xf_StartLocalMoveSize(xfContext* xfc, xfAppWindow* appWindow, - int direction, int x, int y) +void xf_StartLocalMoveSize(xfContext* xfc, xfAppWindow* appWindow, int direction, int x, int y) { if (appWindow->local_move.state != LMS_NOT_ACTIVE) return; /* - * Save original mouse location relative to root. This will be needed - * to end local move to RDP server and/or X server - */ + * Save original mouse location relative to root. This will be needed + * to end local move to RDP server and/or X server + */ appWindow->local_move.root_x = x; appWindow->local_move.root_y = y; appWindow->local_move.state = LMS_STARTING; appWindow->local_move.direction = direction; XUngrabPointer(xfc->display, CurrentTime); - xf_SendClientEvent(xfc, appWindow->handle, - xfc->_NET_WM_MOVERESIZE, /* request X window manager to initiate a local move */ - 5, /* 5 arguments to follow */ - x, /* x relative to root window */ - y, /* y relative to root window */ - direction, /* extended ICCM direction flag */ - 1, /* simulated mouse button 1 */ - 1); /* 1 == application request per extended ICCM */ + xf_SendClientEvent( + xfc, appWindow->handle, + xfc->_NET_WM_MOVERESIZE, /* request X window manager to initiate a local move */ + 5, /* 5 arguments to follow */ + x, /* x relative to root window */ + y, /* y relative to root window */ + direction, /* extended ICCM direction flag */ + 1, /* simulated mouse button 1 */ + 1); /* 1 == application request per extended ICCM */ } void xf_EndLocalMoveSize(xfContext* xfc, xfAppWindow* appWindow) @@ -895,21 +881,21 @@ void xf_EndLocalMoveSize(xfContext* xfc, xfAppWindow* appWindow) * RDP server for local moves. We must cancel the X window manager move. * Per ICCM, the X client can ask to cancel an active move. */ - xf_SendClientEvent(xfc, appWindow->handle, - xfc->_NET_WM_MOVERESIZE, /* request X window manager to abort a local move */ - 5, /* 5 arguments to follow */ - appWindow->local_move.root_x, /* x relative to root window */ - appWindow->local_move.root_y, /* y relative to root window */ - _NET_WM_MOVERESIZE_CANCEL, /* extended ICCM direction flag */ - 1, /* simulated mouse button 1 */ - 1); /* 1 == application request per extended ICCM */ + xf_SendClientEvent( + xfc, appWindow->handle, + xfc->_NET_WM_MOVERESIZE, /* request X window manager to abort a local move */ + 5, /* 5 arguments to follow */ + appWindow->local_move.root_x, /* x relative to root window */ + appWindow->local_move.root_y, /* y relative to root window */ + _NET_WM_MOVERESIZE_CANCEL, /* extended ICCM direction flag */ + 1, /* simulated mouse button 1 */ + 1); /* 1 == application request per extended ICCM */ } appWindow->local_move.state = LMS_NOT_ACTIVE; } -void xf_MoveWindow(xfContext* xfc, xfAppWindow* appWindow, int x, int y, - int width, int height) +void xf_MoveWindow(xfContext* xfc, xfAppWindow* appWindow, int x, int y, int width, int height) { BOOL resize = FALSE; @@ -919,8 +905,7 @@ void xf_MoveWindow(xfContext* xfc, xfAppWindow* appWindow, int x, int y, if ((appWindow->width != width) || (appWindow->height != height)) resize = TRUE; - if (appWindow->local_move.state == LMS_STARTING || - appWindow->local_move.state == LMS_ACTIVE) + if (appWindow->local_move.state == LMS_STARTING || appWindow->local_move.state == LMS_ACTIVE) return; appWindow->x = x; @@ -950,16 +935,17 @@ void xf_ShowWindow(xfContext* xfc, xfAppWindow* appWindow, BYTE state) case WINDOW_SHOW_MAXIMIZED: /* Set the window as maximized */ - xf_SendClientEvent(xfc, appWindow->handle, xfc->_NET_WM_STATE, 4, - _NET_WM_STATE_ADD, - xfc->_NET_WM_STATE_MAXIMIZED_VERT, - xfc->_NET_WM_STATE_MAXIMIZED_HORZ, 0); + xf_SendClientEvent(xfc, appWindow->handle, xfc->_NET_WM_STATE, 4, _NET_WM_STATE_ADD, + xfc->_NET_WM_STATE_MAXIMIZED_VERT, xfc->_NET_WM_STATE_MAXIMIZED_HORZ, + 0); /* - * This is a workaround for the case where the window is maximized locally before the rail server is told to maximize - * the window, this appears to be a race condition where the local window with incomplete data and once the window is - * actually maximized on the server - an update of the new areas may not happen. So, we simply to do a full update of - * the entire window once the rail server notifies us that the window is now maximized. + * This is a workaround for the case where the window is maximized locally before the + * rail server is told to maximize the window, this appears to be a race condition where + * the local window with incomplete data and once the window is actually maximized on + * the server + * - an update of the new areas may not happen. So, we simply to do a full update of the + * entire window once the rail server notifies us that the window is now maximized. */ if (appWindow->rail_state == WINDOW_SHOW_MAXIMIZED) { @@ -971,16 +957,15 @@ void xf_ShowWindow(xfContext* xfc, xfAppWindow* appWindow, BYTE state) case WINDOW_SHOW: /* Ensure the window is not maximized */ - xf_SendClientEvent(xfc, appWindow->handle, xfc->_NET_WM_STATE, 4, - _NET_WM_STATE_REMOVE, - xfc->_NET_WM_STATE_MAXIMIZED_VERT, - xfc->_NET_WM_STATE_MAXIMIZED_HORZ, 0); + xf_SendClientEvent(xfc, appWindow->handle, xfc->_NET_WM_STATE, 4, _NET_WM_STATE_REMOVE, + xfc->_NET_WM_STATE_MAXIMIZED_VERT, xfc->_NET_WM_STATE_MAXIMIZED_HORZ, + 0); /* * Ignore configure requests until both the Maximized properties have been processed - * to prevent condition where WM overrides size of request due to one or both of these properties - * still being set - which causes a position adjustment to be sent back to the server - * thus causing the window to not return to its original size + * to prevent condition where WM overrides size of request due to one or both of these + * properties still being set - which causes a position adjustment to be sent back to + * the server thus causing the window to not return to its original size */ if (appWindow->rail_state == WINDOW_SHOW_MAXIMIZED) appWindow->rail_ignore_configure = TRUE; @@ -988,6 +973,7 @@ void xf_ShowWindow(xfContext* xfc, xfAppWindow* appWindow, BYTE state) if (appWindow->is_transient) xf_SetWindowUnlisted(xfc, appWindow->handle); + XMapWindow(xfc->display, appWindow->handle); break; } @@ -996,8 +982,7 @@ void xf_ShowWindow(xfContext* xfc, xfAppWindow* appWindow, BYTE state) XFlush(xfc->display); } -void xf_SetWindowRects(xfContext* xfc, xfAppWindow* appWindow, - RECTANGLE_16* rects, int nrects) +void xf_SetWindowRects(xfContext* xfc, xfAppWindow* appWindow, RECTANGLE_16* rects, int nrects) { int i; XRectangle* xrects; @@ -1006,7 +991,7 @@ void xf_SetWindowRects(xfContext* xfc, xfAppWindow* appWindow, return; #ifdef WITH_XEXT - xrects = (XRectangle*) calloc(nrects, sizeof(XRectangle)); + xrects = (XRectangle*)calloc(nrects, sizeof(XRectangle)); for (i = 0; i < nrects; i++) { @@ -1016,14 +1001,14 @@ void xf_SetWindowRects(xfContext* xfc, xfAppWindow* appWindow, xrects[i].height = rects[i].bottom - rects[i].top; } - XShapeCombineRectangles(xfc->display, appWindow->handle, ShapeBounding, 0, 0, - xrects, nrects, ShapeSet, 0); + XShapeCombineRectangles(xfc->display, appWindow->handle, ShapeBounding, 0, 0, xrects, nrects, + ShapeSet, 0); free(xrects); #endif } -void xf_SetWindowVisibilityRects(xfContext* xfc, xfAppWindow* appWindow, - UINT32 rectsOffsetX, UINT32 rectsOffsetY, RECTANGLE_16* rects, int nrects) +void xf_SetWindowVisibilityRects(xfContext* xfc, xfAppWindow* appWindow, UINT32 rectsOffsetX, + UINT32 rectsOffsetY, RECTANGLE_16* rects, int nrects) { int i; XRectangle* xrects; @@ -1032,7 +1017,7 @@ void xf_SetWindowVisibilityRects(xfContext* xfc, xfAppWindow* appWindow, return; #ifdef WITH_XEXT - xrects = (XRectangle*) calloc(nrects, sizeof(XRectangle)); + xrects = (XRectangle*)calloc(nrects, sizeof(XRectangle)); for (i = 0; i < nrects; i++) { @@ -1042,20 +1027,23 @@ void xf_SetWindowVisibilityRects(xfContext* xfc, xfAppWindow* appWindow, xrects[i].height = rects[i].bottom - rects[i].top; } - XShapeCombineRectangles(xfc->display, appWindow->handle, ShapeBounding, - rectsOffsetX, rectsOffsetY, xrects, nrects, ShapeSet, 0); + XShapeCombineRectangles(xfc->display, appWindow->handle, ShapeBounding, rectsOffsetX, + rectsOffsetY, xrects, nrects, ShapeSet, 0); free(xrects); #endif } -void xf_UpdateWindowArea(xfContext* xfc, xfAppWindow* appWindow, int x, int y, - int width, int height) +void xf_UpdateWindowArea(xfContext* xfc, xfAppWindow* appWindow, int x, int y, int width, + int height) { int ax, ay; if (appWindow == NULL) return; + if (appWindow->surfaceId < UINT16_MAX) + return; + ax = x + appWindow->windowOffsetX; ay = y + appWindow->windowOffsetY; @@ -1065,18 +1053,18 @@ void xf_UpdateWindowArea(xfContext* xfc, xfAppWindow* appWindow, int x, int y, if (ay + height > appWindow->windowOffsetY + appWindow->height) height = (appWindow->windowOffsetY + appWindow->height - 1) - ay; - xf_lock_x11(xfc, TRUE); + xf_lock_x11(xfc); if (xfc->context.settings->SoftwareGdi) { - XPutImage(xfc->display, xfc->primary, appWindow->gc, xfc->image, - ax, ay, ax, ay, width, height); + XPutImage(xfc->display, xfc->primary, appWindow->gc, xfc->image, ax, ay, ax, ay, width, + height); } - XCopyArea(xfc->display, xfc->primary, appWindow->handle, appWindow->gc, - ax, ay, width, height, x, y); + XCopyArea(xfc->display, xfc->primary, appWindow->handle, appWindow->gc, ax, ay, width, height, + x, y); XFlush(xfc->display); - xf_unlock_x11(xfc, TRUE); + xf_unlock_x11(xfc); } void xf_DestroyWindow(xfContext* xfc, xfAppWindow* appWindow) @@ -1100,7 +1088,7 @@ void xf_DestroyWindow(xfContext* xfc, xfAppWindow* appWindow) close(appWindow->shmid); shm_unlink(get_shm_id()); - appWindow->xfwin = (Window*) - 1; + appWindow->xfwin = (Window*)-1; appWindow->shmid = -1; free(appWindow->title); free(appWindow->windowRects); @@ -1118,8 +1106,10 @@ xfAppWindow* xf_AppWindowFromX11Window(xfContext* xfc, Window wnd) for (index = 0; index < count; index++) { - appWindow = (xfAppWindow*) HashTable_GetItemValue(xfc->railWindows, - (void*) pKeys[index]); + appWindow = xf_rail_get_window(xfc, *(UINT64*)pKeys[index]); + + if (!appWindow) + return NULL; if (appWindow->handle == wnd) { diff --git a/client/X11/xf_window.h b/client/X11/xf_window.h index b0ecb02..3adaa3c 100644 --- a/client/X11/xf_window.h +++ b/client/X11/xf_window.h @@ -34,21 +34,21 @@ typedef struct xf_window xfWindow; #include "xfreerdp.h" // Extended ICCM flags http://standards.freedesktop.org/wm-spec/wm-spec-latest.html -#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0 -#define _NET_WM_MOVERESIZE_SIZE_TOP 1 -#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2 -#define _NET_WM_MOVERESIZE_SIZE_RIGHT 3 -#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4 -#define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5 -#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6 -#define _NET_WM_MOVERESIZE_SIZE_LEFT 7 -#define _NET_WM_MOVERESIZE_MOVE 8 /* movement only */ -#define _NET_WM_MOVERESIZE_SIZE_KEYBOARD 9 /* size via keyboard */ -#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10 /* move via keyboard */ -#define _NET_WM_MOVERESIZE_CANCEL 11 /* cancel operation */ +#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0 +#define _NET_WM_MOVERESIZE_SIZE_TOP 1 +#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2 +#define _NET_WM_MOVERESIZE_SIZE_RIGHT 3 +#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4 +#define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5 +#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6 +#define _NET_WM_MOVERESIZE_SIZE_LEFT 7 +#define _NET_WM_MOVERESIZE_MOVE 8 /* movement only */ +#define _NET_WM_MOVERESIZE_SIZE_KEYBOARD 9 /* size via keyboard */ +#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10 /* move via keyboard */ +#define _NET_WM_MOVERESIZE_CANCEL 11 /* cancel operation */ #define _NET_WM_STATE_REMOVE 0 /* remove/unset property */ -#define _NET_WM_STATE_ADD 1 /* add/set property */ +#define _NET_WM_STATE_ADD 1 /* add/set property */ #define _NET_WM_STATE_TOGGLE 2 /* toggle property */ enum xf_localmove_state @@ -97,7 +97,8 @@ struct xf_app_window int height; char* title; - UINT32 windowId; + UINT32 surfaceId; + UINT64 windowId; UINT32 ownerWindowId; UINT32 dwStyle; @@ -160,11 +161,12 @@ BOOL xf_GetWindowProperty(xfContext* xfc, Window window, Atom property, int leng unsigned long* nitems, unsigned long* bytes, BYTE** prop); void xf_SendClientEvent(xfContext* xfc, Window window, Atom atom, unsigned int numArgs, ...); +int xf_AppWindowCreate(xfContext* xfc, xfAppWindow* appWindow); int xf_AppWindowInit(xfContext* xfc, xfAppWindow* appWindow); void xf_SetWindowText(xfContext* xfc, xfAppWindow* appWindow, const char* name); void xf_MoveWindow(xfContext* xfc, xfAppWindow* appWindow, int x, int y, int width, int height); void xf_ShowWindow(xfContext* xfc, xfAppWindow* appWindow, BYTE state); -//void xf_SetWindowIcon(xfContext* xfc, xfAppWindow* appWindow, rdpIcon* icon); +// void xf_SetWindowIcon(xfContext* xfc, xfAppWindow* appWindow, rdpIcon* icon); void xf_SetWindowRects(xfContext* xfc, xfAppWindow* appWindow, RECTANGLE_16* rects, int nrects); void xf_SetWindowVisibilityRects(xfContext* xfc, xfAppWindow* appWindow, UINT32 rectsOffsetX, UINT32 rectsOffsetY, RECTANGLE_16* rects, int nrects); @@ -172,9 +174,9 @@ void xf_SetWindowStyle(xfContext* xfc, xfAppWindow* appWindow, UINT32 style, UIN void xf_UpdateWindowArea(xfContext* xfc, xfAppWindow* appWindow, int x, int y, int width, int height); void xf_DestroyWindow(xfContext* xfc, xfAppWindow* appWindow); -void xf_SetWindowMinMaxInfo(xfContext* xfc, xfAppWindow* appWindow, - int maxWidth, int maxHeight, int maxPosX, int maxPosY, - int minTrackWidth, int minTrackHeight, int maxTrackWidth, int maxTrackHeight); +void xf_SetWindowMinMaxInfo(xfContext* xfc, xfAppWindow* appWindow, int maxWidth, int maxHeight, + int maxPosX, int maxPosY, int minTrackWidth, int minTrackHeight, + int maxTrackWidth, int maxTrackHeight); void xf_StartLocalMoveSize(xfContext* xfc, xfAppWindow* appWindow, int direction, int x, int y); void xf_EndLocalMoveSize(xfContext* xfc, xfAppWindow* appWindow); xfAppWindow* xf_AppWindowFromX11Window(xfContext* xfc, Window wnd); diff --git a/client/X11/xfreerdp.h b/client/X11/xfreerdp.h index 746ea33..8599d56 100644 --- a/client/X11/xfreerdp.h +++ b/client/X11/xfreerdp.h @@ -22,6 +22,10 @@ #ifndef FREERDP_CLIENT_X11_FREERDP_H #define FREERDP_CLIENT_X11_FREERDP_H +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + typedef struct xf_context xfContext; #include @@ -30,6 +34,10 @@ typedef struct xf_context xfContext; #include "xf_monitor.h" #include "xf_channels.h" +#if defined(CHANNEL_TSMF_CLIENT) +#include +#endif + #include #include #include @@ -85,13 +93,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 +170,6 @@ struct xf_context BOOL use_xinput; BOOL mouse_active; BOOL fullscreen_toggle; - BOOL floatbar; BOOL controlToggle; UINT32 KeyboardLayout; BOOL KeyboardState[256]; @@ -173,7 +181,9 @@ struct xf_context XSetWindowAttributes attribs; BOOL complex_regions; VIRTUAL_SCREEN vscreen; +#if defined(CHANNEL_TSMF_CLIENT) void* xv_context; +#endif Atom* supportedAtoms; unsigned long supportedAtomCount; @@ -216,7 +226,10 @@ struct xf_context Atom WM_DELETE_WINDOW; /* Channels */ +#if defined(CHANNEL_TSMF_CLIENT) TsmfClientContext* tsmf; +#endif + xfClipboard* clipboard; CliprdrClientContext* cliprdr; xfVideoContext* xfVideo; @@ -232,13 +245,14 @@ 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; + UINT32 locked; }; BOOL xf_create_window(xfContext* xfc); void xf_toggle_fullscreen(xfContext* xfc); -void xf_toggle_control(xfContext* xfc); +BOOL xf_toggle_control(xfContext* xfc); void xf_encomsp_init(xfContext* xfc, EncomspClientContext* encomsp); void xf_encomsp_uninit(xfContext* xfc, EncomspClientContext* encomsp); @@ -286,13 +300,19 @@ enum XF_EXIT_CODE XF_EXIT_UNKNOWN = 255, }; -void xf_lock_x11(xfContext* xfc, BOOL display); -void xf_unlock_x11(xfContext* xfc, BOOL display); +#define xf_lock_x11(xfc) xf_lock_x11_(xfc, __FUNCTION__); +#define xf_unlock_x11(xfc) xf_unlock_x11_(xfc, __FUNCTION__); + +void xf_lock_x11_(xfContext* xfc, const char* fkt); +void xf_unlock_x11_(xfContext* xfc, const char* fkt); BOOL xf_picture_transform_required(xfContext* xfc); -void xf_draw_screen(xfContext* xfc, int x, int y, int w, int h); + +#define xf_draw_screen(_xfc, _x, _y, _w, _h) \ + xf_draw_screen_((_xfc), (_x), (_y), (_w), (_h), __FUNCTION__, __FILE__, __LINE__) +void xf_draw_screen_(xfContext* xfc, int x, int y, int w, int h, const char* fkt, const char* file, + int line); FREERDP_API DWORD xf_exit_code_from_disconnect_reason(DWORD reason); #endif /* FREERDP_CLIENT_X11_FREERDP_H */ - diff --git a/client/common/CMakeLists.txt b/client/common/CMakeLists.txt index b6805e5..d4588e1 100644 --- a/client/common/CMakeLists.txt +++ b/client/common/CMakeLists.txt @@ -30,7 +30,8 @@ set(${MODULE_PREFIX}_SRCS cmdline.c compatibility.c compatibility.h - file.c) + file.c + geometry.c) foreach(FREERDP_CHANNELS_CLIENT_SRC ${FREERDP_CHANNELS_CLIENT_SRCS}) get_filename_component(NINC ${FREERDP_CHANNELS_CLIENT_SRC} PATH) diff --git a/client/common/client.c b/client/common/client.c index 06146a4..380d7de 100644 --- a/client/common/client.c +++ b/client/common/client.c @@ -68,8 +68,7 @@ rdpContext* freerdp_client_context_new(RDP_CLIENT_ENTRY_POINTS* pEntryPoints) instance->ContextSize = pEntryPoints->ContextSize; instance->ContextNew = freerdp_client_common_new; instance->ContextFree = freerdp_client_common_free; - instance->pClientEntryPoints = (RDP_CLIENT_ENTRY_POINTS*) malloc( - pEntryPoints->Size); + instance->pClientEntryPoints = (RDP_CLIENT_ENTRY_POINTS*)malloc(pEntryPoints->Size); if (!instance->pClientEntryPoints) goto out_fail; @@ -83,8 +82,8 @@ rdpContext* freerdp_client_context_new(RDP_CLIENT_ENTRY_POINTS* pEntryPoints) context->instance = instance; context->settings = instance->settings; - if (freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, - 0) != CHANNEL_RC_OK) + if (freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0) != + CHANNEL_RC_OK) goto out_fail2; return context; @@ -152,7 +151,7 @@ HANDLE freerdp_client_get_thread(rdpContext* context) if (!context) return NULL; - return ((rdpClientContext*) context)->thread; + return ((rdpClientContext*)context)->thread; } static BOOL freerdp_client_settings_post_process(rdpSettings* settings) @@ -212,9 +211,8 @@ out_error: return FALSE; } - -int freerdp_client_settings_parse_command_line(rdpSettings* settings, int argc, - char** argv, BOOL allowUnknown) +int freerdp_client_settings_parse_command_line(rdpSettings* settings, int argc, char** argv, + BOOL allowUnknown) { int status; @@ -224,8 +222,8 @@ int freerdp_client_settings_parse_command_line(rdpSettings* settings, int argc, if (!argv) return -1; - status = freerdp_client_settings_parse_command_line_arguments(settings, argc, - argv, allowUnknown); + status = + freerdp_client_settings_parse_command_line_arguments(settings, argc, argv, allowUnknown); if (status < 0) return status; @@ -235,11 +233,11 @@ int freerdp_client_settings_parse_command_line(rdpSettings* settings, int argc, if (!freerdp_client_settings_post_process(settings)) status = -1; + WLog_DBG(TAG, "This is %s", freerdp_get_build_config()); return status; } -int freerdp_client_settings_parse_connection_file(rdpSettings* settings, - const char* filename) +int freerdp_client_settings_parse_connection_file(rdpSettings* settings, const char* filename) { rdpFile* file; int ret = -1; @@ -260,8 +258,8 @@ out: return ret; } -int freerdp_client_settings_parse_connection_file_buffer(rdpSettings* settings, - const BYTE* buffer, size_t size) +int freerdp_client_settings_parse_connection_file_buffer(rdpSettings* settings, const BYTE* buffer, + size_t size) { rdpFile* file; int status = -1; @@ -270,8 +268,8 @@ int freerdp_client_settings_parse_connection_file_buffer(rdpSettings* settings, if (!file) return -1; - if (freerdp_client_parse_rdp_file_buffer(file, buffer, size) - && freerdp_client_populate_settings_from_rdp_file(file, settings)) + if (freerdp_client_parse_rdp_file_buffer(file, buffer, size) && + freerdp_client_populate_settings_from_rdp_file(file, settings)) { status = 0; } @@ -280,8 +278,8 @@ int freerdp_client_settings_parse_connection_file_buffer(rdpSettings* settings, return status; } -int freerdp_client_settings_write_connection_file(const rdpSettings* settings, - const char* filename, BOOL unicode) +int freerdp_client_settings_write_connection_file(const rdpSettings* settings, const char* filename, + BOOL unicode) { rdpFile* file; int ret = -1; @@ -302,25 +300,38 @@ out: return ret; } -int freerdp_client_settings_parse_assistance_file(rdpSettings* settings, - const char* filename) +int freerdp_client_settings_parse_assistance_file(rdpSettings* settings, 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; @@ -335,29 +346,19 @@ out: * @see rdp_server_accept_nego() and rdp_check_fds() * @param instance - pointer to the rdp_freerdp structure that contains the connection settings * @param username - unused - * @param password - on return: pointer to a character string that will be filled by the password entered by the user. - * Note that this character string will be allocated inside the function, and needs to be deallocated by the caller - * using free(), even in case this function fails. + * @param password - on return: pointer to a character string that will be filled by the password + * entered by the user. Note that this character string will be allocated inside the function, and + * needs to be deallocated by the caller using free(), even in case this function fails. * @param domain - unused - * @return TRUE if a password was successfully entered. See freerdp_passphrase_read() for more details. + * @return TRUE if a password was successfully entered. See freerdp_passphrase_read() for more + * details. */ -static BOOL client_cli_authenticate_raw(freerdp* instance, BOOL gateway, - char** username, +static BOOL client_cli_authenticate_raw(freerdp* instance, BOOL gateway, char** username, char** password, char** domain) { static const size_t password_size = 512; - const char* auth[] = - { - "Username: ", - "Domain: ", - "Password: " - }; - const char* gw[] = - { - "GatewayUsername: ", - "GatewayDomain: ", - "GatewayPassword: " - }; + const char* auth[] = { "Username: ", "Domain: ", "Password: " }; + const char* gw[] = { "GatewayUsername: ", "GatewayDomain: ", "GatewayPassword: " }; const char** prompt = (gateway) ? gw : auth; if (!username || !password || !domain) @@ -422,8 +423,7 @@ fail: return FALSE; } -BOOL client_cli_authenticate(freerdp* instance, char** username, - char** password, char** domain) +BOOL client_cli_authenticate(freerdp* instance, char** username, char** password, char** domain) { if (instance->settings->SmartcardLogon) { @@ -434,8 +434,7 @@ BOOL client_cli_authenticate(freerdp* instance, char** username, return client_cli_authenticate_raw(instance, FALSE, username, password, domain); } -BOOL client_cli_gw_authenticate(freerdp* instance, char** username, - char** password, char** domain) +BOOL client_cli_gw_authenticate(freerdp* instance, char** username, char** password, char** domain) { return client_cli_authenticate_raw(instance, TRUE, username, password, domain); } @@ -468,14 +467,17 @@ static DWORD client_cli_accept_certificate(rdpSettings* settings) { case 'y': case 'Y': + fgetc(stdin); return 1; case 't': case 'T': + fgetc(stdin); return 2; case 'n': case 'N': + fgetc(stdin); return 0; default: @@ -492,6 +494,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 @@ -500,10 +503,13 @@ static DWORD client_cli_accept_certificate(rdpSettings* settings) * @param host_mismatch Indicates the certificate host does not match. * @return 1 if the certificate is trusted, 2 if temporary trusted, 0 otherwise. */ -DWORD client_cli_verify_certificate(freerdp* instance, const char* common_name, - const char* subject, const char* issuer, - const char* fingerprint, BOOL host_mismatch) +DWORD client_cli_verify_certificate(freerdp* instance, const char* common_name, const char* subject, + const char* issuer, const char* fingerprint, BOOL host_mismatch) { + WINPR_UNUSED(common_name); + WINPR_UNUSED(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); @@ -515,9 +521,49 @@ DWORD client_cli_verify_certificate(freerdp* instance, const char* common_name, } /** 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 @@ -528,13 +574,15 @@ DWORD client_cli_verify_certificate(freerdp* instance, const char* common_name, * @param old_fingerprint * @return 1 if the certificate is trusted, 2 if temporary trusted, 0 otherwise. */ -DWORD client_cli_verify_changed_certificate(freerdp* instance, - 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 client_cli_verify_changed_certificate(freerdp* instance, 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) { + WINPR_UNUSED(common_name); + + 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"); @@ -547,7 +595,69 @@ DWORD client_cli_verify_changed_certificate(freerdp* instance, 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" + 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); +} + +/** 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"); + if (flags & VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1) + { + printf("\tA matching entry with legacy SHA1 was found in local known_hosts2 store.\n"); + printf("\tIf you just upgraded from a FreeRDP version before 2.0 this is expected.\n"); + printf("\tThe hashing algorithm has been upgraded from SHA1 to SHA256.\n"); + printf("\tAll manually accepted certificates must be reconfirmed!\n"); + 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); @@ -558,7 +668,7 @@ BOOL client_auto_reconnect(freerdp* instance) return client_auto_reconnect_ex(instance, NULL); } -BOOL client_auto_reconnect_ex(freerdp* instance, BOOL(*window_events)(freerdp* instance)) +BOOL client_auto_reconnect_ex(freerdp* instance, BOOL (*window_events)(freerdp* instance)) { UINT32 maxRetries; UINT32 numRetries = 0; @@ -595,7 +705,7 @@ BOOL client_auto_reconnect_ex(freerdp* instance, BOOL(*window_events)(freerdp* i } /* Attempt the next reconnect */ - WLog_INFO(TAG, "Attempting reconnect (%"PRIu32" of %"PRIu32")", numRetries, maxRetries); + WLog_INFO(TAG, "Attempting reconnect (%" PRIu32 " of %" PRIu32 ")", numRetries, maxRetries); if (freerdp_reconnect(instance)) return TRUE; @@ -612,5 +722,3 @@ BOOL client_auto_reconnect_ex(freerdp* instance, BOOL(*window_events)(freerdp* i WLog_ERR(TAG, "Maximum reconnect retries exceeded"); return FALSE; } - - diff --git a/client/common/cmdline.c b/client/common/cmdline.c index 103b4d2..bad6619 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -36,8 +36,8 @@ #include #include #include - #include +#include #include #include @@ -48,6 +48,135 @@ #include #define TAG CLIENT_TAG("common.cmdline") +static BOOL freerdp_client_print_codepages(const char* arg) +{ + size_t count = 0, x; + DWORD column = 2; + const char* filter = NULL; + char buffer[80]; + RDP_CODEPAGE* pages; + + if (arg) + filter = strchr(arg, ',') + 1; + pages = freerdp_keyboard_get_matching_codepages(column, filter, &count); + if (!pages) + return TRUE; + + printf("%-10s %-8s %-60s %-36s %-48s\n", "", "", "", "", + ""); + for (x = 0; x < count; x++) + { + const RDP_CODEPAGE* page = &pages[x]; + if (strnlen(page->subLanguageSymbol, ARRAYSIZE(page->subLanguageSymbol)) > 0) + _snprintf(buffer, sizeof(buffer), "[%s|%s]", page->primaryLanguageSymbol, + page->subLanguageSymbol); + else + _snprintf(buffer, sizeof(buffer), "[%s]", page->primaryLanguageSymbol); + printf("id=0x%04" PRIx16 ": [%-6s] %-60s %-36s %-48s\n", page->id, page->locale, buffer, + page->primaryLanguage, page->subLanguage); + } + freerdp_codepages_free(pages); + return TRUE; +} + +static BOOL freerdp_path_valid(const char* path, BOOL* special) +{ + const char DynamicDrives[] = "DynamicDrives"; + BOOL isPath = FALSE; + BOOL isSpecial; + if (!path) + return FALSE; + + isSpecial = (strncmp(path, "*", 2) == 0) || + (strncmp(path, DynamicDrives, sizeof(DynamicDrives)) == 0) || + (strncmp(path, "%", 2) == 0) + ? TRUE + : FALSE; + if (!isSpecial) + isPath = PathFileExistsA(path); + + if (special) + *special = isSpecial; + + return isSpecial || isPath; +} + +static BOOL freerdp_sanitize_drive_name(char* name, const char* invalid, const char* replacement) +{ + if (!name || !invalid || !replacement) + return FALSE; + if (strlen(invalid) != strlen(replacement)) + return FALSE; + + while (*invalid != '\0') + { + const char what = *invalid++; + const char with = *replacement++; + + char* cur = name; + while ((cur = strchr(cur, what)) != NULL) + *cur = with; + } + return TRUE; +} + +static BOOL freerdp_client_add_drive(rdpSettings* settings, const char* path, const char* name) +{ + RDPDR_DRIVE* drive; + + drive = (RDPDR_DRIVE*)calloc(1, sizeof(RDPDR_DRIVE)); + + if (!drive) + return FALSE; + + drive->Type = RDPDR_DTYP_FILESYSTEM; + + if (name) + { + /* Path was entered as secondary argument, swap */ + if (PathFileExistsA(name)) + { + if (!PathFileExistsA(path) || (!PathIsRelativeA(name) && PathIsRelativeA(path))) + { + const char* tmp = path; + path = name; + name = tmp; + } + } + } + + if (name) + { + if (!(drive->Name = _strdup(name))) + goto fail; + } + else /* We need a name to send to the server. */ + if (!(drive->Name = _strdup(path))) + goto fail; + + if (!path || !freerdp_sanitize_drive_name(drive->Name, "\\/", "__")) + goto fail; + else + { + BOOL isSpecial = FALSE; + BOOL isPath = freerdp_path_valid(path, &isSpecial); + + if ((!isPath && !isSpecial) || !(drive->Path = _strdup(path))) + goto fail; + } + + if (!freerdp_device_collection_add(settings, (RDPDR_DEVICE*)drive)) + goto fail; + + return TRUE; + +fail: + free(drive->Path); + free(drive->Name); + free(drive); + return FALSE; +} + static BOOL copy_value(const char* value, char** dst) { if (!dst || !value) @@ -58,10 +187,71 @@ static BOOL copy_value(const char* value, char** dst) return (*dst) != NULL; } +static BOOL append_value(const char* value, char** dst) +{ + size_t x = 0, y; + char* tmp; + if (!dst || !value) + return FALSE; + + if (*dst) + x = strlen(*dst); + y = strlen(value); + tmp = realloc(*dst, x + y + 2); + if (!tmp) + return FALSE; + if (x == 0) + tmp[0] = '\0'; + else + strcat(tmp, ","); + strcat(tmp, value); + *dst = tmp; + return TRUE; +} + +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, - GIT_REVISION); + printf("This is FreeRDP version %s (%s)\n", FREERDP_VERSION_FULL, GIT_REVISION); return TRUE; } @@ -71,6 +261,74 @@ BOOL freerdp_client_print_buildconfig(void) return TRUE; } +static char* print_token(char* text, size_t start_offset, size_t* current, size_t limit, + const char delimiter) +{ + int rc; + size_t len = strlen(text); + + if (*current < start_offset) + { + rc = printf("%*c", (int)(start_offset - *current), ' '); + if (rc < 0) + return NULL; + *current += (size_t)rc; + } + + if (*current + len > limit) + { + size_t x; + + for (x = MIN(len, limit - start_offset); x > 1; x--) + { + if (text[x] == delimiter) + { + printf("%.*s\n", (int)x, text); + *current = 0; + return &text[x]; + } + } + + return NULL; + } + + rc = printf("%s", text); + if (rc < 0) + return NULL; + *current += (size_t)rc; + return NULL; +} + +static size_t print_optionals(const char* text, size_t start_offset, size_t 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 size_t print_description(const char* text, size_t start_offset, size_t 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,48 +336,68 @@ 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 rc; + size_t pos = 0; + const size_t description_offset = 30 + 8; - if (arg->Format) - { - size_t length = (strlen(arg->Name) + strlen(arg->Format) + 2); - - if (arg->Flags & COMMAND_LINE_VALUE_OPTIONAL) - length += 2; + if (arg->Flags & COMMAND_LINE_VALUE_BOOL) + rc = printf(" %s%s", arg->Default ? "-" : "+", arg->Name); + else + rc = printf(" /%s", arg->Name); - if (length >= 20 + 8 + 8) - overlong = TRUE; + if (rc < 0) + return; + pos += (size_t)rc; + if ((arg->Flags & COMMAND_LINE_VALUE_REQUIRED) || + (arg->Flags & COMMAND_LINE_VALUE_OPTIONAL)) + { + if (arg->Format) + { if (arg->Flags & COMMAND_LINE_VALUE_OPTIONAL) - printf("%s[:%s]", arg->Name, overlong ? "..." : arg->Format); + { + rc = printf("[:"); + if (rc < 0) + return; + pos += (size_t)rc; + pos = print_optionals(arg->Format, pos, pos); + rc = printf("]"); + if (rc < 0) + return; + pos += (size_t)rc; + } else - printf("%s:%s", arg->Name, overlong ? "..." : arg->Format); - } - else - { - printf("%-20s", arg->Name); - } + { + rc = printf(":"); + if (rc < 0) + return; + pos += (size_t)rc; + pos = print_optionals(arg->Format, pos, pos); + } - printf("\t%s\n", arg->Text); + if (pos > description_offset) + { + printf("\n"); + pos = 0; + } + } } - else if (arg->Flags & COMMAND_LINE_VALUE_BOOL) + + rc = printf("%*c", (int)(description_offset - pos), ' '); + if (rc < 0) + return; + pos += (size_t)rc; + + 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); + rc = printf("%s ", arg->Default ? "Disable" : "Enable"); + if (rc < 0) + return; + pos += (size_t)rc; } - } - while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + + print_description(arg->Text, description_offset, pos); + } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); } BOOL freerdp_client_print_command_line_help(int argc, char** argv) @@ -128,8 +406,15 @@ 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) + COMMAND_LINE_ARGUMENT_A* custom) { + const char* name = "FreeRDP"; + COMMAND_LINE_ARGUMENT_A largs[ARRAYSIZE(args)]; + memcpy(largs, args, sizeof(args)); + + if (argc > 0) + name = argv[0]; + printf("\n"); printf("FreeRDP - A Free Remote Desktop Protocol Implementation\n"); printf("See www.freerdp.com for more information\n"); @@ -142,13 +427,15 @@ BOOL freerdp_client_print_command_line_help_ex(int argc, char** argv, printf(" +toggle -toggle (enables or disables toggle, where '/' is a synonym of '+')\n"); printf("\n"); freerdp_client_print_command_line_args(custom); - freerdp_client_print_command_line_args(args); + freerdp_client_print_command_line_args(largs); printf("\n"); printf("Examples:\n"); - printf(" xfreerdp connection.rdp /p:Pwd123! /f\n"); - printf(" xfreerdp /u:CONTOSO\\JohnDoe /p:Pwd123! /v:rdp.contoso.com\n"); - printf(" xfreerdp /u:JohnDoe /p:Pwd123! /w:1366 /h:768 /v:192.168.1.100:4489\n"); - printf(" xfreerdp /u:JohnDoe /p:Pwd123! /vmconnect:C824F53E-95D2-46C6-9A18-23A5BB403532 /v:192.168.1.100\n"); + printf(" %s connection.rdp /p:Pwd123! /f\n", name); + printf(" %s /u:CONTOSO\\JohnDoe /p:Pwd123! /v:rdp.contoso.com\n", name); + printf(" %s /u:JohnDoe /p:Pwd123! /w:1366 /h:768 /v:192.168.1.100:4489\n", name); + printf(" %s /u:JohnDoe /p:Pwd123! /vmconnect:C824F53E-95D2-46C6-9A18-23A5BB403532 " + "/v:192.168.1.100\n", + name); printf("\n"); printf("Clipboard Redirection: +clipboard\n"); printf("\n"); @@ -158,15 +445,17 @@ BOOL freerdp_client_print_command_line_help_ex(int argc, char** argv, printf("Serial Port Redirection: /serial:COM1,/dev/ttyS0\n"); printf("Parallel Port Redirection: /parallel:,\n"); printf("Printer Redirection: /printer:,\n"); + printf("TCP redirection: /rdp2tcp:/usr/bin/rdp2tcp\n"); printf("\n"); printf("Audio Output Redirection: /sound:sys:oss,dev:1,format:1\n"); printf("Audio Output Redirection: /sound:sys:alsa\n"); printf("Audio Input Redirection: /microphone:sys:oss,dev:1,format:1\n"); printf("Audio Input Redirection: /microphone:sys:alsa\n"); printf("\n"); - printf("Multimedia Redirection: /multimedia:sys:oss,dev:/dev/dsp1,decoder:ffmpeg\n"); - printf("Multimedia Redirection: /multimedia:sys:alsa\n"); - printf("USB Device Redirection: /usb:id,dev:054c:0268\n"); + printf("Multimedia Redirection: /video\n"); +#ifdef CHANNEL_URBDRC_CLIENT + printf("USB Device Redirection: /usb:id:054c:0268#4669:6e6b,addr:04:0c\n"); +#endif printf("\n"); printf("For Gateways, the https_proxy environment variable is respected:\n"); #ifdef _WIN32 @@ -174,27 +463,30 @@ BOOL freerdp_client_print_command_line_help_ex(int argc, char** argv, #else printf(" export https_proxy=http://proxy.contoso.com:3128/\n"); #endif - printf(" xfreerdp /g:rdp.contoso.com ...\n"); + printf(" %s /g:rdp.contoso.com ...\n", name); printf("\n"); printf("More documentation is coming, in the meantime consult source files\n"); printf("\n"); return TRUE; } -static int freerdp_client_command_line_pre_filter(void* context, int index, - int argc, LPSTR* argv) +static int freerdp_client_command_line_pre_filter(void* context, int index, int argc, LPSTR* argv) { if (index == 1) { size_t length; rdpSettings* settings; + + if (argc <= index) + return -1; + length = strlen(argv[index]); if (length > 4) { if (_stricmp(&(argv[index])[length - 4], ".rdp") == 0) { - settings = (rdpSettings*) context; + settings = (rdpSettings*)context; if (!copy_value(argv[index], &settings->ConnectionFile)) return COMMAND_LINE_ERROR_MEMORY; @@ -207,7 +499,7 @@ static int freerdp_client_command_line_pre_filter(void* context, int index, { if (_stricmp(&(argv[index])[length - 13], ".msrcIncident") == 0) { - settings = (rdpSettings*) context; + settings = (rdpSettings*)context; if (!copy_value(argv[index], &settings->AssistanceFile)) return COMMAND_LINE_ERROR_MEMORY; @@ -220,57 +512,21 @@ static int freerdp_client_command_line_pre_filter(void* context, int index, return 0; } - -BOOL freerdp_client_add_device_channel(rdpSettings* settings, int count, - char** params) +BOOL freerdp_client_add_device_channel(rdpSettings* settings, size_t count, char** params) { if (strcmp(params[0], "drive") == 0) { - RDPDR_DRIVE* drive; - - if (count < 3) + BOOL rc; + if (count < 2) return FALSE; settings->DeviceRedirection = TRUE; - drive = (RDPDR_DRIVE*) calloc(1, sizeof(RDPDR_DRIVE)); - - if (!drive) - return FALSE; - - drive->Type = RDPDR_DTYP_FILESYSTEM; - - if (count > 1) - { - if (!(drive->Name = _strdup(params[1]))) - { - free(drive); - return FALSE; - } - } - - if (count > 2) - { - const BOOL isPath = PathFileExistsA(params[2]); - const BOOL isSpecial = (strncmp(params[2], "*", 2) == 0) || - (strncmp(params[2], "%", 2) == 0) ? TRUE : FALSE; - - if ((!isPath && !isSpecial) || !(drive->Path = _strdup(params[2]))) - { - free(drive->Name); - free(drive); - return FALSE; - } - } - - if (!freerdp_device_collection_add(settings, (RDPDR_DEVICE*) drive)) - { - free(drive->Path); - free(drive->Name); - free(drive); - return FALSE; - } + if (count < 3) + rc = freerdp_client_add_drive(settings, params[1], NULL); + else + rc = freerdp_client_add_drive(settings, params[2], params[1]); - return TRUE; + return rc; } else if (strcmp(params[0], "printer") == 0) { @@ -284,20 +540,17 @@ BOOL freerdp_client_add_device_channel(rdpSettings* settings, int count, if (count > 1) { - printer = (RDPDR_PRINTER*) calloc(1, sizeof(RDPDR_PRINTER)); + printer = (RDPDR_PRINTER*)calloc(1, sizeof(RDPDR_PRINTER)); if (!printer) return FALSE; printer->Type = RDPDR_DTYP_PRINT; - if (count > 1) + if (!(printer->Name = _strdup(params[1]))) { - if (!(printer->Name = _strdup(params[1]))) - { - free(printer); - return FALSE; - } + free(printer); + return FALSE; } if (count > 2) @@ -310,7 +563,7 @@ BOOL freerdp_client_add_device_channel(rdpSettings* settings, int count, } } - if (!freerdp_device_collection_add(settings, (RDPDR_DEVICE*) printer)) + if (!freerdp_device_collection_add(settings, (RDPDR_DEVICE*)printer)) { free(printer->DriverName); free(printer->Name); @@ -330,7 +583,7 @@ BOOL freerdp_client_add_device_channel(rdpSettings* settings, int count, settings->RedirectSmartCards = TRUE; settings->DeviceRedirection = TRUE; - smartcard = (RDPDR_SMARTCARD*) calloc(1, sizeof(RDPDR_SMARTCARD)); + smartcard = (RDPDR_SMARTCARD*)calloc(1, sizeof(RDPDR_SMARTCARD)); if (!smartcard) return FALSE; @@ -346,7 +599,7 @@ BOOL freerdp_client_add_device_channel(rdpSettings* settings, int count, } } - if (!freerdp_device_collection_add(settings, (RDPDR_DEVICE*) smartcard)) + if (!freerdp_device_collection_add(settings, (RDPDR_DEVICE*)smartcard)) { free(smartcard->Name); free(smartcard); @@ -364,7 +617,7 @@ BOOL freerdp_client_add_device_channel(rdpSettings* settings, int count, settings->RedirectSerialPorts = TRUE; settings->DeviceRedirection = TRUE; - serial = (RDPDR_SERIAL*) calloc(1, sizeof(RDPDR_SERIAL)); + serial = (RDPDR_SERIAL*)calloc(1, sizeof(RDPDR_SERIAL)); if (!serial) return FALSE; @@ -413,7 +666,7 @@ BOOL freerdp_client_add_device_channel(rdpSettings* settings, int count, } } - if (!freerdp_device_collection_add(settings, (RDPDR_DEVICE*) serial)) + if (!freerdp_device_collection_add(settings, (RDPDR_DEVICE*)serial)) { free(serial->Permissive); free(serial->Driver); @@ -434,7 +687,7 @@ BOOL freerdp_client_add_device_channel(rdpSettings* settings, int count, settings->RedirectParallelPorts = TRUE; settings->DeviceRedirection = TRUE; - parallel = (RDPDR_PARALLEL*) calloc(1, sizeof(RDPDR_PARALLEL)); + parallel = (RDPDR_PARALLEL*)calloc(1, sizeof(RDPDR_PARALLEL)); if (!parallel) return FALSE; @@ -460,7 +713,7 @@ BOOL freerdp_client_add_device_channel(rdpSettings* settings, int count, } } - if (!freerdp_device_collection_add(settings, (RDPDR_DEVICE*) parallel)) + if (!freerdp_device_collection_add(settings, (RDPDR_DEVICE*)parallel)) { free(parallel->Path); free(parallel->Name); @@ -474,25 +727,24 @@ BOOL freerdp_client_add_device_channel(rdpSettings* settings, int count, return FALSE; } -BOOL freerdp_client_add_static_channel(rdpSettings* settings, int count, - char** params) +BOOL freerdp_client_add_static_channel(rdpSettings* settings, size_t count, char** params) { int index; ADDIN_ARGV* args; - if (!settings || !params || !params[0]) + if (!settings || !params || !params[0] || (count > INT_MAX)) return FALSE; if (freerdp_static_channel_collection_find(settings, params[0])) return TRUE; - args = (ADDIN_ARGV*) calloc(1, sizeof(ADDIN_ARGV)); + args = (ADDIN_ARGV*)calloc(1, sizeof(ADDIN_ARGV)); if (!args) return FALSE; - args->argc = count; - args->argv = (char**) calloc(args->argc, sizeof(char*)); + args->argc = (int)count; + args->argv = (char**)calloc((size_t)args->argc, sizeof(char*)); if (!args->argv) goto error_argv; @@ -526,25 +778,24 @@ error_argv: return FALSE; } -BOOL freerdp_client_add_dynamic_channel(rdpSettings* settings, int count, - char** params) +BOOL freerdp_client_add_dynamic_channel(rdpSettings* settings, size_t count, char** params) { int index; ADDIN_ARGV* args; - if (!settings || !params || !params[0]) + if (!settings || !params || !params[0] || (count > INT_MAX)) return FALSE; if (freerdp_dynamic_channel_collection_find(settings, params[0])) return TRUE; - args = (ADDIN_ARGV*) malloc(sizeof(ADDIN_ARGV)); + args = (ADDIN_ARGV*)malloc(sizeof(ADDIN_ARGV)); if (!args) return FALSE; - args->argc = count; - args->argv = (char**) calloc(args->argc, sizeof(char*)); + args->argc = (int)count; + args->argv = (char**)calloc((size_t)args->argc, sizeof(char*)); if (!args->argv) goto error_argv; @@ -578,108 +829,16 @@ error_argv: return FALSE; } -static char** freerdp_command_line_parse_comma_separated_values_ex(const char* name, - const char* list, - size_t* count) -{ - char** p; - char* str; - size_t nArgs; - size_t index; - size_t nCommas; - size_t prefix, len; - nCommas = 0; - assert(NULL != count); - *count = 0; - - if (!list) - { - if (name) - { - size_t len = strlen(name); - p = (char**) calloc(2UL + len, sizeof(char*)); - - if (p) - { - char* dst = (char*)&p[1]; - p[0] = dst; - sprintf_s(dst, len + 1, "%s", name); - *count = 1; - return p; - } - } - - return NULL; - } - - { - const char* it = list; - - while ((it = strchr(it, ',')) != NULL) - { - it++; - nCommas++; - } - } - - nArgs = nCommas + 1; - - if (name) - nArgs++; - - prefix = (nArgs + 1UL) * sizeof(char*); - len = strlen(list); - p = (char**) calloc(len + prefix + 1, sizeof(char*)); - - if (!p) - return NULL; - - str = &((char*)p)[prefix]; - memcpy(str, list, len); - - if (name) - p[0] = (char*)name; - - for (index = name ? 1 : 0; index < nArgs; index++) - { - char* comma = strchr(str, ','); - p[index] = str; - - if (comma) - { - str = comma + 1; - *comma = '\0'; - } - } - - *count = nArgs; - return p; -} - -static char** freerdp_command_line_parse_comma_separated_values(char* list, - size_t* count) -{ - return freerdp_command_line_parse_comma_separated_values_ex(NULL, list, count); -} - -static char** freerdp_command_line_parse_comma_separated_values_offset( - const char* name, char* list, size_t* count) -{ - return freerdp_command_line_parse_comma_separated_values_ex(name, list, count); -} - -static int freerdp_client_command_line_post_filter(void* context, - COMMAND_LINE_ARGUMENT_A* arg) +static int freerdp_client_command_line_post_filter(void* context, COMMAND_LINE_ARGUMENT_A* arg) { - rdpSettings* settings = (rdpSettings*) context; + rdpSettings* settings = (rdpSettings*)context; BOOL status = TRUE; BOOL enable = arg->Value ? TRUE : FALSE; - CommandLineSwitchStart(arg) - CommandLineSwitchCase(arg, "a") + CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "a") { char** p; size_t count; - p = freerdp_command_line_parse_comma_separated_values(arg->Value, &count); + p = CommandLineParseCommaSeparatedValues(arg->Value, &count); if ((status = freerdp_client_add_device_channel(settings, count, p))) { @@ -692,7 +851,7 @@ static int freerdp_client_command_line_post_filter(void* context, { char** p; size_t count; - p = freerdp_command_line_parse_comma_separated_values(arg->Value, &count); + p = CommandLineParseCommaSeparatedValues(arg->Value, &count); status = freerdp_client_add_static_channel(settings, count, p); free(p); } @@ -700,7 +859,7 @@ static int freerdp_client_command_line_post_filter(void* context, { char** p; size_t count; - p = freerdp_command_line_parse_comma_separated_values(arg->Value, &count); + p = CommandLineParseCommaSeparatedValues(arg->Value, &count); status = freerdp_client_add_dynamic_channel(settings, count, p); free(p); } @@ -708,8 +867,7 @@ static int freerdp_client_command_line_post_filter(void* context, { char** p; size_t count; - p = freerdp_command_line_parse_comma_separated_values_offset(arg->Name, arg->Value, - &count); + p = CommandLineParseCommaSeparatedValuesEx(arg->Name, arg->Value, &count); status = freerdp_client_add_device_channel(settings, count, p); free(p); } @@ -717,8 +875,7 @@ static int freerdp_client_command_line_post_filter(void* context, { char** p; size_t count; - p = freerdp_command_line_parse_comma_separated_values_offset(arg->Name, arg->Value, - &count); + p = CommandLineParseCommaSeparatedValuesEx(arg->Name, arg->Value, &count); status = freerdp_client_add_device_channel(settings, count, p); free(p); } @@ -726,8 +883,7 @@ static int freerdp_client_command_line_post_filter(void* context, { char** p; size_t count; - p = freerdp_command_line_parse_comma_separated_values_offset(arg->Name, arg->Value, - &count); + p = CommandLineParseCommaSeparatedValuesEx(arg->Name, arg->Value, &count); status = freerdp_client_add_device_channel(settings, count, p); free(p); } @@ -735,8 +891,7 @@ static int freerdp_client_command_line_post_filter(void* context, { char** p; size_t count; - p = freerdp_command_line_parse_comma_separated_values_offset(arg->Name, arg->Value, - &count); + p = CommandLineParseCommaSeparatedValuesEx(arg->Name, arg->Value, &count); status = freerdp_client_add_device_channel(settings, count, p); free(p); } @@ -744,8 +899,7 @@ static int freerdp_client_command_line_post_filter(void* context, { char** p; size_t count; - p = freerdp_command_line_parse_comma_separated_values_offset(arg->Name, arg->Value, - &count); + p = CommandLineParseCommaSeparatedValuesEx(arg->Name, arg->Value, &count); status = freerdp_client_add_device_channel(settings, count, p); free(p); } @@ -753,8 +907,7 @@ static int freerdp_client_command_line_post_filter(void* context, { char** p; size_t count; - p = freerdp_command_line_parse_comma_separated_values_offset("urbdrc", arg->Value, - &count); + p = CommandLineParseCommaSeparatedValuesEx(URBDRC_CHANNEL_NAME, arg->Value, &count); status = freerdp_client_add_dynamic_channel(settings, count, p); free(p); } @@ -791,29 +944,32 @@ static int freerdp_client_command_line_post_filter(void* context, { char** p; size_t count; - p = freerdp_command_line_parse_comma_separated_values_offset("rdpsnd", arg->Value, - &count); + p = CommandLineParseCommaSeparatedValuesEx("rdpsnd", arg->Value, &count); status = freerdp_client_add_static_channel(settings, count, p); + if (status) + { + status = freerdp_client_add_dynamic_channel(settings, count, p); + } free(p); } CommandLineSwitchCase(arg, "microphone") { char** p; size_t count; - p = freerdp_command_line_parse_comma_separated_values_offset("audin", arg->Value, - &count); + p = CommandLineParseCommaSeparatedValuesEx("audin", arg->Value, &count); status = freerdp_client_add_dynamic_channel(settings, count, p); free(p); } +#if defined(CHANNEL_TSMF_CLIENT) CommandLineSwitchCase(arg, "multimedia") { char** p; size_t count; - p = freerdp_command_line_parse_comma_separated_values_offset("tsmf", arg->Value, - &count); + p = CommandLineParseCommaSeparatedValuesEx("tsmf", arg->Value, &count); status = freerdp_client_add_dynamic_channel(settings, count, p); free(p); } +#endif CommandLineSwitchCase(arg, "heartbeat") { settings->SupportHeartbeatPdu = enable; @@ -823,8 +979,8 @@ static int freerdp_client_command_line_post_filter(void* context, settings->SupportMultitransport = enable; if (settings->SupportMultitransport) - settings->MultitransportFlags = (TRANSPORT_TYPE_UDP_FECR | - TRANSPORT_TYPE_UDP_FECL | TRANSPORT_TYPE_UDP_PREFERRED); + settings->MultitransportFlags = + (TRANSPORT_TYPE_UDP_FECR | TRANSPORT_TYPE_UDP_FECL | TRANSPORT_TYPE_UDP_PREFERRED); else settings->MultitransportFlags = 0; } @@ -832,27 +988,26 @@ static int freerdp_client_command_line_post_filter(void* context, { settings->PasswordIsSmartcardPin = enable; } - CommandLineSwitchEnd(arg) - return status ? 1 : -1; + CommandLineSwitchEnd(arg) return status ? 1 : -1; } 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) return FALSE; - *domain = (char*) calloc(length + 1UL, sizeof(char)); + *domain = (char*)calloc(length + 1UL, sizeof(char)); if (!*domain) { @@ -897,22 +1052,20 @@ 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)); + *host = (char*)calloc(length + 1UL, sizeof(char)); if (!(*host)) return FALSE; CopyMemory(*host, hostname, length); (*host)[length] = '\0'; - *port = val; + *port = (UINT16)val; } else { @@ -927,7 +1080,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; @@ -994,6 +1147,14 @@ BOOL freerdp_set_connection_type(rdpSettings* settings, int type) settings->DisableMenuAnims = FALSE; settings->DisableThemes = FALSE; settings->NetworkAutoDetect = TRUE; + + /* Automatically activate GFX and RFX codec support */ +#ifdef WITH_GFX_H264 + settings->GfxAVC444 = TRUE; + settings->GfxH264 = TRUE; +#endif + settings->RemoteFxCodec = TRUE; + settings->SupportGraphicsPipeline = TRUE; } else { @@ -1003,7 +1164,7 @@ BOOL freerdp_set_connection_type(rdpSettings* settings, int type) return TRUE; } -int freerdp_map_keyboard_layout_name_to_id(char* name) +static int freerdp_map_keyboard_layout_name_to_id(char* name) { int i; int id = 0; @@ -1016,7 +1177,7 @@ int freerdp_map_keyboard_layout_name_to_id(char* name) for (i = 0; layouts[i].code; i++) { if (_stricmp(layouts[i].name, name) == 0) - id = layouts[i].code; + id = (int)layouts[i].code; } freerdp_keyboard_layouts_free(layouts); @@ -1032,7 +1193,7 @@ int freerdp_map_keyboard_layout_name_to_id(char* name) for (i = 0; layouts[i].code; i++) { if (_stricmp(layouts[i].name, name) == 0) - id = layouts[i].code; + id = (int)layouts[i].code; } freerdp_keyboard_layouts_free(layouts); @@ -1048,7 +1209,7 @@ int freerdp_map_keyboard_layout_name_to_id(char* name) for (i = 0; layouts[i].code; i++) { if (_stricmp(layouts[i].name, name) == 0) - id = layouts[i].code; + id = (int)layouts[i].code; } freerdp_keyboard_layouts_free(layouts); @@ -1059,14 +1220,17 @@ int freerdp_map_keyboard_layout_name_to_id(char* name) return 0; } -static int freerdp_detect_command_line_pre_filter(void* context, int index, - int argc, LPSTR* argv) +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) { @@ -1088,14 +1252,17 @@ static int freerdp_detect_command_line_pre_filter(void* context, int index, return 0; } -static int freerdp_detect_windows_style_command_line_syntax(int argc, char** argv, - size_t* count, BOOL ignoreUnknown) +static int freerdp_detect_windows_style_command_line_syntax(int argc, char** argv, size_t* count, + BOOL ignoreUnknown) { int status; DWORD flags; int detect_status; COMMAND_LINE_ARGUMENT_A* arg; - flags = COMMAND_LINE_SEPARATOR_COLON; + COMMAND_LINE_ARGUMENT_A largs[ARRAYSIZE(args)]; + memcpy(largs, args, sizeof(args)); + + flags = COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_SILENCE_PARSER; flags |= COMMAND_LINE_SIGIL_SLASH | COMMAND_LINE_SIGIL_PLUS_MINUS; if (ignoreUnknown) @@ -1105,14 +1272,14 @@ static int freerdp_detect_windows_style_command_line_syntax(int argc, char** arg *count = 0; detect_status = 0; - CommandLineClearArgumentsA(args); - status = CommandLineParseArgumentsA(argc, argv, args, flags, - NULL, freerdp_detect_command_line_pre_filter, NULL); + CommandLineClearArgumentsA(largs); + status = CommandLineParseArgumentsA(argc, argv, largs, flags, NULL, + freerdp_detect_command_line_pre_filter, NULL); if (status < 0) return status; - arg = args; + arg = largs; do { @@ -1120,8 +1287,7 @@ static int freerdp_detect_windows_style_command_line_syntax(int argc, char** arg continue; (*count)++; - } - while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); if ((status <= COMMAND_LINE_ERROR) && (status >= COMMAND_LINE_ERROR_LAST)) detect_status = -1; @@ -1129,14 +1295,17 @@ static int freerdp_detect_windows_style_command_line_syntax(int argc, char** arg return detect_status; } -int freerdp_detect_posix_style_command_line_syntax(int argc, char** argv, - size_t* count, BOOL ignoreUnknown) +static int freerdp_detect_posix_style_command_line_syntax(int argc, char** argv, size_t* count, + BOOL ignoreUnknown) { int status; DWORD flags; int detect_status; COMMAND_LINE_ARGUMENT_A* arg; - flags = COMMAND_LINE_SEPARATOR_SPACE; + COMMAND_LINE_ARGUMENT_A largs[ARRAYSIZE(args)]; + memcpy(largs, args, sizeof(args)); + + flags = COMMAND_LINE_SEPARATOR_SPACE | COMMAND_LINE_SILENCE_PARSER; flags |= COMMAND_LINE_SIGIL_DASH | COMMAND_LINE_SIGIL_DOUBLE_DASH; flags |= COMMAND_LINE_SIGIL_ENABLE_DISABLE; @@ -1147,14 +1316,14 @@ int freerdp_detect_posix_style_command_line_syntax(int argc, char** argv, *count = 0; detect_status = 0; - CommandLineClearArgumentsA(args); - status = CommandLineParseArgumentsA(argc, argv, args, flags, - NULL, freerdp_detect_command_line_pre_filter, NULL); + CommandLineClearArgumentsA(largs); + status = CommandLineParseArgumentsA(argc, argv, largs, flags, NULL, + freerdp_detect_command_line_pre_filter, NULL); if (status < 0) return status; - arg = args; + arg = largs; do { @@ -1162,8 +1331,7 @@ int freerdp_detect_posix_style_command_line_syntax(int argc, char** argv, continue; (*count)++; - } - while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); if ((status <= COMMAND_LINE_ERROR) && (status >= COMMAND_LINE_ERROR_LAST)) detect_status = -1; @@ -1171,22 +1339,21 @@ int freerdp_detect_posix_style_command_line_syntax(int argc, char** argv, return detect_status; } -static BOOL freerdp_client_detect_command_line(int argc, char** argv, - DWORD* flags, BOOL ignoreUnknown) +static BOOL freerdp_client_detect_command_line(int argc, char** argv, DWORD* flags) { int old_cli_status; - int old_cli_count; + size_t old_cli_count; int posix_cli_status; size_t posix_cli_count; int windows_cli_status; size_t windows_cli_count; BOOL compatibility = FALSE; - windows_cli_status = freerdp_detect_windows_style_command_line_syntax(argc, - argv, &windows_cli_count, ignoreUnknown); - posix_cli_status = freerdp_detect_posix_style_command_line_syntax(argc, argv, - &posix_cli_count, ignoreUnknown); - old_cli_status = freerdp_detect_old_command_line_syntax(argc, argv, - &old_cli_count); + const BOOL ignoreUnknown = TRUE; + windows_cli_status = freerdp_detect_windows_style_command_line_syntax( + argc, argv, &windows_cli_count, ignoreUnknown); + posix_cli_status = + freerdp_detect_posix_style_command_line_syntax(argc, argv, &posix_cli_count, ignoreUnknown); + old_cli_status = freerdp_detect_old_command_line_syntax(argc, argv, &old_cli_count); /* Default is POSIX syntax */ *flags = COMMAND_LINE_SEPARATOR_SPACE; *flags |= COMMAND_LINE_SIGIL_DASH | COMMAND_LINE_SIGIL_DOUBLE_DASH; @@ -1196,8 +1363,8 @@ static BOOL freerdp_client_detect_command_line(int argc, char** argv, return compatibility; /* Check, if this may be windows style syntax... */ - if ((windows_cli_count && (windows_cli_count >= posix_cli_count)) - || (windows_cli_status <= COMMAND_LINE_STATUS_PRINT)) + if ((windows_cli_count && (windows_cli_count >= posix_cli_count)) || + (windows_cli_status <= COMMAND_LINE_STATUS_PRINT)) { windows_cli_count = 1; *flags = COMMAND_LINE_SEPARATOR_COLON; @@ -1206,8 +1373,7 @@ static BOOL freerdp_client_detect_command_line(int argc, char** argv, else if (old_cli_status >= 0) { /* Ignore legacy parsing in case there is an error in the command line. */ - if ((old_cli_status == 1) || ((old_cli_count > posix_cli_count) - && (old_cli_status != -1))) + if ((old_cli_status == 1) || ((old_cli_count > posix_cli_count) && (old_cli_status != -1))) { *flags = COMMAND_LINE_SEPARATOR_SPACE; *flags |= COMMAND_LINE_SIGIL_DASH | COMMAND_LINE_SIGIL_DOUBLE_DASH; @@ -1216,22 +1382,23 @@ static BOOL freerdp_client_detect_command_line(int argc, char** argv, } WLog_DBG(TAG, "windows: %d/%d posix: %d/%d compat: %d/%d", windows_cli_status, - windows_cli_count, - posix_cli_status, posix_cli_count, old_cli_status, old_cli_count); + windows_cli_count, posix_cli_status, posix_cli_count, old_cli_status, old_cli_count); return compatibility; } -int freerdp_client_settings_command_line_status_print(rdpSettings* settings, - int status, int argc, char** argv) +int freerdp_client_settings_command_line_status_print(rdpSettings* settings, int status, int argc, + char** argv) { - return freerdp_client_settings_command_line_status_print_ex( - settings, status, argc, argv, NULL); + return freerdp_client_settings_command_line_status_print_ex(settings, status, argc, argv, NULL); } -int freerdp_client_settings_command_line_status_print_ex(rdpSettings* settings, - int status, int argc, char** argv, COMMAND_LINE_ARGUMENT_A* custom) +int freerdp_client_settings_command_line_status_print_ex(rdpSettings* settings, int status, + int argc, char** argv, + COMMAND_LINE_ARGUMENT_A* custom) { COMMAND_LINE_ARGUMENT_A* arg; + COMMAND_LINE_ARGUMENT_A largs[ARRAYSIZE(args)]; + memcpy(largs, args, sizeof(args)); if (status == COMMAND_LINE_STATUS_PRINT_VERSION) { @@ -1247,40 +1414,51 @@ int freerdp_client_settings_command_line_status_print_ex(rdpSettings* settings, } else if (status == COMMAND_LINE_STATUS_PRINT) { - arg = CommandLineFindArgumentA(args, "kbd-list"); + COMMAND_LINE_ARGUMENT_A largs[ARRAYSIZE(args)]; + memcpy(largs, args, sizeof(largs)); + CommandLineParseArgumentsA(argc, argv, largs, 0x112, NULL, NULL, NULL); + + arg = CommandLineFindArgumentA(largs, "kbd-lang-list"); + + if (arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT) + { + freerdp_client_print_codepages(arg->Value); + } + + arg = CommandLineFindArgumentA(largs, "kbd-list"); if (arg->Flags & COMMAND_LINE_VALUE_PRESENT) { DWORD i; RDP_KEYBOARD_LAYOUT* layouts; layouts = freerdp_keyboard_get_layouts(RDP_KEYBOARD_LAYOUT_TYPE_STANDARD); - //if (!layouts) /* FIXME*/ + // if (!layouts) /* FIXME*/ printf("\nKeyboard Layouts\n"); for (i = 0; layouts[i].code; i++) - printf("0x%08"PRIX32"\t%s\n", layouts[i].code, layouts[i].name); + printf("0x%08" PRIX32 "\t%s\n", layouts[i].code, layouts[i].name); freerdp_keyboard_layouts_free(layouts); layouts = freerdp_keyboard_get_layouts(RDP_KEYBOARD_LAYOUT_TYPE_VARIANT); - //if (!layouts) /* FIXME*/ + // if (!layouts) /* FIXME*/ printf("\nKeyboard Layout Variants\n"); for (i = 0; layouts[i].code; i++) - printf("0x%08"PRIX32"\t%s\n", layouts[i].code, layouts[i].name); + printf("0x%08" PRIX32 "\t%s\n", layouts[i].code, layouts[i].name); freerdp_keyboard_layouts_free(layouts); layouts = freerdp_keyboard_get_layouts(RDP_KEYBOARD_LAYOUT_TYPE_IME); - //if (!layouts) /* FIXME*/ + // if (!layouts) /* FIXME*/ printf("\nKeyboard Input Method Editors (IMEs)\n"); for (i = 0; layouts[i].code; i++) - printf("0x%08"PRIX32"\t%s\n", layouts[i].code, layouts[i].name); + printf("0x%08" PRIX32 "\t%s\n", layouts[i].code, layouts[i].name); freerdp_keyboard_layouts_free(layouts); printf("\n"); } - arg = CommandLineFindArgumentA(args, "monitor-list"); + arg = CommandLineFindArgumentA(largs, "monitor-list"); if (arg->Flags & COMMAND_LINE_VALUE_PRESENT) { @@ -1306,14 +1484,14 @@ static BOOL ends_with(const char* str, const char* ext) if (strLen < extLen) return FALSE; - return strncmp(&str[strLen - extLen], ext, extLen) == 0; + return _strnicmp(&str[strLen - extLen], ext, extLen) == 0; } static void activate_smartcard_logon_rdp(rdpSettings* settings) { settings->SmartcardLogon = TRUE; /* TODO: why not? settings->UseRdpSecurityLayer = TRUE; */ - freerdp_set_param_bool(settings, FreeRDP_PasswordIsSmartcardPin, TRUE); + freerdp_settings_set_bool(settings, FreeRDP_PasswordIsSmartcardPin, TRUE); } /** @@ -1323,21 +1501,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; @@ -1347,16 +1526,17 @@ static BOOL parseSizeValue(const char *input, unsigned long *v1, unsigned long * if ((v == 0 || v == ULONG_MAX) && (errno != 0)) return FALSE; - if (*endPtr != '\0') + if (*endPtr != '\0') return FALSE; + if (v2) *v2 = v; return TRUE; } -int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, - int argc, char** argv, BOOL allowUnknown) +int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, int argc, + char** argv, BOOL allowUnknown) { char* p; char* user = NULL; @@ -1370,6 +1550,8 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, BOOL promptForPassword = FALSE; BOOL compatibility = FALSE; COMMAND_LINE_ARGUMENT_A* arg; + COMMAND_LINE_ARGUMENT_A largs[ARRAYSIZE(args)]; + memcpy(largs, args, sizeof(args)); /* Command line detection fails if only a .rdp or .msrcIncident file * is supplied. Check this case first, only then try to detect @@ -1381,11 +1563,9 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } if (!ext && !assist) - compatibility = freerdp_client_detect_command_line(argc, argv, &flags, - allowUnknown); + compatibility = freerdp_client_detect_command_line(argc, argv, &flags); else - compatibility = freerdp_client_detect_command_line(argc - 1, &argv[1], &flags, - allowUnknown); + compatibility = freerdp_client_detect_command_line(argc - 1, &argv[1], &flags); settings->ProxyHostname = NULL; settings->ProxyUsername = NULL; @@ -1409,14 +1589,12 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (assist) { - if (freerdp_client_settings_parse_assistance_file(settings, - argv[1]) < 0) + if (freerdp_client_settings_parse_assistance_file(settings, argc, argv) < 0) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; } - CommandLineClearArgumentsA(args); - status = CommandLineParseArgumentsA(argc, argv, args, flags, - settings, + CommandLineClearArgumentsA(largs); + status = CommandLineParseArgumentsA(argc, argv, largs, flags, settings, freerdp_client_command_line_pre_filter, freerdp_client_command_line_post_filter); @@ -1424,8 +1602,8 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, return status; } - CommandLineFindArgumentA(args, "v"); - arg = args; + CommandLineFindArgumentA(largs, "v"); + arg = largs; errno = 0; do @@ -1435,9 +1613,10 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (!(arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT)) continue; - CommandLineSwitchStart(arg) - CommandLineSwitchCase(arg, "v") + CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "v") { + if (!arg->Value) + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; free(settings->ServerHostname); settings->ServerHostname = NULL; p = strchr(arg->Value, '['); @@ -1449,15 +1628,15 @@ 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)))) + if (!(settings->ServerHostname = (char*)calloc(length + 1UL, sizeof(char)))) return COMMAND_LINE_ERROR_MEMORY; strncpy(settings->ServerHostname, arg->Value, length); @@ -1477,24 +1656,25 @@ 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)))) + if (!(settings->ServerHostname = (char*)calloc(length, sizeof(char)))) return COMMAND_LINE_ERROR_MEMORY; strncpy(settings->ServerHostname, p + 1, length - 1); 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); + printf("hostname %s port %" PRIu32 "\n", settings->ServerHostname, + settings->ServerPort); } } CommandLineSwitchCase(arg, "spn-class") @@ -1506,6 +1686,8 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, { size_t count = 0; char* cur = arg->Value; + if (!arg->Value) + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; settings->RedirectionPreferType = 0; do @@ -1532,8 +1714,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, mask = (mask & 0x07); settings->RedirectionPreferType |= mask << (count * 3); count++; - } - while (cur != NULL); + } while (cur != NULL); if (count > 3) return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; @@ -1558,35 +1739,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") { - + if (!arg->Value) + return COMMAND_LINE_ERROR_UNEXPECTED_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 +1802,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 +1821,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; @@ -1665,7 +1852,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, UINT32 i; char** p; size_t count = 0; - p = freerdp_command_line_parse_comma_separated_values(arg->Value, &count); + p = CommandLineParseCommaSeparatedValues(arg->Value, &count); if (!p) return COMMAND_LINE_ERROR_MEMORY; @@ -1673,16 +1860,16 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (count > 16) count = 16; - settings->NumMonitorIds = (UINT32) count; + settings->NumMonitorIds = (UINT32)count; 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 +1916,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 +1934,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 +1969,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 +1983,51 @@ 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-lang") + { + LONGLONG val; + + if (!value_to_int(arg->Value, &val, 1, UINT32_MAX)) + { + WLog_ERR(TAG, "Could not identify keyboard active language %s", arg->Value); + WLog_ERR(TAG, "Use /kbd-lang-list to list available layouts"); + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; + } + + settings->KeyboardCodePage = (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 +2049,26 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (arg->Flags & COMMAND_LINE_VALUE_PRESENT) { + if (!arg->Value) + return COMMAND_LINE_ERROR_UNEXPECTED_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 +2094,8 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (arg->Flags & COMMAND_LINE_VALUE_PRESENT) { char* atPtr; + if (!arg->Value) + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; /* value is [scheme://][user:password@]hostname:port */ p = strstr(arg->Value, "://"); @@ -1931,7 +2135,9 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (!colonPtr || (colonPtr > atPtr)) { - WLog_ERR(TAG, "invalid syntax for proxy, expected syntax is user:password@host:port"); + WLog_ERR( + TAG, + "invalid syntax for proxy, expected syntax is user:password@host:port"); return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; } @@ -1960,14 +2166,14 @@ 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; - settings->ProxyHostname = (char*) malloc(length + 1); + 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 +2230,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 +2242,14 @@ 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") { @@ -2056,13 +2262,17 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, settings->DisableWallpaper = TRUE; settings->DisableFullWindowDrag = TRUE; } + CommandLineSwitchCase(arg, "app-workdir") + { + if (!copy_value(arg->Value, &settings->RemoteApplicationWorkingDir)) + return COMMAND_LINE_ERROR_MEMORY; + } CommandLineSwitchCase(arg, "load-balance-info") { if (!copy_value(arg->Value, (char**)&settings->LoadBalanceInfo)) return COMMAND_LINE_ERROR_MEMORY; - settings->LoadBalanceInfoLength = (UINT32) strlen((char*) - settings->LoadBalanceInfo); + settings->LoadBalanceInfoLength = (UINT32)strlen((char*)settings->LoadBalanceInfo); } CommandLineSwitchCase(arg, "app-name") { @@ -2095,12 +2305,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 +2340,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) - { - settings->AudioPlayback = TRUE; - } - else if (mode == AUDIO_MODE_PLAY_ON_SERVER) - { - settings->RemoteConsoleAudio = TRUE; - } - else if (mode == AUDIO_MODE_NONE) + switch (val) { - 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; @@ -2167,17 +2381,18 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, else if (_stricmp(arg->Value, "lan") == 0) type = CONNECTION_TYPE_LAN; else if ((_stricmp(arg->Value, "autodetect") == 0) || - (_stricmp(arg->Value, "auto") == 0) || - (_stricmp(arg->Value, "detect") == 0)) + (_stricmp(arg->Value, "auto") == 0) || (_stricmp(arg->Value, "detect") == 0)) { type = CONNECTION_TYPE_AUTODETECT; } 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 +2423,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") { @@ -2219,6 +2434,13 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, { settings->DisableThemes = !enable; } + CommandLineSwitchCase(arg, "timeout") + { + ULONGLONG val; + if (!value_to_uint(arg->Value, &val, 1, 600000)) + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; + settings->TcpAckTimeout = (UINT32)val; + } CommandLineSwitchCase(arg, "aero") { settings->AllowDesktopComposition = enable; @@ -2236,21 +2458,53 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (arg->Value) { -#ifdef WITH_GFX_H264 + int rc = CHANNEL_RC_OK; + char** p; + size_t count, x; - if (_strnicmp("AVC444", arg->Value, 7) == 0) - { - settings->GfxH264 = TRUE; - settings->GfxAVC444 = TRUE; - } - else if (_strnicmp("AVC420", arg->Value, 7) == 0) - { - settings->GfxH264 = TRUE; - } + p = CommandLineParseCommaSeparatedValues(arg->Value, &count); + if (!p || (count == 0)) + rc = COMMAND_LINE_ERROR; else + { + for (x = 0; x < count; x++) + { + const char* val = p[x]; +#ifdef WITH_GFX_H264 + if (_strnicmp("AVC444", val, 7) == 0) + { + settings->GfxH264 = TRUE; + settings->GfxAVC444 = TRUE; + } + else if (_strnicmp("AVC420", val, 7) == 0) + { + settings->GfxH264 = TRUE; + settings->GfxAVC444 = FALSE; + } + else #endif - if (_strnicmp("RFX", arg->Value, 4) != 0) - return COMMAND_LINE_ERROR; + if (_strnicmp("RFX", val, 4) == 0) + { + settings->GfxAVC444 = FALSE; + settings->GfxH264 = FALSE; + settings->RemoteFxCodec = TRUE; + } + else if (_strnicmp("mask:", val, 5) == 0) + { + ULONGLONG v; + const char* uv = &val[5]; + if (!value_to_uint(uv, &v, 0, UINT32_MAX)) + rc = COMMAND_LINE_ERROR; + else + settings->GfxCapsFilter = (UINT32)v; + } + else + rc = COMMAND_LINE_ERROR; + } + } + free(p); + if (rc != CHANNEL_RC_OK) + return rc; } } CommandLineSwitchCase(arg, "gfx-thin-client") @@ -2285,12 +2539,45 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (arg->Value) { - if (_strnicmp("AVC444", arg->Value, 7) == 0) + int rc = CHANNEL_RC_OK; + char** p; + size_t count, x; + + p = CommandLineParseCommaSeparatedValues(arg->Value, &count); + if (!p || (count == 0)) + rc = COMMAND_LINE_ERROR; + else { - settings->GfxAVC444 = TRUE; + for (x = 0; x < count; x++) + { + const char* val = p[x]; + + if (_strnicmp("AVC444", val, 7) == 0) + { + settings->GfxH264 = TRUE; + settings->GfxAVC444 = TRUE; + } + else if (_strnicmp("AVC420", val, 7) == 0) + { + settings->GfxH264 = TRUE; + settings->GfxAVC444 = FALSE; + } + else if (_strnicmp("mask:", val, 5) == 0) + { + ULONGLONG v; + const char* uv = &val[5]; + if (!value_to_uint(uv, &v, 0, UINT32_MAX)) + rc = COMMAND_LINE_ERROR; + else + settings->GfxCapsFilter = (UINT32)v; + } + else + rc = COMMAND_LINE_ERROR; + } } - else if (_strnicmp("AVC420", arg->Value, 7) != 0) - return COMMAND_LINE_ERROR; + free(p); + if (rc != CHANNEL_RC_OK) + return rc; } } #endif @@ -2300,6 +2587,9 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "rfx-mode") { + if (!arg->Value) + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; + if (strcmp(arg->Value, "video") == 0) settings->RemoteFxCodecMode = 0x00; else if (strcmp(arg->Value, "image") == 0) @@ -2307,12 +2597,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 +2616,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 +2637,19 @@ 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") { + if (!arg->Value) + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; + if (strcmp("rdp", arg->Value) == 0) /* Standard RDP */ { settings->RdpSecurity = TRUE; @@ -2398,7 +2691,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, UINT32 i; char** p; size_t count = 0; - p = freerdp_command_line_parse_comma_separated_values(arg->Value, &count); + p = CommandLineParseCommaSeparatedValues(arg->Value, &count); for (i = 0; i < count; i++) { @@ -2423,7 +2716,9 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (arg->Flags & COMMAND_LINE_VALUE_PRESENT) { - promptForPassword = (strncmp(arg->Value, "force", 6) == 0); + if (!arg->Value) + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; + promptForPassword = (_strnicmp(arg->Value, "force", 6) == 0); if (!promptForPassword) return COMMAND_LINE_ERROR; @@ -2459,6 +2754,8 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "tls-ciphers") { + if (!arg->Value) + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; free(settings->AllowedTlsCiphers); if (strcmp(arg->Value, "netmon") == 0) @@ -2479,12 +2776,53 @@ 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") + { + int rc = 0; + char** p; + size_t count, x; + p = CommandLineParseCommaSeparatedValues(arg->Value, &count); + for (x = 0; (x < count) && (rc == 0); x++) + { + const char deny[] = "deny"; + const char ignore[] = "ignore"; + const char tofu[] = "tofu"; + const char name[5] = "name:"; + const char fingerprints[12] = "fingerprint:"; + + const char* cur = p[x]; + if (_strnicmp(deny, cur, sizeof(deny)) == 0) + settings->AutoDenyCertificate = TRUE; + else if (_strnicmp(ignore, cur, sizeof(ignore)) == 0) + settings->IgnoreCertificate = TRUE; + else if (_strnicmp(tofu, cur, 4) == 0) + settings->AutoAcceptCertificate = TRUE; + else if (_strnicmp(name, cur, sizeof(name)) == 0) + { + const char* val = &cur[sizeof(name)]; + if (!copy_value(val, &settings->CertificateName)) + rc = COMMAND_LINE_ERROR_MEMORY; + } + else if (_strnicmp(fingerprints, cur, sizeof(fingerprints)) == 0) + { + const char* val = &cur[sizeof(fingerprints)]; + if (!append_value(val, &settings->CertificateAcceptedFingerprints)) + rc = COMMAND_LINE_ERROR_MEMORY; + } + else + rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE; + } + free(p); + + if (rc) + return rc; } CommandLineSwitchCase(arg, "cert-name") { @@ -2499,6 +2837,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 +2863,69 @@ 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 +2933,21 @@ 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, "client-build-number") + { + ULONGLONG val; + + if (!value_to_uint(arg->Value, &val, 0, UINT32_MAX)) + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; + if (!freerdp_settings_set_uint32(settings, FreeRDP_ClientBuild, (UINT32)val)) + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; } CommandLineSwitchCase(arg, "bitmap-cache") { @@ -2542,15 +2955,16 @@ 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") { - settings->GlyphSupportLevel = arg->Value ? GLYPH_SUPPORT_FULL : - GLYPH_SUPPORT_NONE; + settings->GlyphSupportLevel = arg->Value ? GLYPH_SUPPORT_FULL : GLYPH_SUPPORT_NONE; } CommandLineSwitchCase(arg, "codec-cache") { + if (!arg->Value) + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; settings->BitmapCacheV3Enabled = TRUE; if (strcmp(arg->Value, "rfx") == 0) @@ -2580,32 +2994,31 @@ 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); + if (val < 0) + settings->MaxTimeInCheckLoop = + 10 * 60 * 60 * 1000; /* 10 hours can be considered as infinite */ + else + settings->MaxTimeInCheckLoop = (UINT32)val; + } + CommandLineSwitchCase(arg, "auto-request-control") + { + if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteAssistanceRequestControl, + enable)) return COMMAND_LINE_ERROR; - } - - if ((long) settings->MaxTimeInCheckLoop <= 0) - { - settings->MaxTimeInCheckLoop = 10 * 60 * 60 * 1000; /* 10 hours can be considered as infinite */ - } } CommandLineSwitchCase(arg, "async-input") { @@ -2641,26 +3054,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; - crypto_base64_decode((const char*)(arg->Value), (int) strlen(arg->Value), - &base64, &length); + if (!arg->Value) + return COMMAND_LINE_ERROR_UNEXPECTED_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 +3086,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 +3119,50 @@ 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) - { - settings->DesktopScaleFactor = scaleFactor; - settings->DeviceScaleFactor = scaleFactor; - } - else + switch (val) { - WLog_ERR(TAG, "scale: invalid scale factor (%d)", scaleFactor); - return COMMAND_LINE_ERROR; + case 100: + case 140: + case 180: + settings->DesktopScaleFactor = (UINT32)val; + 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) - { - settings->DeviceScaleFactor = deviceScaleFactor; - } - else + switch (val) { - 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") @@ -2769,6 +3170,13 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (!copy_value(arg->Value, &settings->ActionScript)) return COMMAND_LINE_ERROR_MEMORY; } + CommandLineSwitchCase(arg, "rdp2tcp") + { + free(settings->RDP2TCPArgs); + + if (!(settings->RDP2TCPArgs = _strdup(arg->Value))) + return COMMAND_LINE_ERROR_MEMORY; + } CommandLineSwitchCase(arg, "fipsmode") { settings->FIPSMode = enable; @@ -2778,12 +3186,94 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (!settings->SmartcardLogon) activate_smartcard_logon_rdp(settings); } + + CommandLineSwitchCase(arg, "tune") + { + size_t x, count; + char** p = CommandLineParseCommaSeparatedValuesEx("tune", arg->Value, &count); + if (!p) + return COMMAND_LINE_ERROR; + for (x = 1; x < count; x++) + { + char* cur = p[x]; + char* sep = strchr(cur, ':'); + if (!sep) + { + free(p); + return COMMAND_LINE_ERROR; + } + *sep++ = '\0'; + if (!freerdp_settings_set_value_for_name(settings, cur, sep)) + { + free(p); + return COMMAND_LINE_ERROR; + } + } + + free(p); + } + CommandLineSwitchCase(arg, "tune-list") + { + size_t x; + SSIZE_T type = 0; + + printf("%s\t%50s\t%s\t%s", "", "", "", "\n"); + for (x = 0; x < FreeRDP_Settings_StableAPI_MAX; x++) + { + const char* name = freerdp_settings_get_name_for_key(x); + type = freerdp_settings_get_type_for_key(x); + + switch (type) + { + case RDP_SETTINGS_TYPE_BOOL: + printf("%" PRIuz "\t%50s\tBOOL\t%s\n", x, name, + freerdp_settings_get_bool(settings, x) ? "TRUE" : "FALSE"); + break; + case RDP_SETTINGS_TYPE_UINT16: + printf("%" PRIuz "\t%50s\tUINT16\t%" PRIu16 "\n", x, name, + freerdp_settings_get_uint16(settings, x)); + break; + case RDP_SETTINGS_TYPE_INT16: + printf("%" PRIuz "\t%50s\tINT16\t%" PRId16 "\n", x, name, + freerdp_settings_get_int16(settings, x)); + break; + case RDP_SETTINGS_TYPE_UINT32: + printf("%" PRIuz "\t%50s\tUINT32\t%" PRIu32 "\n", x, name, + freerdp_settings_get_uint32(settings, x)); + break; + case RDP_SETTINGS_TYPE_INT32: + printf("%" PRIuz "\t%50s\tINT32\t%" PRId32 "\n", x, name, + freerdp_settings_get_int32(settings, x)); + break; + case RDP_SETTINGS_TYPE_UINT64: + printf("%" PRIuz "\t%50s\tUINT64\t%" PRIu64 "\n", x, name, + freerdp_settings_get_uint64(settings, x)); + break; + case RDP_SETTINGS_TYPE_INT64: + printf("%" PRIuz "\t%50s\tINT64\t%" PRId64 "\n", x, name, + freerdp_settings_get_int64(settings, x)); + break; + case RDP_SETTINGS_TYPE_STRING: + printf("%" PRIuz "\t%50s\tSTRING\t%s" + "\n", + x, name, freerdp_settings_get_string(settings, x)); + break; + case RDP_SETTINGS_TYPE_POINTER: + printf("%" PRIuz "\t%50s\tPOINTER\t%p" + "\n", + x, name, freerdp_settings_get_pointer(settings, x)); + break; + default: + break; + } + } + return COMMAND_LINE_STATUS_PRINT; + } CommandLineSwitchDefault(arg) { } CommandLineSwitchEnd(arg) - } - while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); if (user) { @@ -2846,7 +3336,8 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (!settings->GatewayPassword) return COMMAND_LINE_ERROR; - if (!freerdp_passphrase_read("Gateway Password: ", settings->GatewayPassword, size, 1)) + if (!freerdp_passphrase_read("Gateway Password: ", settings->GatewayPassword, size, + 1)) return COMMAND_LINE_ERROR; } } @@ -2854,35 +3345,33 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, freerdp_performance_flags_make(settings); - if (settings->RemoteFxCodec || settings->NSCodec - || settings->SupportGraphicsPipeline) + if (settings->RemoteFxCodec || settings->NSCodec || settings->SupportGraphicsPipeline) { settings->FastPathOutput = TRUE; - settings->LargePointerFlag = TRUE; settings->FrameMarkerCommandEnabled = TRUE; settings->ColorDepth = 32; } - arg = CommandLineFindArgumentA(args, "port"); + arg = CommandLineFindArgumentA(largs, "port"); 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"); + arg = CommandLineFindArgumentA(largs, "p"); if (arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT) { FillMemory(arg->Value, strlen(arg->Value), '*'); } - arg = CommandLineFindArgumentA(args, "gp"); + arg = CommandLineFindArgumentA(largs, "gp"); if (arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT) { @@ -2892,13 +3381,13 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, return status; } -static BOOL freerdp_client_load_static_channel_addin(rdpChannels* channels, - rdpSettings* settings, char* name, void* data) +static BOOL freerdp_client_load_static_channel_addin(rdpChannels* channels, rdpSettings* settings, + char* name, void* data) { PVIRTUALCHANNELENTRY entry = NULL; PVIRTUALCHANNELENTRYEX entryEx = NULL; - entryEx = (PVIRTUALCHANNELENTRYEX) freerdp_load_channel_addin_entry(name, NULL, NULL, - FREERDP_ADDIN_CHANNEL_STATIC | FREERDP_ADDIN_CHANNEL_ENTRYEX); + entryEx = (PVIRTUALCHANNELENTRYEX)(void*)freerdp_load_channel_addin_entry( + name, NULL, NULL, FREERDP_ADDIN_CHANNEL_STATIC | FREERDP_ADDIN_CHANNEL_ENTRYEX); if (!entryEx) entry = freerdp_load_channel_addin_entry(name, NULL, NULL, FREERDP_ADDIN_CHANNEL_STATIC); @@ -2928,12 +3417,40 @@ BOOL freerdp_client_load_addins(rdpChannels* channels, rdpSettings* settings) UINT32 index; ADDIN_ARGV* args; + if (settings->AudioPlayback) + { + char* p[] = { "rdpsnd" }; + + if (!freerdp_client_add_static_channel(settings, ARRAYSIZE(p), p)) + return FALSE; + } + + /* for audio playback also load the dynamic sound channel */ + if (settings->AudioPlayback) + { + char* p[] = { "rdpsnd" }; + + if (!freerdp_client_add_dynamic_channel(settings, ARRAYSIZE(p), p)) + return FALSE; + } + + if (settings->AudioCapture) + { + char* p[] = { "audin" }; + + if (!freerdp_client_add_dynamic_channel(settings, ARRAYSIZE(p), p)) + return FALSE; + } + if ((freerdp_static_channel_collection_find(settings, "rdpsnd")) || - (freerdp_dynamic_channel_collection_find(settings, "tsmf"))) + (freerdp_dynamic_channel_collection_find(settings, "rdpsnd")) +#if defined(CHANNEL_TSMF_CLIENT) + || (freerdp_dynamic_channel_collection_find(settings, "tsmf")) +#endif + ) { settings->DeviceRedirection = TRUE; /* rdpsnd requires rdpdr to be registered */ - settings->AudioPlayback = - TRUE; /* Both rdpsnd and tsmf require this flag to be set */ + settings->AudioPlayback = TRUE; /* Both rdpsnd and tsmf require this flag to be set */ } if (freerdp_dynamic_channel_collection_find(settings, "audin")) @@ -2941,22 +3458,79 @@ BOOL freerdp_client_load_addins(rdpChannels* channels, rdpSettings* settings) settings->AudioCapture = TRUE; } - if (settings->NetworkAutoDetect || - settings->SupportHeartbeatPdu || + if (settings->NetworkAutoDetect || settings->SupportHeartbeatPdu || settings->SupportMultitransport) { - settings->DeviceRedirection = - TRUE; /* these RDP8 features require rdpdr to be registered */ + settings->DeviceRedirection = TRUE; /* these RDP8 features require rdpdr to be registered */ } - if (settings->RedirectDrives || settings->RedirectHomeDrive - || settings->RedirectSerialPorts - || settings->RedirectSmartCards || settings->RedirectPrinters) + if (settings->DrivesToRedirect && (strlen(settings->DrivesToRedirect) != 0)) { - settings->DeviceRedirection = TRUE; /* All of these features require rdpdr */ - } + /* + * Drives to redirect: + * + * Very similar to DevicesToRedirect, but can contain a + * comma-separated list of drive letters to redirect. + */ + char* value; + char* tok; + char* context = NULL; + + value = _strdup(settings->DrivesToRedirect); + if (!value) + return FALSE; + + tok = strtok_s(value, ";", &context); + if (!tok) + { + free(value); + return FALSE; + } - if (settings->RedirectDrives) + while (tok) + { + /* Syntax: Comma seperated list of the following entries: + * '*' ... Redirect all drives, including hotplug + * 'DynamicDrives' ... hotplug + *