diff --git a/.gitmodules b/.gitmodules index 650d2867a..ca1dc1b81 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,7 @@ [submodule "build_scripts/OBS"] path = build_scripts/OBS url = https://github.com/RetroShare/OBS.git +[submodule "supportlibs/udp-discovery-cpp"] + path = supportlibs/udp-discovery-cpp + url = https://github.com/truvorskameikin/udp-discovery-cpp.git + branch = develop diff --git a/.travis.yml b/.travis.yml index f1bddf0ac..cc75af004 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,7 +22,7 @@ before_install: - if [ $TRAVIS_OS_NAME == osx ]; then brew install ccach; export PATH="/usr/local/opt/ccache/libexec:$PATH" ; fi - if [ $TRAVIS_OS_NAME == osx ]; then brew install qt5; fi - if [ $TRAVIS_OS_NAME == osx ]; then brew link --force qt5 ; fi - - if [ $TRAVIS_OS_NAME == osx ]; then brew install openssl miniupnpc libmicrohttpd sqlcipher xapian; fi + - if [ $TRAVIS_OS_NAME == osx ]; then brew install openssl miniupnpc libmicrohttpd sqlcipher xapian cmark; fi - if [ $TRAVIS_OS_NAME == osx ]; then brew install p7zip; fi - if [ $TRAVIS_OS_NAME == osx ]; then npm install -g appdmg; fi @@ -47,8 +47,9 @@ addons: branch_pattern: coverity_scan before_script: - - if [ $TRAVIS_OS_NAME == linux ]; then qmake QMAKE_CC=$CC QMAKE_CXX=$CXX; fi - - if [ $TRAVIS_OS_NAME == osx ]; then qmake QMAKE_CC=$CC QMAKE_CXX=$CXX CONFIG+=rs_macos10.14 CONFIG+=no_retroshare_plugins INCLUDEPATH+=/usr/local/opt/openssl/include/ INCLUDEPATH+=/usr/local/Cellar/sqlcipher/4.0.1/include INCLUDEPATH+=/usr/local/Cellar/libmicrohttpd/0.9.62_1/include QMAKE_LIBDIR+=/usr/local/opt/openssl/lib/ QMAKE_LIBDIR+=/usr/local/Cellar/libmicrohttpd/0.9.62_1/lib QMAKE_LIBDIR+=/usr/local/Cellar/sqlcipher/4.0.1/lib; fi + - env + - if [ $TRAVIS_OS_NAME == linux ]; then qmake; fi + - if [ $TRAVIS_OS_NAME == osx ]; then qmake CONFIG+=rs_macos10.14 INCLUDEPATH+=/usr/local/opt/openssl/include/ INCLUDEPATH+=$(find /usr/local/Cellar/sqlcipher/*/include | headn -n 1) INCLUDEPATH+=$(find /usr/local/Cellar/libmicrohttpd/*/include | head -n 1) QMAKE_LIBDIR+=/usr/local/opt/openssl/lib/ QMAKE_LIBDIR+=$(find /usr/local/Cellar/libmicrohttpd/*/lib | head -n 1) QMAKE_LIBDIR+=$(find /usr/local/Cellar/sqlcipher/*/lib | head -n 1); fi script: - if [ $TRAVIS_OS_NAME == osx ] && [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then make -j4; fi diff --git a/WindowsMSys2_InstallGuide.md b/WindowsMSys2_InstallGuide.md index f5754c74f..c9ce0edd7 100644 --- a/WindowsMSys2_InstallGuide.md +++ b/WindowsMSys2_InstallGuide.md @@ -46,6 +46,7 @@ Install all needed dependencies: pacman -S mingw-w64-i686-xapian-core pacman -S mingw-w64-i686-sqlcipher pacman -S mingw-w64-i686-qt5 + pacman -S mingw32/mingw-w64-i686-cmake We're done installing MSYS2, close the shell terminal. diff --git a/appveyor.yml b/appveyor.yml index 420e0bb9b..98686b717 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -90,7 +90,7 @@ install: # Configuring MSys2 - set PATH=C:\msys64\usr\bin;%PATH% - set PATH=C:\msys64\mingw32\bin;%PATH% - - pacman --noconfirm -S mingw-w64-i686-qt5 mingw-w64-i686-miniupnpc mingw-w64-i686-sqlcipher mingw-w64-i686-libmicrohttpd mingw-w64-i686-xapian-core + - pacman --noconfirm -S mingw-w64-i686-qt5 mingw-w64-i686-miniupnpc mingw-w64-i686-sqlcipher mingw-w64-i686-libmicrohttpd mingw-w64-i686-xapian-core mingw-w64-i686-cmark #- pacman --noconfirm -S mingw-w64-i686-qt5-static mingw-w64-i686-miniupnpc mingw-w64-i686-sqlcipher mingw-w64-i686-libmicrohttpd #- set PATH=C:\msys64\mingw32\qt5-static\bin\;%PATH% @@ -105,6 +105,15 @@ install: - copy C:\msys64\mingw64\x86_64-w64-mingw32\bin\ranlib.exe C:\msys64\mingw64\bin\x86_64-w64-mingw32-ranlib.exe - copy C:\msys64\mingw64\bin\windres.exe C:\msys64\mingw64\bin\x86_64-w64-mingw32-windres.exe + # Work-around linker looking for Qt dll in wrong place + - copy C:\msys64\mingw32\bin\Qt5PrintSupport.dll C:\msys64\mingw32\lib\Qt5PrintSupport.dll + - copy C:\msys64\mingw32\bin\Qt5Widgets.dll C:\msys64\mingw32\lib\Qt5Widgets.dll + - copy C:\msys64\mingw32\bin\Qt5Multimedia.dll C:\msys64\mingw32\lib\Qt5Multimedia.dll + - copy C:\msys64\mingw32\bin\Qt5Gui.dll C:\msys64\mingw32\lib\Qt5Gui.dll + - copy C:\msys64\mingw32\bin\Qt5Network.dll C:\msys64\mingw32\lib\Qt5Network.dll + - copy C:\msys64\mingw32\bin\Qt5Xml.dll C:\msys64\mingw32\lib\Qt5Xml.dll + - copy C:\msys64\mingw32\bin\Qt5Core.dll C:\msys64\mingw32\lib\Qt5Core.dll + #---------------------------------# # build configuration # @@ -136,13 +145,15 @@ before_package: # to run your custom scripts instead of automatic MSBuild build_script: + - env + - git submodule update --init - qmake -Wall -spec win32-g++ "CONFIG=debug" - mingw32-make -j3 # scripts to run after build after_build: - mkdir %RS_DEPLOY% - - copy retroshare-nogui\src\retroshare-nogui.exe %RS_DEPLOY%\ + - copy retroshare-service\src\retroshare-service.exe %RS_DEPLOY%\ - copy retroshare-gui\src\retroshare.exe %RS_DEPLOY%\ ## In Debug build winedeplyqt forget the non debug Qt libs @@ -235,6 +246,10 @@ after_build: - copy C:\msys64\mingw32\bin\libunistring*.dll %RS_DEPLOY%\ - copy C:\msys64\mingw32\bin\libffi*.dll %RS_DEPLOY%\ +## Needed for cmark + - copy C:\msys64\mingw32\bin\libcmark*.dll %RS_DEPLOY%\ + - copy C:\msys64\mingw32\bin\libdouble-conversion*.dll %RS_DEPLOY%\ + - find C:\projects\RetroShare >> filelist.txt # to disable automatic builds @@ -244,10 +259,11 @@ after_build: # artifacts configuration # #---------------------------------# -artifacts: - - path: $(RS_DEPLOY) - - path: '**\*.exe' - - path: filelist.txt +#artifacts: +# - path: '**\*.exe' +# - path: filelist.txt +# - path: $(RS_DEPLOY) + # # # pushing a single file # - path: test.zip diff --git a/build_scripts/Android/prepare-toolchain-clang.sh b/build_scripts/Android/prepare-toolchain-clang.sh index 81f7a398d..dcea8b2e2 100755 --- a/build_scripts/Android/prepare-toolchain-clang.sh +++ b/build_scripts/Android/prepare-toolchain-clang.sh @@ -21,24 +21,27 @@ define_default_value HOST_NUM_CPU $(nproc) define_default_value BZIP2_SOURCE_VERSION "1.0.6" define_default_value BZIP2_SOURCE_SHA256 a2848f34fcd5d6cf47def00461fcb528a0484d8edef8208d6d2e2909dc61d9cd -define_default_value OPENSSL_SOURCE_VERSION "1.1.1" -define_default_value OPENSSL_SOURCE_SHA256 2836875a0f89c03d0fdf483941512613a50cfb421d6fd94b9f41d7279d586a3d +define_default_value OPENSSL_SOURCE_VERSION "1.1.1c" +define_default_value OPENSSL_SOURCE_SHA256 f6fb3079ad15076154eda9413fed42877d668e7069d9b87396d0804fdb3f4c90 define_default_value SQLITE_SOURCE_YEAR "2018" define_default_value SQLITE_SOURCE_VERSION "3250200" define_default_value SQLITE_SOURCE_SHA256 da9a1484423d524d3ac793af518cdf870c8255d209e369bd6a193e9f9d0e3181 -define_default_value SQLCIPHER_SOURCE_VERSION "3.4.2" -define_default_value SQLCIPHER_SOURCE_SHA256 69897a5167f34e8a84c7069f1b283aba88cdfa8ec183165c4a5da2c816cfaadb +define_default_value SQLCIPHER_SOURCE_VERSION "4.2.0" +define_default_value SQLCIPHER_SOURCE_SHA256 105c1b813f848da038c03647a8bfc9d42fb46865e6aaf4edfd46ff3b18cdccfc -define_default_value LIBUPNP_SOURCE_VERSION "1.6.25" -define_default_value LIBUPNP_SOURCE_SHA256 c5a300b86775435c076d58a79cc0d5a977d76027d2a7d721590729b7f369fa43 +define_default_value LIBUPNP_SOURCE_VERSION "1.8.4" +define_default_value LIBUPNP_SOURCE_SHA256 976c3e4555604cdd8391ed2f359c08c9dead3b6bf131c24ce78e64d6669af2ed define_default_value INSTALL_QT_ANDROID "false" define_default_value QT_VERSION "5.12.0" define_default_value QT_ANDROID_INSTALLER_SHA256 a214084e2295c9a9f8727e8a0131c37255bf724bfc69e80f7012ba3abeb1f763 -define_default_value RESTBED_SOURCE_VERSION "4.6" +define_default_value RESTBED_SOURCE_VERSION f74f9329dac82e662c1d570b7cd72c192b729eb4 + +define_default_value UDP_DISCOVERY_CPP_SOURCE "https://github.com/truvorskameikin/udp-discovery-cpp.git" +define_default_value UDP_DISCOVERY_CPP_VERSION "develop" define_default_value XAPIAN_SOURCE_VERSION "1.4.7" define_default_value XAPIAN_SOURCE_SHA256 13f08a0b649c7afa804fa0e85678d693fd6069dd394c9b9e7d41973d74a3b5d3 @@ -78,15 +81,24 @@ function verified_download() } } +cArch="" +eABI="" - -if [ "${ANDROID_NDK_ARCH}" == "x86" ]; then - cArch="i686" - eABI="" -else +case "${ANDROID_NDK_ARCH}" in +"arm") cArch="${ANDROID_NDK_ARCH}" eABI="eabi" -fi + ;; +"arm64") + cArch="aarch64" + eABI="" + ;; +"x86") + cArch="i686" + eABI="" + ;; +esac + export SYSROOT="${NATIVE_LIBS_TOOLCHAIN_PATH}/sysroot/" export PREFIX="${SYSROOT}/usr/" export CC="${NATIVE_LIBS_TOOLCHAIN_PATH}/bin/${cArch}-linux-android${eABI}-clang" @@ -98,6 +110,12 @@ export RANLIB="${NATIVE_LIBS_TOOLCHAIN_PATH}/bin/${cArch}-linux-android${eABI}-r ## More information available at https://android.googlesource.com/platform/ndk/+/ics-mr0/docs/STANDALONE-TOOLCHAIN.html build_toolchain() { + echo "build_toolchain() +################################################################################ +################################################################################ +################################################################################ +" + rm -rf ${NATIVE_LIBS_TOOLCHAIN_PATH} ${ANDROID_NDK_PATH}/build/tools/make_standalone_toolchain.py --verbose \ --arch ${ANDROID_NDK_ARCH} --install-dir ${NATIVE_LIBS_TOOLCHAIN_PATH} \ @@ -108,6 +126,11 @@ build_toolchain() ## This avoid include errors due to -isystem and -I ordering issue delete_copied_includes() { + echo "delete_copied_includes() +################################################################################ +################################################################################ +################################################################################ +" cat "${NATIVE_LIBS_TOOLCHAIN_PATH}/deletefiles" | while read delFile ; do rm "$delFile" done @@ -116,6 +139,12 @@ delete_copied_includes() ## More information available at https://gitlab.com/relan/provisioners/merge_requests/1 and http://stackoverflow.com/a/34032216 install_qt_android() { + echo "install_qt_android() +################################################################################ +################################################################################ +################################################################################ +" + QT_VERSION_CODE=$(echo $QT_VERSION | tr -d .) QT_INSTALL_PATH=${NATIVE_LIBS_TOOLCHAIN_PATH}/Qt QT_INSTALLER="qt-unified-linux-x64-3.0.2-online.run" @@ -199,11 +228,17 @@ QT_QPA_PLATFORM=minimal ./${QT_INSTALLER} --script ${QT_INSTALLER_SCRIPT} ## More information available at retroshare://file?name=Android%20Native%20Development%20Kit%20Cookbook.pdf&size=29214468&hash=0123361c1b14366ce36118e82b90faf7c7b1b136 build_bzlib() { + echo "build_bzlib() +################################################################################ +################################################################################ +################################################################################ +" + B_dir="bzip2-${BZIP2_SOURCE_VERSION}" rm -rf $B_dir verified_download $B_dir.tar.gz $BZIP2_SOURCE_SHA256 \ - http://trumpetti.atm.tut.fi/gentoo/distfiles/bzip2-${BZIP2_SOURCE_VERSION}.tar.gz + http://distfiles.gentoo.org/distfiles/bzip2-${BZIP2_SOURCE_VERSION}.tar.gz tar -xf $B_dir.tar.gz cd $B_dir @@ -223,6 +258,12 @@ build_bzlib() ## More information available at http://doc.qt.io/qt-5/opensslsupport.html build_openssl() { + echo "build_openssl() +################################################################################ +################################################################################ +################################################################################ +" + B_dir="openssl-${OPENSSL_SOURCE_VERSION}" rm -rf $B_dir @@ -240,7 +281,7 @@ build_openssl() [[ ${ANDROID_NDK_ARCH} =~ .*64.* ]] && oBits=64 ANDROID_NDK="${ANDROID_NDK_PATH}" PATH="${SYSROOT}/bin/:${PATH}" \ - ./Configure linux-generic${oBits} --prefix="${PREFIX}" \ + ./Configure linux-generic${oBits} -fPIC --prefix="${PREFIX}" \ --openssldir="${SYSROOT}/etc/ssl" # sed -i 's/LIBNAME=$$i LIBVERSION=$(SHLIB_MAJOR).$(SHLIB_MINOR) \\/LIBNAME=$$i \\/g' Makefile # sed -i '/LIBCOMPATVERSIONS=";$(SHLIB_VERSION_HISTORY)" \\/d' Makefile @@ -253,14 +294,21 @@ build_openssl() build_sqlite() { + echo "build_sqlite() +################################################################################ +################################################################################ +################################################################################ +" + B_dir="sqlite-autoconf-${SQLITE_SOURCE_VERSION}" + rm -rf $B_dir verified_download $B_dir.tar.gz $SQLITE_SOURCE_SHA256 \ https://www.sqlite.org/${SQLITE_SOURCE_YEAR}/$B_dir.tar.gz tar -xf $B_dir.tar.gz cd $B_dir - ./configure --prefix="${PREFIX}" --host=${ANDROID_NDK_ARCH}-linux + ./configure --with-pic --prefix="${PREFIX}" --host=${cArch}-linux make -j${HOST_NUM_CPU} make install rm -f ${PREFIX}/lib/libsqlite3.so* @@ -271,6 +319,12 @@ build_sqlite() build_sqlcipher() { + echo "build_sqlcipher() +################################################################################ +################################################################################ +################################################################################ +" + B_dir="sqlcipher-${SQLCIPHER_SOURCE_VERSION}" rm -rf $B_dir @@ -281,8 +335,16 @@ build_sqlcipher() tar -xf $T_file cd $B_dir - ./configure --build=$(sh ./config.guess) \ - --host=${ANDROID_NDK_ARCH}-linux \ + case "${ANDROID_NDK_ARCH}" in + "arm64") + # SQLCipher config.sub is outdated and doesn't recognize newer architectures + rm config.sub + autoreconf --verbose --install --force + automake --add-missing --copy --force-missing + ;; + esac + ./configure --with-pic --build=$(sh ./config.guess) \ + --host=${cArch}-linux \ --prefix="${PREFIX}" --with-sysroot="${SYSROOT}" \ --enable-tempstore=yes \ --disable-tcl --disable-shared \ @@ -294,20 +356,30 @@ build_sqlcipher() build_libupnp() { - B_dir="libupnp-${LIBUPNP_SOURCE_VERSION}" + echo "build_libupnp() +################################################################################ +################################################################################ +################################################################################ +" + + B_dir="pupnp-release-${LIBUPNP_SOURCE_VERSION}" + B_ext=".tar.gz" + B_file="${B_dir}${B_ext}" rm -rf $B_dir - verified_download $B_dir.tar.bz2 $LIBUPNP_SOURCE_SHA256 \ - https://sourceforge.net/projects/pupnp/files/pupnp/libUPnP%20${LIBUPNP_SOURCE_VERSION}/$B_dir.tar.bz2 + verified_download $B_file $LIBUPNP_SOURCE_SHA256 \ + https://github.com/mrjimenez/pupnp/archive/release-${LIBUPNP_SOURCE_VERSION}${B_ext} - tar -xf $B_dir.tar.bz2 + tar -xf $B_file cd $B_dir + ./bootstrap ## liupnp must be configured as static library because if not the linker will ## look for libthreadutils.so.6 at runtime that cannot be packaged on android ## as it supports only libname.so format for libraries, thus resulting in a ## crash at startup. - ./configure --enable-static --disable-shared --disable-samples \ - --prefix="${PREFIX}" --host=${ANDROID_NDK_ARCH}-linux + ./configure --with-pic --enable-static --disable-shared --disable-samples \ + --disable-largefile \ + --prefix="${PREFIX}" --host=${cArch}-linux make -j${HOST_NUM_CPU} make install cd .. @@ -315,6 +387,12 @@ build_libupnp() build_rapidjson() { + echo "build_rapidjson() +################################################################################ +################################################################################ +################################################################################ +" + B_dir="rapidjson-${RAPIDJSON_SOURCE_VERSION}" D_file="${B_dir}.tar.gz" verified_download $D_file $RAPIDJSON_SOURCE_SHA256 \ @@ -325,25 +403,65 @@ build_rapidjson() build_restbed() { + echo "build_restbed() +################################################################################ +################################################################################ +################################################################################ +" + [ -d restbed ] || git clone --depth=2000 https://github.com/Corvusoft/restbed.git cd restbed - git fetch --tags - git checkout tags/${RESTBED_SOURCE_VERSION} +# git fetch --tags +# git checkout tags/${RESTBED_SOURCE_VERSION} + git checkout ${RESTBED_SOURCE_VERSION} git submodule update --init dependency/asio git submodule update --init dependency/catch git submodule update --init dependency/kashmir cd .. rm -rf restbed-build; mkdir restbed-build ; cd restbed-build - cmake -DBUILD_SSL=OFF -DCMAKE_INSTALL_PREFIX="${PREFIX}" -B. -H../restbed + cmake \ + -DCMAKE_POSITION_INDEPENDENT_CODE=ON \ + -DBUILD_SSL=OFF -DCMAKE_INSTALL_PREFIX="${PREFIX}" -B. -H../restbed make -j${HOST_NUM_CPU} make install cp "${PREFIX}/library/librestbed.a" "${PREFIX}/lib/" cd .. } +build_udp-discovery-cpp() +{ + echo "build_udp-discovery-cpp() +################################################################################ +################################################################################ +################################################################################ +" + + S_dir="udp-discovery-cpp" + [ -d $S_dir ] || git clone $UDP_DISCOVERY_CPP_SOURCE $S_dir + cd $S_dir + git checkout $UDP_DISCOVERY_CPP_VERSION + cd .. + + B_dir="udp-discovery-cpp-build" + rm -rf ${B_dir}; mkdir ${B_dir}; cd ${B_dir} + cmake \ + -DCMAKE_POSITION_INDEPENDENT_CODE=ON \ + -DCMAKE_INSTALL_PREFIX="${PREFIX}" -B. -H../udp-discovery-cpp + make -j${HOST_NUM_CPU} + cp libudp-discovery.a "${PREFIX}/lib/" + cp ../$S_dir/*.hpp "${PREFIX}/include/" + cd .. +} + build_xapian() { + echo "build_xapian() +################################################################################ +################################################################################ +################################################################################ +" + B_dir="xapian-core-${XAPIAN_SOURCE_VERSION}" D_file="$B_dir.tar.xz" verified_download $D_file $XAPIAN_SOURCE_SHA256 \ @@ -355,9 +473,10 @@ build_xapian() B_large_file="" [ "${ANDROID_PLATFORM_VER}" -lt "24" ] && B_large_file="--disable-largefile" ./configure ${B_endiannes_detection_failure_workaround} ${B_large_file} \ + --with-pic \ --disable-backend-inmemory --disable-backend-remote \ --disable--backend-chert --enable-backend-glass \ - --host=${ANDROID_NDK_ARCH}-linux --enable-static --disable-shared \ + --host=${cArch}-linux --enable-static --disable-shared \ --prefix="${PREFIX}" --with-sysroot="${SYSROOT}" make -j${HOST_NUM_CPU} make install @@ -372,6 +491,7 @@ build_sqlcipher build_libupnp build_rapidjson build_restbed +build_udp-discovery-cpp build_xapian delete_copied_includes diff --git a/build_scripts/Debian/debian/copyright b/build_scripts/Debian/debian/copyright index ba2e9f6df..c94948a36 100644 --- a/build_scripts/Debian/debian/copyright +++ b/build_scripts/Debian/debian/copyright @@ -7,6 +7,10 @@ Files: openpgpsdk/* Copyright: 2005-2008 Ben Laurie, Rachel Willmer, Retroshare Team License: Apache-2.0 +Files: jsonapi-generator/* libretroshare/src/jsonapi/* +Copyright: 2018-2019 Gioacchino Mazzurco +License: AGPL-3+ + Files: libretroshare/* Copyright: 2007-2018, Retroshare Team License: LGPL-3+ diff --git a/build_scripts/OBS b/build_scripts/OBS index aafa7aef1..a8c1d3bca 160000 --- a/build_scripts/OBS +++ b/build_scripts/OBS @@ -1 +1 @@ -Subproject commit aafa7aef112f5701c039a13864e1d446d2fbfe46 +Subproject commit a8c1d3bca9de4c93d0212ed9dcda22fe06c833ec diff --git a/jsonapi-generator/src/async-method-wrapper-template.cpp.tmpl b/jsonapi-generator/src/async-method-wrapper-template.cpp.tmpl index 402f32975..81b97265b 100644 --- a/jsonapi-generator/src/async-method-wrapper-template.cpp.tmpl +++ b/jsonapi-generator/src/async-method-wrapper-template.cpp.tmpl @@ -1,23 +1,25 @@ -/* - * RetroShare JSON API - * Copyright (C) 2018 Gioacchino Mazzurco - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ +/******************************************************************************* + * RetroShare JSON API * + * * + * Copyright (C) 2018-2019 Gioacchino Mazzurco * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ -registerHandler("$%apiPath%$", - [$%captureVars%$](const std::shared_ptr session) +registerHandler( "$%apiPath%$", + [this](const std::shared_ptr session) { const std::multimap headers { @@ -27,7 +29,7 @@ registerHandler("$%apiPath%$", session->yield(rb::OK, headers); size_t reqSize = session->get_request()->get_header("Content-Length", 0); - session->fetch( reqSize, [$%captureVars%$]( + session->fetch( reqSize, [this]( const std::shared_ptr session, const rb::Bytes& body ) { @@ -41,14 +43,25 @@ $%paramsDeclaration%$ $%inputParamsDeserialization%$ - $%callbackName%$ = [session]($%callbackParams%$) + const std::weak_ptr weakSession(session); + $%callbackName%$ = [this, weakSession]($%callbackParams%$) { + auto session = weakSession.lock(); + if(!session || session->is_closed()) return; + $%callbackParamsSerialization%$ - std::stringstream message; - message << "data: " << compactJSON << ctx.mJson << "\n\n"; - session->yield(message.str()); - $%sessionEarlyClose%$ + std::stringstream sStream; + sStream << "data: " << compactJSON << ctx.mJson << "\n\n"; + const std::string message = sStream.str(); + + mService.schedule( [weakSession, message]() + { + auto session = weakSession.lock(); + if(!session || session->is_closed()) return; + session->yield(message); + $%sessionEarlyClose%$ + } ); }; $%functionCall%$ @@ -61,5 +74,4 @@ $%outputParamsSerialization%$ session->yield(message.str()); $%sessionDelayedClose%$ } ); -}, $%requiresAuth%$); - +}, $%requiresAuth%$ ); diff --git a/jsonapi-generator/src/jsonapi-generator.cpp b/jsonapi-generator/src/jsonapi-generator.cpp index 90d44cbd9..0a6bf3231 100644 --- a/jsonapi-generator/src/jsonapi-generator.cpp +++ b/jsonapi-generator/src/jsonapi-generator.cpp @@ -1,20 +1,22 @@ -/* - * RetroShare JSON API - * Copyright (C) 2018 Gioacchino Mazzurco - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ +/******************************************************************************* + * RetroShare JSON API * + * * + * Copyright (C) 2018-2019 Gioacchino Mazzurco * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ #include #include @@ -90,7 +92,7 @@ int main(int argc, char *argv[]) { QDomDocument hDoc; QString hFilePath(it.next()); - QString parseError; int line, column; + QString parseError; int line = -1, column = -1; QFile hFile(hFilePath); if (!hFile.open(QIODevice::ReadOnly) || !hDoc.setContent(&hFile, &parseError, &line, &column)) @@ -318,18 +320,13 @@ int main(int argc, char *argv[]) "\t\t\tRS_SERIAL_PROCESS(retval);\n"; if(hasOutput) outputParamsSerialization += "\t\t}\n"; - QString captureVars; - QString sessionEarlyClose; if(hasSingleCallback) sessionEarlyClose = "session->close();"; QString sessionDelayedClose; if(hasMultiCallback) - { - sessionDelayedClose = "mService.schedule( [session](){session->close();}, std::chrono::seconds(maxWait+120) );"; - captureVars = "this"; - } + sessionDelayedClose = "RsThread::async( [=](){ std::this_thread::sleep_for(std::chrono::seconds(maxWait+120)); mService.schedule( [=](){ auto session = weakSession.lock(); if(session && session->is_open()) session->close(); } ); } );"; QString callbackParamsSerialization; @@ -379,7 +376,6 @@ int main(int argc, char *argv[]) substitutionsMap.insert("apiPath", apiPath); substitutionsMap.insert("sessionEarlyClose", sessionEarlyClose); substitutionsMap.insert("sessionDelayedClose", sessionDelayedClose); - substitutionsMap.insert("captureVars", captureVars); substitutionsMap.insert("callbackName", callbackName); substitutionsMap.insert("callbackParams", callbackParams); substitutionsMap.insert("callbackParamsSerialization", callbackParamsSerialization); diff --git a/jsonapi-generator/src/method-wrapper-template.cpp.tmpl b/jsonapi-generator/src/method-wrapper-template.cpp.tmpl index bdcef3aee..a3927fba9 100644 --- a/jsonapi-generator/src/method-wrapper-template.cpp.tmpl +++ b/jsonapi-generator/src/method-wrapper-template.cpp.tmpl @@ -1,23 +1,25 @@ -/* - * RetroShare JSON API - * Copyright (C) 2018 Gioacchino Mazzurco - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ +/******************************************************************************* + * RetroShare JSON API * + * * + * Copyright (C) 2018-2019 Gioacchino Mazzurco * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ -registerHandler("$%apiPath%$", - [$%captureVars%$](const std::shared_ptr session) +registerHandler( "$%apiPath%$", + [](const std::shared_ptr session) { size_t reqSize = session->get_request()->get_header("Content-Length", 0); session->fetch( reqSize, []( @@ -44,5 +46,5 @@ $%outputParamsSerialization%$ // return them to the API caller DEFAULT_API_CALL_JSON_RETURN(rb::OK); } ); -}, $%requiresAuth%$); +}, $%requiresAuth%$ ); diff --git a/libbitdht/src/bitdht/bdmsgs.cc b/libbitdht/src/bitdht/bdmsgs.cc index 1af0c9814..07114dbab 100644 --- a/libbitdht/src/bitdht/bdmsgs.cc +++ b/libbitdht/src/bitdht/bdmsgs.cc @@ -827,9 +827,10 @@ int decodeCompactPeerId(struct sockaddr_in *addr, char *enc, int len) memset(addr, 0, sizeof(struct sockaddr_in)); - uint32_t *ip = (uint32_t *) (enc); + //uint32_t *ip = (uint32_t *) (enc); uint16_t *port = (uint16_t *) (&enc[4]); - addr->sin_addr.s_addr = (*ip); + + memcpy(& addr->sin_addr.s_addr, enc, sizeof(in_addr_t)); // aligned version of "addr->sin_addr.s_addr = (*ip); " addr->sin_port = (*port); addr->sin_family = AF_INET; diff --git a/libresapi/src/api/FileSearchHandler.cpp b/libresapi/src/api/FileSearchHandler.cpp index 7f719aa5b..ceb3765c9 100644 --- a/libresapi/src/api/FileSearchHandler.cpp +++ b/libresapi/src/api/FileSearchHandler.cpp @@ -32,8 +32,8 @@ namespace resource_api { -FileSearchHandler::FileSearchHandler(StateTokenServer *sts, RsNotify *notify, RsTurtle *turtle, RsFiles *files): - mStateTokenServer(sts), mNotify(notify), mTurtle(turtle), mRsFiles(files), +FileSearchHandler::FileSearchHandler(StateTokenServer *sts, RsNotify *notify, RsTurtle */*turtle*/, RsFiles *files): + mStateTokenServer(sts), mNotify(notify)/*, mTurtle(turtle)*/, mRsFiles(files), mMtx("FileSearchHandler") { mNotify->registerNotifyClient(this); @@ -50,7 +50,7 @@ FileSearchHandler::~FileSearchHandler() mStateTokenServer->discardToken(mSearchesStateToken); } -void FileSearchHandler::notifyTurtleSearchResult(const RsPeerId& pid,uint32_t search_id, const std::list& files) +void FileSearchHandler::notifyTurtleSearchResult(const RsPeerId& /*pid*/,uint32_t search_id, const std::list& files) { RS_STACK_MUTEX(mMtx); // ********** LOCKED ********** std::map::iterator mit = mSearches.find(search_id); diff --git a/libresapi/src/api/FileSearchHandler.h b/libresapi/src/api/FileSearchHandler.h index 7e9b294b1..ec1585eef 100644 --- a/libresapi/src/api/FileSearchHandler.h +++ b/libresapi/src/api/FileSearchHandler.h @@ -45,7 +45,7 @@ private: StateTokenServer* mStateTokenServer; RsNotify* mNotify; - RsTurtle* mTurtle; + //RsTurtle* mTurtle; RsFiles* mRsFiles; class Search{ diff --git a/libresapi/src/api/RsControlModule.cpp b/libresapi/src/api/RsControlModule.cpp index 5f07ed7ff..199711a63 100644 --- a/libresapi/src/api/RsControlModule.cpp +++ b/libresapi/src/api/RsControlModule.cpp @@ -145,7 +145,8 @@ void RsControlModule::run() #endif RsInit::InitRsConfig(); - int initResult = RsInit::InitRetroShare(argc, argv, true); + RsConfigOptions opt; + int initResult = RsInit::InitRetroShare(opt); if (initResult < 0) { std::cerr << "RsControlModule: FATAL ERROR, initialising libretroshare FAILED." << std::endl; diff --git a/libresapi/src/api/json.h b/libresapi/src/api/json.h index 30b054259..8b437b7d4 100644 --- a/libresapi/src/api/json.h +++ b/libresapi/src/api/json.h @@ -614,4 +614,4 @@ namespace json } } -#endif //__SUPER_EASY_JSON_H__ \ No newline at end of file +#endif //__SUPER_EASY_JSON_H__ diff --git a/libretroshare/src/chat/distantchat.cc b/libretroshare/src/chat/distantchat.cc index 2fbe0d4e8..cc372b01c 100644 --- a/libretroshare/src/chat/distantchat.cc +++ b/libretroshare/src/chat/distantchat.cc @@ -67,13 +67,10 @@ uint32_t msecs_of_day() static const uint32_t DISTANT_CHAT_GXS_TUNNEL_SERVICE_ID = 0xa0001 ; -typedef RsGxsTunnelService::RsGxsTunnelId RsGxsTunnelId; - -DistantChatService::DistantChatService() : mDistantChatMtx("distant chat") -{ - mGxsTunnels = NULL ; - mDistantChatPermissions = RS_DISTANT_CHAT_CONTACT_PERMISSION_FLAG_FILTER_NONE ; // default: accept everyone -} +DistantChatService::DistantChatService() : + // default: accept everyone + mDistantChatPermissions(RS_DISTANT_CHAT_CONTACT_PERMISSION_FLAG_FILTER_NONE), + mGxsTunnels(nullptr), mDistantChatMtx("distant chat") {} void DistantChatService::connectToGxsTunnelService(RsGxsTunnelService *tr) { @@ -181,7 +178,8 @@ bool DistantChatService::acceptDataFromPeer(const RsGxsId& gxs_id,const RsGxsTun return res ; } -void DistantChatService::notifyTunnelStatus(const RsGxsTunnelService::RsGxsTunnelId &tunnel_id, uint32_t tunnel_status) +void DistantChatService::notifyTunnelStatus( + const RsGxsTunnelId& tunnel_id, uint32_t tunnel_status ) { #ifdef DEBUG_DISTANT_CHAT DISTANT_CHAT_DEBUG() << "DistantChatService::notifyTunnelStatus(): got notification " << std::hex << tunnel_status << std::dec << " for tunnel " << tunnel_id << std::endl; @@ -207,7 +205,8 @@ void DistantChatService::notifyTunnelStatus(const RsGxsTunnelService::RsGxsTunne } } -void DistantChatService::receiveData(const RsGxsTunnelService::RsGxsTunnelId &tunnel_id, unsigned char *data, uint32_t data_size) +void DistantChatService::receiveData( + const RsGxsTunnelId& tunnel_id, unsigned char* data, uint32_t data_size) { #ifdef DEBUG_DISTANT_CHAT DISTANT_CHAT_DEBUG() << "DistantChatService::receiveData(): got data of size " << std::dec << data_size << " for tunnel " << tunnel_id << std::endl; @@ -249,7 +248,8 @@ void DistantChatService::receiveData(const RsGxsTunnelService::RsGxsTunnelId &tu void DistantChatService::markDistantChatAsClosed(const DistantChatPeerId& dcpid) { - mGxsTunnels->closeExistingTunnel(RsGxsTunnelService::RsGxsTunnelId(dcpid),DISTANT_CHAT_GXS_TUNNEL_SERVICE_ID) ; + mGxsTunnels->closeExistingTunnel( + RsGxsTunnelId(dcpid), DISTANT_CHAT_GXS_TUNNEL_SERVICE_ID ); RS_STACK_MUTEX(mDistantChatMtx) ; diff --git a/libretroshare/src/chat/distantchat.h b/libretroshare/src/chat/distantchat.h index e978b7d72..eda55da49 100644 --- a/libretroshare/src/chat/distantchat.h +++ b/libretroshare/src/chat/distantchat.h @@ -30,12 +30,13 @@ class RsGixs ; static const uint32_t DISTANT_CHAT_AES_KEY_SIZE = 16 ; +/** + * Public interface only uses DistandChatPeerId, but internally, this is + * converted into a RsGxsTunnelId + */ class DistantChatService: public RsGxsTunnelService::RsGxsTunnelClientService { public: - // So, public interface only uses DistandChatPeerId, but internally, this is converted into a RsGxsTunnelService::RsGxsTunnelId - - DistantChatService() ; virtual void triggerConfigSave()=0 ; @@ -91,9 +92,13 @@ public: virtual void connectToGxsTunnelService(RsGxsTunnelService *tunnel_service) ; private: - virtual bool acceptDataFromPeer(const RsGxsId& gxs_id, const RsGxsTunnelService::RsGxsTunnelId& tunnel_id, bool am_I_client_side) ; - virtual void notifyTunnelStatus(const RsGxsTunnelService::RsGxsTunnelId& tunnel_id,uint32_t tunnel_status) ; - virtual void receiveData(const RsGxsTunnelService::RsGxsTunnelId& id,unsigned char *data,uint32_t data_size) ; + virtual bool acceptDataFromPeer( + const RsGxsId& gxs_id, const RsGxsTunnelId& tunnel_id, + bool am_I_client_side); + virtual void notifyTunnelStatus( + const RsGxsTunnelId& tunnel_id, uint32_t tunnel_status); + virtual void receiveData( + const RsGxsTunnelId& id, unsigned char* data, uint32_t data_size ); // Utility functions. diff --git a/libretroshare/src/chat/distributedchat.cc b/libretroshare/src/chat/distributedchat.cc index aeb88b7f1..45fc4e29e 100644 --- a/libretroshare/src/chat/distributedchat.cc +++ b/libretroshare/src/chat/distributedchat.cc @@ -39,12 +39,12 @@ //#define DEBUG_CHAT_LOBBIES 1 -static const int CONNECTION_CHALLENGE_MAX_COUNT = 20 ; // sends a connection challenge every 20 messages -static const rstime_t CONNECTION_CHALLENGE_MAX_MSG_AGE = 30 ; // maximum age of a message to be used in a connection challenge -static const int CONNECTION_CHALLENGE_MIN_DELAY = 15 ; // sends a connection at most every 15 seconds -static const int LOBBY_CACHE_CLEANING_PERIOD = 10 ; // clean lobby caches every 10 secs (remove old messages) +static const int CONNECTION_CHALLENGE_MAX_COUNT = 20 ; // sends a connection challenge every 20 messages +static const rstime_t CONNECTION_CHALLENGE_MAX_MSG_AGE = 30 ; // maximum age of a message to be used in a connection challenge +static const int CONNECTION_CHALLENGE_MIN_DELAY = 15 ; // sends a connection at most every 15 seconds +static const int LOBBY_CACHE_CLEANING_PERIOD = 10 ; // clean lobby caches every 10 secs (remove old messages) -static const rstime_t MAX_KEEP_MSG_RECORD = 1200 ; // keep msg record for 1200 secs max. +static const rstime_t MAX_KEEP_MSG_RECORD = 1200 ; // keep msg record for 1200 secs max. static const rstime_t MAX_KEEP_INACTIVE_NICKNAME = 180 ; // keep inactive nicknames for 3 mn max. static const rstime_t MAX_DELAY_BETWEEN_LOBBY_KEEP_ALIVE = 120 ; // send keep alive packet every 2 minutes. static const rstime_t MAX_KEEP_PUBLIC_LOBBY_RECORD = 60 ; // keep inactive lobbies records for 60 secs max. @@ -52,7 +52,7 @@ static const rstime_t MIN_DELAY_BETWEEN_PUBLIC_LOBBY_REQ = 20 ; // don't ask static const rstime_t LOBBY_LIST_AUTO_UPDATE_TIME = 121 ; // regularly ask for available lobbies every 5 minutes, to allow auto-subscribe to work static const uint32_t MAX_ALLOWED_LOBBIES_IN_LIST_WARNING = 50 ; -//static const uint32_t MAX_MESSAGES_PER_SECONDS_NUMBER = 5 ; // max number of messages from a given peer in a window for duration below +//static const uint32_t MAX_MESSAGES_PER_SECONDS_NUMBER = 5 ; // max number of messages from a given peer in a window for duration below static const uint32_t MAX_MESSAGES_PER_SECONDS_PERIOD = 10 ; // duration window for max number of messages before messages get dropped. #define IS_PUBLIC_LOBBY(flags) (flags & RS_CHAT_LOBBY_FLAGS_PUBLIC ) @@ -933,7 +933,7 @@ void DistributedChatService::sendLobbyStatusPeerChangedNickname(const ChatLobbyI } -void DistributedChatService::sendLobbyStatusPeerLiving(const ChatLobbyId& lobby_id) +void DistributedChatService::sendLobbyStatusPeerLeaving(const ChatLobbyId& lobby_id) { sendLobbyStatusItem(lobby_id,RS_CHAT_LOBBY_EVENT_PEER_LEFT,std::string()) ; } @@ -990,7 +990,7 @@ bool DistributedChatService::locked_initLobbyBouncableObject(const ChatLobbyId& while( lobby.msg_cache.find(item.msg_id) != lobby.msg_cache.end() ) ; RsIdentityDetails details ; - if(!rsIdentity->getIdDetails(lobby.gxs_id,details)) + if(!rsIdentity || !rsIdentity->getIdDetails(lobby.gxs_id,details)) { std::cerr << "(EE) Cannot send chat lobby object. Signign identity " << lobby.gxs_id << " is unknown." << std::endl; return false ; @@ -1580,6 +1580,9 @@ bool DistributedChatService::joinVisibleChatLobby(const ChatLobbyId& lobby_id,co } _chat_lobbys[lobby_id] = entry ; } + setLobbyAutoSubscribe(lobby_id,true); + + triggerConfigSave(); // so that we save the subscribed lobbies for(std::list::const_iterator it(invited_friends.begin());it!=invited_friends.end();++it) invitePeerToLobby(lobby_id,*it) ; @@ -1629,6 +1632,8 @@ ChatLobbyId DistributedChatService::createChatLobby(const std::string& lobby_nam RsServer::notify()->notifyListChange(NOTIFY_LIST_CHAT_LOBBY_LIST, NOTIFY_TYPE_ADD) ; + triggerConfigSave(); + return lobby_id ; } @@ -1666,10 +1671,11 @@ void DistributedChatService::handleFriendUnsubscribeLobby(RsChatLobbyUnsubscribe void DistributedChatService::unsubscribeChatLobby(const ChatLobbyId& id) { // send AKN item - sendLobbyStatusPeerLiving(id) ; + sendLobbyStatusPeerLeaving(id) ; + setLobbyAutoSubscribe(id, false); { - RsStackMutex stack(mDistributedChatMtx); /********** STACK LOCKED MTX ******/ + RS_STACK_MUTEX(mDistributedChatMtx); std::map::iterator it = _chat_lobbys.find(id) ; @@ -1704,6 +1710,7 @@ void DistributedChatService::unsubscribeChatLobby(const ChatLobbyId& id) _chat_lobbys.erase(it) ; } + triggerConfigSave(); // so that we save the subscribed lobbies RsServer::notify()->notifyListChange(NOTIFY_LIST_CHAT_LOBBY_LIST, NOTIFY_TYPE_DEL) ; // done! @@ -1826,15 +1833,27 @@ bool DistributedChatService::setIdentityForChatLobby(const ChatLobbyId& lobby_id void DistributedChatService::setLobbyAutoSubscribe(const ChatLobbyId& lobby_id, const bool autoSubscribe) { - if(autoSubscribe){ - _known_lobbies_flags[lobby_id] |= RS_CHAT_LOBBY_FLAGS_AUTO_SUBSCRIBE; - RsGxsId gxsId; - if (getIdentityForChatLobby(lobby_id, gxsId)) - _lobby_default_identity[lobby_id] = gxsId; - } else { - _known_lobbies_flags[lobby_id] &= ~RS_CHAT_LOBBY_FLAGS_AUTO_SUBSCRIBE ; - _lobby_default_identity.erase(lobby_id); - } + + if(autoSubscribe) + { + { + RS_STACK_MUTEX(mDistributedChatMtx); + _known_lobbies_flags[lobby_id] |= RS_CHAT_LOBBY_FLAGS_AUTO_SUBSCRIBE; + } + RsGxsId gxsId; + + if (getIdentityForChatLobby(lobby_id, gxsId)) + { + RS_STACK_MUTEX(mDistributedChatMtx); + _lobby_default_identity[lobby_id] = gxsId; + } + } + else + { + RS_STACK_MUTEX(mDistributedChatMtx); + _known_lobbies_flags[lobby_id] &= ~RS_CHAT_LOBBY_FLAGS_AUTO_SUBSCRIBE ; + _lobby_default_identity.erase(lobby_id); + } RsServer::notify()->notifyListChange(NOTIFY_LIST_CHAT_LOBBY_LIST, NOTIFY_TYPE_ADD) ; triggerConfigSave(); @@ -1966,6 +1985,15 @@ void DistributedChatService::addToSaveList(std::list& list) const list.push_back(clci) ; } + for(auto it(_chat_lobbys.begin());it!=_chat_lobbys.end();++it) + { + RsSubscribedChatLobbyConfigItem *scli = new RsSubscribedChatLobbyConfigItem; + + scli->info = it->second; // copies the ChatLobbyInfo part only + + list.push_back(scli); + } + /* Save Default Nick Name */ { RsConfigKeyValueSet *vitem = new RsConfigKeyValueSet ; @@ -2061,6 +2089,59 @@ bool DistributedChatService::processLoadListItem(const RsItem *item) if(!own_ids.empty()) _default_identity = own_ids.front() ; } + + const RsSubscribedChatLobbyConfigItem *scli = dynamic_cast(item); + + if(scli != NULL) + { + if(_chat_lobbys.find(scli->info.lobby_id) != _chat_lobbys.end()) // do nothing if the lobby is already subscribed + return true; + + std::cerr << "Re-subscribing to chat lobby " << (void*)scli->info.lobby_id << ", flags = " << scli->info.lobby_flags << std::endl; + + rstime_t now = time(NULL); + + // Add the chat room into visible chat rooms + { + RS_STACK_MUTEX(mDistributedChatMtx); /********** STACK LOCKED MTX ******/ + + VisibleChatLobbyRecord& rec(_visible_lobbies[scli->info.lobby_id]) ; + + rec.lobby_id = scli->info.lobby_id ; + rec.lobby_name = scli->info.lobby_name ; + rec.lobby_topic = scli->info.lobby_topic ; + rec.participating_friends = scli->info.participating_friends; + rec.total_number_of_peers = 0; + rec.last_report_time = now ; + rec.lobby_flags = EXTRACT_PRIVACY_FLAGS(scli->info.lobby_flags) ; + + _known_lobbies_flags[scli->info.lobby_id] |= RS_CHAT_LOBBY_FLAGS_AUTO_SUBSCRIBE; + } + + // Add the chat room into subscribed chat rooms + + ChatLobbyEntry entry ; + (ChatLobbyInfo&)entry = scli->info; + + entry.virtual_peer_id = makeVirtualPeerId(entry.lobby_id) ; // not random, so we keep the same id at restart + entry.connexion_challenge_count = 0 ; + entry.last_activity = now ; + entry.last_connexion_challenge_time = now ; + entry.last_keep_alive_packet_time = now ; + + { + RS_STACK_MUTEX(mDistributedChatMtx); /********** STACK LOCKED MTX ******/ + _chat_lobbys[entry.lobby_id] = entry ; + } + + // make the UI aware of the existing chat room + + RsServer::notify()->notifyListChange(NOTIFY_LIST_CHAT_LOBBY_LIST, NOTIFY_TYPE_ADD) ; + + return true; + } + + return false ; } diff --git a/libretroshare/src/chat/distributedchat.h b/libretroshare/src/chat/distributedchat.h index 61a5c1b4d..d80fe185f 100644 --- a/libretroshare/src/chat/distributedchat.h +++ b/libretroshare/src/chat/distributedchat.h @@ -72,6 +72,7 @@ class DistributedChatService void setLobbyAutoSubscribe(const ChatLobbyId& lobby_id, const bool autoSubscribe); bool getLobbyAutoSubscribe(const ChatLobbyId& lobby_id); void sendLobbyStatusString(const ChatLobbyId& id,const std::string& status_string) ; + void sendLobbyStatusPeerLeaving(const ChatLobbyId& lobby_id) ; ChatLobbyId createChatLobby(const std::string& lobby_name,const RsGxsId& lobby_identity,const std::string& lobby_topic, const std::set& invited_friends,ChatLobbyFlags flags) ; @@ -93,7 +94,7 @@ class DistributedChatService bool sendLobbyChat(const ChatLobbyId &lobby_id, const std::string&) ; bool handleRecvChatLobbyMsgItem(RsChatMsgItem *item) ; - bool checkSignature(RsChatLobbyBouncingObject *obj,const RsPeerId& peer_id) ; + bool checkSignature(RsChatLobbyBouncingObject *obj,const RsPeerId& peer_id) ; private: /// make some statistics about time shifts, to prevent various issues. @@ -119,7 +120,6 @@ class DistributedChatService bool bounceLobbyObject(RsChatLobbyBouncingObject *obj, const RsPeerId& peer_id) ; void sendLobbyStatusItem(const ChatLobbyId&, int type, const std::string& status_string) ; - void sendLobbyStatusPeerLiving(const ChatLobbyId& lobby_id) ; void sendLobbyStatusPeerChangedNickname(const ChatLobbyId& lobby_id, const std::string& newnick) ; void sendLobbyStatusNewPeer(const ChatLobbyId& lobby_id) ; diff --git a/libretroshare/src/chat/rschatitems.cc b/libretroshare/src/chat/rschatitems.cc index 55cd6cd88..d3a837b07 100644 --- a/libretroshare/src/chat/rschatitems.cc +++ b/libretroshare/src/chat/rschatitems.cc @@ -21,6 +21,7 @@ *******************************************************************************/ #include +#include "retroshare/rsmsgs.h" #include "util/rstime.h" #include "serialiser/rsbaseserial.h" #include "serialiser/rstlvbase.h" @@ -52,6 +53,7 @@ RsItem *RsChatSerialiser::create_item(uint16_t service_id,uint8_t item_sub_id) c case RS_PKT_SUBTYPE_CHAT_LOBBY_LIST_REQUEST: return new RsChatLobbyListRequestItem(); case RS_PKT_SUBTYPE_CHAT_LOBBY_LIST: return new RsChatLobbyListItem(); case RS_PKT_SUBTYPE_CHAT_LOBBY_CONFIG: return new RsChatLobbyConfigItem(); + case RS_PKT_SUBTYPE_SUBSCRIBED_CHAT_LOBBY_CONFIG: return new RsSubscribedChatLobbyConfigItem(); case RS_PKT_SUBTYPE_OUTGOING_MAP: return new PrivateOugoingMapItem(); default: std::cerr << "Unknown packet type in chat!" << std::endl; @@ -172,6 +174,11 @@ void RsChatAvatarItem::serial_process(RsGenericSerializer::SerializeJob j,RsGene RsTypeSerializer::serial_process(j,ctx,b,"image data") ; } +void RsSubscribedChatLobbyConfigItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) +{ + info.serial_process(j,ctx); +} + void RsChatLobbyConfigItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) { RsTypeSerializer::serial_process(j,ctx,lobby_Id,"lobby_Id") ; diff --git a/libretroshare/src/chat/rschatitems.h b/libretroshare/src/chat/rschatitems.h index f2ca0731d..244be60b2 100644 --- a/libretroshare/src/chat/rschatitems.h +++ b/libretroshare/src/chat/rschatitems.h @@ -34,6 +34,7 @@ #include "serialiser/rstlvidset.h" #include "serialiser/rstlvfileitem.h" +#include "retroshare/rsmsgs.h" /* chat Flags */ const uint32_t RS_CHAT_FLAG_PRIVATE = 0x0001; @@ -82,6 +83,8 @@ const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_INVITE_DEPRECATED = 0x1A ; // to be remo const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_INVITE = 0x1B ; const uint8_t RS_PKT_SUBTYPE_OUTGOING_MAP = 0x1C ; +const uint8_t RS_PKT_SUBTYPE_SUBSCRIBED_CHAT_LOBBY_CONFIG = 0x1D ; + typedef uint64_t ChatLobbyId ; typedef uint64_t ChatLobbyMsgId ; typedef std::string ChatLobbyNickName ; @@ -298,6 +301,19 @@ struct RsPrivateChatMsgConfigItem : RsChatItem uint32_t recvTime; }; +class RsSubscribedChatLobbyConfigItem: public RsChatItem +{ +public: + RsSubscribedChatLobbyConfigItem() :RsChatItem(RS_PKT_SUBTYPE_SUBSCRIBED_CHAT_LOBBY_CONFIG) {} + virtual ~RsSubscribedChatLobbyConfigItem() {} + + virtual void clear() { RsChatItem::clear(); info.clear(); } + + void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx); + + ChatLobbyInfo info; +}; + class RsChatLobbyConfigItem: public RsChatItem { public: diff --git a/libretroshare/src/crypto/hashstream.h b/libretroshare/src/crypto/hashstream.h index b6babe6df..b303b6509 100644 --- a/libretroshare/src/crypto/hashstream.h +++ b/libretroshare/src/crypto/hashstream.h @@ -47,10 +47,10 @@ namespace librs template friend HashStream& operator<<(HashStream& u, const T&) ; - template - friend HashStream& operator<<(HashStream& u,const t_RsGenericIdType& r) + template + friend HashStream& operator<<(HashStream& u, const t_RsGenericIdType& r) { - EVP_DigestUpdate(u.mdctx,r.toByteArray(),ID_SIZE_IN_BYTES); + EVP_DigestUpdate(u.mdctx, r.toByteArray(), ID_SIZE_IN_BYTES); return u; } private: diff --git a/libretroshare/src/dht/p3bitdht.cc b/libretroshare/src/dht/p3bitdht.cc index a1fed1824..f6ed68b68 100644 --- a/libretroshare/src/dht/p3bitdht.cc +++ b/libretroshare/src/dht/p3bitdht.cc @@ -85,7 +85,10 @@ virtual int dhtInfoCallback(const bdId *id, uint32_t type, uint32_t flags, std:: return 0; // now check the filter - if(rsBanList->isAddressAccepted(*(const sockaddr_storage*)addr, RSBANLIST_CHECKING_FLAGS_BLACKLIST, NULL)) { + if(rsBanList->isAddressAccepted( + *reinterpret_cast(addr), + RSBANLIST_CHECKING_FLAGS_BLACKLIST )) + { *isBanned = false; } else { #ifdef DEBUG_BITDHT diff --git a/libretroshare/src/file_sharing/p3filelists.cc b/libretroshare/src/file_sharing/p3filelists.cc index ff825f691..e4ea57dc7 100644 --- a/libretroshare/src/file_sharing/p3filelists.cc +++ b/libretroshare/src/file_sharing/p3filelists.cc @@ -65,6 +65,7 @@ p3FileDatabase::p3FileDatabase(p3ServiceControl *mpeers) mRemoteDirectories.clear() ; // we should load them! mOwnId = mpeers->getOwnId() ; + mBannedFileListNeedsUpdate = false; mLocalSharedDirs = new LocalDirectoryStorage(mFileSharingDir + "/" + LOCAL_SHARED_DIRS_FILE_NAME,mOwnId); mHashCache = new HashStorage(mFileSharingDir + "/" + HASH_CACHE_FILE_NAME) ; @@ -968,16 +969,18 @@ int p3FileDatabase::getSharedDirStatistics(const RsPeerId& pid,SharedDirStats& s } } -void p3FileDatabase::removeExtraFile(const RsFileHash& hash) +bool p3FileDatabase::removeExtraFile(const RsFileHash& hash) { + bool ret = false; { RS_STACK_MUTEX(mFLSMtx) ; - mExtraFiles->removeExtraFile(hash); + ret = mExtraFiles->removeExtraFile(hash); mLastExtraFilesCacheUpdate = 0 ; // forced cache reload } RsServer::notify()->notifyListChange(NOTIFY_LIST_DIRLIST_LOCAL, 0); + return ret; } void p3FileDatabase::getExtraFilesDirDetails(void *ref,DirectoryStorage::EntryIndex e,DirDetails& d) const @@ -1945,7 +1948,10 @@ p3FileDatabase::DirSyncRequestId p3FileDatabase::makeDirSyncReqId(const RsPeerId // This is kind of arbitrary. The important thing is that the same ID needs to be generated every time for a given (peer_id,entry index) pair, in a way // that cannot be brute-forced or reverse-engineered, which explains the random bias and the usage of the hash, that is itself random. - uint64_t r = random_bias ^ *((uint64_t*)tmp.toByteArray()) ; + uint64_t tmp2 ; + memcpy(&tmp2,tmp.toByteArray(),sizeof(uint64_t)); + + uint64_t r = random_bias ^ tmp2; #ifdef DEBUG_P3FILELISTS std::cerr << "Creating ID " << std::hex << r << std::dec << " from peer id " << peer_id << " and hash " << hash << std::endl; diff --git a/libretroshare/src/file_sharing/p3filelists.h b/libretroshare/src/file_sharing/p3filelists.h index 9b2b1be29..7ddc6d282 100644 --- a/libretroshare/src/file_sharing/p3filelists.h +++ b/libretroshare/src/file_sharing/p3filelists.h @@ -109,8 +109,8 @@ class p3FileDatabase: public p3Service, public p3Config, public ftSearch //, pub virtual int SearchKeywords(const std::list& keywords, std::list& results,FileSearchFlags flags,const RsPeerId& peer_id) ; virtual int SearchBoolExp(RsRegularExpression::Expression *exp, std::list& results,FileSearchFlags flags,const RsPeerId& peer_id) const ; - // Extra file list - virtual void removeExtraFile(const RsFileHash& hash); + // Extra file list + virtual bool removeExtraFile(const RsFileHash& hash); // Interface for browsing dir hierarchy // diff --git a/libretroshare/src/ft/ftextralist.cc b/libretroshare/src/ft/ftextralist.cc index 558e9ff4d..6fb757753 100644 --- a/libretroshare/src/ft/ftextralist.cc +++ b/libretroshare/src/ft/ftextralist.cc @@ -3,7 +3,8 @@ * * * libretroshare: retroshare core library * * * - * Copyright 2008 by Robert Fernie * + * Copyright (C) 2008 Robert Fernie * + * Copyright (C) 2018-2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -272,7 +273,8 @@ bool ftExtraList::cleanupEntry(std::string /*path*/, TransferRequestFlags /*flag * file is removed after period. **/ -bool ftExtraList::hashExtraFile(std::string path, uint32_t period, TransferRequestFlags flags) +bool ftExtraList::hashExtraFile( + std::string path, uint32_t period, TransferRequestFlags flags ) { #ifdef DEBUG_ELIST std::cerr << "ftExtraList::hashExtraFile() path: " << path; @@ -282,12 +284,25 @@ bool ftExtraList::hashExtraFile(std::string path, uint32_t period, TransferRequ std::cerr << std::endl; #endif - /* add into queue */ - RS_STACK_MUTEX(extMutex); + auto failure = [](std::string errMsg) + { + RsErr() << __PRETTY_FUNCTION__ << " " << errMsg << std::endl; + return false; + }; + + if(!RsDirUtil::fileExists(path)) + return failure("file: " + path + "not found"); + + if(RsDirUtil::checkDirectory(path)) + return failure("Cannot add a directory: " + path + "as extra file"); FileDetails details(path, period, flags); - details.info.age = time(NULL) + period; - mToHash.push_back(details); + details.info.age = static_cast(time(nullptr) + period); + + { + RS_STACK_MUTEX(extMutex); + mToHash.push_back(details); /* add into queue */ + } return true; } diff --git a/libretroshare/src/ft/ftserver.cc b/libretroshare/src/ft/ftserver.cc index 906bae6f1..132973bfd 100644 --- a/libretroshare/src/ft/ftserver.cc +++ b/libretroshare/src/ft/ftserver.cc @@ -678,14 +678,13 @@ bool ftServer::ExtraFileAdd(std::string fname, const RsFileHash& hash, uint64_t } bool ftServer::ExtraFileRemove(const RsFileHash& hash) -{ - mFileDatabase->removeExtraFile(hash); - return true; -} +{ return mFileDatabase->removeExtraFile(hash); } -bool ftServer::ExtraFileHash(std::string localpath, uint32_t period, TransferRequestFlags flags) +bool ftServer::ExtraFileHash( + std::string localpath, rstime_t period, TransferRequestFlags flags ) { - return mFtExtra->hashExtraFile(localpath, period, flags); + return mFtExtra->hashExtraFile( + localpath, static_cast(period), flags ); } bool ftServer::ExtraFileStatus(std::string localpath, FileInfo &info) @@ -1227,6 +1226,7 @@ void ftServer::deriveEncryptionKey(const RsFileHash& hash, uint8_t *key) SHA256_Final (key, &sha_ctx); } +#ifdef USE_NEW_METHOD static const uint32_t ENCRYPTED_FT_INITIALIZATION_VECTOR_SIZE = 12 ; static const uint32_t ENCRYPTED_FT_AUTHENTICATION_TAG_SIZE = 16 ; static const uint32_t ENCRYPTED_FT_HEADER_SIZE = 4 ; @@ -1234,7 +1234,7 @@ static const uint32_t ENCRYPTED_FT_EDATA_SIZE = 4 ; static const uint8_t ENCRYPTED_FT_FORMAT_AEAD_CHACHA20_POLY1305 = 0x01 ; static const uint8_t ENCRYPTED_FT_FORMAT_AEAD_CHACHA20_SHA256 = 0x02 ; - +#endif //USE_NEW_METHOD bool ftServer::encryptItem(RsTurtleGenericTunnelItem *clear_item,const RsFileHash& hash,RsTurtleGenericDataItem *& encrypted_item) { diff --git a/libretroshare/src/ft/ftserver.h b/libretroshare/src/ft/ftserver.h index 2094459a1..a8879541a 100644 --- a/libretroshare/src/ft/ftserver.h +++ b/libretroshare/src/ft/ftserver.h @@ -181,7 +181,7 @@ public: ***/ virtual bool ExtraFileAdd(std::string fname, const RsFileHash& hash, uint64_t size, uint32_t period, TransferRequestFlags flags); virtual bool ExtraFileRemove(const RsFileHash& hash); - virtual bool ExtraFileHash(std::string localpath, uint32_t period, TransferRequestFlags flags); + virtual bool ExtraFileHash(std::string localpath, rstime_t period, TransferRequestFlags flags); virtual bool ExtraFileStatus(std::string localpath, FileInfo &info); virtual bool ExtraFileMove(std::string fname, const RsFileHash& hash, uint64_t size, std::string destpath); diff --git a/libretroshare/src/rsitems/rsdiscovery2items.cc b/libretroshare/src/gossipdiscovery/gossipdiscoveryitems.cc similarity index 69% rename from libretroshare/src/rsitems/rsdiscovery2items.cc rename to libretroshare/src/gossipdiscovery/gossipdiscoveryitems.cc index b851e27cb..bee4c9b59 100644 --- a/libretroshare/src/rsitems/rsdiscovery2items.cc +++ b/libretroshare/src/gossipdiscovery/gossipdiscoveryitems.cc @@ -1,9 +1,10 @@ /******************************************************************************* - * libretroshare/src/rsitems: rsdiscitems.cc * + * Gossip discovery service items * * * * libretroshare: retroshare core library * * * - * Copyright 2007-2008 by Robert Fernie * + * Copyright (C) 2007-2008 Robert Fernie * + * Copyright (C) 2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -19,73 +20,62 @@ * along with this program. If not, see . * * * *******************************************************************************/ -#include "rsitems/rsdiscovery2items.h" + +#include "gossipdiscovery/gossipdiscoveryitems.h" #include "serialiser/rsbaseserial.h" - #include "serialiser/rstypeserializer.h" - -#if 0 - -#include "rsitems/rsserviceids.h" - -#include "serialiser/rstlvbase.h" -#include "serialiser/rstlvtypes.h" -#endif - -/*** - * #define RSSERIAL_DEBUG 1 - * #define RSSERIAL_ERROR_DEBUG 1 - ***/ - -#define RSSERIAL_ERROR_DEBUG 1 +#include "serialiser/rsserializable.h" #include -RsItem *RsDiscSerialiser::create_item(uint16_t service,uint8_t item_subtype) const +RsItem *RsDiscSerialiser::create_item( + uint16_t service, uint8_t item_subtype ) const { - if(service != RS_SERVICE_TYPE_DISC) - return NULL ; + if(service != RS_SERVICE_TYPE_DISC) return nullptr; - switch(item_subtype) - { - case RS_PKT_SUBTYPE_DISC_PGP_LIST : return new RsDiscPgpListItem() ; //= 0x01; - case RS_PKT_SUBTYPE_DISC_PGP_CERT : return new RsDiscPgpCertItem() ; //= 0x02; - case RS_PKT_SUBTYPE_DISC_CONTACT_deprecated : return NULL ; //= 0x03; -#if 0 - case RS_PKT_SUBTYPE_DISC_SERVICES : return new RsDiscServicesItem(); //= 0x04; -#endif - case RS_PKT_SUBTYPE_DISC_CONTACT : return new RsDiscContactItem(); //= 0x05; - case RS_PKT_SUBTYPE_DISC_IDENTITY_LIST : return new RsDiscIdentityListItem(); //= 0x06; + switch(static_cast(item_subtype)) + { + case RsGossipDiscoveryItemType::PGP_LIST: return new RsDiscPgpListItem(); + case RsGossipDiscoveryItemType::PGP_CERT_BINARY: return new RsDiscPgpKeyItem(); + case RsGossipDiscoveryItemType::CONTACT: return new RsDiscContactItem(); + case RsGossipDiscoveryItemType::IDENTITY_LIST: return new RsDiscIdentityListItem(); default: - return NULL ; - } + return nullptr; + } + + return nullptr; } /*************************************************************************/ -void RsDiscPgpListItem::clear() +void RsDiscPgpListItem::clear() { - mode = DISC_PGP_LIST_MODE_NONE; + mode = RsGossipDiscoveryPgpListMode::NONE; pgpIdSet.TlvClear(); } -void RsDiscPgpListItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) +void RsDiscPgpListItem::serial_process( + RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) { - RsTypeSerializer::serial_process(j,ctx,mode,"mode") ; - RsTypeSerializer::serial_process(j,ctx,pgpIdSet,"pgpIdSet") ; + RS_SERIAL_PROCESS(mode); + RS_SERIAL_PROCESS(pgpIdSet); } -void RsDiscPgpCertItem::clear() +void RsDiscPgpKeyItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) { - pgpId.clear(); - pgpCert.clear(); + RsTypeSerializer::serial_process(j,ctx,pgpKeyId,"pgpKeyId") ; + + RsTypeSerializer::TlvMemBlock_proxy prox(bin_data,bin_len) ; + RsTypeSerializer::serial_process(j,ctx,prox,"keyData") ; } - -void RsDiscPgpCertItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) +void RsDiscPgpKeyItem::clear() { - RsTypeSerializer::serial_process(j,ctx,pgpId,"pgpId") ; - RsTypeSerializer::serial_process(j,ctx,TLV_TYPE_STR_PGPCERT,pgpCert,"pgpCert") ; + pgpKeyId.clear(); + free(bin_data); + bin_data = nullptr; + bin_len=0; } void RsDiscContactItem::clear() @@ -156,3 +146,9 @@ void RsDiscIdentityListItem::serial_process(RsGenericSerializer::SerializeJob j, RS_SERIAL_PROCESS(ownIdentityList); } +RsDiscItem::RsDiscItem(RsGossipDiscoveryItemType subtype) + : RsItem( RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_DISC, static_cast(subtype) ) +{ +} + +RsDiscItem::~RsDiscItem() {} diff --git a/libretroshare/src/rsitems/rsdiscovery2items.h b/libretroshare/src/gossipdiscovery/gossipdiscoveryitems.h similarity index 50% rename from libretroshare/src/rsitems/rsdiscovery2items.h rename to libretroshare/src/gossipdiscovery/gossipdiscoveryitems.h index 3ca7226bf..f5e219b95 100644 --- a/libretroshare/src/rsitems/rsdiscovery2items.h +++ b/libretroshare/src/gossipdiscovery/gossipdiscoveryitems.h @@ -1,9 +1,10 @@ /******************************************************************************* - * libretroshare/src/rsitems: rsdiscitems.h * + * Gossip discovery service items * * * * libretroshare: retroshare core library * * * - * Copyright 2004-2008 by Robert Fernie * + * Copyright (C) 2004-2008 Robert Fernie * + * Copyright (C) 2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -19,91 +20,94 @@ * along with this program. If not, see . * * * *******************************************************************************/ -#ifndef RS_DISC_ITEMS_H -#define RS_DISC_ITEMS_H +#pragma once #include "serialiser/rsserial.h" #include "serialiser/rstlvidset.h" #include "serialiser/rstlvaddrs.h" +#include "serialiser/rstlvbinary.h" #include "rsitems/rsserviceids.h" #include "rsitems/rsitem.h" #include "rsitems/itempriorities.h" #include "serialiser/rsserializer.h" -const uint8_t RS_PKT_SUBTYPE_DISC_PGP_LIST = 0x01; -const uint8_t RS_PKT_SUBTYPE_DISC_PGP_CERT = 0x02; -const uint8_t RS_PKT_SUBTYPE_DISC_CONTACT_deprecated = 0x03; -const uint8_t RS_PKT_SUBTYPE_DISC_SERVICES = 0x04; -const uint8_t RS_PKT_SUBTYPE_DISC_CONTACT = 0x05; -const uint8_t RS_PKT_SUBTYPE_DISC_IDENTITY_LIST = 0x06; +enum class RsGossipDiscoveryItemType : uint8_t +{ + PGP_LIST = 0x1, + PGP_CERT = 0x2, // deprecated + CONTACT = 0x5, + IDENTITY_LIST = 0x6, + PGP_CERT_BINARY = 0x9, +}; class RsDiscItem: public RsItem { - protected: - RsDiscItem(uint8_t subtype) :RsItem(RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_DISC, subtype) {} +protected: + RsDiscItem(RsGossipDiscoveryItemType subtype); + +public: + RsDiscItem() = delete; + virtual ~RsDiscItem(); }; - -#define DISC_PGP_LIST_MODE_NONE 0x00 -#define DISC_PGP_LIST_MODE_FRIENDS 0x01 -#define DISC_PGP_LIST_MODE_GETCERT 0x02 +/** + * This enum is underlined by uint32_t for historical reasons. + * We are conscious that uint32_t is an overkill for so few possible values but, + * changing here it at this point would break binary serialized item + * retro-compatibility. + */ +enum class RsGossipDiscoveryPgpListMode : uint32_t +{ + NONE = 0x0, + FRIENDS = 0x1, + GETCERT = 0x2 +}; class RsDiscPgpListItem: public RsDiscItem { public: - RsDiscPgpListItem() - :RsDiscItem(RS_PKT_SUBTYPE_DISC_PGP_LIST) - { - setPriorityLevel(QOS_PRIORITY_RS_DISC_PGP_LIST); - } + RsDiscPgpListItem() : RsDiscItem(RsGossipDiscoveryItemType::PGP_LIST) + { setPriorityLevel(QOS_PRIORITY_RS_DISC_PGP_LIST); } - virtual ~RsDiscPgpListItem(){} + void clear() override; + void serial_process( + RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) override; - virtual void clear(); - virtual void serial_process(RsGenericSerializer::SerializeJob /* j */,RsGenericSerializer::SerializeContext& /* ctx */); - - uint32_t mode; + RsGossipDiscoveryPgpListMode mode; RsTlvPgpIdSet pgpIdSet; }; - - -class RsDiscPgpCertItem: public RsDiscItem +class RsDiscPgpKeyItem: public RsDiscItem { public: - RsDiscPgpCertItem() - :RsDiscItem(RS_PKT_SUBTYPE_DISC_PGP_CERT) - { - setPriorityLevel(QOS_PRIORITY_RS_DISC_PGP_CERT); - } + RsDiscPgpKeyItem() : RsDiscItem(RsGossipDiscoveryItemType::PGP_CERT_BINARY) + { setPriorityLevel(QOS_PRIORITY_RS_DISC_PGP_CERT); } - virtual ~RsDiscPgpCertItem(){} + virtual ~RsDiscPgpKeyItem() { delete[](bin_data);bin_data=nullptr;bin_len=0;} - virtual void clear(); - virtual void serial_process(RsGenericSerializer::SerializeJob /* j */,RsGenericSerializer::SerializeContext& /* ctx */); + void clear() override; + void serial_process( RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext& ctx) override; - RsPgpId pgpId; - std::string pgpCert; + RsPgpId pgpKeyId; // duplicate information for practical reasons + unsigned char *bin_data; // binry key data allocated with new unsigned char[] + uint32_t bin_len; }; - class RsDiscContactItem: public RsDiscItem { public: - RsDiscContactItem() - :RsDiscItem(RS_PKT_SUBTYPE_DISC_CONTACT) - { - setPriorityLevel(QOS_PRIORITY_RS_DISC_CONTACT); - } + RsDiscContactItem() : RsDiscItem(RsGossipDiscoveryItemType::CONTACT) + { setPriorityLevel(QOS_PRIORITY_RS_DISC_CONTACT); } - virtual ~RsDiscContactItem() {} - - virtual void clear(); - virtual void serial_process(RsGenericSerializer::SerializeJob /* j */,RsGenericSerializer::SerializeContext& /* ctx */); + void clear() override; + void serial_process( + RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) override; RsPgpId pgpId; RsPeerId sslId; @@ -143,53 +147,23 @@ class RsDiscIdentityListItem: public RsDiscItem { public: - RsDiscIdentityListItem() - :RsDiscItem(RS_PKT_SUBTYPE_DISC_IDENTITY_LIST) - { - setPriorityLevel(QOS_PRIORITY_RS_DISC_CONTACT); - } + RsDiscIdentityListItem() : + RsDiscItem(RsGossipDiscoveryItemType::IDENTITY_LIST) + { setPriorityLevel(QOS_PRIORITY_RS_DISC_CONTACT); } - virtual ~RsDiscIdentityListItem() {} + void clear() override { ownIdentityList.clear(); } + void serial_process( + RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx) override; - virtual void clear() { ownIdentityList.clear() ; } - virtual void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx); - - std::list ownIdentityList ; + std::list ownIdentityList; }; -#if 0 -class RsDiscServicesItem: public RsDiscItem -{ - public: - - RsDiscServicesItem() - :RsDiscItem(RS_PKT_SUBTYPE_DISC_SERVICES) - { - setPriorityLevel(QOS_PRIORITY_RS_DISC_SERVICES); - } - -virtual ~RsDiscServicesItem(); - -virtual void clear(); -virtual std::ostream &print(std::ostream &out, uint16_t indent = 0); - - - std::string version; - RsTlvServiceIdMap mServiceIdMap; -}; - -#endif - class RsDiscSerialiser: public RsServiceSerializer { - public: - RsDiscSerialiser() :RsServiceSerializer(RS_SERVICE_TYPE_DISC) {} +public: + RsDiscSerialiser() :RsServiceSerializer(RS_SERVICE_TYPE_DISC) {} + virtual ~RsDiscSerialiser() {} - virtual ~RsDiscSerialiser() {} - - RsItem *create_item(uint16_t service,uint8_t item_subtype) const ; + RsItem* create_item(uint16_t service, uint8_t item_subtype) const; }; - - -#endif // RS_DISC_ITEMS_H - diff --git a/libretroshare/src/services/p3discovery2.cc b/libretroshare/src/gossipdiscovery/p3gossipdiscovery.cc similarity index 60% rename from libretroshare/src/services/p3discovery2.cc rename to libretroshare/src/gossipdiscovery/p3gossipdiscovery.cc index cde3d1f04..d7cf5f1a7 100644 --- a/libretroshare/src/services/p3discovery2.cc +++ b/libretroshare/src/gossipdiscovery/p3gossipdiscovery.cc @@ -1,10 +1,10 @@ /******************************************************************************* - * libretroshare/src/services: p3discovery2.cc * + * RetroShare gossip discovery service implementation * * * * libretroshare: retroshare core library * * * - * Copyright 2004-2013 Robert Fernie * - * Copyright (C) 2018 Gioacchino Mazzurco * + * Copyright (C) 2004-2013 Robert Fernie * + * Copyright (C) 2018-2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -20,20 +20,21 @@ * along with this program. If not, see . * * * *******************************************************************************/ -#include "services/p3discovery2.h" + +#include "gossipdiscovery/p3gossipdiscovery.h" #include "pqi/p3peermgr.h" #include "retroshare/rsversion.h" - #include "retroshare/rsiface.h" #include "rsserver/p3face.h" - - -// Interface pointer. -RsDisc *rsDisc = NULL; +#include "util/rsdebug.h" +#include "retroshare/rspeers.h" /**** * #define P3DISC_DEBUG 1 ****/ +#define P3DISC_DEBUG 1 + +/*extern*/ std::shared_ptr rsGossipDiscovery(nullptr); static bool populateContactInfo( const peerState &detail, RsDiscContactItem *pkt, @@ -48,8 +49,8 @@ static bool populateContactInfo( const peerState &detail, pkt->netMode = detail.netMode; pkt->vs_disc = detail.vs_disc; pkt->vs_dht = detail.vs_dht; - - pkt->lastContact = time(NULL); + + pkt->lastContact = time(nullptr); if (detail.hiddenNode) { @@ -84,9 +85,9 @@ static bool populateContactInfo( const peerState &detail, return true; } -void DiscPgpInfo::mergeFriendList(const std::set &friends) +void DiscPgpInfo::mergeFriendList(const std::set &friends) { - std::set::const_iterator it; + std::set::const_iterator it; for(it = friends.begin(); it != friends.end(); ++it) { mFriendSet.insert(*it); @@ -94,24 +95,27 @@ void DiscPgpInfo::mergeFriendList(const std::set &friends) } -p3discovery2::p3discovery2(p3PeerMgr *peerMgr, p3LinkMgr *linkMgr, p3NetMgr *netMgr, p3ServiceControl *sc, RsGixs *gixs) -:p3Service(), mPeerMgr(peerMgr), mLinkMgr(linkMgr), mNetMgr(netMgr), mServiceCtrl(sc), mGixs(gixs),mDiscMtx("p3discovery2") +p3discovery2::p3discovery2( + p3PeerMgr* peerMgr, p3LinkMgr* linkMgr, p3NetMgr* netMgr, + p3ServiceControl* sc, RsGixs* gixs ) : + p3Service(), mRsEventsHandle(0), mPeerMgr(peerMgr), mLinkMgr(linkMgr), + mNetMgr(netMgr), mServiceCtrl(sc), mGixs(gixs), mDiscMtx("p3discovery2"), + mLastPgpUpdate(0) { - RsStackMutex stack(mDiscMtx); /********** STACK LOCKED MTX ******/ + Dbg3() << __PRETTY_FUNCTION__ << std::endl; + RS_STACK_MUTEX(mDiscMtx); addSerialType(new RsDiscSerialiser()); -#ifdef P3DISC_DEBUG - std::cerr << "p3discovery2::p3discovery2()"; - std::cerr << std::endl; -#endif - - mLastPgpUpdate = 0; - // Add self into PGP FriendList. mFriendList[AuthGPG::getAuthGPG()->getGPGOwnId()] = DiscPgpInfo(); - - return; + + if(rsEvents) + rsEvents->registerEventsHandler( + [this](std::shared_ptr event) + { + rsEventsHandler(*event); + }, mRsEventsHandle ); // mRsEventsHandle is zeroed in initializer list } @@ -131,25 +135,16 @@ RsServiceInfo p3discovery2::getServiceInfo() DISCOVERY_MIN_MINOR_VERSION); } - - - - - p3discovery2::~p3discovery2() -{ - return; - -} +{ rsEvents->unregisterEventsHandler(mRsEventsHandle); } - -void p3discovery2::addFriend(const SSLID &sslId) +void p3discovery2::addFriend(const RsPeerId &sslId) { - PGPID pgpId = getPGPId(sslId); + RsPgpId pgpId = getPGPId(sslId); RsStackMutex stack(mDiscMtx); /********** STACK LOCKED MTX ******/ - std::map::iterator it; + std::map::iterator it; it = mFriendList.find(pgpId); if (it == mFriendList.end()) { @@ -164,9 +159,9 @@ void p3discovery2::addFriend(const SSLID &sslId) } - /* now add SSLID */ + /* now add RsPeerId */ - std::map::iterator sit; + std::map::iterator sit; sit = it->second.mSslIds.find(sslId); if (sit == it->second.mSslIds.end()) { @@ -191,13 +186,13 @@ void p3discovery2::addFriend(const SSLID &sslId) } } -void p3discovery2::removeFriend(const SSLID &sslId) +void p3discovery2::removeFriend(const RsPeerId &sslId) { - PGPID pgpId = getPGPId(sslId); + RsPgpId pgpId = getPGPId(sslId); RsStackMutex stack(mDiscMtx); /********** STACK LOCKED MTX ******/ - std::map::iterator it; + std::map::iterator it; it = mFriendList.find(pgpId); if (it == mFriendList.end()) { @@ -208,7 +203,7 @@ void p3discovery2::removeFriend(const SSLID &sslId) return; } - std::map::iterator sit; + std::map::iterator sit; sit = it->second.mSslIds.find(sslId); if (sit == it->second.mSslIds.end()) { @@ -243,15 +238,13 @@ void p3discovery2::removeFriend(const SSLID &sslId) } } - -PGPID p3discovery2::getPGPId(const SSLID &id) +RsPgpId p3discovery2::getPGPId(const RsPeerId &id) { - PGPID pgpId; + RsPgpId pgpId; mPeerMgr->getGpgId(id, pgpId); return pgpId; } - int p3discovery2::tick() { return handleIncoming(); @@ -259,62 +252,48 @@ int p3discovery2::tick() int p3discovery2::handleIncoming() { - RsItem *item = NULL; + RsItem* item = nullptr; int nhandled = 0; // While messages read while(nullptr != (item = recvItem())) { - RsDiscPgpListItem *pgplist = nullptr; - RsDiscPgpCertItem *pgpcert = nullptr; - RsDiscContactItem *contact = nullptr; - RsDiscIdentityListItem *gxsidlst = nullptr; - nhandled++; + RsDiscPgpListItem* pgplist = nullptr; + RsDiscPgpKeyItem* pgpkey = nullptr; + RsDiscContactItem* contact = nullptr; + RsDiscIdentityListItem* gxsidlst = nullptr; -#ifdef P3DISC_DEBUG - std::cerr << "p3discovery2::handleIncoming() Received Message!" << std::endl; - item -> print(std::cerr); - std::cerr << std::endl; -#endif + ++nhandled; - if (nullptr != (contact = dynamic_cast (item))) + Dbg4() << __PRETTY_FUNCTION__ << " Received item: " << std::endl + << *item << std::endl; + + if((contact = dynamic_cast(item)) != nullptr) { - if (item->PeerId() == contact->sslId) /* self describing */ + if (item->PeerId() == contact->sslId) recvOwnContactInfo(item->PeerId(), contact); - else + else processContactInfo(item->PeerId(), contact); } - else if (nullptr != (gxsidlst = dynamic_cast (item))) - { - recvIdentityList(item->PeerId(),gxsidlst->ownIdentityList) ; - delete item; - } - else if (nullptr != (pgpcert = dynamic_cast (item))) - recvPGPCertificate(item->PeerId(), pgpcert); - else if (nullptr != (pgplist = dynamic_cast (item))) + else if( (gxsidlst = dynamic_cast(item)) != nullptr ) { - /* two types */ - if (pgplist->mode == DISC_PGP_LIST_MODE_FRIENDS) - { + recvIdentityList(item->PeerId(),gxsidlst->ownIdentityList); + delete item; + } + else if((pgpkey = dynamic_cast(item)) != nullptr) + recvPGPCertificate(item->PeerId(), pgpkey); + else if((pgplist = dynamic_cast(item)) != nullptr) + { + if (pgplist->mode == RsGossipDiscoveryPgpListMode::FRIENDS) processPGPList(pgplist->PeerId(), pgplist); - - } - else if (pgplist->mode == DISC_PGP_LIST_MODE_GETCERT) - { + else if (pgplist->mode == RsGossipDiscoveryPgpListMode::GETCERT) recvPGPCertificateRequest(pgplist->PeerId(), pgplist); - } - else - { - delete item ; - } + else delete item; } else { -#ifdef P3DISC_DEBUG - std::cerr << "p3discovery2::handleIncoming() Unknown Received Message!" << std::endl; - item -> print(std::cerr); - std::cerr << std::endl; -#endif + RsWarn() << __PRETTY_FUNCTION__ << " Received unknown item type " << (int)item->PacketSubType() << "! " << std::endl ; + RsWarn() << item << std::endl; delete item; } } @@ -322,9 +301,7 @@ int p3discovery2::handleIncoming() return nhandled; } - - -void p3discovery2::sendOwnContactInfo(const SSLID &sslid) +void p3discovery2::sendOwnContactInfo(const RsPeerId &sslid) { #ifdef P3DISC_DEBUG @@ -335,9 +312,13 @@ void p3discovery2::sendOwnContactInfo(const SSLID &sslid) if (mPeerMgr->getOwnNetStatus(detail)) { RsDiscContactItem *pkt = new RsDiscContactItem(); + /* Cyril: we dont send our own IP to an hidden node. It will not use it - * anyway. */ + * anyway. Furthermore, a Tor node is not supposed to have any mean to send the IPs of his friend nodes + * to other nodes. This would be a very serious security risk. */ + populateContactInfo(detail, pkt, !rsPeers->isHiddenNode(sslid)); + /* G10h4ck: sending IP information also to hidden nodes has proven very * helpful in the usecase of non hidden nodes, that share a common * hidden trusted node, to discover each other IP. @@ -346,7 +327,6 @@ void p3discovery2::sendOwnContactInfo(const SSLID &sslid) * permission matrix. Disabling this instead will make life more * difficult for average user, that moreover whould have no way to * revert an hardcoded policy. */ - //populateContactInfo(detail, pkt, true); pkt->version = RS_HUMAN_READABLE_VERSION; pkt->PeerId(sslid); @@ -372,9 +352,9 @@ void p3discovery2::sendOwnContactInfo(const SSLID &sslid) } } - -void p3discovery2::recvOwnContactInfo(const SSLID &fromId, const RsDiscContactItem *item) +void p3discovery2::recvOwnContactInfo(const RsPeerId &fromId, const RsDiscContactItem *item) { + std::unique_ptr pitem(item); // ensures that item will be destroyed whichever door we leave through #ifdef P3DISC_DEBUG std::cerr << "p3discovery2::recvOwnContactInfo()"; @@ -387,6 +367,21 @@ void p3discovery2::recvOwnContactInfo(const SSLID &fromId, const RsDiscContactIt std::cerr << " -> location : " << item->location << std::endl; std::cerr << std::endl; #endif + // Check that the "own" ID sent corresponds to the one we think it should be. + // Some of these checks may look superfluous but it's better to risk to check twice than not check at all. + + // was obtained using a short invite. , and that the friend is marked as "ignore PGP validation" because it + RsPeerDetails det ; + if(!rsPeers->getPeerDetails(fromId,det)) + { + RsErr() << "(EE) Cannot obtain details from " << fromId << " who is supposed to be a friend! Dropping the info." << std::endl; + return; + } + if(det.gpg_id != item->pgpId) + { + RsErr() << "(EE) peer " << fromId << " sent own details with PGP key ID " << item->pgpId << " which does not match the known key id " << det.gpg_id << ". Dropping the info." << std::endl; + return; + } // Peer Own Info replaces the existing info, because the // peer is the primary source of his own IPs. @@ -399,21 +394,37 @@ void p3discovery2::recvOwnContactInfo(const SSLID &fromId, const RsDiscContactIt updatePeerAddresses(item); + // if the peer is not validated, we stop the exchange here + + if(det.skip_pgp_signature_validation) + { +#ifdef P3DISC_DEBUG + std::cerr << "p3discovery2::recvOwnContactInfo() missing PGP key " << item->pgpId << " from short invite friend " << fromId << ". Requesting it." << std::endl; +#endif + requestPGPCertificate(det.gpg_id, fromId); + return; + } + // This information will be sent out to online peers, at the receipt of their PGPList. // It is important that PGPList is received after the OwnContactItem. // This should happen, but is not enforced by the protocol. - // start peer list exchange. - sendPGPList(fromId); + // Start peer list exchange, if discovery is enabled + + peerState ps; + mPeerMgr->getOwnNetStatus(ps); + + if(ps.vs_disc != RS_VS_DISC_OFF) + sendPGPList(fromId); // Update mDiscStatus. RS_STACK_MUTEX(mDiscMtx); - PGPID pgpId = getPGPId(fromId); - std::map::iterator it = mFriendList.find(pgpId); + RsPgpId pgpId = getPGPId(fromId); + std::map::iterator it = mFriendList.find(pgpId); if (it != mFriendList.end()) { - std::map::iterator sit = it->second.mSslIds.find(fromId); + std::map::iterator sit = it->second.mSslIds.find(fromId); if (sit != it->second.mSslIds.end()) { sit->second.mDiscStatus = item->vs_disc; @@ -432,17 +443,6 @@ void p3discovery2::recvOwnContactInfo(const SSLID &fromId, const RsDiscContactIt #endif } } - else - { -#ifdef P3DISC_DEBUG - std::cerr << "p3discovery2::recvOwnContactInfo()"; - std::cerr << " ERROR missing PGP Entry: " << pgpId; - std::cerr << std::endl; -#endif - } - - // cleanup. - delete item; } void p3discovery2::recvIdentityList(const RsPeerId& pid,const std::list& ids) @@ -477,7 +477,6 @@ void p3discovery2::updatePeerAddresses(const RsDiscContactItem *item) } } - void p3discovery2::updatePeerAddressList(const RsDiscContactItem *item) { if (item->isHidden) @@ -512,10 +511,9 @@ void p3discovery2::updatePeerAddressList(const RsDiscContactItem *item) } } - // Starts the Discovery process. // should only be called it DISC2_STATUS_NOT_HIDDEN(OwnInfo.status). -void p3discovery2::sendPGPList(const SSLID &toId) +void p3discovery2::sendPGPList(const RsPeerId &toId) { updatePgpFriendList(); @@ -528,12 +526,19 @@ void p3discovery2::sendPGPList(const SSLID &toId) RsDiscPgpListItem *pkt = new RsDiscPgpListItem(); - pkt->mode = DISC_PGP_LIST_MODE_FRIENDS; + pkt->mode = RsGossipDiscoveryPgpListMode::FRIENDS; - std::map::const_iterator it; - for(it = mFriendList.begin(); it != mFriendList.end(); ++it) + for(auto it = mFriendList.begin(); it != mFriendList.end(); ++it) { - pkt->pgpIdSet.ids.insert(it->first); + // Check every friend, and only send his PGP key if the friend tells that he wants discovery. Because this action over profiles depends on a node information, + // we check each node of a given progile and only send the profile key if at least one node allows it. + + for(auto it2(it->second.mSslIds.begin());it2!=it->second.mSslIds.end();++it2) + if(it2->second.mDiscStatus != RS_VS_DISC_OFF) + { + pkt->pgpIdSet.ids.insert(it->first); + break; + } } pkt->PeerId(toId); @@ -569,14 +574,14 @@ void p3discovery2::updatePgpFriendList() mLastPgpUpdate = time(NULL); - std::list pgpList; - std::set pgpSet; + std::list pgpList; + std::set pgpSet; - std::set::iterator sit; - std::list::iterator lit; - std::map::iterator it; + std::set::iterator sit; + std::list::iterator lit; + std::map::iterator it; - PGPID ownPgpId = AuthGPG::getAuthGPG()->getGPGOwnId(); + RsPgpId ownPgpId = AuthGPG::getAuthGPG()->getGPGOwnId(); AuthGPG::getAuthGPG()->getGPGAcceptedList(pgpList); pgpList.push_back(ownPgpId); @@ -586,8 +591,8 @@ void p3discovery2::updatePgpFriendList() pgpSet.insert(*lit); } - std::list pgpToAdd; - std::list pgpToRemove; + std::list pgpToAdd; + std::list pgpToRemove; sit = pgpSet.begin(); @@ -653,10 +658,7 @@ void p3discovery2::updatePgpFriendList() } - - - -void p3discovery2::processPGPList(const SSLID &fromId, const RsDiscPgpListItem *item) +void p3discovery2::processPGPList(const RsPeerId &fromId, const RsDiscPgpListItem *item) { RsStackMutex stack(mDiscMtx); /********** STACK LOCKED MTX ******/ @@ -665,9 +667,8 @@ void p3discovery2::processPGPList(const SSLID &fromId, const RsDiscPgpListItem * std::cerr << std::endl; #endif - std::map::iterator it; - PGPID fromPgpId = getPGPId(fromId); - it = mFriendList.find(fromPgpId); + RsPgpId fromPgpId = getPGPId(fromId); + auto it = mFriendList.find(fromPgpId); if (it == mFriendList.end()) { #ifdef P3DISC_DEBUG @@ -684,9 +685,7 @@ void p3discovery2::processPGPList(const SSLID &fromId, const RsDiscPgpListItem * peerState pstate; mPeerMgr->getOwnNetStatus(pstate); if (pstate.vs_disc != RS_VS_DISC_FULL) - { requestUnknownPgpCerts = false; - } uint32_t linkType = mLinkMgr->getLinkType(fromId); if ((linkType & RS_NET_CONN_SPEED_TRICKLE) || @@ -699,13 +698,13 @@ void p3discovery2::processPGPList(const SSLID &fromId, const RsDiscPgpListItem * if (requestUnknownPgpCerts) { - std::set::const_iterator fit; + std::set::const_iterator fit; for(fit = item->pgpIdSet.ids.begin(); fit != item->pgpIdSet.ids.end(); ++fit) { if (!AuthGPG::getAuthGPG()->isGPGId(*fit)) { #ifdef P3DISC_DEBUG - std::cerr << "p3discovery2::processPGPList() requesting PgpId: " << *fit; + std::cerr << "p3discovery2::processPGPList() requesting certificate for PgpId: " << *fit; std::cerr << " from SslId: " << fromId; std::cerr << std::endl; #endif @@ -726,7 +725,7 @@ void p3discovery2::processPGPList(const SSLID &fromId, const RsDiscPgpListItem * * -> Update Other Peers about B. * -> Update B about Other Peers. */ -void p3discovery2::updatePeers_locked(const SSLID &aboutId) +void p3discovery2::updatePeers_locked(const RsPeerId &aboutId) { #ifdef P3DISC_DEBUG @@ -734,10 +733,9 @@ void p3discovery2::updatePeers_locked(const SSLID &aboutId) std::cerr << std::endl; #endif - PGPID aboutPgpId = getPGPId(aboutId); + RsPgpId aboutPgpId = getPGPId(aboutId); - std::map::const_iterator ait; - ait = mFriendList.find(aboutPgpId); + auto ait = mFriendList.find(aboutPgpId); if (ait == mFriendList.end()) { @@ -748,13 +746,12 @@ void p3discovery2::updatePeers_locked(const SSLID &aboutId) return; } - std::set mutualFriends; - std::set onlineFriends; - std::set::const_iterator sit; + std::set mutualFriends; + std::set onlineFriends; - const std::set &friendSet = ait->second.mFriendSet; - std::set::const_iterator fit; - for(fit = friendSet.begin(); fit != friendSet.end(); ++fit) + const std::set &friendSet = ait->second.mFriendSet; + + for(auto fit = friendSet.begin(); fit != friendSet.end(); ++fit) { #ifdef P3DISC_DEBUG @@ -762,8 +759,8 @@ void p3discovery2::updatePeers_locked(const SSLID &aboutId) std::cerr << std::endl; #endif - std::map::const_iterator ffit; - ffit = mFriendList.find(*fit); + auto ffit = mFriendList.find(*fit); + if (ffit == mFriendList.end()) { @@ -771,7 +768,7 @@ void p3discovery2::updatePeers_locked(const SSLID &aboutId) std::cerr << "p3discovery2::updatePeer_locked() Ignoring not our friend"; std::cerr << std::endl; #endif - // Not our friend, or we have no Locations (SSL) for this PGPID (same difference) + // Not our friend, or we have no Locations (SSL) for this RsPgpId (same difference) continue; } @@ -784,16 +781,14 @@ void p3discovery2::updatePeers_locked(const SSLID &aboutId) #endif mutualFriends.insert(*fit); - std::map::const_iterator mit; - for(mit = ffit->second.mSslIds.begin(); - mit != ffit->second.mSslIds.end(); ++mit) + for(auto mit = ffit->second.mSslIds.begin(); mit != ffit->second.mSslIds.end(); ++mit) { - SSLID sslid = mit->first; + RsPeerId sslid = mit->first; if (mServiceCtrl->isPeerConnected(getServiceInfo().mServiceType, sslid)) { // TODO IGNORE if sslid == aboutId, or sslid == ownId. #ifdef P3DISC_DEBUG - std::cerr << "p3discovery2::updatePeer_locked() Adding Online SSLID: " << sslid; + std::cerr << "p3discovery2::updatePeer_locked() Adding Online RsPeerId: " << sslid; std::cerr << std::endl; #endif onlineFriends.insert(sslid); @@ -807,17 +802,15 @@ void p3discovery2::updatePeers_locked(const SSLID &aboutId) std::cerr << std::endl; #endif // update aboutId about Other Peers. - for(fit = mutualFriends.begin(); fit != mutualFriends.end(); ++fit) - { + for(auto fit = mutualFriends.begin(); fit != mutualFriends.end(); ++fit) sendContactInfo_locked(*fit, aboutId); - } #ifdef P3DISC_DEBUG std::cerr << "p3discovery2::updatePeer_locked() Updating Online Peers about " << aboutId; std::cerr << std::endl; #endif // update Other Peers about aboutPgpId. - for(sit = onlineFriends.begin(); sit != onlineFriends.end(); ++sit) + for(auto sit = onlineFriends.begin(); sit != onlineFriends.end(); ++sit) { // This could be more efficient, and only be specific about aboutId. // but we'll leave it like this for the moment. @@ -825,14 +818,13 @@ void p3discovery2::updatePeers_locked(const SSLID &aboutId) } } - -void p3discovery2::sendContactInfo_locked(const PGPID &aboutId, const SSLID &toId) +void p3discovery2::sendContactInfo_locked(const RsPgpId &aboutId, const RsPeerId &toId) { #ifdef P3DISC_DEBUG std::cerr << "p3discovery2::sendContactInfo_locked() aboutPGPId: " << aboutId << " toId: " << toId; std::cerr << std::endl; #endif - std::map::const_iterator it; + std::map::const_iterator it; it = mFriendList.find(aboutId); if (it == mFriendList.end()) { @@ -843,7 +835,7 @@ void p3discovery2::sendContactInfo_locked(const PGPID &aboutId, const SSLID &toI return; } - std::map::const_iterator sit; + std::map::const_iterator sit; for(sit = it->second.mSslIds.begin(); sit != it->second.mSslIds.end(); ++sit) { #ifdef P3DISC_DEBUG @@ -899,36 +891,37 @@ void p3discovery2::sendContactInfo_locked(const PGPID &aboutId, const SSLID &toI else { #ifdef P3DISC_DEBUG - std::cerr << "p3discovery2::sendContactInfo_locked() SSLID Hidden"; + std::cerr << "p3discovery2::sendContactInfo_locked() RsPeerId Hidden"; std::cerr << std::endl; #endif } } } - -void p3discovery2::processContactInfo(const SSLID &fromId, const RsDiscContactItem *item) +void p3discovery2::processContactInfo(const RsPeerId &fromId, const RsDiscContactItem *item) { (void) fromId; // remove unused parameter warnings, debug only RS_STACK_MUTEX(mDiscMtx); + // This case is the node fromId sending information about ourselves to us. There's one good use of this: + // read the IP information the friend knows about us, and use it to extimate our external address. + if (item->sslId == rsPeers->getOwnId()) { if(sockaddr_storage_isExternalNet(item->currentConnectAddress.addr)) - mPeerMgr->addCandidateForOwnExternalAddress( - item->PeerId(), item->currentConnectAddress.addr); + mPeerMgr->addCandidateForOwnExternalAddress(item->PeerId(), item->currentConnectAddress.addr); delete item; return; } - std::map::iterator it; - it = mFriendList.find(item->pgpId); - if (it == mFriendList.end()) + auto it = mFriendList.find(item->pgpId); // is this the PGP id one of our friends? + + if (it == mFriendList.end()) // no it's not. { #ifdef P3DISC_DEBUG - std::cerr << "p3discovery2::processContactInfo(" << fromId << ") PGPID: "; + std::cerr << "p3discovery2::processContactInfo(" << fromId << ") RsPgpId: "; std::cerr << item->pgpId << " Not Friend."; std::cerr << std::endl; std::cerr << "p3discovery2::processContactInfo(" << fromId << ") THIS SHOULD NEVER HAPPEN!"; @@ -946,53 +939,55 @@ void p3discovery2::processContactInfo(const SSLID &fromId, const RsDiscContactIt mNetMgr->netAssistFriend(item->sslId,false); /* inform NetMgr that we know this peer */ - mNetMgr->netAssistKnownPeer(item->sslId, item->extAddrV4.addr, - NETASSIST_KNOWN_PEER_FOF | NETASSIST_KNOWN_PEER_OFFLINE); + mNetMgr->netAssistKnownPeer(item->sslId, item->extAddrV4.addr, NETASSIST_KNOWN_PEER_FOF | NETASSIST_KNOWN_PEER_OFFLINE); } delete item; return; } - bool should_notify_discovery = false; - std::map::iterator sit; - sit = it->second.mSslIds.find(item->sslId); - if (sit == it->second.mSslIds.end()) - { - /* insert! */ - DiscSslInfo sslInfo; - it->second.mSslIds[item->sslId] = sslInfo; - //sit = it->second.mSslIds.find(item->sslId); + // The peer the discovery info is about is a friend. We gather the nodes for that profile into the local structure and notify p3peerMgr. + if(!rsPeers->isGPGAccepted(item->pgpId)) // this is an additional check, because the friendship previously depends on the local cache. We need + return ; // fresh information here. + + bool should_notify_discovery = false; + auto sit= it->second.mSslIds.find(item->sslId); + + DiscSslInfo& sslInfo(it->second.mSslIds[item->sslId]); // This line inserts the entry while not removing already existing data + // do not remove it! + + if (!mPeerMgr->isFriend(item->sslId)) + { should_notify_discovery = true; - if (!mPeerMgr->isFriend(item->sslId)) - { - // Add with no disc by default. If friend already exists, it will do nothing - // NO DISC is important - otherwise, we'll just enter a nasty loop, - // where every addition triggers requests, then they are cleaned up, and readded... + // Add with no disc by default. If friend already exists, it will do nothing + // NO DISC is important - otherwise, we'll just enter a nasty loop, + // where every addition triggers requests, then they are cleaned up, and readded... - // This way we get their addresses, but don't advertise them until we get a - // connection. + // This way we get their addresses, but don't advertise them until we get a + // connection. #ifdef P3DISC_DEBUG - std::cerr << "--> Adding to friends list " << item->sslId << " - " << item->pgpId << std::endl; + std::cerr << "--> Adding to friends list " << item->sslId << " - " << item->pgpId << std::endl; #endif - // We pass RS_NODE_PERM_ALL because the PGP id is already a friend, so we should keep the existing - // permission flags. Therefore the mask needs to be 0xffff. + // We pass RS_NODE_PERM_ALL because the PGP id is already a friend, so we should keep the existing + // permission flags. Therefore the mask needs to be 0xffff. - // set last seen to RS_PEER_OFFLINE_NO_DISC minus 1 so that it won't be shared with other friends - // until a first connection is established + // set last seen to RS_PEER_OFFLINE_NO_DISC minus 1 so that it won't be shared with other friends + // until a first connection is established - mPeerMgr->addFriend( item->sslId, item->pgpId, item->netMode, - RS_VS_DISC_OFF, RS_VS_DHT_FULL, - time(NULL) - RS_PEER_OFFLINE_NO_DISC - 1, - RS_NODE_PERM_ALL ); - updatePeerAddresses(item); - } + // This code is a bit dangerous: we add a friend without the insurance that the PGP key that will validate this friend actually has + // the supplied PGP id. Of course, because it comes from a friend, we should trust that friend. Anyway, it is important that + // when connecting the handshake is always doen w.r.t. the known PGP key, and not the one that is indicated in the certificate issuer field. + + mPeerMgr->addFriend( item->sslId, item->pgpId, item->netMode, + RS_VS_DISC_OFF, RS_VS_DHT_FULL, + time(NULL) - RS_PEER_OFFLINE_NO_DISC - 1, + RS_NODE_PERM_ALL ); + + updatePeerAddresses(item); } - updatePeerAddressList(item); - RsServer::notify()->notifyListChange(NOTIFY_LIST_NEIGHBOURS, NOTIFY_TYPE_MOD); if(should_notify_discovery) @@ -1001,11 +996,9 @@ void p3discovery2::processContactInfo(const SSLID &fromId, const RsDiscContactIt delete item; } - - /* we explictly request certificates, instead of getting them all the time */ -void p3discovery2::requestPGPCertificate(const PGPID &aboutId, const SSLID &toId) +void p3discovery2::requestPGPCertificate(const RsPgpId &aboutId, const RsPeerId &toId) { #ifdef P3DISC_DEBUG std::cerr << "p3discovery2::requestPGPCertificate() aboutId: " << aboutId << " to: " << toId; @@ -1014,7 +1007,7 @@ void p3discovery2::requestPGPCertificate(const PGPID &aboutId, const SSLID &toId RsDiscPgpListItem *pkt = new RsDiscPgpListItem(); - pkt->mode = DISC_PGP_LIST_MODE_GETCERT; + pkt->mode = RsGossipDiscoveryPgpListMode::GETCERT; pkt->pgpIdSet.ids.insert(aboutId); pkt->PeerId(toId); @@ -1027,93 +1020,114 @@ void p3discovery2::requestPGPCertificate(const PGPID &aboutId, const SSLID &toId sendItem(pkt); } - /* comment */ -void p3discovery2::recvPGPCertificateRequest(const SSLID &fromId, const RsDiscPgpListItem *item) +void p3discovery2::recvPGPCertificateRequest( const RsPeerId& fromId, const RsDiscPgpListItem* item ) { #ifdef P3DISC_DEBUG - std::cerr << "p3discovery2::recvPPGPCertificateRequest() from " << fromId; - std::cerr << std::endl; + std::cerr << __PRETTY_FUNCTION__ << " from " << fromId << std::endl; #endif + peerState ps; + mPeerMgr->getOwnNetStatus(ps); + + if(ps.vs_disc == RS_VS_DISC_OFF) + { + std::cerr << "(WW) refusing PGP certificate request from " << fromId << " because discovery is OFF" << std::endl; + return; + } + + RsPgpId ownPgpId = AuthGPG::getAuthGPG()->getGPGOwnId(); + for(const RsPgpId& pgpId : item->pgpIdSet.ids) + if (pgpId == ownPgpId) + sendPGPCertificate(pgpId, fromId); + else if(ps.vs_disc != RS_VS_DISC_OFF && AuthGPG::getAuthGPG()->isGPGAccepted(pgpId)) + sendPGPCertificate(pgpId, fromId); + else + std::cerr << "(WW) not sending certificate " << pgpId << " asked by friend " << fromId << " because this either this cert is not a friend, or discovery is off" << std::endl; - std::set::const_iterator it; - for(it = item->pgpIdSet.ids.begin(); it != item->pgpIdSet.ids.end(); ++it) - { - // NB: This doesn't include own certificates? why not. - // shouldn't be a real problem. Peer must have own PgpCert already. - if (AuthGPG::getAuthGPG()->isGPGAccepted(*it)) - { - sendPGPCertificate(*it, fromId); - } - } delete item; } -void p3discovery2::sendPGPCertificate(const PGPID &aboutId, const SSLID &toId) +void p3discovery2::sendPGPCertificate(const RsPgpId &aboutId, const RsPeerId &toId) { + RsDiscPgpKeyItem *pgp_key_item = new RsDiscPgpKeyItem; - /* for Relay Connections (and other slow ones) we don't want to - * to waste bandwidth sending certificates. So don't add it. - */ + pgp_key_item->PeerId(toId); + pgp_key_item->pgpKeyId = aboutId; + unsigned char *bin_data; + size_t bin_len; - uint32_t linkType = mLinkMgr->getLinkType(toId); - if ((linkType & RS_NET_CONN_SPEED_TRICKLE) || - (linkType & RS_NET_CONN_SPEED_LOW)) + if(!AuthGPG::getAuthGPG()->exportPublicKey(aboutId,bin_data,bin_len,false,true)) + { + std::cerr << "(EE) cannot export public key " << aboutId << " requested by peer " << toId << std::endl; + return ; + } + + pgp_key_item->bin_data = bin_data; + pgp_key_item->bin_len = bin_len; + + sendItem(pgp_key_item); +} + +void p3discovery2::recvPGPCertificate(const RsPeerId& fromId, RsDiscPgpKeyItem* item ) +{ + // 1 - check that the cert structure is valid. + + RsPgpId cert_pgp_id; + std::string cert_name; + std::list cert_signers; + + if(!AuthGPG::getAuthGPG()->getGPGDetailsFromBinaryBlock( (unsigned char*)item->bin_data,item->bin_len, cert_pgp_id, cert_name, cert_signers )) { - std::cerr << "p3discovery2::sendPGPCertificate() Not sending Certificates to: " << toId; - std::cerr << " (low bandwidth)" << std::endl; + std::cerr << "(EE) cannot parse own PGP key sent by " << fromId << std::endl; return; } - RsDiscPgpCertItem *item = new RsDiscPgpCertItem(); - item->pgpId = aboutId; - item->PeerId(toId); - - -#ifdef P3DISC_DEBUG - std::cerr << "p3discovery2::sendPGPCertificate() queuing for Cert generation:" << std::endl; - item->print(std::cerr); - std::cerr << std::endl; -#endif - - RsStackMutex stack(mDiscMtx); /********** STACK LOCKED MTX ******/ - /* queue it! */ - - mPendingDiscPgpCertOutList.push_back(item); -} - - -void p3discovery2::recvPGPCertificate(const SSLID &/*fromId*/, RsDiscPgpCertItem *item) -{ - -#ifdef P3DISC_DEBUG - std::cerr << "p3discovery2::recvPGPCertificate() queuing for Cert loading" << std::endl; - std::cerr << std::endl; -#endif - - - /* should only happen if in FULL Mode */ - peerState pstate; - mPeerMgr->getOwnNetStatus(pstate); - if (pstate.vs_disc != RS_VS_DISC_FULL) + if(cert_pgp_id != item->pgpKeyId) { + std::cerr << "(EE) received a PGP key from " << fromId << " which ID (" << cert_pgp_id << ") is different from the one anounced in the packet (" << item->pgpKeyId << ")!" << std::endl; + return; + } + + // 2 - check if the peer who is sending us a cert is already validated + + RsPeerDetails det; + if(!rsPeers->getPeerDetails(fromId,det)) + { + std::cerr << "(EE) cannot get peer details from friend " << fromId << ": this is very wrong!"<< std::endl; + return; + } + + // We treat own pgp keys right away when they are sent by a friend for which we dont have it. This way we can keep the skip_pgg_signature_validation consistent + + if(det.skip_pgp_signature_validation) + { #ifdef P3DISC_DEBUG - std::cerr << "p3discovery2::recvPGPCertificate() Not Loading Certificates as in MINIMAL MODE"; - std::cerr << std::endl; + std::cerr << __PRETTY_FUNCTION__ << " Received own full certificate from short-invite friend " << fromId << std::endl; #endif + // do some extra checks. Dont remove them. They cost nothing as compared to what they could avoid. - delete item; - } + if(item->pgpKeyId != det.gpg_id) + { + std::cerr << "(EE) received a PGP key with ID " << item->pgpKeyId << " from non validated peer " << fromId << ", which should only be allowed to send his own key " << det.gpg_id << std::endl; + return; + } + } + RsPgpId tmp_pgp_id; + std::string error_string; - RsStackMutex stack(mDiscMtx); /********** STACK LOCKED MTX ******/ - /* push this back to be processed by pgp when possible */ +#ifdef P3DISC_DEBUG + std::cerr << __PRETTY_FUNCTION__ << "Received PGP key " << cert_pgp_id << " from from friend " << fromId << ". Adding to keyring." << std::endl; +#endif + // now that will add the key *and* set the skip_signature_validation flag at once + rsPeers->loadPgpKeyFromBinaryData((unsigned char*)item->bin_data,item->bin_len, tmp_pgp_id,error_string); // no error should occur at this point because we called loadDetailsFromStringCert() already + delete item; - mPendingDiscPgpCertInList.push_back(item); + // Make sure we allow connections after the key is added. This is not the case otherwise. We only do that if the peer is non validated peer, since + // otherwise the connection should already be accepted. This only happens when the short invite peer sends its own PGP key. + + if(det.skip_pgp_signature_validation) + AuthGPG::getAuthGPG()->AllowConnection(det.gpg_id,true); } - - - - /************* from pqiServiceMonitor *******************/ void p3discovery2::statusChange(const std::list &plist) @@ -1170,8 +1184,8 @@ bool p3discovery2::getDiscFriends(const RsPeerId& id, std::list &proxy RsStackMutex stack(mDiscMtx); /********** STACK LOCKED MTX ******/ - std::map::const_iterator it; - PGPID pgp_id = getPGPId(id); + std::map::const_iterator it; + RsPgpId pgp_id = getPGPId(id); it = mFriendList.find(pgp_id); if (it == mFriendList.end()) @@ -1180,9 +1194,9 @@ bool p3discovery2::getDiscFriends(const RsPeerId& id, std::list &proxy return false; } - // For each of their friends that we know, grab that set of SSLIDs. - const std::set &friendSet = it->second.mFriendSet; - std::set::const_iterator fit; + // For each of their friends that we know, grab that set of RsPeerId. + const std::set &friendSet = it->second.mFriendSet; + std::set::const_iterator fit; for(fit = friendSet.begin(); fit != friendSet.end(); ++fit) { it = mFriendList.find(*fit); @@ -1191,7 +1205,7 @@ bool p3discovery2::getDiscFriends(const RsPeerId& id, std::list &proxy continue; } - std::map::const_iterator sit; + std::map::const_iterator sit; for(sit = it->second.mSslIds.begin(); sit != it->second.mSslIds.end(); ++sit) { @@ -1205,14 +1219,13 @@ bool p3discovery2::getDiscFriends(const RsPeerId& id, std::list &proxy bool p3discovery2::getWaitingDiscCount(size_t &sendCount, size_t &recvCount) { RS_STACK_MUTEX(mDiscMtx); - sendCount = mPendingDiscPgpCertOutList.size(); - recvCount = mPendingDiscPgpCertInList.size(); + sendCount = 0;//mPendingDiscPgpCertOutList.size(); + recvCount = 0;//mPendingDiscPgpCertInList.size(); return true; } - - -bool p3discovery2::getDiscPgpFriends(const PGPID &pgp_id, std::list &proxyPgpIds) + +bool p3discovery2::getDiscPgpFriends(const RsPgpId &pgp_id, std::list &proxyPgpIds) { /* find id -> and extract the neighbour_of ids */ @@ -1221,7 +1234,7 @@ bool p3discovery2::getDiscPgpFriends(const PGPID &pgp_id, std::list &prox RsStackMutex stack(mDiscMtx); /********** STACK LOCKED MTX ******/ - std::map::const_iterator it; + std::map::const_iterator it; it = mFriendList.find(pgp_id); if (it == mFriendList.end()) { @@ -1229,20 +1242,19 @@ bool p3discovery2::getDiscPgpFriends(const PGPID &pgp_id, std::list &prox return false; } - std::set::const_iterator fit; + std::set::const_iterator fit; for(fit = it->second.mFriendSet.begin(); fit != it->second.mFriendSet.end(); ++fit) { proxyPgpIds.push_back(*fit); } return true; } - - -bool p3discovery2::getPeerVersion(const SSLID &peerId, std::string &version) + +bool p3discovery2::getPeerVersion(const RsPeerId &peerId, std::string &version) { RsStackMutex stack(mDiscMtx); /********** STACK LOCKED MTX ******/ - std::map::const_iterator it; + std::map::const_iterator it; it = mLocationMap.find(peerId); if (it == mLocationMap.end()) { @@ -1253,13 +1265,12 @@ bool p3discovery2::getPeerVersion(const SSLID &peerId, std::string &version) version = it->second.mVersion; return true; } - - -bool p3discovery2::setPeerVersion(const SSLID &peerId, const std::string &version) + +bool p3discovery2::setPeerVersion(const RsPeerId &peerId, const std::string &version) { RsStackMutex stack(mDiscMtx); /********** STACK LOCKED MTX ******/ - std::map::iterator it; + std::map::iterator it; it = mLocationMap.find(peerId); if (it == mLocationMap.end()) { @@ -1270,77 +1281,75 @@ bool p3discovery2::setPeerVersion(const SSLID &peerId, const std::string &versio it->second.mVersion = version; return true; } - + +void p3discovery2::rsEventsHandler(const RsEvent& event) +{ + Dbg3() << __PRETTY_FUNCTION__ << " " << static_cast(event.mType) << std::endl; +} + /*************************************************************************************/ /* AuthGPGService */ /*************************************************************************************/ -AuthGPGOperation *p3discovery2::getGPGOperation() -{ - { - RsStackMutex stack(mDiscMtx); /********** STACK LOCKED MTX ******/ +// AuthGPGOperation *p3discovery2::getGPGOperation() +// { +// { +// RsStackMutex stack(mDiscMtx); /********** STACK LOCKED MTX ******/ +// +// /* process disc reply in list */ +// if (!mPendingDiscPgpCertInList.empty()) { +// RsDiscPgpCertItem *item = mPendingDiscPgpCertInList.front(); +// mPendingDiscPgpCertInList.pop_front(); +// +// return new AuthGPGOperationLoadOrSave(true, item->pgpId, item->pgpCert, item); +// } +// } +// +// return NULL; +// } - /* process disc reply in list */ - if (!mPendingDiscPgpCertInList.empty()) { - RsDiscPgpCertItem *item = mPendingDiscPgpCertInList.front(); - mPendingDiscPgpCertInList.pop_front(); - - return new AuthGPGOperationLoadOrSave(true, item->pgpId, item->pgpCert, item); - } - } - - { - RsStackMutex stack(mDiscMtx); /********** STACK LOCKED MTX ******/ - - /* process disc reply in list */ - if (!mPendingDiscPgpCertOutList.empty()) { - RsDiscPgpCertItem *item = mPendingDiscPgpCertOutList.front(); - mPendingDiscPgpCertOutList.pop_front(); - - return new AuthGPGOperationLoadOrSave(false, item->pgpId, "", item); - } - } - return NULL; -} - -void p3discovery2::setGPGOperation(AuthGPGOperation *operation) -{ - AuthGPGOperationLoadOrSave *loadOrSave = dynamic_cast(operation); - if (loadOrSave) - { - RsDiscPgpCertItem *item = (RsDiscPgpCertItem *) loadOrSave->m_userdata; - if (!item) - { - return; - } - - if (loadOrSave->m_load) - { - -#ifdef P3DISC_DEBUG - std::cerr << "p3discovery2::setGPGOperation() Loaded Cert" << std::endl; - item->print(std::cerr, 5); - std::cerr << std::endl; -#endif - // It has already been processed by PGP. - delete item; - } - else - { - // Attaching Certificate. - item->pgpCert = loadOrSave->m_certGpg; - -#ifdef P3DISC_DEBUG - std::cerr << "p3discovery2::setGPGOperation() Sending Message:" << std::endl; - item->print(std::cerr, 5); -#endif - - // Send off message - sendItem(item); - } - return; - } - - /* ignore other operations */ -} +// void p3discovery2::setGPGOperation(AuthGPGOperation *operation) +// { +// AuthGPGOperationLoadOrSave *loadOrSave = dynamic_cast(operation); +// if (loadOrSave) +// { +// RsDiscPgpCertItem *item = (RsDiscPgpCertItem *) loadOrSave->m_userdata; +// if (!item) +// { +// return; +// } +// +// if (loadOrSave->m_load) +// { +// +// #ifdef P3DISC_DEBUG +// std::cerr << "p3discovery2::setGPGOperation() Loaded Cert" << std::endl; +// item->print(std::cerr, 5); +// std::cerr << std::endl; +// #endif +// // It has already been processed by PGP. +// delete item; +// } +// else +// { +// // Attaching Certificate. +// item->pgpCert = loadOrSave->m_certGpg; +// +// #ifdef P3DISC_DEBUG +// std::cerr << "p3discovery2::setGPGOperation() Sending Message:" << std::endl; +// item->print(std::cerr, 5); +// #endif +// +// // Send off message +// sendItem(item); +// } +// return; +// } +// +// /* ignore other operations */ +// } +// (cyril) do we still need this?? +RsGossipDiscoveryFriendInviteReceivedEvent::RsGossipDiscoveryFriendInviteReceivedEvent(const std::string& invite) : + RsEvent(RsEventType::GOSSIP_DISCOVERY_INVITE_RECEIVED), + mInvite(invite) {} diff --git a/libretroshare/src/gossipdiscovery/p3gossipdiscovery.h b/libretroshare/src/gossipdiscovery/p3gossipdiscovery.h new file mode 100644 index 000000000..95773df69 --- /dev/null +++ b/libretroshare/src/gossipdiscovery/p3gossipdiscovery.h @@ -0,0 +1,222 @@ +/******************************************************************************* + * RetroShare gossip discovery service implementation * + * * + * libretroshare: retroshare core library * + * * + * Copyright (C) 2004-2013 Robert Fernie * + * Copyright (C) 2019 Gioacchino Mazzurco * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ +#pragma once + +// +// p3GossipDiscovery is reponsible for facilitating the circulation of public keys between friend nodes. +// +// The service locally holds a cache that stores: +// * the list of friend profiles, in each of which the list of locations with their own discovery flag (which means whether they allow discovery or not) +// * the list of friend nodes, with their version number +// +// Data flow +// ========= +// +// statusChange(std::list&) // called by pqiMonitor when peers are added,removed, or recently connected +// | +// +---- sendOwnContactInfo(RsPeerId) // [On connection] sends own PgpId, discovery flag, list of own signed GxsIds +// | | +// | +---->[to friend] +// | +// +---- locally add/remove cache info // [New/Removed friend] updates the list of friends, along with their own discovery flag +// +// tick() +// | +// +------ handleIncoming() +// | +// +-- recvOwnContactInfo(RsPeerId) // update location, IP addresses of a peer. +// | | +// | +------(if the peer has short_invite flag) +// | | | +// | | +---------requestPGPKey()->[to friend] // requests the full PGP public key, so as to be +// | | // able to validate connections. +// | | +// | +------(if disc != RS_VS_DISC_OFF) +// | | +// | +---------sendPgpList()->[to friend] // sends own list of friend profiles for which at least one location +// | // accepts discovery +// +-- processContactInfo(item->PeerId(), contact); +// | | +// | +------ addFriend() // called on nodes signed by the PGP key mentionned in the disc info +// | | +// | +------ update local discovery info +// | +// +-- recvIdentityList(Gxs Identity List) +// | | +// | +------ mGixs->requestKey(*it,peers,use_info) ; // requestKey() takes care of requesting the GxsIds that are missing +// | +// +-- recvPGPCertificate(item->PeerId(), pgpkey); +// | | +// | +------(if peer has short invite flag) +// | | +// | +--------- add key to keyring, accept connections and notify peerMgr +// | +// +-- processPGPList(pgplist->PeerId(), pgplist); // list of PGP keys of a friend, received from himself +// | | +// | +------ requestPgpCertificate() // request missing keys only +// | | +// | +------ updatePeers_locked(fromId) +// | | +// | +--------- sendContactInfo_locked(from,to) // sends IP information about mutual friends to the origin of the info +// | | +// | +--------- sendContactInfo_locked(to,from) // sends IP information origin to online mutual friends +// | +// +-- recvPGPCertificateRequest(pgplist->PeerId(), pgplist); +// | +// +------ sendPGPCertificate() // only sends the ones we are friend with, and only send own cert +// // if discovery is off +// +// Notes: +// * Tor nodes never send their own IP, and normal nodes never send their IP to Tor nodes either. +// A Tor node may accidentally know the IP of a normal node when it adds its certificate. However, the IP is dropped and not saved in this case. +// Generally speaking, no IP information should leave or transit through a Tor node. +// +// * the decision to call recvOwnContactInfo() or processContactInfo() depends on whether the item's peer id is the one the info is about. This is +// a bit unsafe. We should probably have to different items here especially if the information is not exactly the same. +// +#include + +#include "retroshare/rsgossipdiscovery.h" +#include "pqi/p3peermgr.h" +#include "pqi/p3linkmgr.h" +#include "pqi/p3netmgr.h" +#include "pqi/pqiservicemonitor.h" +#include "gossipdiscovery/gossipdiscoveryitems.h" +#include "services/p3service.h" +#include "pqi/authgpg.h" +#include "gxs/rsgixs.h" + +class p3ServiceControl; + +struct DiscSslInfo +{ + DiscSslInfo() : mDiscStatus(RS_VS_DISC_OFF) {} // default is to not allow discovery, until the peer tells about it + uint16_t mDiscStatus; +}; + +struct DiscPeerInfo +{ + DiscPeerInfo() {} + + std::string mVersion; +}; + +struct DiscPgpInfo +{ + DiscPgpInfo() {} + + void mergeFriendList(const std::set &friends); + + std::set mFriendSet; + std::map mSslIds; +}; + + +class p3discovery2 : + public RsGossipDiscovery, public p3Service, public pqiServiceMonitor + //public AuthGPGService +{ +public: + + p3discovery2( p3PeerMgr* peerMgr, p3LinkMgr* linkMgr, p3NetMgr* netMgr, + p3ServiceControl* sc, RsGixs* gixs ); + virtual ~p3discovery2(); + +virtual RsServiceInfo getServiceInfo(); + + /************* from pqiServiceMonitor *******************/ + virtual void statusChange(const std::list &plist); + /************* from pqiServiceMonitor *******************/ + + int tick(); + + /* external interface */ + bool getDiscFriends(const RsPeerId &id, std::list &friends); + bool getDiscPgpFriends(const RsPgpId &pgpid, std::list &gpg_friends); + bool getPeerVersion(const RsPeerId &id, std::string &version); + bool getWaitingDiscCount(size_t &sendCount, size_t &recvCount); + + /************* from AuthGPService ****************/ + // virtual AuthGPGOperation *getGPGOperation(); + // virtual void setGPGOperation(AuthGPGOperation *operation); + + +private: + + RsPgpId getPGPId(const RsPeerId &id); + + int handleIncoming(); + void updatePgpFriendList(); + + void addFriend(const RsPeerId &sslId); + void removeFriend(const RsPeerId &sslId); + + void updatePeerAddresses(const RsDiscContactItem *item); + void updatePeerAddressList(const RsDiscContactItem *item); + + void sendOwnContactInfo(const RsPeerId &sslid); + void recvOwnContactInfo(const RsPeerId &fromId, const RsDiscContactItem *item); + + void sendPGPList(const RsPeerId &toId); + void processPGPList(const RsPeerId &fromId, const RsDiscPgpListItem *item); + + void processContactInfo(const RsPeerId &fromId, const RsDiscContactItem *info); + + // send/recv information + + void requestPGPCertificate(const RsPgpId &aboutId, const RsPeerId &toId); + void recvPGPCertificateRequest(const RsPeerId& fromId, const RsDiscPgpListItem* item ); + void sendPGPCertificate(const RsPgpId &aboutId, const RsPeerId &toId); + void recvPGPCertificate(const RsPeerId &fromId, RsDiscPgpKeyItem *item); + void recvIdentityList(const RsPeerId& pid,const std::list& ids); + + bool setPeerVersion(const RsPeerId &peerId, const std::string &version); + + void rsEventsHandler(const RsEvent& event); + RsEventsHandlerId_t mRsEventsHandle; + + p3PeerMgr *mPeerMgr; + p3LinkMgr *mLinkMgr; + p3NetMgr *mNetMgr; + p3ServiceControl *mServiceCtrl; + RsGixs* mGixs; + + /* data */ + RsMutex mDiscMtx; + + void updatePeers_locked(const RsPeerId &aboutId); + void sendContactInfo_locked(const RsPgpId &aboutId, const RsPeerId &toId); + + rstime_t mLastPgpUpdate; + + std::map mFriendList; + std::map mLocationMap; + +// This was used to async the receiving of PGP keys, mainly because PGPHandler cross-checks all signatures, so receiving these keys in large loads can be costly +// Because discovery is not running in the main thread, there's no reason to re-async this into another process (e.g. AuthGPG) +// +// std::list mPendingDiscPgpCertInList; + +protected: + RS_SET_CONTEXT_DEBUG_LEVEL(1) +}; diff --git a/libretroshare/src/gxs/rsgenexchange.cc b/libretroshare/src/gxs/rsgenexchange.cc index c5da0df55..2ac0736e5 100644 --- a/libretroshare/src/gxs/rsgenexchange.cc +++ b/libretroshare/src/gxs/rsgenexchange.cc @@ -3,7 +3,8 @@ * * * libretroshare: retroshare core library * * * - * Copyright 2012-2012 by Robert Fernie, Evi-Parker Christopher * + * Copyright (C) 2012 Christopher Evi-Parker * + * Copyright (C) 2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -36,6 +37,7 @@ #include "rsgixs.h" #include "rsgxsutil.h" #include "rsserver/p3face.h" +#include "retroshare/rsevents.h" #include @@ -64,10 +66,11 @@ static const uint32_t INDEX_AUTHEN_ADMIN = 0x00000040; // admin key static const uint32_t MSG_CLEANUP_PERIOD = 60*59; // 59 minutes static const uint32_t INTEGRITY_CHECK_PERIOD = 60*31; // 31 minutes -RsGenExchange::RsGenExchange(RsGeneralDataService *gds, RsNetworkExchangeService *ns, - RsSerialType *serviceSerialiser, uint16_t servType, RsGixs* gixs, - uint32_t authenPolicy) - : mGenMtx("GenExchange"), +RsGenExchange::RsGenExchange( + RsGeneralDataService* gds, RsNetworkExchangeService* ns, + RsSerialType* serviceSerialiser, uint16_t servType, RsGixs* gixs, + uint32_t authenPolicy ) : + mGenMtx("GenExchange"), mDataStore(gds), mNetService(ns), mSerialiser(serviceSerialiser), @@ -1097,7 +1100,10 @@ void RsGenExchange::receiveChanges(std::vector& changes) #ifdef GEN_EXCH_DEBUG std::cerr << "RsGenExchange::receiveChanges()" << std::endl; #endif - RsGxsChanges out; + std::unique_ptr evt(new RsGxsChanges); + evt->mServiceType = static_cast(mServType); + + RsGxsChanges& out = *evt; out.mService = getTokenService(); // collect all changes in one GxsChanges object @@ -1109,7 +1115,7 @@ void RsGenExchange::receiveChanges(std::vector& changes) RsGxsMsgChange* mc; RsGxsDistantSearchResultChange *gt; - if((mc = dynamic_cast(n)) != NULL) + if((mc = dynamic_cast(n)) != nullptr) { if (mc->metaChange()) { @@ -1120,7 +1126,7 @@ void RsGenExchange::receiveChanges(std::vector& changes) addMessageChanged(out.mMsgs, mc->msgChangeMap); } } - else if((gc = dynamic_cast(n)) != NULL) + else if((gc = dynamic_cast(n)) != nullptr) { if(gc->metaChange()) { @@ -1131,18 +1137,20 @@ void RsGenExchange::receiveChanges(std::vector& changes) out.mGrps.splice(out.mGrps.end(), gc->mGrpIdList); } } - else if((gt = dynamic_cast(n)) != NULL) + else if(( gt = + dynamic_cast(n) ) != nullptr) { out.mDistantSearchReqs.push_back(gt->mRequestId); } else - std::cerr << "(EE) Unknown changes type!!" << std::endl; - + RsErr() << __PRETTY_FUNCTION__ << " Unknown changes type!" + << std::endl; delete n; } changes.clear() ; - - RsServer::notify()->notifyGxsChange(out); + + RsServer::notify()->notifyGxsChange(out); + if(rsEvents) rsEvents->postEvent(std::move(evt)); } bool RsGenExchange::subscribeToGroup(uint32_t& token, const RsGxsGroupId& grpId, bool subscribe) @@ -1154,8 +1162,7 @@ bool RsGenExchange::subscribeToGroup(uint32_t& token, const RsGxsGroupId& grpId, setGroupSubscribeFlags(token, grpId, GXS_SERV::GROUP_SUBSCRIBE_NOT_SUBSCRIBED, (GXS_SERV::GROUP_SUBSCRIBE_SUBSCRIBED | GXS_SERV::GROUP_SUBSCRIBE_NOT_SUBSCRIBED)); - if(mNetService != NULL) - mNetService->subscribeStatusChanged(grpId,subscribe) ; + if(mNetService) mNetService->subscribeStatusChanged(grpId,subscribe); #ifdef GEN_EXCH_DEBUG else std::cerr << "(EE) No mNetService in RsGenExchange for service 0x" << std::hex << mServType << std::dec << std::endl; @@ -3437,3 +3444,7 @@ bool RsGenExchange::localSearch( const std::string& matchString, { return mNetService->search(matchString, results); } + +RsGxsChanges::RsGxsChanges() : + RsEvent(RsEventType::GXS_CHANGES), mServiceType(RsServiceType::NONE), + mService(nullptr) {} diff --git a/libretroshare/src/gxs/rsgenexchange.h b/libretroshare/src/gxs/rsgenexchange.h index 70bcc1fb7..f2efd9b66 100644 --- a/libretroshare/src/gxs/rsgenexchange.h +++ b/libretroshare/src/gxs/rsgenexchange.h @@ -113,7 +113,10 @@ public: * @param gixs This is used for verification of msgs and groups received by Gen Exchange using identities. * @param authenPolicy This determines the authentication used for verfying authorship of msgs and groups */ - RsGenExchange(RsGeneralDataService* gds, RsNetworkExchangeService* ns, RsSerialType* serviceSerialiser, uint16_t mServType, RsGixs* gixs, uint32_t authenPolicy); + RsGenExchange( + RsGeneralDataService* gds, RsNetworkExchangeService* ns, + RsSerialType* serviceSerialiser, uint16_t mServType, RsGixs* gixs, + uint32_t authenPolicy ); virtual ~RsGenExchange(); diff --git a/libretroshare/src/gxs/rsgixs.h b/libretroshare/src/gxs/rsgixs.h index 0175bbda9..76581fe4f 100644 --- a/libretroshare/src/gxs/rsgixs.h +++ b/libretroshare/src/gxs/rsgixs.h @@ -92,8 +92,6 @@ * as these will be used very frequently. *****/ -typedef PGPIdType RsPgpId; - /* Identity Interface for GXS Message Verification. */ class RsGixs diff --git a/libretroshare/src/gxs/rsgxsnetutils.cc b/libretroshare/src/gxs/rsgxsnetutils.cc index 6f80cc261..41402c9eb 100644 --- a/libretroshare/src/gxs/rsgxsnetutils.cc +++ b/libretroshare/src/gxs/rsgxsnetutils.cc @@ -217,7 +217,9 @@ bool GrpCircleVetting::expired() { return time(NULL) > (mTimeStamp + EXPIRY_PERIOD_OFFSET); } -bool GrpCircleVetting::canSend(const SSLIdType& peerId, const RsGxsCircleId& circleId,bool& should_encrypt) +bool GrpCircleVetting::canSend( + const RsPeerId& peerId, const RsGxsCircleId& circleId, + bool& should_encrypt ) { if(mCircles->isLoaded(circleId)) { diff --git a/libretroshare/src/gxs/rsgxsutil.cc b/libretroshare/src/gxs/rsgxsutil.cc index de7644ab4..14b93cda8 100644 --- a/libretroshare/src/gxs/rsgxsutil.cc +++ b/libretroshare/src/gxs/rsgxsutil.cc @@ -146,9 +146,16 @@ bool RsGxsMessageCleanUp::clean() } RsGxsIntegrityCheck::RsGxsIntegrityCheck( - RsGeneralDataService* const dataService, RsGenExchange* genex, - RsSerialType& serializer, RsGixs* gixs ) : - mDs(dataService), mGenExchangeClient(genex), mSerializer(serializer), + RsGeneralDataService* const dataService, RsGenExchange* genex, + RsSerialType& +#ifdef RS_DEEP_SEARCH + serializer +#endif + , RsGixs* gixs ) + : mDs(dataService), mGenExchangeClient(genex), +#ifdef RS_DEEP_SEARCH + mSerializer(serializer), +#endif mDone(false), mIntegrityMutex("integrity"), mGixs(gixs) {} void RsGxsIntegrityCheck::run() diff --git a/libretroshare/src/gxs/rsgxsutil.h b/libretroshare/src/gxs/rsgxsutil.h index d4770303e..c1a610a3d 100644 --- a/libretroshare/src/gxs/rsgxsutil.h +++ b/libretroshare/src/gxs/rsgxsutil.h @@ -21,8 +21,7 @@ * * *******************************************************************************/ -#ifndef GXSUTIL_H_ -#define GXSUTIL_H_ +#pragma once #include #include "rsitems/rsnxsitems.h" @@ -214,8 +213,9 @@ private: RsGeneralDataService* const mDs; RsGenExchange *mGenExchangeClient; +#ifdef RS_DEEP_SEARCH RsSerialType& mSerializer; - +#endif bool mDone; RsMutex mIntegrityMutex; std::list mDeletedGrps; @@ -262,5 +262,3 @@ public: GxsMsgReq mMsgs ; uint32_t mToken; }; - -#endif /* GXSUTIL_H_ */ diff --git a/libretroshare/src/gxstrans/p3gxstrans.cc b/libretroshare/src/gxstrans/p3gxstrans.cc index 899dcd177..85292c383 100644 --- a/libretroshare/src/gxstrans/p3gxstrans.cc +++ b/libretroshare/src/gxstrans/p3gxstrans.cc @@ -3,7 +3,7 @@ * * * libretroshare: retroshare core library * * * - * Copyright (C) 2016-2017 Gioacchino Mazzurco * + * Copyright (C) 2016-2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -22,12 +22,13 @@ #include "util/rsdir.h" #include "gxstrans/p3gxstrans.h" #include "util/stacktrace.h" +#include "util/rsdebug.h" //#define DEBUG_GXSTRANS 1 typedef unsigned int uint; -RsGxsTrans *rsGxsTrans = NULL ; +/*extern*/ RsGxsTrans* rsGxsTrans = nullptr; const uint32_t p3GxsTrans::MAX_DELAY_BETWEEN_CLEANUPS = 900; // every 15 mins. Could be less. @@ -240,10 +241,7 @@ void p3GxsTrans::handleResponse(uint32_t token, uint32_t req_type) if(!have_preferred_group) { /* This is true only at first run when we haven't received mail - * distribuition groups from friends - * TODO: We should check if we have some connected friend too, to - * avoid to create yet another never used mail distribution group. - */ + * distribuition groups from friends */ #ifdef DEBUG_GXSTRANS std::cerr << "p3GxsTrans::handleResponse(...) preferredGroupId.isNu" @@ -533,6 +531,14 @@ void p3GxsTrans::service_tick() for(std::map::const_iterator it(per_user_statistics.begin());it!=per_user_statistics.end();++it) std::cerr << " " << it->first << ": " << it->second.count << " " << it->second.size << std::endl; #endif + // Waiting here is very important because the thread may still be updating its semaphores after setting isDone() to true + // If we delete it during this operation it will corrupt the stack and cause unpredictable errors. + + while(mCleanupThread->isRunning()) + { + std::cerr << "Waiting for mCleanupThread to terminate..." << std::endl; + rstime::rs_usleep(500*1000); + } delete mCleanupThread; mCleanupThread=NULL ; @@ -613,9 +619,10 @@ void p3GxsTrans::service_tick() } else { - /* TODO: It is a receipt for a message sent by someone else + /* It is a receipt for a message sent by someone else * we can delete original mail from our GXS DB without - * waiting for GXS_STORAGE_PERIOD */ + * waiting for GXS_STORAGE_PERIOD, this has been implemented + * already by Cyril into GxsTransIntegrityCleanupThread */ } break; } @@ -956,9 +963,9 @@ void p3GxsTrans::locked_processOutgoingRecord(OutgoingRecord& pr) { case RsGxsTransEncryptionMode::CLEAR_TEXT: { - std::cerr << "p3GxsTrans::sendMail(...) you are sending a mail " - << "without encryption, everyone can read it!" - << std::endl; + RsWarn() << __PRETTY_FUNCTION__ << " you are sending a mail " + << "without encryption, everyone can read it!" + << std::endl; break; } case RsGxsTransEncryptionMode::RSA: @@ -978,15 +985,15 @@ void p3GxsTrans::locked_processOutgoingRecord(OutgoingRecord& pr) } else { - std::cerr << "p3GxsTrans::sendMail(...) RSA encryption failed! " - << "error_status: " << encryptError << std::endl; + RsErr() << __PRETTY_FUNCTION__ << " RSA encryption failed! " + << "error_status: " << encryptError << std::endl; pr.status = GxsTransSendStatus::FAILED_ENCRYPTION; goto processingFailed; } } case RsGxsTransEncryptionMode::UNDEFINED_ENCRYPTION: default: - std::cerr << "p3GxsTrans::sendMail(...) attempt to send mail with " + RsErr() << __PRETTY_FUNCTION__ << " attempt to send mail with " << "wrong EncryptionMode: " << static_cast(pr.mailItem.cryptoType) << " dropping mail!" << std::endl; @@ -1032,7 +1039,8 @@ void p3GxsTrans::locked_processOutgoingRecord(OutgoingRecord& pr) { RS_STACK_MUTEX(mIngoingMutex); auto range = mIncomingQueue.equal_range(pr.mailItem.mailId); - bool changed = false ; + bool changed = false; + bool received = false; for( auto it = range.first; it != range.second; ++it) { @@ -1043,14 +1051,21 @@ void p3GxsTrans::locked_processOutgoingRecord(OutgoingRecord& pr) mIncomingQueue.erase(it); delete rt; pr.status = GxsTransSendStatus::RECEIPT_RECEIVED; - changed = true ; + changed = true; + received = true; break; } } + + if(!received && time(nullptr) - pr.sent_ts > GXS_STORAGE_PERIOD) + { + changed = true; + pr.status = GxsTransSendStatus::FAILED_TIMED_OUT; + } + if(changed) IndicateConfigChanged(); - // TODO: Resend message if older then treshold break; } case GxsTransSendStatus::RECEIPT_RECEIVED: @@ -1059,14 +1074,13 @@ void p3GxsTrans::locked_processOutgoingRecord(OutgoingRecord& pr) processingFailed: case GxsTransSendStatus::FAILED_RECEIPT_SIGNATURE: case GxsTransSendStatus::FAILED_ENCRYPTION: + case GxsTransSendStatus::FAILED_TIMED_OUT: default: - { - std::cout << "p3GxsTrans::processRecord(" << pr.mailItem.mailId - << ") failed with: " << static_cast(pr.status) + RsErr() << __PRETTY_FUNCTION__ << " processing:" << pr.mailItem.mailId + << " failed with: " << static_cast(pr.status) << std::endl; break; } - } } void p3GxsTrans::notifyClientService(const OutgoingRecord& pr) diff --git a/libretroshare/src/gxstrans/p3gxstrans.h b/libretroshare/src/gxstrans/p3gxstrans.h index c730d8177..32b07e1b9 100644 --- a/libretroshare/src/gxstrans/p3gxstrans.h +++ b/libretroshare/src/gxstrans/p3gxstrans.h @@ -3,7 +3,7 @@ * * * libretroshare: retroshare core library * * * - * Copyright (C) 2016-2017 Gioacchino Mazzurco * + * Copyright (C) 2016-2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -21,7 +21,7 @@ *******************************************************************************/ #pragma once -#include +#include #include #include @@ -70,7 +70,7 @@ struct MsgSizeCount }; /** - * @brief p3GxsTrans is a mail delivery service based on GXS. + * @brief p3GxsTrans asyncronous redundant small mail trasport on top of GXS. * p3GxsTrans is capable of asynchronous mail delivery and acknowledgement. * p3GxsTrans is meant to be capable of multiple encryption options, * @see RsGxsTransEncryptionMode at moment messages are encrypted using RSA diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.cc b/libretroshare/src/gxstunnel/p3gxstunnel.cc index d5e3b3a90..ba8bcede2 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.cc +++ b/libretroshare/src/gxstunnel/p3gxstunnel.cc @@ -1062,7 +1062,7 @@ void p3GxsTunnelService::handleRecvDHPublicKey(RsGxsTunnelDHPublicKeyItem *item) // Note: for some obscure reason, the typedef does not work here. Looks like a compiler error. So I use the primary type. -/*static*/ GXSTunnelId p3GxsTunnelService::makeGxsTunnelId( +/*static*/ RsGxsTunnelId p3GxsTunnelService::makeGxsTunnelId( const RsGxsId &own_id, const RsGxsId &distant_id ) { unsigned char mem[RsGxsId::SIZE_IN_BYTES * 2] ; diff --git a/libretroshare/src/jsonapi/jsonapi.cpp b/libretroshare/src/jsonapi/jsonapi.cpp index a6293d00f..be808b163 100644 --- a/libretroshare/src/jsonapi/jsonapi.cpp +++ b/libretroshare/src/jsonapi/jsonapi.cpp @@ -1,20 +1,19 @@ /******************************************************************************* - * libretroshare/src/gxs: jsonapi.cpp * - * * * RetroShare JSON API * - * Copyright (C) 2018 Gioacchino Mazzurco * + * * + * Copyright (C) 2018-2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License as * + * it under the terms of the GNU Affero General Public License as * * published by the Free Software Foundation, either version 3 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU Lesser General Public License for more details. * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * * * - * You should have received a copy of the GNU Lesser General Public License * + * You should have received a copy of the GNU Affero General Public License * * along with this program. If not, see . * * * *******************************************************************************/ @@ -38,6 +37,7 @@ #include "retroshare/rsinit.h" #include "util/rsurl.h" #include "util/rstime.h" +#include "retroshare/rsevents.h" // Generated at compile time #include "jsonapi-includes.inl" @@ -96,7 +96,7 @@ JsonApiServer::corsOptionsHeaders = /*static*/ bool JsonApiServer::checkRsServicePtrReady( - void* serviceInstance, const std::string& serviceName, + const void* serviceInstance, const std::string& serviceName, RsGenericSerializer::SerializeContext& ctx, const std::shared_ptr session) { @@ -279,6 +279,69 @@ JsonApiServer::JsonApiServer(uint16_t port, const std::string& bindAddress, } ); }, true); + registerHandler("/rsEvents/registerEventsHandler", + [this](const std::shared_ptr session) + { + const std::multimap headers + { + { "Connection", "keep-alive" }, + { "Content-Type", "text/event-stream" } + }; + session->yield(rb::OK, headers); + + size_t reqSize = static_cast( + session->get_request()->get_header("Content-Length", 0) ); + session->fetch( reqSize, [this]( + const std::shared_ptr session, + const rb::Bytes& body ) + { + INITIALIZE_API_CALL_JSON_CONTEXT; + + if( !checkRsServicePtrReady( + rsEvents, "rsEvents", cAns, session ) ) + return; + + const std::weak_ptr weakSession(session); + RsEventsHandlerId_t hId = rsEvents->generateUniqueHandlerId(); + std::function)> multiCallback = + [this, weakSession, hId](std::shared_ptr event) + { + mService.schedule( [weakSession, hId, event]() + { + auto session = weakSession.lock(); + if(!session || session->is_closed()) + { + if(rsEvents) rsEvents->unregisterEventsHandler(hId); + return; + } + + RsGenericSerializer::SerializeContext ctx; + RsTypeSerializer::serial_process( + RsGenericSerializer::TO_JSON, ctx, + *const_cast(event.get()), "event" ); + + std::stringstream message; + message << "data: " << compactJSON << ctx.mJson << "\n\n"; + + session->yield(message.str()); + } ); + }; + + bool retval = rsEvents->registerEventsHandler(multiCallback, hId); + + { + RsGenericSerializer::SerializeContext& ctx(cAns); + RsGenericSerializer::SerializeJob j(RsGenericSerializer::TO_JSON); + RS_SERIAL_PROCESS(retval); + } + + // return them to the API caller + std::stringstream message; + message << "data: " << compactJSON << cAns.mJson << "\n\n"; + session->yield(message.str()); + } ); + }, true); + // Generated at compile time #include "jsonapi-wrappers.inl" } diff --git a/libretroshare/src/jsonapi/jsonapi.h b/libretroshare/src/jsonapi/jsonapi.h index 1622bf49b..886687917 100644 --- a/libretroshare/src/jsonapi/jsonapi.h +++ b/libretroshare/src/jsonapi/jsonapi.h @@ -1,24 +1,22 @@ /******************************************************************************* - * libretroshare/src/gxs: jsonapi.h * - * * * RetroShare JSON API * - * Copyright (C) 2018 Gioacchino Mazzurco * + * * + * Copyright (C) 2018-2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License as * + * it under the terms of the GNU Affero General Public License as * * published by the Free Software Foundation, either version 3 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU Lesser General Public License for more details. * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * * * - * You should have received a copy of the GNU Lesser General Public License * + * You should have received a copy of the GNU Affero General Public License * * along with this program. If not, see . * * * *******************************************************************************/ - #pragma once #include @@ -54,6 +52,8 @@ extern JsonApiServer* jsonApiServer; */ struct JsonApiServer : RsSingleJobThread, p3Config { + static const uint16_t DEFAULT_PORT = 9092 ; + /** * @brief construct a JsonApiServer instance with given parameters * @param[in] port listening port fpt the JSON API socket @@ -64,7 +64,7 @@ struct JsonApiServer : RsSingleJobThread, p3Config * false otherwise, this usually requires user interacion to confirm access */ JsonApiServer( - uint16_t port = 9092, + uint16_t port = DEFAULT_PORT, const std::string& bindAddress = "127.0.0.1", const std::function newAccessRequestCallback = [](const std::string&){return false;} ); @@ -199,8 +199,18 @@ private: static void handleCorsOptions(const std::shared_ptr session); static bool checkRsServicePtrReady( - void* serviceInstance, const std::string& serviceName, + const void* serviceInstance, const std::string& serviceName, RsGenericSerializer::SerializeContext& ctx, const std::shared_ptr session ); + + static inline bool checkRsServicePtrReady( + const std::shared_ptr serviceInstance, + const std::string& serviceName, + RsGenericSerializer::SerializeContext& ctx, + const std::shared_ptr session ) + { + return checkRsServicePtrReady( + serviceInstance.get(), serviceName, ctx, session ); + } }; diff --git a/libretroshare/src/jsonapi/jsonapiitems.h b/libretroshare/src/jsonapi/jsonapiitems.h index 14173675d..4c67bf79c 100644 --- a/libretroshare/src/jsonapi/jsonapiitems.h +++ b/libretroshare/src/jsonapi/jsonapiitems.h @@ -1,24 +1,22 @@ /******************************************************************************* - * libretroshare/src/gxs: jsonapiitems.h * - * * * RetroShare JSON API * - * Copyright (C) 2018 Gioacchino Mazzurco * + * * + * Copyright (C) 2018-2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License as * + * it under the terms of the GNU Affero General Public License as * * published by the Free Software Foundation, either version 3 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU Lesser General Public License for more details. * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * * * - * You should have received a copy of the GNU Lesser General Public License * + * You should have received a copy of the GNU Affero General Public License * * along with this program. If not, see . * * * *******************************************************************************/ - #pragma once #include diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index 0d9d6fd76..248ff5563 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -108,7 +108,7 @@ SOURCES += tcponudp/udppeer.cc \ tcponudp/tcppacket.cc \ tcponudp/tcpstream.cc \ tcponudp/tou.cc \ - tcponudp/bss_tou.c \ + tcponudp/bss_tou.cc \ tcponudp/udprelay.cc \ pqi/pqissludp.cc \ @@ -134,6 +134,8 @@ SOURCES += tcponudp/udppeer.cc \ PUBLIC_HEADERS = retroshare/rsdisc.h \ + retroshare/rsgossipdiscovery \ + retroshare/rsevents.h \ retroshare/rsexpr.h \ retroshare/rsfiles.h \ retroshare/rshistory.h \ @@ -193,13 +195,13 @@ linux-* { } } - # Check if the systems libupnp has been Debian-patched - system(grep -E 'char[[:space:]]+PublisherUrl' /usr/include/upnp/upnp.h >/dev/null 2>&1) { - # Normal libupnp - } else { - # Patched libupnp or new unreleased version - DEFINES *= PATCHED_LIBUPNP - } + contains(RS_UPNP_LIB, threadutil) { # ensure we don't break libpnp-1.8.x + # Check if the systems libupnp-1.6.x has been Debian-patched + !system(grep -E 'char[[:space:]]+PublisherUrl' /usr/include/upnp/upnp.h >/dev/null 2>&1) { + # Patched libupnp or new unreleased version + DEFINES *= PATCHED_LIBUPNP + } + } PKGCONFIG *= libssl equals(RS_UPNP_LIB, "upnp ixml threadutil"):PKGCONFIG *= libupnp @@ -451,7 +453,7 @@ HEADERS += rsitems/rsitem.h \ serialiser/rstlvbanlist.h \ rsitems/rsbanlistitems.h \ rsitems/rsbwctrlitems.h \ - rsitems/rsdiscovery2items.h \ + gossipdiscovery/gossipdiscoveryitems.h \ rsitems/rsheartbeatitems.h \ rsitems/rsrttitems.h \ rsitems/rsgxsrecognitems.h \ @@ -459,13 +461,14 @@ HEADERS += rsitems/rsitem.h \ rsitems/rsserviceinfoitems.h \ HEADERS += services/autoproxy/p3i2pbob.h \ + services/rseventsservice.h \ services/autoproxy/rsautoproxymonitor.h \ services/p3msgservice.h \ services/p3service.h \ services/p3statusservice.h \ services/p3banlist.h \ - services/p3bwctrl.h \ - services/p3discovery2.h \ + services/p3bwctrl.h \ + gossipdiscovery/p3gossipdiscovery.h \ services/p3heartbeat.h \ services/p3rtt.h \ services/p3serviceinfo.h \ @@ -477,6 +480,7 @@ HEADERS += turtle/p3turtle.h \ HEADERS += util/folderiterator.h \ util/rsdebug.h \ + util/rskbdinput.h \ util/rsmemory.h \ util/smallobject.h \ util/rsdir.h \ @@ -557,9 +561,7 @@ SOURCES += pqi/authgpg.cc \ pqi/pqiqosstreamer.cc \ pqi/sslfns.cc \ pqi/pqinetstatebox.cc \ - pqi/p3servicecontrol.cc \ - -# pqi/p3dhtmgr.cc \ + pqi/p3servicecontrol.cc SOURCES += rsserver/p3face-config.cc \ rsserver/p3face-server.cc \ @@ -571,7 +573,6 @@ SOURCES += rsserver/p3face-config.cc \ rsserver/rsinit.cc \ rsserver/rsaccounts.cc \ rsserver/rsloginhandler.cc \ - rsserver/rstypes.cc \ rsserver/p3serverconfig.cc SOURCES += grouter/p3grouter.cc \ @@ -601,7 +602,7 @@ SOURCES += serialiser/rsbaseserial.cc \ serialiser/rstlvbanlist.cc \ rsitems/rsbanlistitems.cc \ rsitems/rsbwctrlitems.cc \ - rsitems/rsdiscovery2items.cc \ + gossipdiscovery/gossipdiscoveryitems.cc \ rsitems/rsrttitems.cc \ rsitems/rsgxsrecognitems.cc \ rsitems/rsgxsupdateitems.cc \ @@ -609,26 +610,24 @@ SOURCES += serialiser/rsbaseserial.cc \ SOURCES += services/autoproxy/rsautoproxymonitor.cc \ + services/rseventsservice.cc \ services/autoproxy/p3i2pbob.cc \ services/p3msgservice.cc \ services/p3service.cc \ services/p3statusservice.cc \ services/p3banlist.cc \ services/p3bwctrl.cc \ - services/p3discovery2.cc \ + gossipdiscovery/p3gossipdiscovery.cc \ services/p3heartbeat.cc \ services/p3rtt.cc \ services/p3serviceinfo.cc \ SOURCES += turtle/p3turtle.cc \ - turtle/rsturtleitem.cc -# turtle/turtlerouting.cc \ -# turtle/turtlesearch.cc \ -# turtle/turtletunnels.cc - + turtle/rsturtleitem.cc SOURCES += util/folderiterator.cc \ util/rsdebug.cc \ + util/rskbdinput.cc \ util/rsexpr.cc \ util/smallobject.cc \ util/rsdir.cc \ @@ -648,37 +647,14 @@ SOURCES += util/folderiterator.cc \ util/rsurl.cc equals(RS_UPNP_LIB, miniupnpc) { - HEADERS += upnp/upnputil.h upnp/upnphandler_miniupnp.h - SOURCES += upnp/upnputil.c upnp/upnphandler_miniupnp.cc -} else { - HEADERS += upnp/UPnPBase.h upnp/upnphandler_linux.h - SOURCES += upnp/UPnPBase.cpp upnp/upnphandler_linux.cc - DEFINES *= RS_USE_LIBUPNP + HEADERS += rs_upnp/upnputil.h rs_upnp/upnphandler_miniupnp.h + SOURCES += rs_upnp/upnputil.c rs_upnp/upnphandler_miniupnp.cc } -zeroconf { - -HEADERS += zeroconf/p3zeroconf.h \ - -SOURCES += zeroconf/p3zeroconf.cc \ - -# Disable Zeroconf (we still need the code for zcnatassist -# DEFINES *= RS_ENABLE_ZEROCONF - -} - -# This is seperated from the above for windows/linux platforms. -# It is acceptable to build in zeroconf and have it not work, -# but unacceptable to rely on Apple's libraries for Upnp when we have alternatives. ' - -zcnatassist { - -HEADERS += zeroconf/p3zcnatassist.h \ - -SOURCES += zeroconf/p3zcnatassist.cc \ - - DEFINES *= RS_ENABLE_ZCNATASSIST - +contains(RS_UPNP_LIB, upnp) { + HEADERS += rs_upnp/upnp18_retrocompat.h + HEADERS += rs_upnp/UPnPBase.h rs_upnp/upnphandler_linux.h + SOURCES += rs_upnp/UPnPBase.cpp rs_upnp/upnphandler_linux.cc } # new gxs cache system @@ -865,22 +841,26 @@ rs_jsonapi { DUMMYRESTBEDINPUT = FORCE CMAKE_GENERATOR_OVERRIDE="" win32-g++:CMAKE_GENERATOR_OVERRIDE="-G \"MSYS Makefiles\"" - genrestbedlib.name = Generating libresbed. + genrestbedlib.name = Generating librestbed. genrestbedlib.input = DUMMYRESTBEDINPUT genrestbedlib.output = $$clean_path($${RESTBED_BUILD_PATH}/librestbed.a) genrestbedlib.CONFIG += target_predeps combine genrestbedlib.variable_out = PRE_TARGETDEPS genrestbedlib.commands = \ - cd $${RS_SRC_PATH} && \ - git submodule update --init --recommend-shallow supportlibs/restbed && \ - cd $${RESTBED_SRC_PATH} && \ - git submodule update --init --recommend-shallow dependency/asio && \ - git submodule update --init --recommend-shallow dependency/catch && \ - git submodule update --init --recommend-shallow dependency/kashmir && \ - mkdir -p $${RESTBED_BUILD_PATH}; cd $${RESTBED_BUILD_PATH} && \ - cmake -DCMAKE_CXX_COMPILER=$$QMAKE_CXX $${CMAKE_GENERATOR_OVERRIDE} -DBUILD_SSL=OFF \ - -DCMAKE_INSTALL_PREFIX=. -B. -H$$shell_path($${RESTBED_SRC_PATH}) && \ - make + cd $${RS_SRC_PATH} && ( \ + git submodule update --init supportlibs/restbed ; \ + cd $${RESTBED_SRC_PATH} ; \ + git submodule update --init dependency/asio ; \ + git submodule update --init dependency/catch ; \ + git submodule update --init dependency/kashmir ; \ + true ) && \ + mkdir -p $${RESTBED_BUILD_PATH} && cd $${RESTBED_BUILD_PATH} && \ + cmake \ + -DCMAKE_CXX_COMPILER=$$QMAKE_CXX \ + $${CMAKE_GENERATOR_OVERRIDE} -DBUILD_SSL=OFF \ + -DCMAKE_INSTALL_PREFIX=. -B. \ + -H$$shell_path($${RESTBED_SRC_PATH}) && \ + $(MAKE) QMAKE_EXTRA_COMPILERS += genrestbedlib RESTBED_HEADER_FILE=$$clean_path($${RESTBED_BUILD_PATH}/include/restbed) @@ -889,7 +869,7 @@ rs_jsonapi { genrestbedheader.output = $${RESTBED_HEADER_FILE} genrestbedheader.CONFIG += target_predeps combine no_link genrestbedheader.variable_out = HEADERS - genrestbedheader.commands = cd $${RESTBED_BUILD_PATH} && make install + genrestbedheader.commands = cd $${RESTBED_BUILD_PATH} && $(MAKE) install QMAKE_EXTRA_COMPILERS += genrestbedheader } @@ -925,6 +905,37 @@ rs_deep_search { HEADERS += deep_search/deep_search.h } +rs_broadcast_discovery { + HEADERS += retroshare/rsbroadcastdiscovery.h \ + services/broadcastdiscoveryservice.h + SOURCES += services/broadcastdiscoveryservice.cc + + no_rs_cross_compiling { + DUMMYQMAKECOMPILERINPUT = FORCE + CMAKE_GENERATOR_OVERRIDE="" + win32-g++:CMAKE_GENERATOR_OVERRIDE="-G \"MSYS Makefiles\"" + udpdiscoverycpplib.name = Generating libudp-discovery.a. + udpdiscoverycpplib.input = DUMMYQMAKECOMPILERINPUT + udpdiscoverycpplib.output = $$clean_path($${UDP_DISCOVERY_BUILD_PATH}/libudp-discovery.a) + udpdiscoverycpplib.CONFIG += target_predeps combine + udpdiscoverycpplib.variable_out = PRE_TARGETDEPS + udpdiscoverycpplib.commands = \ + cd $${RS_SRC_PATH} && ( \ + git submodule update --init supportlibs/udp-discovery-cpp || \ + true ) && \ + mkdir -p $${UDP_DISCOVERY_BUILD_PATH} && \ + cd $${UDP_DISCOVERY_BUILD_PATH} && \ + cmake -DCMAKE_C_COMPILER=$$fixQmakeCC($$QMAKE_CC) \ + -DCMAKE_CXX_COMPILER=$$QMAKE_CXX \ + $${CMAKE_GENERATOR_OVERRIDE} \ + -DBUILD_EXAMPLE=OFF -DBUILD_TOOL=OFF \ + -DCMAKE_INSTALL_PREFIX=. -B. \ + -H$$shell_path($${UDP_DISCOVERY_SRC_PATH}) && \ + $(MAKE) + QMAKE_EXTRA_COMPILERS += udpdiscoverycpplib + } +} + ########################################################################################################### # OLD CONFIG OPTIONS. # Not used much - but might be useful one day. diff --git a/libretroshare/src/pgp/pgpauxutils.h b/libretroshare/src/pgp/pgpauxutils.h index 6ead67a2d..604a5d6e0 100644 --- a/libretroshare/src/pgp/pgpauxutils.h +++ b/libretroshare/src/pgp/pgpauxutils.h @@ -23,6 +23,7 @@ #include "retroshare/rsids.h" #include "retroshare/rstypes.h" +#include "util/rsdeprecate.h" /* This is a small collection of PGP functions that are widely used in libretroshare. * This interface class allows these functions to be easily mocked for testing. @@ -40,6 +41,9 @@ class PgpAuxUtils virtual bool parseSignature(unsigned char *sign, unsigned int signlen, RsPgpId& issuer) const =0; virtual bool VerifySignBin(const void *data, uint32_t len, unsigned char *sign, unsigned int signlen, const PGPFingerprintType& withfingerprint) = 0; + + /** @deprecated this method depends on retroshare-gui to work */ + RS_DEPRECATED_FOR("AuthGPG::SignDataBin") virtual bool askForDeferredSelfSignature(const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen,int& signature_result, std::string reason) = 0; }; diff --git a/libretroshare/src/pgp/pgphandler.cc b/libretroshare/src/pgp/pgphandler.cc index 7769aa4c8..48915aa85 100644 --- a/libretroshare/src/pgp/pgphandler.cc +++ b/libretroshare/src/pgp/pgphandler.cc @@ -908,12 +908,14 @@ bool PGPHandler::checkAndImportKeyPair(ops_keyring_t *tmp_keyring, RsPgpId &impo return false ; } - if(pubkey == NULL || seckey == NULL || pubkey == seckey) + if(pubkey == nullptr || seckey == nullptr || pubkey == seckey) { import_error = "File does not contain a public and a private key. Sorry." ; return false ; } - if(memcmp(pubkey->fingerprint.fingerprint,seckey->fingerprint.fingerprint,PGP_KEY_FINGERPRINT_SIZE) != 0) + if(memcmp( pubkey->fingerprint.fingerprint, + seckey->fingerprint.fingerprint, + RsPgpFingerprint::SIZE_IN_BYTES ) != 0) { import_error = "Public and private keys do nt have the same fingerprint. Sorry!" ; return false ; @@ -940,7 +942,10 @@ bool PGPHandler::checkAndImportKeyPair(ops_keyring_t *tmp_keyring, RsPgpId &impo bool found = false ; for(uint32_t i=0;ivalid_count;++i) - if(!memcmp((unsigned char*)result->valid_sigs[i].signer_id,pubkey->key_id,PGP_KEY_ID_SIZE)) + if(!memcmp( + static_cast(result->valid_sigs[i].signer_id), + pubkey->key_id, + RsPgpId::SIZE_IN_BYTES )) { found = true ; break ; @@ -1032,7 +1037,17 @@ void PGPHandler::addNewKeyToOPSKeyring(ops_keyring_t *kr,const ops_keydata_t& ke kr->nkeys++ ; } +bool PGPHandler::LoadCertificateFromBinaryData(const unsigned char *data,uint32_t data_len,RsPgpId& id,std::string& error_string) +{ + return LoadCertificate(data,data_len,ops_false,id,error_string); +} + bool PGPHandler::LoadCertificateFromString(const std::string& pgp_cert,RsPgpId& id,std::string& error_string) +{ + return LoadCertificate((unsigned char*)(pgp_cert.c_str()),pgp_cert.length(),ops_true,id,error_string); +} + +bool PGPHandler::LoadCertificate(const unsigned char *data,uint32_t data_len,bool armoured,RsPgpId& id,std::string& error_string) { RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. #ifdef DEBUG_PGPHANDLER @@ -1041,9 +1056,9 @@ bool PGPHandler::LoadCertificateFromString(const std::string& pgp_cert,RsPgpId& ops_keyring_t *tmp_keyring = allocateOPSKeyring(); ops_memory_t *mem = ops_memory_new() ; - ops_memory_add(mem,(unsigned char *)pgp_cert.c_str(),pgp_cert.length()) ; + ops_memory_add(mem,data,data_len) ; - if(!ops_keyring_read_from_mem(tmp_keyring,ops_true,mem)) + if(!ops_keyring_read_from_mem(tmp_keyring,armoured,mem)) { ops_keyring_free(tmp_keyring) ; free(tmp_keyring) ; @@ -1087,7 +1102,10 @@ bool PGPHandler::LoadCertificateFromString(const std::string& pgp_cert,RsPgpId& bool found = false ; for(uint32_t i=0;ivalid_count;++i) - if(!memcmp((unsigned char*)result->valid_sigs[i].signer_id,keydata->key_id,PGP_KEY_ID_SIZE)) + if(!memcmp( + static_cast(result->valid_sigs[i].signer_id), + keydata->key_id, + RsPgpId::SIZE_IN_BYTES )) { found = true ; break ; @@ -1164,7 +1182,9 @@ bool PGPHandler::locked_addOrMergeKey(ops_keyring_t *keyring,std::mapfingerprint.fingerprint, keydata->fingerprint.fingerprint,PGP_KEY_FINGERPRINT_SIZE)) + if(memcmp( existing_key->fingerprint.fingerprint, + keydata->fingerprint.fingerprint, + RsPgpFingerprint::SIZE_IN_BYTES )) { std::cerr << "(EE) attempt to merge key with identical id, but different fingerprint!" << std::endl; return false ; @@ -1187,37 +1207,7 @@ bool PGPHandler::locked_addOrMergeKey(ops_keyring_t *keyring,std::maptype != OPS_PTAG_CT_PUBLIC_KEY) -// { -// std::cerr << "PGPHandler::encryptTextToFile(): ERROR: supplied id did not return a public key!" << std::endl; -// return false ; -// } -// -// ops_create_info_t *info; -// ops_memory_t *buf = NULL ; -// ops_setup_memory_write(&info, &buf, 0); -// -// ops_encrypt_stream(info, public_key, NULL, ops_false, ops_true); -// ops_write(text.c_str(), text.length(), info); -// ops_writer_close(info); -// -// outstring = std::string((char *)ops_memory_get_data(buf),ops_memory_get_length(buf)) ; -// ops_create_info_delete(info); -// -// return true ; -// } + bool PGPHandler::encryptTextToFile(const RsPgpId& key_id,const std::string& text,const std::string& outfile) { RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. @@ -1591,6 +1581,11 @@ void PGPHandler::locked_updateOwnSignatureFlag(PGPCertificateInfo& cert,const Rs cert._flags &= ~PGPCertificateInfo::PGP_CERTIFICATE_FLAG_HAS_SIGNED_ME ; } +RsPgpId PGPHandler::pgpIdFromFingerprint(const PGPFingerprintType& f) +{ + return RsPgpId(f.toByteArray() + _RsIdSize::PGP_FINGERPRINT - _RsIdSize::PGP_ID); +} + bool PGPHandler::getKeyFingerprint(const RsPgpId& id,PGPFingerprintType& fp) const { RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. @@ -1792,7 +1787,8 @@ bool PGPHandler::privateTrustCertificate(const RsPgpId& id,int trustlvl) struct PrivateTrustPacket { - unsigned char user_id[PGP_KEY_ID_SIZE] ; // pgp id in unsigned char format. + /// pgp id in unsigned char format. + unsigned char user_id[RsPgpId::SIZE_IN_BYTES]; uint8_t trust_level ; // trust level. From 0 to 6. uint32_t time_stamp ; // last time the cert was ever used, in seconds since the epoch. 0 means not initialized. }; @@ -1854,9 +1850,12 @@ bool PGPHandler::locked_writePrivateTrustDatabase() } PrivateTrustPacket trustpacket ; - for(std::map::iterator it = _public_keyring_map.begin();it!=_public_keyring_map.end() ;++it) + for( std::map::iterator it = + _public_keyring_map.begin(); it!=_public_keyring_map.end(); ++it ) { - memcpy(trustpacket.user_id,RsPgpId(it->first).toByteArray(),PGP_KEY_ID_SIZE) ; + memcpy( trustpacket.user_id, + it->first.toByteArray(), + RsPgpId::SIZE_IN_BYTES ); trustpacket.trust_level = it->second._trustLvl ; trustpacket.time_stamp = it->second._time_stamp ; @@ -2115,4 +2114,3 @@ bool PGPHandler::removeKeysFromPGPKeyring(const std::set& keys_to_remov return true ; } - diff --git a/libretroshare/src/pgp/pgphandler.h b/libretroshare/src/pgp/pgphandler.h index 5137d5ba1..fee240e6a 100644 --- a/libretroshare/src/pgp/pgphandler.h +++ b/libretroshare/src/pgp/pgphandler.h @@ -21,10 +21,6 @@ *******************************************************************************/ #pragma once -#pragma once - -// This class implements an abstract pgp handler to be used in RetroShare. -// #include #include #include @@ -80,6 +76,7 @@ class PGPCertificateInfo static const uint8_t PGP_CERTIFICATE_TYPE_RSA = 0x02 ; }; +/// This class offer an abstract pgp handler to be used in RetroShare. class PGPHandler { public: @@ -107,6 +104,7 @@ class PGPHandler bool GeneratePGPCertificate(const std::string& name, const std::string& email, const std::string& passwd, RsPgpId& pgpId, const int keynumbits, std::string& errString) ; bool LoadCertificateFromString(const std::string& pem, RsPgpId& gpg_id, std::string& error_string); + bool LoadCertificateFromBinaryData(const unsigned char *bin_data,uint32_t bin_data_len, RsPgpId& gpg_id, std::string& error_string); std::string SaveCertificateToString(const RsPgpId& id,bool include_signatures) const ; bool exportPublicKey(const RsPgpId& id,unsigned char *& mem,size_t& mem_size,bool armoured,bool include_signatures) const ; @@ -125,8 +123,6 @@ class PGPHandler bool encryptTextToFile(const RsPgpId& key_id,const std::string& text,const std::string& outfile) ; bool decryptTextFromFile(const RsPgpId& key_id,std::string& text,const std::string& encrypted_inputfile) ; - //bool encryptTextToString(const RsPgpId& key_id,const std::string& text,std::string& outstring) ; - //bool decryptTextFromString(const RsPgpId& key_id,const std::string& encrypted_text,std::string& outstring) ; bool getKeyFingerprint(const RsPgpId& id,PGPFingerprintType& fp) const ; void setAcceptConnexion(const RsPgpId&,bool) ; @@ -158,6 +154,7 @@ class PGPHandler static void setPassphraseCallback(PassphraseCallback cb) ; static PassphraseCallback passphraseCallback() { return _passphrase_callback ; } + static RsPgpId pgpIdFromFingerprint(const PGPFingerprintType& f) ; // Gets info about the key. Who are the signers, what's the owner's name, etc. // @@ -176,6 +173,7 @@ class PGPHandler bool syncDatabase() ; private: + bool LoadCertificate(const unsigned char *bin_data,uint32_t bin_data_len, bool armoured, RsPgpId& gpg_id, std::string& error_string); void initCertificateInfo(PGPCertificateInfo& cert,const ops_keydata_t *keydata,uint32_t i) ; // Returns true if the signatures have been updated @@ -232,4 +230,3 @@ class PGPHandler static PassphraseCallback _passphrase_callback ; static bool mergeKeySignatures(ops_keydata_t *dst,const ops_keydata_t *src) ; // returns true if signature lists are different }; - diff --git a/libretroshare/src/pgp/rscertificate.cc b/libretroshare/src/pgp/rscertificate.cc index a580f8fe8..f3007bb01 100644 --- a/libretroshare/src/pgp/rscertificate.cc +++ b/libretroshare/src/pgp/rscertificate.cc @@ -3,8 +3,8 @@ * * * libretroshare: retroshare core library * * * - * Copyright 2016 Cyril Soler * - * Copyright 2018 Gioacchino Mazzurco * + * Copyright (C) 2016 Cyril Soler * + * Copyright (C) 2018-2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -31,6 +31,7 @@ #include "rscertificate.h" #include "util/rsstring.h" #include "util/stacktrace.h" +#include "util/rsdebug.h" //#define DEBUG_RSCERTIFICATE @@ -55,6 +56,7 @@ static bool is_acceptable_radix64Char(char c) return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '+' || c == '/' || c == '=' ; } + RsCertificate::~RsCertificate() { delete[] binary_pgp_key ; @@ -166,28 +168,16 @@ std::string RsCertificate::toStdString() const return out2 ; } -RsCertificate::RsCertificate(const std::string& str) : - location_name(""), pgp_version("Version: OpenPGP:SDK v0.9"), - dns_name(""), only_pgp(true) -{ - uint32_t err_code; - binary_pgp_key = nullptr; - - if(!initializeFromString(str, err_code)) - { - std::cerr << __PRETTY_FUNCTION__ << " is deprecated because it can " - << "miserably fail like this! str: " << str - << " err_code: " << err_code << std::endl; - print_stacktrace(); - throw err_code; - } -} - RsCertificate::RsCertificate(const RsPeerDetails& Detail, const unsigned char *binary_pgp_block,size_t binary_pgp_block_size) :pgp_version("Version: OpenPGP:SDK v0.9") { - if(binary_pgp_block_size == 0 || binary_pgp_block == NULL) - throw std::runtime_error("Cannot init a certificate with a void key block.") ; + if(binary_pgp_block_size == 0 || binary_pgp_block == nullptr) + { + RsErr() << __PRETTY_FUNCTION__ << " is deprecated because it can " + << "miserably fail like this! " << std::endl; + print_stacktrace(); + throw std::runtime_error("Cannot init a certificate with a void key block."); + } binary_pgp_key = new unsigned char[binary_pgp_block_size] ; memcpy(binary_pgp_key,binary_pgp_block,binary_pgp_block_size) ; @@ -256,6 +246,91 @@ RsCertificate::RsCertificate(const RsPeerDetails& Detail, const unsigned char *b } } + +/*static*/ std::unique_ptr RsCertificate::fromMemoryBlock( + const RsPeerDetails& details, const uint8_t* binary_pgp_block, + size_t binary_pgp_block_size ) +{ + if(binary_pgp_block_size == 0 || binary_pgp_block == nullptr) + { + RsErr() << __PRETTY_FUNCTION__ << " invalid parameters! " << std::endl; + print_stacktrace(); + return nullptr; + } + + std::unique_ptr crt(new RsCertificate); + + crt->binary_pgp_key = new uint8_t[binary_pgp_block_size]; + memcpy(crt->binary_pgp_key, binary_pgp_block, binary_pgp_block_size); + crt->binary_pgp_key_size = binary_pgp_block_size; + + if(!details.isOnlyGPGdetail) + { + crt->only_pgp = false; + crt->location_id = RsPeerId(details.id); + crt->location_name = details.location; + + if (details.isHiddenNode) + { + crt->hidden_node = true; + crt->hidden_node_address = details.hiddenNodeAddress; + rs_sprintf_append( + crt->hidden_node_address, ":%u", details.hiddenNodePort); + + memset(crt->ipv4_internal_ip_and_port, 0, 6); + memset(crt->ipv4_external_ip_and_port, 0, 6); + crt->dns_name = ""; + } + else + { + crt->hidden_node = false; + crt->hidden_node_address = ""; + + try + { + scan_ip( details.localAddr, details.localPort, + crt->ipv4_internal_ip_and_port ); + } + catch(...) + { + RsErr() << __PRETTY_FUNCTION__ << " Invalid LocalAddress: " + << details.localAddr << std::endl; + memset(crt->ipv4_internal_ip_and_port, 0, 6); + } + + try + { + scan_ip( details.extAddr, details.extPort, + crt->ipv4_external_ip_and_port ); + } + catch(...) + { + RsErr() << __PRETTY_FUNCTION__ << " Invalid ExternalAddress: " + << details.extAddr << std::endl; + memset(crt->ipv4_external_ip_and_port, 0, 6); + } + + crt->dns_name = details.dyndns; + + for(auto&& ipr : details.ipAddressList) + crt->mLocators.insert(RsUrl(ipr.substr(0, ipr.find(' ')))); + } + } + else + { + crt->only_pgp = true; + crt->hidden_node = false; + crt->hidden_node_address = ""; + crt->location_id = RsPeerId(); + crt->location_name = ""; + memset(crt->ipv4_internal_ip_and_port, 0, 6); + memset(crt->ipv4_external_ip_and_port, 0, 6); + crt->dns_name = ""; + } + + return crt; // Implicit move semantic +} + void RsCertificate::scan_ip(const std::string& ip_string, unsigned short port,unsigned char *ip_and_port) { int d0,d1,d2,d3 ; @@ -272,165 +347,174 @@ void RsCertificate::scan_ip(const std::string& ip_string, unsigned short port,un ip_and_port[5] = port & 0xff ; } -bool RsCertificate::initializeFromString(const std::string& instr,uint32_t& err_code) +/*static*/ std::unique_ptr RsCertificate::fromString( + const std::string& instr, uint32_t& err_code ) { - try + Dbg3() << __PRETTY_FUNCTION__ << std::endl; + + std::unique_ptr crt(new RsCertificate); + + std::string str; + err_code = CERTIFICATE_PARSING_ERROR_NO_ERROR; + + // 0 - clean the string and check that it is pure radix64 + for(uint32_t i=0;i bf = Radix64::decode(str) ; - size_t size = bf.size(); - - bool checksum_check_passed = false; - unsigned char *buf = bf.data(); - size_t total_s = 0; - only_pgp = true; - uint8_t certificate_version = 0x00; - - while(total_s < size) - { - uint8_t ptag = buf[0]; - buf = &buf[1]; - - unsigned char *buf2 = buf; - uint32_t s = PGPKeyParser::read_125Size(buf); - - total_s += 1 + ((size_t)buf-(size_t)buf2) ; - - if(total_s > size) - { - err_code = CERTIFICATE_PARSING_ERROR_SIZE_ERROR ; - return false ; - } - -#ifdef DEBUG_RSCERTIFICATE - std::cerr << "Packet parse: read ptag " << (int)ptag << ", size " << s << ", total_s = " << total_s << ", expected total = " << size << std::endl; -#endif - switch(ptag) - { - case CERTIFICATE_PTAG_VERSION_SECTION: - certificate_version = buf[0]; - break; - case CERTIFICATE_PTAG_PGP_SECTION: - binary_pgp_key = new unsigned char[s]; - memcpy(binary_pgp_key,buf,s); - binary_pgp_key_size = s; - break; - case CERTIFICATE_PTAG_NAME_SECTION: - location_name = std::string((char *)buf,s); - break; - case CERTIFICATE_PTAG_SSLID_SECTION: - if(s != location_id.SIZE_IN_BYTES) - { - err_code = CERTIFICATE_PARSING_ERROR_INVALID_LOCATION_ID; - return false; - } - location_id = RsPeerId(buf); - only_pgp = false; - break; - case CERTIFICATE_PTAG_DNS_SECTION: - dns_name = std::string((char *)buf,s); - break; - case CERTIFICATE_PTAG_HIDDENNODE_SECTION: - hidden_node_address = std::string((char *)buf,s); - hidden_node = true; - break; - case CERTIFICATE_PTAG_LOCIPANDPORT_SECTION: - if(s != 6) - { - err_code = CERTIFICATE_PARSING_ERROR_INVALID_LOCAL_IP; - return false; - } - memcpy(ipv4_internal_ip_and_port,buf,s); - break; - case CERTIFICATE_PTAG_EXTIPANDPORT_SECTION: - if(s != 6) - { - err_code = CERTIFICATE_PARSING_ERROR_INVALID_EXTERNAL_IP; - return false; - } - memcpy(ipv4_external_ip_and_port,buf,s); - break; - case CERTIFICATE_PTAG_CHECKSUM_SECTION: - { - if(s != 3 || total_s+3 != size) - { - err_code = - CERTIFICATE_PARSING_ERROR_INVALID_CHECKSUM_SECTION; - return false; - } - uint32_t computed_crc = - PGPKeyManagement::compute24bitsCRC(bf.data(),size-5); - uint32_t certificate_crc = - buf[0] + (buf[1] << 8) + (buf[2] << 16); - if(computed_crc != certificate_crc) - { - err_code = CERTIFICATE_PARSING_ERROR_CHECKSUM_ERROR; - return false; - } - else checksum_check_passed = true; - break; - } - case CERTIFICATE_PTAG_EXTRA_LOCATOR: - mLocators.insert(RsUrl(std::string((char *)buf, s))); - break; - default: - std::cerr << "(WW) unknwown PTAG 0x" << std::hex << ptag - << std::dec << " in certificate! Ignoring it." - << std::endl; - break; - } - - buf = &buf[s]; - total_s += s ; - } - - if(!checksum_check_passed) - { - err_code = CERTIFICATE_PARSING_ERROR_MISSING_CHECKSUM ; - return false ; - } - - if(certificate_version != CERTIFICATE_VERSION_06) - { - err_code = CERTIFICATE_PARSING_ERROR_WRONG_VERSION ; - return false ; - } -#ifdef DEBUG_RSCERTIFICATE - std::cerr << "Certificate is version " << (int)certificate_version << std::endl; -#endif - - if(total_s != size) - std::cerr << "(EE) Certificate contains trailing characters. Weird." << std::endl; - - return true ; + str += instr[i]; } - catch(std::exception& e) + + Dbg4() << __PRETTY_FUNCTION__ << " Decoding from: " << str << std::endl; + + // 1 - decode the string. + + std::vector bf = Radix64::decode(str); + size_t size = bf.size(); + + bool checksum_check_passed = false; + unsigned char* buf = bf.data(); + size_t total_s = 0; + crt->only_pgp = true; + uint8_t certificate_version = 0x00; + + while(total_s < size) { - if(binary_pgp_key != NULL) - delete[] binary_pgp_key ; + uint8_t ptag = buf[0]; + buf = &buf[1]; - err_code = CERTIFICATE_PARSING_ERROR_SIZE_ERROR ; - return false ; + unsigned char *buf2 = buf; + uint32_t s = 0; + + try { s = PGPKeyParser::read_125Size(buf); } + catch (...) + { + err_code = CERTIFICATE_PARSING_ERROR_SIZE_ERROR; + return nullptr; + } + + total_s += 1 + ( + reinterpret_cast(buf) - + reinterpret_cast(buf2) ); + + if(total_s > size) + { + err_code = CERTIFICATE_PARSING_ERROR_SIZE_ERROR; + return nullptr; + } + + Dbg3() << __PRETTY_FUNCTION__ << " Read ptag: " + << static_cast(ptag) + << ", size " << s << ", total_s = " << total_s + << ", expected total = " << size << std::endl; + + switch(ptag) + { + case CERTIFICATE_PTAG_VERSION_SECTION: + certificate_version = buf[0]; + break; + case CERTIFICATE_PTAG_PGP_SECTION: + crt->binary_pgp_key = new unsigned char[s]; + memcpy(crt->binary_pgp_key, buf, s); + crt->binary_pgp_key_size = s; + break; + case CERTIFICATE_PTAG_NAME_SECTION: + crt->location_name = + std::string(reinterpret_cast(buf), s); + break; + case CERTIFICATE_PTAG_SSLID_SECTION: + if(s != crt->location_id.SIZE_IN_BYTES) + { + err_code = CERTIFICATE_PARSING_ERROR_INVALID_LOCATION_ID; + return nullptr; + } + // We just checked buffer size so next line is not unsafe + crt->location_id = RsPeerId::fromBufferUnsafe(buf); + crt->only_pgp = false; + break; + case CERTIFICATE_PTAG_DNS_SECTION: + crt->dns_name = std::string(reinterpret_cast(buf), s); + break; + case CERTIFICATE_PTAG_HIDDENNODE_SECTION: + crt->hidden_node_address = + std::string(reinterpret_cast(buf),s); + crt->hidden_node = true; + break; + case CERTIFICATE_PTAG_LOCIPANDPORT_SECTION: + if(s != 6) + { + err_code = CERTIFICATE_PARSING_ERROR_INVALID_LOCAL_IP; + return nullptr; + } + memcpy(crt->ipv4_internal_ip_and_port, buf, s); + break; + case CERTIFICATE_PTAG_EXTIPANDPORT_SECTION: + if(s != 6) + { + err_code = CERTIFICATE_PARSING_ERROR_INVALID_EXTERNAL_IP; + return nullptr; + } + memcpy(crt->ipv4_external_ip_and_port, buf, s); + break; + case CERTIFICATE_PTAG_CHECKSUM_SECTION: + { + if(s != 3 || total_s+3 != size) + { + err_code = + CERTIFICATE_PARSING_ERROR_INVALID_CHECKSUM_SECTION; + return nullptr; + } + uint32_t computed_crc = + PGPKeyManagement::compute24bitsCRC(bf.data(),size-5); + uint32_t certificate_crc = static_cast( + buf[0] + (buf[1] << 8) + (buf[2] << 16) ); + if(computed_crc != certificate_crc) + { + err_code = CERTIFICATE_PARSING_ERROR_CHECKSUM_ERROR; + return nullptr; + } + else checksum_check_passed = true; + break; + } + case CERTIFICATE_PTAG_EXTRA_LOCATOR: + crt->mLocators.insert( + RsUrl(std::string(reinterpret_cast(buf), s))); + break; + default: + RsWarn() << __PRETTY_FUNCTION__ << " unknwown ptag: " + << static_cast(ptag) + << " in certificate! Ignoring it." << std::endl; + break; + } + + buf = &buf[s]; + total_s += s; } + + if(!checksum_check_passed) + { + err_code = CERTIFICATE_PARSING_ERROR_MISSING_CHECKSUM; + return nullptr; + } + + if(certificate_version != CERTIFICATE_VERSION_06) + { + err_code = CERTIFICATE_PARSING_ERROR_WRONG_VERSION; + return nullptr; + } + + Dbg3() << __PRETTY_FUNCTION__ << " Certificate version: " + << static_cast(certificate_version) << std::endl; + + if(total_s != size) + RsWarn() << __PRETTY_FUNCTION__ << " Certificate contains trailing " + << "characters. Weird." << std::endl; + + return crt; // Implicit move semantic } std::string RsCertificate::hidden_node_string() const @@ -450,6 +534,7 @@ std::string RsCertificate::ext_ip_string() const os << (int)ipv4_external_ip_and_port[0] << "." << (int)ipv4_external_ip_and_port[1] << "." << (int)ipv4_external_ip_and_port[2] << "." << (int)ipv4_external_ip_and_port[3] ; return os.str() ; } + std::string RsCertificate::loc_ip_string() const { std::ostringstream os ; @@ -467,28 +552,29 @@ unsigned short RsCertificate::loc_port_us() const return (int)ipv4_internal_ip_and_port[4]*256 + (int)ipv4_internal_ip_and_port[5] ; } -bool RsCertificate::cleanCertificate(const std::string& input,std::string& output,Format& format,int& error_code,bool check_content) +bool RsCertificate::cleanCertificate( const std::string& input, std::string& output, Format& format, uint32_t& error_code, bool check_content ) { - if(cleanCertificate(input,output,error_code)) + if(cleanRadix64(input,output,error_code)) { - format = RS_CERTIFICATE_RADIX ; + RsPeerDetails details; - if(!check_content) - return true ; + if(rsPeers->parseShortInvite(output,details,error_code)) + { + format = RS_CERTIFICATE_SHORT_RADIX; + return true; + } - try - { - RsCertificate c(input) ; - return true ; - } - catch(uint32_t err_code) - { - error_code = err_code ; - return false; - } + format = RS_CERTIFICATE_RADIX; + + if(!check_content) return true; + + uint32_t errCode; + auto crt = RsCertificate::fromString(input, errCode); + error_code = static_cast(errCode); + return crt != nullptr; } - return false ; + return false; } std::string RsCertificate::armouredPGPKey() const @@ -498,7 +584,7 @@ std::string RsCertificate::armouredPGPKey() const // Yeah, this is simple, and that is what's good about the radix format. Can't be broken ;-) // -bool RsCertificate::cleanCertificate(const std::string& instr,std::string& str,int& error_code) +bool RsCertificate::cleanRadix64(const std::string& instr,std::string& str,uint32_t& error_code) { error_code = RS_PEER_CERT_CLEANING_CODE_NO_ERROR ; diff --git a/libretroshare/src/pgp/rscertificate.h b/libretroshare/src/pgp/rscertificate.h index 6b8438b8c..1ba3db633 100644 --- a/libretroshare/src/pgp/rscertificate.h +++ b/libretroshare/src/pgp/rscertificate.h @@ -3,7 +3,8 @@ * * * libretroshare: retroshare core library * * * - * Copyright 2016 Cyril Soler * + * Copyright (C) 2016 Cyril Soler * + * Copyright (C) 2018-2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -23,42 +24,45 @@ #include "retroshare/rstypes.h" #include "util/rsurl.h" +#include "util/rsmemory.h" +#include "util/rsdebug.h" #include #include +#include struct RsPeerDetails; class RsCertificate { public: - typedef enum { RS_CERTIFICATE_OLD_FORMAT, RS_CERTIFICATE_RADIX } Format; + typedef enum { RS_CERTIFICATE_OLD_FORMAT, RS_CERTIFICATE_RADIX, RS_CERTIFICATE_SHORT_RADIX } Format; /** - * @brief Costruct an empty certificate, use toghether with - * if(initializeFromString) for safe certificate radix string parsing + * @brief Create certificate object from certificate string + * @param[in] str radix format certificate string + * @param[out] errorCode Optional storage for eventual error code, + * meaningful only on failure + * @return nullptr on failure, pointer to the generated certificate + * otherwise */ - RsCertificate() : - ipv4_external_ip_and_port{0,0,0,0,0,0}, - ipv4_internal_ip_and_port{0,0,0,0,0,0}, - binary_pgp_key(nullptr), binary_pgp_key_size(0), - pgp_version("Version: OpenPGP:SDK v0.9"), only_pgp(true), - hidden_node(false) {} + static std::unique_ptr fromString( + const std::string& str, + uint32_t& errorCode = RS_DEFAULT_STORAGE_PARAM(uint32_t) ); /** - * @brief Initialize from certificate string - * @param[in] str radix format string - * @param[out] errCode storage for eventual error code - * @return false on failure, true otherwise + * @brief Create certificate object from peer details and PGP memory block + * @param[in] details peer details + * @param[in] binary_pgp_block pointer to PGP memory block + * @param[in] binary_pgp_block_size size of PGP memory block + * @return nullptr on failure, pointer to the generated certificate + * otherwise */ - bool initializeFromString(const std::string& str, uint32_t& errCode); + static std::unique_ptr fromMemoryBlock( + const RsPeerDetails& details, const uint8_t* binary_pgp_block, + size_t binary_pgp_block_size ); - /// Constructs from binary gpg key, and RsPeerDetails. - RsCertificate( const RsPeerDetails& details, - const unsigned char *gpg_mem_block, - size_t gpg_mem_block_size ); - - virtual ~RsCertificate(); + ~RsCertificate(); /// Convert to certificate radix string std::string toStdString() const; @@ -80,21 +84,22 @@ public: static bool cleanCertificate( const std::string& input, std::string& output, - RsCertificate::Format& format, int& error_code, bool check_content); + RsCertificate::Format& format, uint32_t& error_code, bool check_content); const std::set& locators() const { return mLocators; } /** * @deprecated using this costructor may raise exception that cause - * crash if not handled, use empty constructor + if(initFromString) for a - * safer behaviour. + * crash if not handled. */ - RS_DEPRECATED explicit RsCertificate(const std::string& input_string); + RS_DEPRECATED_FOR("RsCertificate::fromMemoryBlock(...)") + RsCertificate( const RsPeerDetails& details, + const unsigned char *gpg_mem_block, + size_t gpg_mem_block_size ); private: // new radix format - static bool cleanCertificate( const std::string& input, - std::string& output, int&); + static bool cleanRadix64(const std::string& input, std::string& output, uint32_t &); static void scan_ip( const std::string& ip_string, unsigned short port, unsigned char *destination_memory ); @@ -105,6 +110,14 @@ private: RsCertificate(const RsCertificate&) {} /// non copy-able const RsCertificate& operator=(const RsCertificate&); /// non copy-able + /// @brief Costruct an empty certificate + RsCertificate() : + ipv4_external_ip_and_port{0,0,0,0,0,0}, + ipv4_internal_ip_and_port{0,0,0,0,0,0}, + binary_pgp_key(nullptr), binary_pgp_key_size(0), + pgp_version("Version: OpenPGP:SDK v0.9"), only_pgp(true), + hidden_node(false) {} + unsigned char ipv4_external_ip_and_port[6]; unsigned char ipv4_internal_ip_and_port[6]; @@ -120,5 +133,7 @@ private: bool only_pgp ; /// does the cert contain only pgp info? bool hidden_node; /// IP or hidden Node Address. + + RS_SET_CONTEXT_DEBUG_LEVEL(1) }; diff --git a/libretroshare/src/pqi/authgpg.cc b/libretroshare/src/pqi/authgpg.cc index bf485a2ad..076cb66b5 100644 --- a/libretroshare/src/pqi/authgpg.cc +++ b/libretroshare/src/pqi/authgpg.cc @@ -534,6 +534,19 @@ bool AuthGPG::getGPGSignedList(std::list &ids) return PGPHandler::SaveCertificateToString(id,include_signatures) ; } +/* import to GnuPG and other Certificates */ +bool AuthGPG::LoadPGPKeyFromBinaryData(const unsigned char *data,uint32_t data_len, RsPgpId& gpg_id,std::string& error_string) +{ + RsStackMutex stack(gpgMtxEngine); /******* LOCKED ******/ + + if(PGPHandler::LoadCertificateFromBinaryData(data,data_len,gpg_id,error_string)) + { + updateOwnSignatureFlag(gpg_id,mOwnGpgId) ; + return true ; + } + + return false ; +} /* import to GnuPG and other Certificates */ bool AuthGPG::LoadCertificateFromString(const std::string &str, RsPgpId& gpg_id,std::string& error_string) diff --git a/libretroshare/src/pqi/authgpg.h b/libretroshare/src/pqi/authgpg.h index 11b7203dd..871830445 100644 --- a/libretroshare/src/pqi/authgpg.h +++ b/libretroshare/src/pqi/authgpg.h @@ -172,6 +172,7 @@ public: * ****/ virtual bool LoadCertificateFromString(const std::string &pem, RsPgpId& gpg_id,std::string& error_string); + virtual bool LoadPGPKeyFromBinaryData(const unsigned char *data,uint32_t data_len, RsPgpId& gpg_id,std::string& error_string); virtual std::string SaveCertificateToString(const RsPgpId &id,bool include_signatures) ; // Cached certificates. diff --git a/libretroshare/src/pqi/authssl.cc b/libretroshare/src/pqi/authssl.cc index 797786783..0b2fa91ec 100644 --- a/libretroshare/src/pqi/authssl.cc +++ b/libretroshare/src/pqi/authssl.cc @@ -3,7 +3,8 @@ * * * libretroshare: retroshare core library * * * - * Copyright 2004-2008 by Robert Fernie, Retroshare Team. * + * Copyright (C) 2004-2008 Robert Fernie * + * Copyright (C) 2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -54,7 +55,7 @@ const uint32_t RS_SSL_HANDSHAKE_DIAGNOSTIC_MALLOC_ERROR = 0x04 ; const uint32_t RS_SSL_HANDSHAKE_DIAGNOSTIC_WRONG_SIGNATURE = 0x05 ; const uint32_t RS_SSL_HANDSHAKE_DIAGNOSTIC_CERTIFICATE_MISSING = 0x06 ; const uint32_t RS_SSL_HANDSHAKE_DIAGNOSTIC_HASH_ALGORITHM_NOT_ACCEPTED = 0x07 ; -const uint32_t RS_SSL_HANDSHAKE_DIAGNOSTIC_KEY_ALGORITHM_NOT_ACCEPTED = 0x08 ; +//const uint32_t RS_SSL_HANDSHAKE_DIAGNOSTIC_KEY_ALGORITHM_NOT_ACCEPTED = 0x08 ; const uint32_t RS_SSL_HANDSHAKE_DIAGNOSTIC_WRONG_SIGNATURE_TYPE = 0x09 ; const uint32_t RS_SSL_HANDSHAKE_DIAGNOSTIC_WRONG_SIGNATURE_VERSION = 0x0a ; @@ -62,9 +63,7 @@ const uint32_t RS_SSL_HANDSHAKE_DIAGNOSTIC_WRONG_SIGNATURE_VERSION = 0x0a ; * #define AUTHSSL_DEBUG 1 ***/ -// initialisation du pointeur de singleton -AuthSSL *AuthSSL::instance_ssl = NULL; -static pthread_mutex_t *mutex_buf = NULL; +static pthread_mutex_t* mutex_buf = nullptr; struct CRYPTO_dynlock_value { @@ -214,31 +213,17 @@ void tls_cleanup() } } -/* hidden function - for testing purposes() */ -void AuthSSL::setAuthSSL_debug(AuthSSL *newssl) +/*static*/ AuthSSL& AuthSSL::instance() { - instance_ssl = newssl; + static AuthSSLimpl mInstance; + return mInstance; } -void AuthSSL::AuthSSLInit() -{ - if (instance_ssl == NULL) - { - instance_ssl = new AuthSSLimpl(); - } -} - -AuthSSL *AuthSSL::getAuthSSL() -{ - return instance_ssl; -} +AuthSSL* AuthSSL::getAuthSSL() { return &instance(); } + +AuthSSL::~AuthSSL() = default; -AuthSSL::AuthSSL() -{ - return; -} - /********************************************************************************/ /********************************************************************************/ /********************* Cert Search / Add / Remove **************************/ @@ -247,26 +232,55 @@ AuthSSL::AuthSSL() static int verify_x509_callback(int preverify_ok, X509_STORE_CTX *ctx); - -sslcert::sslcert(X509 *x509, const RsPeerId& pid) +std::string RsX509Cert::getCertName(const X509& x509) { - certificate = x509; - id = pid; #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) - // cppcheck-suppress useInitializationList - name = getX509CNString(x509->cert_info->subject); - org = getX509OrgString(x509->cert_info->subject); - location = getX509LocString(x509->cert_info->subject); - issuer = RsPgpId(std::string(getX509CNString(x509->cert_info->issuer))); + return getX509CNString(x509.cert_info->subject); #else - name = getX509CNString(X509_get_subject_name(x509)); - org = getX509OrgString(X509_get_subject_name(x509)); - location = getX509LocString(X509_get_subject_name(x509)); - issuer = RsPgpId(std::string(getX509CNString(X509_get_issuer_name(x509)))); + return getX509CNString(X509_get_subject_name(&x509)); #endif - email = ""; +} - authed = false; +std::string RsX509Cert::getCertLocation(const X509& x509) +{ +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) + return getX509LocString(x509.cert_info->subject); +#else + return getX509LocString(X509_get_subject_name(&x509)); +#endif +} + +std::string RsX509Cert::getCertOrg(const X509& x509) +{ +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) + return getX509OrgString(x509.cert_info->subject); +#else + return getX509OrgString(X509_get_subject_name(&x509)); +#endif +} + +/*static*/ RsPgpId RsX509Cert::getCertIssuer(const X509& x509) +{ +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) + return RsPgpId(getX509CNString(x509.cert_info->issuer)); +#else + return RsPgpId(getX509CNString(X509_get_issuer_name(&x509))); +#endif +} + +/*static*/ std::string RsX509Cert::getCertIssuerString(const X509& x509) +{ +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) + return getX509CNString(x509.cert_info->issuer); +#else + return getX509CNString(X509_get_issuer_name(&x509)); +#endif +} + +/*static*/ RsPeerId RsX509Cert::getCertSslId(const X509& x509) +{ + RsPeerId sslid; + return getX509id(const_cast(&x509), sslid) ? sslid : RsPeerId(); } /************************************************************************ @@ -289,28 +303,18 @@ sslcert::sslcert(X509 *x509, const RsPeerId& pid) /********************************************************************************/ -AuthSSLimpl::AuthSSLimpl() - : p3Config(), sslctx(NULL), - mOwnCert(NULL), sslMtx("AuthSSL"), mOwnPrivateKey(NULL), mOwnPublicKey(NULL), init(0) +AuthSSLimpl::AuthSSLimpl() : + p3Config(), sslctx(nullptr), mOwnCert(nullptr), sslMtx("AuthSSL"), + mOwnPrivateKey(nullptr), mOwnPublicKey(nullptr), init(0) {} + +bool AuthSSLimpl::active() { return init; } + +int AuthSSLimpl::InitAuth( + const char* cert_file, const char* priv_key_file, const char* passwd, + std::string locationName ) { -} - -bool AuthSSLimpl::active() -{ - return init; -} - - -int AuthSSLimpl::InitAuth(const char *cert_file, const char *priv_key_file, - const char *passwd, std::string alternative_location_name) -{ -#ifdef AUTHSSL_DEBUG - std::cerr << "AuthSSLimpl::InitAuth()"; - std::cerr << std::endl; -#endif - /* single call here si don't need to invoke mutex yet */ -static int initLib = 0; + static int initLib = 0; if (!initLib) { initLib = 1; @@ -498,12 +502,7 @@ static int initLib = 0; std::cerr << "SSL Verification Set" << std::endl; - mOwnCert = new sslcert(x509, mOwnId); - - // New locations don't store the name in the cert. - // If empty, use the external supplied value. - if (mOwnCert->location == "") - mOwnCert->location = alternative_location_name ; + mOwnCert = x509; std::cerr << "Inited SSL context: " << std::endl; std::cerr << " Certificate: " << mOwnId << std::endl; @@ -521,6 +520,8 @@ static int initLib = 0; else std::cerr << std::endl; + mOwnLocationName = locationName; + init = 1; return 1; } @@ -533,7 +534,7 @@ bool AuthSSLimpl::validateOwnCertificate(X509 *x509, EVP_PKEY *pkey) uint32_t diagnostic ; /* standard authentication */ - if (!AuthX509WithGPG(x509,diagnostic)) + if (!AuthX509WithGPG(x509,true,diagnostic)) { std::cerr << "Validate Own certificate ERROR: diagnostic = " << diagnostic << std::endl; return false; @@ -576,20 +577,10 @@ const RsPeerId& AuthSSLimpl::OwnId() } std::string AuthSSLimpl::getOwnLocation() -{ -#ifdef AUTHSSL_DEBUG - std::cerr << "AuthSSLimpl::OwnId()" << std::endl; -#endif - return mOwnCert->location; -} +{ return mOwnLocationName; } std::string AuthSSLimpl::SaveOwnCertificateToString() -{ -#ifdef AUTHSSL_DEBUG - std::cerr << "AuthSSLimpl::SaveOwnCertificateToString() " << std::endl; -#endif - return saveX509ToPEM(mOwnCert->certificate); -} +{ return saveX509ToPEM(mOwnCert); } /********************************************************************************/ /********************************************************************************/ @@ -670,25 +661,20 @@ bool AuthSSLimpl::VerifySignBin(const void *data, const uint32_t len, RsStackMutex stack(sslMtx); /***** STACK LOCK MUTEX *****/ /* find the peer */ - sslcert *peer; - if (sslId == mOwnId) - { - peer = mOwnCert; - } - else if (!locked_FindCert(sslId, &peer)) + X509* peercert; + if (sslId == mOwnId) peercert = mOwnCert; + else if (!locked_FindCert(sslId, &peercert)) { std::cerr << "VerifySignBin() no peer" << std::endl; return false; } - return SSL_VerifySignBin(data, len, sign, signlen, peer->certificate); + return SSL_VerifySignBin(data, len, sign, signlen, peercert); } bool AuthSSLimpl::VerifyOwnSignBin(const void *data, const uint32_t len, unsigned char *sign, unsigned int signlen) -{ - return SSL_VerifySignBin(data, len, sign, signlen, mOwnCert->certificate); -} +{ return SSL_VerifySignBin(data, len, sign, signlen, mOwnCert); } /********************************************************************************/ @@ -984,152 +970,129 @@ X509 *AuthSSLimpl::SignX509ReqWithGPG(X509_REQ *req, long /*days*/) } -/* This function, checks that the X509 is signed by a known GPG key, - * NB: we do not have to have approved this person as a friend. - * this is important - as it allows non-friends messages to be validated. - */ - -bool AuthSSLimpl::AuthX509WithGPG(X509 *x509,uint32_t& diagnostic) +bool AuthSSLimpl::AuthX509WithGPG(X509 *x509,bool verbose, uint32_t& diagnostic) { -#ifdef AUTHSSL_DEBUG - fprintf(stderr, "AuthSSLimpl::AuthX509WithGPG() called\n"); -#endif - - if (!CheckX509Certificate(x509)) - { - std::cerr << "AuthSSLimpl::AuthX509() X509 NOT authenticated : Certificate failed basic checks" << std::endl; - diagnostic = RS_SSL_HANDSHAKE_DIAGNOSTIC_CERTIFICATE_NOT_VALID ; - return false; - } - - /* extract CN for peer Id */ -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) - RsPgpId issuer(std::string(getX509CNString(x509->cert_info->issuer))); -#else - RsPgpId issuer(std::string(getX509CNString(X509_get_issuer_name(x509)))); -#endif + RsPgpId issuer = RsX509Cert::getCertIssuer(*x509); RsPeerDetails pd; -#ifdef AUTHSSL_DEBUG - std::cerr << "Checking GPG issuer : " << issuer.toStdString() << std::endl ; -#endif - if (!AuthGPG::getAuthGPG()->getGPGDetails(issuer, pd)) { - std::cerr << "AuthSSLimpl::AuthX509() X509 NOT authenticated : AuthGPG::getAuthGPG()->getGPGDetails() returned false." << std::endl; - diagnostic = RS_SSL_HANDSHAKE_DIAGNOSTIC_ISSUER_UNKNOWN ; + if (!AuthGPG::getAuthGPG()->getGPGDetails(issuer, pd)) + { + RsInfo() << __PRETTY_FUNCTION__ << " X509 NOT authenticated : " + << "AuthGPG::getAuthGPG()->getGPGDetails(" << issuer + << ",...) returned false." << std::endl; + diagnostic = RS_SSL_HANDSHAKE_DIAGNOSTIC_ISSUER_UNKNOWN; return false; } + else + Dbg3() << __PRETTY_FUNCTION__ << " issuer: " << issuer << " found" + << std::endl; /* verify GPG signature */ - /*** NOW The Manual signing bit (HACKED FROM asn1/a_sign.c) ***/ #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) int (*i2d)(X509_CINF*, unsigned char**) = i2d_X509_CINF; - ASN1_BIT_STRING *signature = x509->signature; - X509_CINF *data = x509->cert_info; + ASN1_BIT_STRING* signature = x509->signature; + X509_CINF* data = x509->cert_info; #else - const ASN1_BIT_STRING *signature = NULL ; - const X509_ALGOR *algor2=NULL; - + const ASN1_BIT_STRING* signature = nullptr; + const X509_ALGOR* algor2 = nullptr; X509_get0_signature(&signature,&algor2,x509); #endif - uint32_t certificate_version = getX509RetroshareCertificateVersion(x509) ; + uint32_t certificate_version = getX509RetroshareCertificateVersion(x509); - EVP_MD_CTX *ctx = EVP_MD_CTX_create(); - int inl=0; + EVP_MD_CTX* ctx = EVP_MD_CTX_create(); + int inl = 0; - const unsigned char *signed_data = NULL ; - uint32_t signed_data_length =0; + const unsigned char* signed_data = nullptr; + uint32_t signed_data_length = 0; /* input buffer */ #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) - inl=i2d(data,NULL); - unsigned char *buf_in=(unsigned char *)OPENSSL_malloc((unsigned int)inl); - unsigned char *p=NULL; + inl = i2d(data, nullptr); + unsigned char* buf_in = static_cast( + OPENSSL_malloc(static_cast(inl)) ); + unsigned char* p = nullptr; #else - unsigned char *buf_in=NULL; + unsigned char* buf_in = nullptr; inl=i2d_re_X509_tbs(x509,&buf_in) ; // this does the i2d over x509->cert_info #endif - if(buf_in == NULL) + if(buf_in == nullptr) { - fprintf(stderr, "AuthSSLimpl::AuthX509: ASN1err(ASN1_F_ASN1_SIGN,ERR_R_MALLOC_FAILURE)\n"); + RsErr() << __PRETTY_FUNCTION__ + << " ASN1err(ASN1_F_ASN1_SIGN,ERR_R_MALLOC_FAILURE)" << std::endl; diagnostic = RS_SSL_HANDSHAKE_DIAGNOSTIC_MALLOC_ERROR ; - - return false ; + return false; } -#ifdef AUTHSSL_DEBUG - std::cerr << "Buffers Allocated" << std::endl; -#endif - #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) - p=buf_in; + p = buf_in; i2d(data,&p); #endif { // this scope is to avoid cross-initialization jumps to err. - const Sha1CheckSum sha1 = RsDirUtil::sha1sum(buf_in,inl) ; // olds the memory until destruction + const Sha1CheckSum sha1 = RsDirUtil::sha1sum( + buf_in, static_cast(inl) ); if(certificate_version < RS_CERTIFICATE_VERSION_NUMBER_07_0001) { - // If the certificate belongs to 0.6 version, we hash it here, and then re-hash the hash it in the PGP signature. - - signed_data = sha1.toByteArray() ; + /* If the certificate belongs to 0.6 version, we hash it here, and + * then re-hash the hash it in the PGP signature */ + signed_data = sha1.toByteArray(); signed_data_length = sha1.SIZE_IN_BYTES; } else { signed_data = buf_in ; - signed_data_length = inl ; + signed_data_length = static_cast(inl); } /* NOW check sign via GPG Functions */ - //get the fingerprint of the key that is supposed to sign -#ifdef AUTHSSL_DEBUG - std::cerr << "AuthSSLimpl::AuthX509() verifying the gpg sig with keyprint : " << pd.fpr << std::endl; - std::cerr << "Sigoutl = " << sigoutl << std::endl ; - std::cerr << "pd.fpr = " << pd.fpr << std::endl ; -#endif - // Take a early look at signature parameters. In particular we dont accept signatures with unsecure hash algorithms. + Dbg2() << __PRETTY_FUNCTION__ + << " verifying the PGP Key signature with finger print: " + << pd.fpr << std::endl; + + /* Take a early look at signature parameters. In particular we dont + * accept signatures with unsecure hash algorithms */ PGPSignatureInfo signature_info ; - PGPKeyManagement::parseSignature(signature->data,signature->length,signature_info) ; + PGPKeyManagement::parseSignature( + signature->data, static_cast(signature->length), + signature_info ); if(signature_info.signature_version != PGP_PACKET_TAG_SIGNATURE_VERSION_V4) { - diagnostic = RS_SSL_HANDSHAKE_DIAGNOSTIC_WRONG_SIGNATURE_VERSION ; - goto err ; + diagnostic = RS_SSL_HANDSHAKE_DIAGNOSTIC_WRONG_SIGNATURE_VERSION; + goto err; } - std::string sigtypestring ; + std::string sigtypestring; switch(signature_info.signature_type) { - case PGP_PACKET_TAG_SIGNATURE_TYPE_BINARY_DOCUMENT : - break ; - - case PGP_PACKET_TAG_SIGNATURE_TYPE_STANDALONE_SIG : - case PGP_PACKET_TAG_SIGNATURE_TYPE_CANONICAL_TEXT : - case PGP_PACKET_TAG_SIGNATURE_TYPE_UNKNOWN : + case PGP_PACKET_TAG_SIGNATURE_TYPE_BINARY_DOCUMENT: break; + case PGP_PACKET_TAG_SIGNATURE_TYPE_STANDALONE_SIG: /*fallthrough*/ + case PGP_PACKET_TAG_SIGNATURE_TYPE_CANONICAL_TEXT: /*fallthrough*/ + case PGP_PACKET_TAG_SIGNATURE_TYPE_UNKNOWN: /*fallthrough*/ default: - diagnostic = RS_SSL_HANDSHAKE_DIAGNOSTIC_WRONG_SIGNATURE_TYPE ; - goto err ; + diagnostic = RS_SSL_HANDSHAKE_DIAGNOSTIC_WRONG_SIGNATURE_TYPE; + goto err; } switch(signature_info.public_key_algorithm) { - case PGP_PACKET_TAG_PUBLIC_KEY_ALGORITHM_RSA_ES : - case PGP_PACKET_TAG_PUBLIC_KEY_ALGORITHM_RSA_S : sigtypestring = "RSA" ; + case PGP_PACKET_TAG_PUBLIC_KEY_ALGORITHM_RSA_ES: /*fallthrough*/ + case PGP_PACKET_TAG_PUBLIC_KEY_ALGORITHM_RSA_S: + sigtypestring = "RSA"; break ; - - case PGP_PACKET_TAG_PUBLIC_KEY_ALGORITHM_DSA : sigtypestring = "DSA" ; + case PGP_PACKET_TAG_PUBLIC_KEY_ALGORITHM_DSA: + sigtypestring = "DSA"; break ; - - case PGP_PACKET_TAG_PUBLIC_KEY_ALGORITHM_RSA_E : - case PGP_PACKET_TAG_PUBLIC_KEY_ALGORITHM_UNKNOWN: + case PGP_PACKET_TAG_PUBLIC_KEY_ALGORITHM_RSA_E: /*fallthrough*/ + case PGP_PACKET_TAG_PUBLIC_KEY_ALGORITHM_UNKNOWN: /*fallthrough*/ default: diagnostic = RS_SSL_HANDSHAKE_DIAGNOSTIC_HASH_ALGORITHM_NOT_ACCEPTED ; goto err ; @@ -1137,95 +1100,58 @@ bool AuthSSLimpl::AuthX509WithGPG(X509 *x509,uint32_t& diagnostic) switch(signature_info.hash_algorithm) { - case PGP_PACKET_TAG_HASH_ALGORITHM_SHA1 : sigtypestring += "+SHA1" ; break; - case PGP_PACKET_TAG_HASH_ALGORITHM_SHA256: sigtypestring += "+SHA256" ; break; - case PGP_PACKET_TAG_HASH_ALGORITHM_SHA512: sigtypestring += "+SHA512" ; break; - - // We dont accept signatures with unknown or week hash algorithms. - - case PGP_PACKET_TAG_HASH_ALGORITHM_MD5: - case PGP_PACKET_TAG_HASH_ALGORITHM_UNKNOWN: + case PGP_PACKET_TAG_HASH_ALGORITHM_SHA1: + sigtypestring += "+SHA1"; + break; + case PGP_PACKET_TAG_HASH_ALGORITHM_SHA256: + sigtypestring += "+SHA256"; + break; + case PGP_PACKET_TAG_HASH_ALGORITHM_SHA512: + sigtypestring += "+SHA512"; + break; + // We dont accept signatures with unknown or weak hash algorithms. + case PGP_PACKET_TAG_HASH_ALGORITHM_MD5: /*fallthrough*/ + case PGP_PACKET_TAG_HASH_ALGORITHM_UNKNOWN: /*fallthrough*/ default: - diagnostic = RS_SSL_HANDSHAKE_DIAGNOSTIC_HASH_ALGORITHM_NOT_ACCEPTED ; - goto err ; + diagnostic = RS_SSL_HANDSHAKE_DIAGNOSTIC_HASH_ALGORITHM_NOT_ACCEPTED; + goto err; } // passed, verify the signature itself - if (!AuthGPG::getAuthGPG()->VerifySignBin(signed_data, signed_data_length, signature->data, signature->length, pd.fpr)) + if (!AuthGPG::getAuthGPG()->VerifySignBin( + signed_data, signed_data_length, signature->data, + static_cast(signature->length), pd.fpr )) { - diagnostic = RS_SSL_HANDSHAKE_DIAGNOSTIC_WRONG_SIGNATURE ; + diagnostic = RS_SSL_HANDSHAKE_DIAGNOSTIC_WRONG_SIGNATURE; goto err; } - RsPeerId peerIdstr ; - getX509id(x509, peerIdstr) ; - - std::string fpr = pd.fpr.toStdString(); - std::cerr << "Verified " << sigtypestring << " signature of certificate " << peerIdstr << ", Version " << std::hex << certificate_version - << std::dec << " using PGP key " ; - for(uint32_t i=0;iVerifyX509Callback(preverify_ok, ctx); + /* According to OpenSSL documentation must return 0 if verification failed + * and 1 if succeded (aka can continue connection). + * About preverify_ok OpenSSL documentation doesn't tell which value is + * passed to the first callback in the authentication chain, it just says + * that the result of previous step is passed down, so I have tested it + * and we get passed 0 always so in our case as there is no other + * verifications step vefore we ignore it completely */ - X509 *x509 = X509_STORE_CTX_get_current_cert(ctx) ; + constexpr int verificationFailed = 0; + constexpr int verificationSuccess = 1; - if(x509 != NULL) + using Evt_t = RsAuthSslConnectionAutenticationEvent; + std::unique_ptr ev = std::unique_ptr(new Evt_t); + + X509* x509Cert = X509_STORE_CTX_get_current_cert(ctx); + if(!x509Cert) { -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) - RsPgpId gpgid (std::string(getX509CNString(x509->cert_info->issuer))); -#else - RsPgpId gpgid (std::string(getX509CNString(X509_get_issuer_name(x509)))); -#endif + std::string errMsg = "Cannot get certificate! OpenSSL error: " + + std::to_string(X509_STORE_CTX_get_error(ctx)) + " depth: " + + std::to_string(X509_STORE_CTX_get_error_depth(ctx)); - if(gpgid.isNull()) + RsErr() << __PRETTY_FUNCTION__ << " " << errMsg << std::endl; + + if(rsEvents) { -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) - std::cerr << "verify_x509_callback(): wrong PGP id \"" << std::string(getX509CNString(x509->cert_info->issuer)) << "\"" << std::endl; -#else - std::cerr << "verify_x509_callback(): wrong PGP id \"" << std::string(getX509CNString(X509_get_issuer_name(x509))) << "\"" << std::endl; -#endif - return false ; + ev->mErrorMsg = errMsg; + rsEvents->postEvent(std::move(ev)); } -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) - std::string sslcn = getX509CNString(x509->cert_info->subject); -#else - std::string sslcn = getX509CNString(X509_get_subject_name(x509)); -#endif - RsPeerId sslid ; + return verificationFailed; + } - getX509id(x509,sslid); + RsPeerId sslId = RsX509Cert::getCertSslId(*x509Cert); + std::string sslCn = RsX509Cert::getCertIssuerString(*x509Cert); - if(sslid.isNull()) + RsPgpId pgpId(sslCn); + + if(sslCn.length() == RsPgpFingerprint::SIZE_IN_BYTES*2) + { + RsPgpFingerprint pgpFpr(sslCn); // we also accept fingerprint format, so that in the future we can switch to fingerprints without backward compatibility issues + + if(!pgpFpr.isNull()) + pgpId = PGPHandler::pgpIdFromFingerprint(pgpFpr); // in the future, we drop PGP ids and keep the fingerprint all along + } + + if(sslId.isNull()) + { + std::string errMsg = "x509Cert has invalid sslId!"; + + RsInfo() << __PRETTY_FUNCTION__ << " " << errMsg << std::endl; + + if(rsEvents) { - std::cerr << "verify_x509_callback(): wrong PGP id \"" << sslcn << "\"" << std::endl; - return false ; + ev->mSslCn = sslCn; + ev->mPgpId = pgpId; + ev->mErrorMsg = errMsg; + rsEvents->postEvent(std::move(ev)); } - AuthSSL::getAuthSSL()->setCurrentConnectionAttemptInfo(gpgid,sslid,sslcn) ; - } + return verificationFailed; + } - return verify; + if(pgpId.isNull()) + { + std::string errMsg = "x509Cert has invalid pgpId! sslCn >>>" + sslCn + + "<<<"; + + RsInfo() << __PRETTY_FUNCTION__ << " " << errMsg << std::endl; + + if(rsEvents) + { + ev->mSslId = sslId; + ev->mSslCn = sslCn; + ev->mErrorMsg = errMsg; + rsEvents->postEvent(std::move(ev)); + } + + return verificationFailed; + } + + bool isSslOnlyFriend = false; + + // For SSL only friends (ones added through short invites) we check that the fingerprint + // in the key (det.gpg_id) matches the one of the handshake. + { + RsPeerDetails det; + + if(rsPeers->getPeerDetails(sslId,det)) + isSslOnlyFriend = det.skip_pgp_signature_validation; + + if(det.skip_pgp_signature_validation && det.gpg_id != pgpId)// in the future, we should compare fingerprints instead + { + std::string errorMsg = "Peer " + sslId.toStdString() + " trying to connect with issuer ID " + pgpId.toStdString() + + " whereas key ID " + det.gpg_id.toStdString() + " was expected! Refusing connection." ; + + RsErr() << __PRETTY_FUNCTION__ << errorMsg << std::endl; + + if(rsEvents) + { + ev->mSslId = sslId; + ev->mSslCn = sslCn; + ev->mPgpId = pgpId; + ev->mErrorMsg = errorMsg; + rsEvents->postEvent(std::move(ev)); + } + + return verificationFailed; + } + } + + uint32_t auth_diagnostic; + if(!isSslOnlyFriend && !AuthX509WithGPG(x509Cert,true, auth_diagnostic)) + { + std::string errMsg = "Certificate was rejected because PGP " + "signature verification failed with diagnostic: " + + std::to_string(auth_diagnostic) + " certName: " + + RsX509Cert::getCertName(*x509Cert) + " sslId: " + + RsX509Cert::getCertSslId(*x509Cert).toStdString() + + " issuerString: " + RsX509Cert::getCertIssuerString(*x509Cert); + + RsInfo() << __PRETTY_FUNCTION__ << " " << errMsg << std::endl; + + if(rsEvents) + { + ev->mSslId = sslId; + ev->mSslCn = sslCn; + ev->mPgpId = pgpId; + ev->mErrorMsg = errMsg; + rsEvents->postEvent(std::move(ev)); + } + + return verificationFailed; + } + + if ( !isSslOnlyFriend && pgpId != AuthGPG::getAuthGPG()->getGPGOwnId() && !AuthGPG::getAuthGPG()->isGPGAccepted(pgpId) ) + { + std::string errMsg = "Connection attempt signed by PGP key id: " + + pgpId.toStdString() + " not accepted because it is not" + " a friend."; + + Dbg1() << __PRETTY_FUNCTION__ << " " << errMsg << std::endl; + + if(rsEvents) + { + ev->mSslId = sslId; + ev->mSslCn = sslCn; + ev->mPgpId = pgpId; + ev->mErrorMsg = errMsg; + rsEvents->postEvent(std::move(ev)); + } + + return verificationFailed; + } + + setCurrentConnectionAttemptInfo(pgpId, sslId, sslCn); + LocalStoreCert(x509Cert); + + RsInfo() << __PRETTY_FUNCTION__ << " authentication successfull for " + << "sslId: " << sslId << " isSslOnlyFriend: " << isSslOnlyFriend + << std::endl; + + if(rsEvents) + { + ev->mSuccess = true; + ev->mSslId = sslId; + ev->mSslCn = sslCn; + ev->mPgpId = pgpId; + rsEvents->postEvent(std::move(ev)); + } + + return verificationSuccess; } -int AuthSSLimpl::VerifyX509Callback(int preverify_ok, X509_STORE_CTX *ctx) +bool AuthSSLimpl::parseX509DetailsFromFile( + const std::string& certFilePath, RsPeerId& certId, + RsPgpId& issuer, std::string& location ) { - char buf[256]; - X509 *err_cert; + FILE* tmpfp = RsDirUtil::rs_fopen(certFilePath.c_str(), "r"); + if(!tmpfp) + { + RsErr() << __PRETTY_FUNCTION__ << " Failed to open Certificate File: " + << certFilePath << std::endl; + return false; + } - err_cert = X509_STORE_CTX_get_current_cert(ctx); -#ifdef AUTHSSL_DEBUG - int err, depth; - err = X509_STORE_CTX_get_error(ctx); - depth = X509_STORE_CTX_get_error_depth(ctx); -#endif + // get xPGP certificate. + X509* x509 = PEM_read_X509(tmpfp, nullptr, nullptr, nullptr); + fclose(tmpfp); - if(err_cert == NULL) - { - std::cerr << "AuthSSLimpl::VerifyX509Callback(): Cannot get certificate. Error!" << std::endl; - return false ; - } -#ifdef AUTHSSL_DEBUG - std::cerr << "AuthSSLimpl::VerifyX509Callback(preverify_ok: " << preverify_ok - << " Err: " << err << " Depth: " << depth << std::endl; -#endif + if(!x509) + { + RsErr() << __PRETTY_FUNCTION__ << " PEM_read_X509 failed!" << std::endl; + return false; + } - /* - * Retrieve the pointer to the SSL of the connection currently treated - * and the application specific data stored into the SSL object. - */ + uint32_t diagnostic = 0; + if(!AuthX509WithGPG(x509,false, diagnostic)) + { + RsErr() << __PRETTY_FUNCTION__ << " AuthX509WithGPG failed with " + << "diagnostic: " << diagnostic << std::endl; + return false; + } - X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256); + certId = RsX509Cert::getCertSslId(*x509); + issuer = RsX509Cert::getCertIssuer(*x509); + location = RsX509Cert::getCertLocation(*x509); -#ifdef AUTHSSL_DEBUG - std::cerr << "AuthSSLimpl::VerifyX509Callback: depth: " << depth << ":" << buf << std::endl; -#endif + X509_free(x509); + if(certId.isNull() || issuer.isNull()) return false; - if (!preverify_ok) { -#ifdef AUTHSSL_DEBUG - fprintf(stderr, "Verify error:num=%d:%s:depth=%d:%s\n", err, - X509_verify_cert_error_string(err), depth, buf); -#endif - } - - /* - * At this point, err contains the last verification error. We can use - * it for something special - */ - - if (!preverify_ok) - { - - X509_NAME_oneline(X509_get_issuer_name(X509_STORE_CTX_get_current_cert(ctx)), buf, 256); -#ifdef AUTHSSL_DEBUG - printf("issuer= %s\n", buf); -#endif - -#ifdef AUTHSSL_DEBUG - fprintf(stderr, "Doing REAL PGP Certificates\n"); -#endif - uint32_t auth_diagnostic ; - - /* do the REAL Authentication */ - if (!AuthX509WithGPG(X509_STORE_CTX_get_current_cert(ctx),auth_diagnostic)) - { -#ifdef AUTHSSL_DEBUG - fprintf(stderr, "AuthSSLimpl::VerifyX509Callback() X509 not authenticated.\n"); -#endif - std::cerr << "(WW) Certificate was rejected because authentication failed. Diagnostic = " << auth_diagnostic << std::endl; - return false; - } -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) - RsPgpId pgpid(std::string(getX509CNString(X509_STORE_CTX_get_current_cert(ctx)->cert_info->issuer))); -#else - RsPgpId pgpid(std::string(getX509CNString(X509_get_issuer_name(X509_STORE_CTX_get_current_cert(ctx))))); -#endif - - if (pgpid != AuthGPG::getAuthGPG()->getGPGOwnId() && !AuthGPG::getAuthGPG()->isGPGAccepted(pgpid)) - { -#ifdef AUTHSSL_DEBUG - fprintf(stderr, "AuthSSLimpl::VerifyX509Callback() pgp key not accepted : \n"); - fprintf(stderr, "issuer pgpid : "); - fprintf(stderr, "%s\n",pgpid.c_str()); - fprintf(stderr, "\n AuthGPG::getAuthGPG()->getGPGOwnId() : "); - fprintf(stderr, "%s\n",AuthGPG::getAuthGPG()->getGPGOwnId().c_str()); - fprintf(stderr, "\n"); -#endif - return false; - } - - preverify_ok = true; - - } else { -#ifdef AUTHSSL_DEBUG - fprintf(stderr, "A normal certificate is probably a security breach attempt. We sould fail it !!!\n"); -#endif - preverify_ok = false; - } - - if (preverify_ok) { - - //sslcert *cert = NULL; - RsPeerId certId; - getX509id(X509_STORE_CTX_get_current_cert(ctx), certId); - - } - -#ifdef AUTHSSL_DEBUG - if (preverify_ok) { - fprintf(stderr, "AuthSSLimpl::VerifyX509Callback returned true.\n"); - } else { - fprintf(stderr, "AuthSSLimpl::VerifyX509Callback returned false.\n"); - } -#endif - - return preverify_ok; + return true; } @@ -1406,33 +1387,21 @@ int AuthSSLimpl::VerifyX509Callback(int preverify_ok, X509_STORE_CTX *ctx) bool AuthSSLimpl::encrypt(void *&out, int &outlen, const void *in, int inlen, const RsPeerId& peerId) { - RsStackMutex stack(sslMtx); /******* LOCKED ******/ + RS_STACK_MUTEX(sslMtx); -#ifdef AUTHSSL_DEBUG - std::cerr << "AuthSSLimpl::encrypt() called for peerId : " << peerId << " with inlen : " << inlen << std::endl; -#endif - //TODO : use ssl to crypt the binary input buffer -// out = malloc(inlen); -// memcpy(out, in, inlen); -// outlen = inlen; - - EVP_PKEY *public_key; - if (peerId == mOwnId) { - public_key = mOwnPublicKey; - } else { - if (!mCerts[peerId]) { - #ifdef AUTHSSL_DEBUG - std::cerr << "AuthSSLimpl::encrypt() public key not found." << std::endl; - #endif - return false; - } else { -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) - public_key = mCerts[peerId]->certificate->cert_info->key->pkey; -#else - public_key = X509_get0_pubkey(mCerts[peerId]->certificate) ; -#endif - } - } + /*const*/ EVP_PKEY* public_key = nullptr; + if (peerId == mOwnId) { public_key = mOwnPublicKey; } + else + { + if (!mCerts[peerId]) + { + RsErr() << __PRETTY_FUNCTION__ << " public key not found." + << std::endl; + return false; + } + else public_key = const_cast( + RsX509Cert::getPubKey(*mCerts[peerId]) ); + } EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); int eklen, net_ekl; @@ -1640,104 +1609,10 @@ void AuthSSLimpl::getCurrentConnectionAttemptInfo(RsPgpId& gpg_id,RsPeerId& ssl_ ssl_cn = _last_sslcn_to_connect ; } -/* store for discovery */ -bool AuthSSLimpl::FailedCertificate(X509 *x509, const RsPgpId& gpgid, - const RsPeerId& sslid, - const std::string& sslcn, - const struct sockaddr_storage& addr, - bool incoming) -{ - std::string ip_address = sockaddr_storage_tostring(addr); - - uint32_t auth_diagnostic = 0 ; - bool authed ; - - if(x509 == NULL) - { - auth_diagnostic = RS_SSL_HANDSHAKE_DIAGNOSTIC_CERTIFICATE_MISSING ; - authed = false ; - } - else - authed = AuthX509WithGPG(x509,auth_diagnostic) ; - - if(authed) - LocalStoreCert(x509); - -#ifdef AUTHSSL_DEBUG - std::cerr << "AuthSSLimpl::FailedCertificate() "; -#endif - if (incoming) - { - RsServer::notify()->AddPopupMessage(RS_POPUP_CONNECT_ATTEMPT, gpgid.toStdString(), sslcn, sslid.toStdString()); - - switch(auth_diagnostic) - { - case RS_SSL_HANDSHAKE_DIAGNOSTIC_CERTIFICATE_MISSING: - RsServer::notify()->notifyConnectionWithoutCert(); - RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_MISSING_CERTIFICATE, gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address); - break ; - case RS_SSL_HANDSHAKE_DIAGNOSTIC_CERTIFICATE_NOT_VALID: - RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_BAD_CERTIFICATE, gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address); - break ; - case RS_SSL_HANDSHAKE_DIAGNOSTIC_ISSUER_UNKNOWN: - RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_UNKNOWN_IN , gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address); - break ; - case RS_SSL_HANDSHAKE_DIAGNOSTIC_MALLOC_ERROR: - RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_INTERNAL_ERROR , gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address); - break ; - case RS_SSL_HANDSHAKE_DIAGNOSTIC_WRONG_SIGNATURE: - RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_WRONG_SIGNATURE, gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address); - break ; - case RS_SSL_HANDSHAKE_DIAGNOSTIC_OK: - case RS_SSL_HANDSHAKE_DIAGNOSTIC_UNKNOWN: - default: - RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_CONNECT_ATTEMPT, gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address); - } - -#ifdef AUTHSSL_DEBUG - std::cerr << " Incoming from: "; -#endif - } - else - { - if(authed) - RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_AUTH_DENIED, gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address); - else - RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_UNKNOWN_OUT, gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address); - -#ifdef AUTHSSL_DEBUG - std::cerr << " Outgoing to: "; -#endif - } - -#ifdef AUTHSSL_DEBUG - std::cerr << "GpgId: " << gpgid << " SSLcn: " << sslcn << " peerId: " << sslid << ", ip address: " << ip_address; - std::cerr << std::endl; -#endif - - return false; -} - -bool AuthSSLimpl::CheckCertificate(const RsPeerId& id, X509 *x509) -{ - (void) id; /* remove unused parameter warning */ - - uint32_t diagnos ; - /* if auths -> store */ - if (AuthX509WithGPG(x509,diagnos)) - { - LocalStoreCert(x509); - return true; - } - return false; -} - - - /* Locked search -> internal help function */ -bool AuthSSLimpl::locked_FindCert(const RsPeerId& id, sslcert **cert) +bool AuthSSLimpl::locked_FindCert(const RsPeerId& id, X509** cert) { - std::map::iterator it; + std::map::iterator it; if (mCerts.end() != (it = mCerts.find(id))) { @@ -1752,21 +1627,15 @@ bool AuthSSLimpl::locked_FindCert(const RsPeerId& id, sslcert **cert) bool AuthSSLimpl::RemoveX509(RsPeerId id) { - std::map::iterator it; + std::map::iterator it; RsStackMutex stack(sslMtx); /******* LOCKED ******/ if (mCerts.end() != (it = mCerts.find(id))) { - sslcert *cert = it->second; - - /* clean up */ - X509_free(cert->certificate); - cert->certificate = NULL; - delete cert; - + X509* cert = it->second; + X509_free(cert); mCerts.erase(it); - return true; } return false; @@ -1803,15 +1672,15 @@ bool AuthSSLimpl::LocalStoreCert(X509* x509) } /* do a search */ - std::map::iterator it; + std::map::iterator it; if (mCerts.end() != (it = mCerts.find(peerId))) { - sslcert *cert = it->second; + X509* cert = it->second; /* found something */ /* check that they are exact */ - if (0 != X509_cmp(cert->certificate, x509)) + if (0 != X509_cmp(cert, x509)) { /* MAJOR ERROR */ std::cerr << "ERROR : AuthSSLimpl::LocalStoreCert() got two ssl certificates with identical ids -> dropping second"; @@ -1825,7 +1694,7 @@ bool AuthSSLimpl::LocalStoreCert(X509* x509) #ifdef AUTHSSL_DEBUG std::cerr << "AuthSSLimpl::LocalStoreCert() storing certificate for " << peerId << std::endl; #endif - mCerts[peerId] = new sslcert(X509_dup(x509), peerId); + mCerts[peerId] = X509_dup(x509); /* flag for saving config */ IndicateConfigChanged(); @@ -1859,7 +1728,7 @@ bool AuthSSLimpl::saveList(bool& cleanup, std::list& lst) // Now save config for network digging strategies RsConfigKeyValueSet *vitem = new RsConfigKeyValueSet ; - std::map::iterator mapIt; + std::map::iterator mapIt; for (mapIt = mCerts.begin(); mapIt != mCerts.end(); ++mapIt) { if (mapIt->first == mOwnId) { continue; @@ -1869,7 +1738,7 @@ bool AuthSSLimpl::saveList(bool& cleanup, std::list& lst) #ifdef AUTHSSL_DEBUG std::cerr << "AuthSSLimpl::saveList() called (mapIt->first) : " << (mapIt->first) << std::endl ; #endif - kv.value = saveX509ToPEM(mapIt->second->certificate); + kv.value = saveX509ToPEM(mapIt->second); vitem->tlvkvs.pairs.push_back(kv) ; } lst.push_back(vitem); @@ -1904,7 +1773,7 @@ bool AuthSSLimpl::loadList(std::list& load) X509 *peer = loadX509FromPEM(kit->value); /* authenticate it */ uint32_t diagnos ; - if (AuthX509WithGPG(peer,diagnos)) + if (AuthX509WithGPG(peer,false,diagnos)) { LocalStoreCert(peer); } @@ -1916,9 +1785,14 @@ bool AuthSSLimpl::loadList(std::list& load) return true; } -/********************************************************************************/ -/********************************************************************************/ -/********************************************************************************/ -/********************************************************************************/ -/********************************************************************************/ +RsAuthSslConnectionAutenticationEvent::RsAuthSslConnectionAutenticationEvent() : + RsEvent(RsEventType::AUTHSSL_CONNECTION_AUTENTICATION), mSuccess(false) {} +const EVP_PKEY*RsX509Cert::getPubKey(const X509& x509) +{ +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) + return x509.cert_info->key->pkey; +#else + return X509_get0_pubkey(&x509); +#endif +} diff --git a/libretroshare/src/pqi/authssl.h b/libretroshare/src/pqi/authssl.h index e6dd33078..d7973e869 100644 --- a/libretroshare/src/pqi/authssl.h +++ b/libretroshare/src/pqi/authssl.h @@ -3,7 +3,8 @@ * * * libretroshare: retroshare core library * * * - * Copyright 2004-2008 by Robert Fernie, Retroshare Team. * + * Copyright (C) 2004-2008 Robert Fernie * + * Copyright (C) 2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -19,21 +20,8 @@ * along with this program. If not, see . * * * *******************************************************************************/ -#ifndef MRK_AUTH_SSL_HEADER -#define MRK_AUTH_SSL_HEADER +#pragma once -/* - * This is an implementation of SSL certificate authentication, which is - * overloaded with pgp style signatures, and web-of-trust authentication. - * - * only the owner ssl cert is store, the rest is jeus callback verification - * - * To use as an SSL authentication system, you must use a common CA certificate. - * * The pqissl stuff doesn't need to differentiate between SSL, SSL + PGP, - * as its X509 certs. - * * The rsserver stuff has to distinguish between all three types ;( - * - */ #include #include @@ -42,197 +30,273 @@ #include #include "util/rsthreads.h" - #include "pqi/pqi_base.h" #include "pqi/pqinetwork.h" #include "pqi/p3cfgmgr.h" +#include "util/rsmemory.h" +#include "retroshare/rsevents.h" -/* This #define removes Connection Manager references in AuthSSL. - * They should not be here. What about Objects and orthogonality? - * This code is also stopping immediate reconnections from working. +/** + * Functions to interact elegantly with X509 certificates, using this functions + * you can avoid annoying #ifdef *SSL_VERSION_NUMBER all around the code. + * Function names should be self descriptive. */ - -class AuthSSL; - -class sslcert +namespace RsX509Cert { - public: - sslcert(X509* x509, const RsPeerId& id); - sslcert(); - - /* certificate parameters */ - RsPeerId id; - std::string name; - std::string location; - std::string org; - std::string email; - - RsPgpId issuer; - PGPFingerprintType fpr; - - /* Auth settings */ - bool authed; - - /* INTERNAL Parameters */ - X509* certificate; +std::string getCertName(const X509& x509); +std::string getCertLocation(const X509& x509); +std::string getCertOrg(const X509& x509); +RsPgpId getCertIssuer(const X509& x509); +std::string getCertIssuerString(const X509& x509); +RsPeerId getCertSslId(const X509& x509); +const EVP_PKEY* getPubKey(const X509& x509); }; -/* required to install instance */ +/** + * Event triggered by AuthSSL when authentication of a connection attempt either + * fail or success + */ +struct RsAuthSslConnectionAutenticationEvent : RsEvent +{ + RsAuthSslConnectionAutenticationEvent(); + bool mSuccess; + RsPeerId mSslId; + std::string mSslCn; + RsPgpId mPgpId; + std::string mErrorMsg; + + ///* @see RsEvent @see RsSerializable + void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx) override + { + RsEvent::serial_process(j, ctx); + RS_SERIAL_PROCESS(mSuccess); + RS_SERIAL_PROCESS(mSslId); + RS_SERIAL_PROCESS(mSslCn); + RS_SERIAL_PROCESS(mPgpId); + RS_SERIAL_PROCESS(mErrorMsg); + } +}; + + +/** + * This is an implementation of SSL certificate authentication with PGP + * signatures, instead of centralized certification authority. + */ class AuthSSL { - public: - AuthSSL(); +public: + static AuthSSL& instance(); -static AuthSSL *getAuthSSL(); -static void AuthSSLInit(); + RS_DEPRECATED_FOR(AuthSSL::instance()) + static AuthSSL* getAuthSSL(); - /* Initialisation Functions (Unique) */ -virtual bool validateOwnCertificate(X509 *x509, EVP_PKEY *pkey) = 0; + /* Initialisation Functions (Unique) */ + virtual bool validateOwnCertificate(X509 *x509, EVP_PKEY *pkey) = 0; -virtual bool active() = 0; -virtual int InitAuth(const char *srvr_cert, const char *priv_key, - const char *passwd, std::string alternative_location_name) = 0; -virtual bool CloseAuth() = 0; + virtual bool active() = 0; + virtual int InitAuth( + const char* srvr_cert, const char* priv_key, const char* passwd, + std::string locationName ) = 0; + virtual bool CloseAuth() = 0; /*********** Overloaded Functions from p3AuthMgr **********/ - - /* get Certificate Id */ -virtual const RsPeerId& OwnId() = 0; -virtual std::string getOwnLocation() = 0; + + /* get Certificate Id */ + virtual const RsPeerId& OwnId() = 0; + virtual std::string getOwnLocation() = 0; /* Load/Save certificates */ -virtual std::string SaveOwnCertificateToString() = 0; - + virtual std::string SaveOwnCertificateToString() = 0; + /* Sign / Encrypt / Verify Data */ -virtual bool SignData(std::string input, std::string &sign) = 0; -virtual bool SignData(const void *data, const uint32_t len, std::string &sign) = 0; + virtual bool SignData(std::string input, std::string &sign) = 0; + virtual bool SignData( + const void* data, const uint32_t len, std::string& sign ) = 0; -virtual bool SignDataBin(std::string, unsigned char*, unsigned int*) = 0; -virtual bool SignDataBin(const void*, uint32_t, unsigned char*, unsigned int*) = 0; -virtual bool VerifyOwnSignBin(const void*, uint32_t, unsigned char*, unsigned int) = 0; -virtual bool VerifySignBin(const void *data, const uint32_t len, - unsigned char *sign, unsigned int signlen, const RsPeerId& sslId) = 0; + virtual bool SignDataBin(std::string, unsigned char*, unsigned int*) = 0; + virtual bool SignDataBin( + const void*, uint32_t, unsigned char*, unsigned int* ) = 0; + virtual bool VerifyOwnSignBin( + const void*, uint32_t, unsigned char*, unsigned int ) = 0; + virtual bool VerifySignBin( + const void* data, const uint32_t len, unsigned char* sign, + unsigned int signlen, const RsPeerId& sslId ) = 0; -// return : false if encrypt failed -virtual bool encrypt(void *&out, int &outlen, const void *in, int inlen, const RsPeerId& peerId) = 0; -// return : false if decrypt fails -virtual bool decrypt(void *&out, int &outlen, const void *in, int inlen) = 0; + /// return false if failed + virtual bool encrypt( + void*& out, int& outlen, const void* in, int inlen, + const RsPeerId& peerId ) = 0; + /// return false if failed + virtual bool decrypt(void*& out, int& outlen, const void* in, int inlen) = 0; + + virtual X509* SignX509ReqWithGPG(X509_REQ* req, long days) = 0; + + /** + * @brief Verify PGP signature correcteness on given X509 certificate + * Beware this doesn't check if the PGP signer is friend or not, just if the + * signature is valid! + * @param[in] x509 pointer ti the X509 certificate to check + * @param[out] diagnostic one of RS_SSL_HANDSHAKE_DIAGNOSTIC_* diagnostic + * codes + * @param[in] verbose if true, prints the authentication result to screen. + * @return true if correctly signed, false otherwise + */ + virtual bool AuthX509WithGPG( + X509* x509, + bool verbose, + uint32_t& diagnostic = RS_DEFAULT_STORAGE_PARAM(uint32_t) + ) = 0; + + /** + * @brief Callback provided to OpenSSL to authenticate connections + * This is the ultimate place where connection attempts get accepted + * if authenticated or refused if not authenticated. + * Emits @see RsAuthSslConnectionAutenticationEvent. + * @param preverify_ok passed by OpenSSL ignored as this call is the first + * in the authentication callback chain + * @param ctx OpenSSL connection context + * @return 0 if authentication failed, 1 if success see OpenSSL + * documentation + */ + virtual int VerifyX509Callback(int preverify_ok, X509_STORE_CTX* ctx) = 0; + + /// SSL specific functions used in pqissl/pqissllistener + virtual SSL_CTX* getCTX() = 0; + + virtual void setCurrentConnectionAttemptInfo( + const RsPgpId& gpg_id, const RsPeerId& ssl_id, + const std::string& ssl_cn ) = 0; + virtual void getCurrentConnectionAttemptInfo( + RsPgpId& gpg_id, RsPeerId& ssl_id, std::string& ssl_cn ) = 0; -virtual X509* SignX509ReqWithGPG(X509_REQ *req, long days) = 0; -virtual bool AuthX509WithGPG(X509 *x509,uint32_t& auth_diagnostic)=0; + /** + * This function parse X509 certificate from the file and return some + * verified informations, like ID and signer + * @return false on error, true otherwise + */ + virtual bool parseX509DetailsFromFile( + const std::string& certFilePath, RsPeerId& certId, RsPgpId& issuer, + std::string& location ) = 0; + virtual ~AuthSSL(); -virtual int VerifyX509Callback(int preverify_ok, X509_STORE_CTX *ctx) = 0; -virtual bool ValidateCertificate(X509 *x509, RsPeerId& peerId) = 0; /* validate + get id */ +protected: + AuthSSL() {} - public: /* SSL specific functions used in pqissl/pqissllistener */ -virtual SSL_CTX *getCTX() = 0; - -/* Restored these functions: */ -virtual void setCurrentConnectionAttemptInfo(const RsPgpId& gpg_id,const RsPeerId& ssl_id,const std::string& ssl_cn) = 0 ; -virtual void getCurrentConnectionAttemptInfo( RsPgpId& gpg_id, RsPeerId& ssl_id, std::string& ssl_cn) = 0 ; - -virtual bool FailedCertificate(X509 *x509, const RsPgpId& gpgid,const RsPeerId& sslid,const std::string& sslcn,const struct sockaddr_storage &addr, bool incoming) = 0; /* store for discovery */ -virtual bool CheckCertificate(const RsPeerId& peerId, X509 *x509) = 0; /* check that they are exact match */ - -static void setAuthSSL_debug(AuthSSL*) ; // used for debug only. The real function is InitSSL() -static AuthSSL *instance_ssl ; + RS_SET_CONTEXT_DEBUG_LEVEL(2) }; class AuthSSLimpl : public AuthSSL, public p3Config { - public: +public: - /* Initialisation Functions (Unique) */ + /** Initialisation Functions (Unique) */ AuthSSLimpl(); -bool validateOwnCertificate(X509 *x509, EVP_PKEY *pkey); + bool validateOwnCertificate(X509 *x509, EVP_PKEY *pkey) override; -virtual bool active(); -virtual int InitAuth(const char *srvr_cert, const char *priv_key, - const char *passwd, std::string alternative_location_name); -virtual bool CloseAuth(); + bool active() override; + int InitAuth( const char *srvr_cert, const char *priv_key, + const char *passwd, std::string locationName ) + override; + + bool CloseAuth() override; /*********** Overloaded Functions from p3AuthMgr **********/ - - /* get Certificate Id */ -virtual const RsPeerId& OwnId(); -virtual std::string getOwnLocation(); + + const RsPeerId& OwnId() override; + virtual std::string getOwnLocation() override; /* Load/Save certificates */ -virtual std::string SaveOwnCertificateToString(); - + virtual std::string SaveOwnCertificateToString() override; + /* Sign / Encrypt / Verify Data */ -virtual bool SignData(std::string input, std::string &sign); -virtual bool SignData(const void *data, const uint32_t len, std::string &sign); + bool SignData(std::string input, std::string &sign) override; + bool SignData( + const void *data, const uint32_t len, std::string &sign) override; -virtual bool SignDataBin(std::string, unsigned char*, unsigned int*); -virtual bool SignDataBin(const void*, uint32_t, unsigned char*, unsigned int*); -virtual bool VerifyOwnSignBin(const void*, uint32_t, unsigned char*, unsigned int); -virtual bool VerifySignBin(const void *data, const uint32_t len, - unsigned char *sign, unsigned int signlen, const RsPeerId& sslId); + bool SignDataBin(std::string, unsigned char*, unsigned int*) override; + virtual bool SignDataBin( + const void*, uint32_t, unsigned char*, unsigned int*) override; + bool VerifyOwnSignBin( + const void*, uint32_t, unsigned char*, unsigned int) override; + virtual bool VerifySignBin( + const void *data, const uint32_t len, unsigned char *sign, + unsigned int signlen, const RsPeerId& sslId) override; -// return : false if encrypt failed -virtual bool encrypt(void *&out, int &outlen, const void *in, int inlen, const RsPeerId& peerId); -// return : false if decrypt fails -virtual bool decrypt(void *&out, int &outlen, const void *in, int inlen); + bool encrypt( + void*& out, int& outlen, const void* in, int inlen, + const RsPeerId& peerId ) override; + bool decrypt(void *&out, int &outlen, const void *in, int inlen) override; + virtual X509* SignX509ReqWithGPG(X509_REQ *req, long days) override; -virtual X509* SignX509ReqWithGPG(X509_REQ *req, long days); -virtual bool AuthX509WithGPG(X509 *x509,uint32_t& auth_diagnostic); + /// @see AuthSSL + bool AuthX509WithGPG(X509 *x509, bool verbose, uint32_t& auth_diagnostic) override; + /// @see AuthSSL + int VerifyX509Callback(int preverify_ok, X509_STORE_CTX *ctx) override; -virtual int VerifyX509Callback(int preverify_ok, X509_STORE_CTX *ctx); -virtual bool ValidateCertificate(X509 *x509, RsPeerId& peerId); /* validate + get id */ + /// @see AuthSSL + bool parseX509DetailsFromFile( + const std::string& certFilePath, RsPeerId& certId, + RsPgpId& issuer, std::string& location ) override; /*****************************************************************/ /*********************** p3config ******************************/ - /* Key Functions to be overloaded for Full Configuration */ - virtual RsSerialiser *setupSerialiser(); - virtual bool saveList(bool &cleanup, std::list& ); - virtual bool loadList(std::list& load); + /* Key Functions to be overloaded for Full Configuration */ + RsSerialiser* setupSerialiser() override; + bool saveList(bool &cleanup, std::list& ) override; + bool loadList(std::list& load) override; /*****************************************************************/ - public: /* SSL specific functions used in pqissl/pqissllistener */ -virtual SSL_CTX *getCTX(); +public: + /* SSL specific functions used in pqissl/pqissllistener */ + SSL_CTX* getCTX() override; -/* Restored these functions: */ -virtual void setCurrentConnectionAttemptInfo(const RsPgpId& gpg_id,const RsPeerId& ssl_id,const std::string& ssl_cn) ; -virtual void getCurrentConnectionAttemptInfo( RsPgpId& gpg_id, RsPeerId& ssl_id, std::string& ssl_cn) ; -virtual bool FailedCertificate(X509 *x509, const RsPgpId& gpgid,const RsPeerId& sslid,const std::string& sslcn,const struct sockaddr_storage &addr, bool incoming); /* store for discovery */ -virtual bool CheckCertificate(const RsPeerId& peerId, X509 *x509); /* check that they are exact match */ + /* Restored these functions: */ + void setCurrentConnectionAttemptInfo( + const RsPgpId& gpg_id, const RsPeerId& ssl_id, + const std::string& ssl_cn ) override; + void getCurrentConnectionAttemptInfo( + RsPgpId& gpg_id, RsPeerId& ssl_id, std::string& ssl_cn ) override; - private: +private: -bool LocalStoreCert(X509* x509); -bool RemoveX509(const RsPeerId id); + bool LocalStoreCert(X509* x509); + bool RemoveX509(const RsPeerId id); /*********** LOCKED Functions ******/ -bool locked_FindCert(const RsPeerId& id, sslcert **cert); + bool locked_FindCert(const RsPeerId& id, X509** cert); /* Data */ /* these variables are constants -> don't need to protect */ SSL_CTX *sslctx; RsPeerId mOwnId; - sslcert *mOwnCert; + X509* mOwnCert; - RsMutex sslMtx; /* protects all below */ + /** + * If the location name is included in SSL certificate it becomes a public + * information, because anyone able to open an SSL connection to the host is + * able to read it. To avoid that location name is now stored separately and + * and not included in the SSL certificate. + */ + std::string mOwnLocationName; + RsMutex sslMtx; /* protects all below */ - EVP_PKEY *mOwnPrivateKey; - EVP_PKEY *mOwnPublicKey; + EVP_PKEY* mOwnPrivateKey; + EVP_PKEY* mOwnPublicKey; int init; + std::map mCerts; - std::map mCerts; - - RsPgpId _last_gpgid_to_connect ; - std::string _last_sslcn_to_connect ; - RsPeerId _last_sslid_to_connect ; + RsPgpId _last_gpgid_to_connect; + std::string _last_sslcn_to_connect; + RsPeerId _last_sslid_to_connect; }; - -#endif // MRK_AUTH_SSL_HEADER diff --git a/libretroshare/src/pqi/p3linkmgr.cc b/libretroshare/src/pqi/p3linkmgr.cc index 2110e23a8..fec5b8e5f 100644 --- a/libretroshare/src/pqi/p3linkmgr.cc +++ b/libretroshare/src/pqi/p3linkmgr.cc @@ -101,14 +101,20 @@ peerAddrInfo::peerAddrInfo() } peerConnectState::peerConnectState() - : connecttype(0), - lastavailable(0), - lastattempt(0), - name(""), - state(0), actions(0), - source(0), - inConnAttempt(0), - wasDeniedConnection(false), deniedTS(false), deniedInConnAttempt(false) + : dhtVisible(false), + connecttype(0), + actAsServer(false), + lastavailable(0), + lastattempt(0), + name(""), + state(0), + actions(0), + linkType(0), + source(0), + inConnAttempt(false), + wasDeniedConnection(false), + deniedTS(0), + deniedInConnAttempt(false) { } @@ -471,12 +477,24 @@ void p3LinkMgrIMPL::tickMonitors() if (peer.actions & RS_PEER_CONNECTED) { p3Notify *notify = RsServer::notify(); + if (notify) { + // normally these two below should disappear: there's no notion of popup in libretroshare. + // all GUI-type display features should be chosen in NotifyQt. notify->AddPopupMessage(RS_POPUP_CONNECT, peer.id.toStdString(),"", "Online: "); notify->AddFeedItem(RS_FEED_ITEM_PEER_CONNECT, peer.id.toStdString()); + + notify->notifyPeerConnected(peer.id.toStdString()); } } + if (peer.actions & RS_PEER_DISCONNECTED) + { + p3Notify *notify = RsServer::notify(); + + if (notify) + notify->notifyPeerDisconnected(peer.id.toStdString()); + } } } @@ -1032,47 +1050,6 @@ bool p3LinkMgrIMPL::connectResult(const RsPeerId &id, bool success, bool isIncom * From various sources */ -// from pqissl, when a connection failed due to security -void p3LinkMgrIMPL::notifyDeniedConnection(const RsPgpId& gpgid,const RsPeerId& sslid,const std::string& sslcn,const struct sockaddr_storage &/*addr*/, bool incoming) -{ - std::cerr << "p3LinkMgrIMPL::notifyDeniedConnection()"; - std::cerr << " pgpid: " << gpgid; - std::cerr << " sslid: " << sslid; - std::cerr << " sslcn: " << sslcn; - std::cerr << std::endl; - - RsStackMutex stack(mLinkMtx); /****** STACK LOCK MUTEX *******/ - - std::map::iterator it; - it = mFriendList.find(sslid); - if (it == mFriendList.end()) - { - std::cerr << "p3LinkMgrIMPL::notifyDeniedConnection() of NON-FRIEND: " << sslid; - std::cerr << std::endl; - return; - } - - it->second.wasDeniedConnection = true; - it->second.deniedTS = time(NULL); - - if ((!incoming) && it->second.inConnAttempt) - { - it->second.deniedInConnAttempt = true; - it->second.deniedConnectionAttempt = it->second.currentConnAddrAttempt; - - std::cerr << "p3LinkMgrIMPL::notifyDeniedConnection() Denied In Connection Attempt"; - std::cerr << std::endl; - } - else - { - it->second.deniedInConnAttempt = false; - std::cerr << "p3LinkMgrIMPL::notifyDeniedConnection() Denied NOT In Connection Attempt"; - std::cerr << std::endl; - } - return; -} - - void p3LinkMgrIMPL::peerStatus(const RsPeerId& id, const pqiIpAddrSet &addrs, uint32_t type, uint32_t flags, uint32_t source) { @@ -1656,30 +1633,8 @@ bool p3LinkMgrIMPL::retryConnectTCP(const RsPeerId &id) return false; } - -#define MAX_TCP_ADDR_AGE (3600 * 24 * 14) // two weeks in seconds. - -bool p3LinkMgrIMPL::locked_CheckPotentialAddr(const struct sockaddr_storage &addr, rstime_t age) +bool p3LinkMgrIMPL::locked_CheckPotentialAddr(const sockaddr_storage& addr) { -#ifdef LINKMGR_DEBUG - std::cerr << "p3LinkMgrIMPL::locked_CheckPotentialAddr("; - std::cerr << sockaddr_storage_tostring(addr); - std::cerr << ", " << age << ")"; - std::cerr << std::endl; -#endif - - /* - * if it is old - quick rejection - */ - if (age > MAX_TCP_ADDR_AGE) - { -#ifdef LINKMGR_DEBUG - std::cerr << "p3LinkMgrIMPL::locked_CheckPotentialAddr() REJECTING - TOO OLD"; - std::cerr << std::endl; -#endif - return false; - } - /* if invalid - quick rejection */ if ( ! sockaddr_storage_isValidNet(addr) ) { @@ -1726,7 +1681,7 @@ void p3LinkMgrIMPL::locked_ConnectAttempt_SpecificAddress(peerConnectState *pee std::cerr << "p3LinkMgrIMPL::locked_ConnectAttempt_SpecificAddresses()"; std::cerr << std::endl; #endif - if (locked_CheckPotentialAddr(remoteAddr, 0)) + if(locked_CheckPotentialAddr(remoteAddr)) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::locked_ConnectAttempt_SpecificAddresses() "; @@ -1757,7 +1712,7 @@ void p3LinkMgrIMPL::locked_ConnectAttempt_CurrentAddresses(peerConnectState *pe #endif // Just push all the addresses onto the stack. /* try "current addresses" first */ - if (locked_CheckPotentialAddr(localAddr, 0)) + if (locked_CheckPotentialAddr(localAddr)) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::locked_ConnectAttempt_CurrentAddresses() "; @@ -1778,7 +1733,7 @@ void p3LinkMgrIMPL::locked_ConnectAttempt_CurrentAddresses(peerConnectState *pe addAddressIfUnique(peer->connAddrs, pca, false); } - if (locked_CheckPotentialAddr(serverAddr, 0)) + if (locked_CheckPotentialAddr(serverAddr)) { #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::locked_ConnectAttempt_CurrentAddresses() "; @@ -1806,7 +1761,6 @@ void p3LinkMgrIMPL::locked_ConnectAttempt_HistoricalAddresses(peerConnectState /* now try historical addresses */ /* try local addresses first */ std::list::const_iterator ait; - rstime_t now = time(NULL); #ifdef LINKMGR_DEBUG std::cerr << "p3LinkMgrIMPL::locked_ConnectAttempt_HistoricalAddresses()"; @@ -1814,7 +1768,7 @@ void p3LinkMgrIMPL::locked_ConnectAttempt_HistoricalAddresses(peerConnectState #endif for(ait = ipAddrs.mLocal.mAddrs.begin(); ait != ipAddrs.mLocal.mAddrs.end(); ++ait) { - if (locked_CheckPotentialAddr(ait->mAddr, now - ait->mSeenTime)) + if (locked_CheckPotentialAddr(ait->mAddr)) { #ifdef LINKMGR_DEBUG @@ -1841,7 +1795,7 @@ void p3LinkMgrIMPL::locked_ConnectAttempt_HistoricalAddresses(peerConnectState for(ait = ipAddrs.mExt.mAddrs.begin(); ait != ipAddrs.mExt.mAddrs.end(); ++ait) { - if (locked_CheckPotentialAddr(ait->mAddr, now - ait->mSeenTime)) + if (locked_CheckPotentialAddr(ait->mAddr)) { #ifdef LINKMGR_DEBUG @@ -1898,7 +1852,7 @@ void p3LinkMgrIMPL::locked_ConnectAttempt_AddDynDNS(peerConnectState *peer, std pca.bandwidth = 0; /* check address validity */ - if (locked_CheckPotentialAddr(pca.addr, 0)) + if (locked_CheckPotentialAddr(pca.addr)) { addAddressIfUnique(peer->connAddrs, pca, true); } @@ -1959,7 +1913,7 @@ void p3LinkMgrIMPL::locked_ConnectAttempt_ProxyAddress(peerConnectState *peer, pca.domain_port = domain_port; /* check address validity */ - if (locked_CheckPotentialAddr(pca.addr, 0)) + if (locked_CheckPotentialAddr(pca.addr)) { addAddressIfUnique(peer->connAddrs, pca, true); } @@ -2207,11 +2161,10 @@ void p3LinkMgrIMPL::printPeerLists(std::ostream &out) return; } -bool p3LinkMgrIMPL::checkPotentialAddr(const sockaddr_storage &addr, rstime_t age) +bool p3LinkMgrIMPL::checkPotentialAddr(const sockaddr_storage& addr) { - RsStackMutex stack(mLinkMtx); /****** STACK LOCK MUTEX *******/ - - return locked_CheckPotentialAddr(addr,age) ; + RS_STACK_MUTEX(mLinkMtx); + return locked_CheckPotentialAddr(addr); } diff --git a/libretroshare/src/pqi/p3linkmgr.h b/libretroshare/src/pqi/p3linkmgr.h index d10a3fbfe..3b2c5c638 100644 --- a/libretroshare/src/pqi/p3linkmgr.h +++ b/libretroshare/src/pqi/p3linkmgr.h @@ -171,8 +171,6 @@ virtual bool connectAttempt(const RsPeerId &id, struct sockaddr_storage &raddr, virtual bool connectResult(const RsPeerId &id, bool success, bool isIncomingConnection, uint32_t flags, const struct sockaddr_storage &remote_peer_address) = 0; virtual bool retryConnect(const RsPeerId &id) = 0; -virtual void notifyDeniedConnection(const RsPgpId& gpgid,const RsPeerId& sslid,const std::string& sslcn,const struct sockaddr_storage &addr, bool incoming) = 0; - /* Network Addresses */ virtual bool setLocalAddress(const struct sockaddr_storage &addr) = 0; virtual bool getLocalAddress(struct sockaddr_storage &addr) = 0; @@ -182,7 +180,7 @@ virtual bool getLocalAddress(struct sockaddr_storage &addr) = 0; virtual void getFriendList(std::list &ssl_peers) = 0; // ONLY used by p3peers.cc USE p3PeerMgr instead. virtual bool getFriendNetStatus(const RsPeerId &id, peerConnectState &state) = 0; // ONLY used by p3peers.cc -virtual bool checkPotentialAddr(const struct sockaddr_storage &addr, rstime_t age)=0; + virtual bool checkPotentialAddr(const sockaddr_storage& addr) = 0; /************* DEPRECIATED FUNCTIONS (TO REMOVE) ********/ virtual int addFriend(const RsPeerId &ssl_id, bool isVisible) = 0; @@ -230,8 +228,6 @@ virtual bool connectAttempt(const RsPeerId &id, struct sockaddr_storage &raddr, virtual bool connectResult(const RsPeerId &id, bool success, bool isIncomingConnection, uint32_t flags, const struct sockaddr_storage &remote_peer_address); virtual bool retryConnect(const RsPeerId &id); -virtual void notifyDeniedConnection(const RsPgpId& gpgid,const RsPeerId& sslid,const std::string& sslcn,const struct sockaddr_storage &addr, bool incoming); - /* Network Addresses */ virtual bool setLocalAddress(const struct sockaddr_storage &addr); virtual bool getLocalAddress(struct sockaddr_storage &addr); @@ -269,7 +265,8 @@ int removeFriend(const RsPeerId &ssl_id); void printPeerLists(std::ostream &out); -virtual bool checkPotentialAddr(const struct sockaddr_storage &addr, rstime_t age); + virtual bool checkPotentialAddr(const sockaddr_storage& addr); + protected: /* THESE CAN PROBABLY BE REMOVED */ //bool shutdown(); /* blocking shutdown call */ @@ -302,7 +299,8 @@ void locked_ConnectAttempt_ProxyAddress(peerConnectState *peer, const uint32_t bool locked_ConnectAttempt_Complete(peerConnectState *peer); -bool locked_CheckPotentialAddr(const struct sockaddr_storage &addr, rstime_t age); + bool locked_CheckPotentialAddr(const sockaddr_storage& addr); + bool addAddressIfUnique(std::list &addrList, peerConnectAddress &pca, bool pushFront); diff --git a/libretroshare/src/pqi/p3notify.cc b/libretroshare/src/pqi/p3notify.cc index 2ffd3c5cd..621c34119 100644 --- a/libretroshare/src/pqi/p3notify.cc +++ b/libretroshare/src/pqi/p3notify.cc @@ -217,6 +217,8 @@ void p3Notify::notifyChatLobbyEvent(uint64_t lobby_id, uint32_t event_type,const void p3Notify::notifyListPreChange(int list, int type) { FOR_ALL_NOTIFY_CLIENTS (*it)->notifyListPreChange(list,type) ; } void p3Notify::notifyListChange (int list, int type) { FOR_ALL_NOTIFY_CLIENTS (*it)->notifyListChange (list,type) ; } +void p3Notify::notifyPeerConnected (const std::string& peer_id) { FOR_ALL_NOTIFY_CLIENTS (*it)->notifyPeerConnected(peer_id); } +void p3Notify::notifyPeerDisconnected (const std::string& peer_id) { FOR_ALL_NOTIFY_CLIENTS (*it)->notifyPeerDisconnected(peer_id); } void p3Notify::notifyErrorMsg (int list, int sev, std::string msg) { FOR_ALL_NOTIFY_CLIENTS (*it)->notifyErrorMsg(list,sev,msg) ; } void p3Notify::notifyChatMessage (const ChatMessage &msg) { FOR_ALL_NOTIFY_CLIENTS (*it)->notifyChatMessage(msg) ; } void p3Notify::notifyChatStatus (const ChatId& chat_id, const std::string& status_string) { FOR_ALL_NOTIFY_CLIENTS (*it)->notifyChatStatus(chat_id,status_string) ; } diff --git a/libretroshare/src/pqi/p3notify.h b/libretroshare/src/pqi/p3notify.h index d288091c3..7cbbbef55 100644 --- a/libretroshare/src/pqi/p3notify.h +++ b/libretroshare/src/pqi/p3notify.h @@ -91,6 +91,8 @@ class p3Notify: public RsNotify // Notifications of clients. Can be called from anywhere inside libretroshare. // + void notifyPeerConnected (const std::string& /* peer_id */); + void notifyPeerDisconnected (const std::string& /* peer_id */); void notifyListPreChange (int /* list */, int /* type */) ; void notifyListChange (int /* list */, int /* type */) ; void notifyErrorMsg (int /* list */, int /* sev */, std::string /* msg */) ; diff --git a/libretroshare/src/pqi/p3peermgr.cc b/libretroshare/src/pqi/p3peermgr.cc index 1274c38c0..1adf191d1 100644 --- a/libretroshare/src/pqi/p3peermgr.cc +++ b/libretroshare/src/pqi/p3peermgr.cc @@ -89,7 +89,7 @@ static const std::string kConfigKeyProxyServerPortI2P = "PROXY_SERVER_PORT_I2P"; void printConnectState(std::ostream &out, peerState &peer); peerState::peerState() - :netMode(RS_NET_MODE_UNKNOWN), vs_disc(RS_VS_DISC_FULL), vs_dht(RS_VS_DHT_FULL), lastcontact(0), + :skip_pgp_signature_validation(false),netMode(RS_NET_MODE_UNKNOWN), vs_disc(RS_VS_DISC_FULL), vs_dht(RS_VS_DHT_FULL), lastcontact(0), hiddenNode(false), hiddenPort(0), hiddenType(RS_HIDDEN_TYPE_NONE) { sockaddr_storage_clear(localaddr); @@ -338,17 +338,31 @@ bool p3PeerMgrIMPL::isFriend(const RsPeerId& id) #ifdef PEER_DEBUG_COMMON std::cerr << "p3PeerMgrIMPL::isFriend(" << id << ") called" << std::endl; #endif - RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ + RS_STACK_MUTEX(mPeerMtx); bool ret = (mFriendList.end() != mFriendList.find(id)); #ifdef PEER_DEBUG_COMMON std::cerr << "p3PeerMgrIMPL::isFriend(" << id << ") returning : " << ret << std::endl; #endif return ret; } +bool p3PeerMgrIMPL::isSslOnlyFriend(const RsPeerId& id) +{ +#ifdef PEER_DEBUG_COMMON + std::cerr << "p3PeerMgrIMPL::isFriend(" << id << ") called" << std::endl; +#endif + RS_STACK_MUTEX(mPeerMtx); + auto it = mFriendList.find(id); + bool ret = it != mFriendList.end() && it->second.skip_pgp_signature_validation ; + +#ifdef PEER_DEBUG_COMMON + std::cerr << "p3PeerMgrIMPL::isFriend(" << id << ") returning : " << ret << std::endl; +#endif + return ret; +} bool p3PeerMgrIMPL::getPeerName(const RsPeerId &ssl_id, std::string &name) { - RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ + RS_STACK_MUTEX(mPeerMtx); /* check for existing */ std::map::iterator it; @@ -826,19 +840,6 @@ bool p3PeerMgrIMPL::getFriendNetStatus(const RsPeerId &id, peerState &state) } -bool p3PeerMgrIMPL::getOthersNetStatus(const RsPeerId &id, peerState &state) -{ - RS_STACK_MUTEX(mPeerMtx); - - /* check for existing */ - std::map::iterator it; - it = mOthersList.find(id); - if (it == mOthersList.end()) return false; - - state = it->second; - return true; -} - int p3PeerMgrIMPL::getConnectAddresses( const RsPeerId &id, sockaddr_storage &lAddr, sockaddr_storage &eAddr, pqiIpAddrSet &histAddrs, std::string &dyndns ) @@ -872,8 +873,7 @@ bool p3PeerMgrIMPL::haveOnceConnected() RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ /* check for existing */ - std::map::iterator it; - for(it = mFriendList.begin(); it != mFriendList.end(); ++it) + for(auto it = mFriendList.begin(); it != mFriendList.end(); ++it) { if (it->second.lastcontact > 0) { @@ -896,6 +896,28 @@ bool p3PeerMgrIMPL::haveOnceConnected() } +bool p3PeerMgrIMPL::notifyPgpKeyReceived(const RsPgpId& pgp_id) +{ + RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ + + bool changed = false; + + for(auto it(mFriendList.begin());it!=mFriendList.end();++it) + { + if(it->second.gpg_id == pgp_id) + { + std::cerr << "(WW) notification that full key " << pgp_id << " is available. Reseting short invite flag for peer " << it->first << std::endl; + it->second.skip_pgp_signature_validation = false; + + changed = true; + } + } + + if(changed) + IndicateConfigChanged(); + + return true; +} /*******************************************************************/ /*******************************************************************/ @@ -915,9 +937,7 @@ bool p3PeerMgrIMPL::addFriend(const RsPeerId& input_id, const RsPgpId& input_gpg if (id == AuthSSL::getAuthSSL()->OwnId()) { -#ifdef PEER_DEBUG - std::cerr << "p3PeerMgrIMPL::addFriend() cannot add own id as a friend." << std::endl; -#endif + RsErr() << "p3PeerMgrIMPL::addFriend() cannot add own id as a friend. That's a bug!" << std::endl; /* (1) already exists */ return false; } @@ -932,15 +952,27 @@ bool p3PeerMgrIMPL::addFriend(const RsPeerId& input_id, const RsPgpId& input_gpg #endif std::map::iterator it; - if (mFriendList.end() != mFriendList.find(id)) + if (mFriendList.end() != (it=mFriendList.find(id))) { -#ifdef PEER_DEBUG - std::cerr << "p3PeerMgrIMPL::addFriend() Already Exists" << std::endl; -#endif - /* (1) already exists */ - return true; + // The friend may already be here, including with a short invite (meaning the PGP key is unknown). + + if(it->second.gpg_id != input_gpg_id)// already exists as a friend with a different PGP id!! + { + RsErr() << "Trying to add SSL id (" << id << ") that is already a friend with existing PGP key (" << it->second.gpg_id << ") but using a different PGP key (" << input_gpg_id << "). This is a bug!" << std::endl; + return false; + } + else + return true; /* (1) already exists */ } + // check that the PGP key is known + + if(!AuthGPG::getAuthGPG()->isGPGId(gpg_id)) + { + RsErr() << "Trying to add SSL id (" << id << ") to be validated with unknown PGP key (" << gpg_id << ". This is a bug!" << std::endl; + return false; + } + //Authentication is now tested at connection time, we don't store the ssl cert anymore // if (!AuthGPG::getAuthGPG()->isGPGAccepted(gpg_id) && gpg_id != AuthGPG::getAuthGPG()->getGPGOwnId()) @@ -952,61 +984,70 @@ bool p3PeerMgrIMPL::addFriend(const RsPeerId& input_id, const RsPgpId& input_gpg return false; } + // after that, we know that we have the key, because AuthGPG wouldn't answer yes for a key it doesn't know. /* check if it is in others */ - if (mOthersList.end() != (it = mOthersList.find(id))) - { - /* (2) in mOthersList -> move over */ +// if (mOthersList.end() != (it = mOthersList.find(id))) +// { +// /* (2) in mOthersList -> move over */ +//#ifdef PEER_DEBUG +// std::cerr << "p3PeerMgrIMPL::addFriend() Move from Others" << std::endl; +//#endif +// if(!it->second.gpg_id.isNull() && it->second.gpg_id != input_gpg_id)// already exists as a friend with a different PGP id!! +// RsErr() << "Trying to add SSL id (" << id << ") that is already known (but not friend) with existing PGP key (" << it->second.gpg_id +// << ") but using a different PGP key (" << input_gpg_id << "). This looks like a bug! The friend will be added again with the new PGP key ID." << std::endl; +// +// mFriendList[id] = it->second; +// mOthersList.erase(it); +// +// it = mFriendList.find(id); +// +// /* setup connectivity parameters */ +// it->second.vs_disc = vs_disc; +// it->second.vs_dht = vs_dht; +// +// it->second.netMode = netMode; +// it->second.lastcontact = lastContact; +// +// it->second.gpg_id = input_gpg_id; +// it->second.skip_pgp_signature_validation = false; +// +// mStatusChanged = true; +// +// notifyLinkMgr = true; +// +// IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/ +// } +// else + #ifdef PEER_DEBUG - std::cerr << "p3PeerMgrIMPL::addFriend() Move from Others" << std::endl; + std::cerr << "p3PeerMgrIMPL::addFriend() Creating New Entry" << std::endl; #endif - mFriendList[id] = it->second; - mOthersList.erase(it); + /* create a new entry */ + peerState pstate; - it = mFriendList.find(id); + pstate.id = id; + pstate.gpg_id = gpg_id; + pstate.name = AuthGPG::getAuthGPG()->getGPGName(gpg_id); - /* setup connectivity parameters */ - it->second.vs_disc = vs_disc; - it->second.vs_dht = vs_dht; + pstate.vs_disc = vs_disc; + pstate.vs_dht = vs_dht; + pstate.netMode = netMode; + pstate.lastcontact = lastContact; - it->second.netMode = netMode; - it->second.lastcontact = lastContact; + pstate.gpg_id = input_gpg_id; + pstate.skip_pgp_signature_validation = false; - mStatusChanged = true; + /* addr & timestamps -> auto cleared */ - notifyLinkMgr = true; + mFriendList[id] = pstate; - IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/ - } - else - { -#ifdef PEER_DEBUG - std::cerr << "p3PeerMgrIMPL::addFriend() Creating New Entry" << std::endl; -#endif + mStatusChanged = true; - /* create a new entry */ - peerState pstate; + notifyLinkMgr = true; - pstate.id = id; - pstate.gpg_id = gpg_id; - pstate.name = AuthGPG::getAuthGPG()->getGPGName(gpg_id); - - pstate.vs_disc = vs_disc; - pstate.vs_dht = vs_dht; - pstate.netMode = netMode; - pstate.lastcontact = lastContact; - - /* addr & timestamps -> auto cleared */ - - mFriendList[id] = pstate; - - mStatusChanged = true; - - notifyLinkMgr = true; - - IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/ - } + IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/ } if (notifyLinkMgr) @@ -1029,6 +1070,93 @@ bool p3PeerMgrIMPL::addFriend(const RsPeerId& input_id, const RsPgpId& input_gpg return true; } + +bool p3PeerMgrIMPL::addSslOnlyFriend( const RsPeerId& sslId, const RsPgpId& pgp_id,const RsPeerDetails& dt ) +{ + if(sslId.isNull() || sslId == getOwnId()) + { + RsErr() <<"Attempt to add yourself or a null ID as SSL-only friend (id=" << sslId << ")" << std::endl; + return false; + } + + peerState pstate; + +// { +// RS_STACK_MUTEX(mPeerMtx); +// +// /* If in mOthersList -> move over */ +// auto it = mOthersList.find(sslId); +// if (it != mOthersList.end()) +// { +// pstate = it->second; +// mOthersList.erase(it); +// } +// +// +// } // RS_STACK_MUTEX(mPeerMtx); + + if(!pstate.gpg_id.isNull() && AuthGPG::getAuthGPG()->isGPGAccepted(pstate.gpg_id)) + { + RsErr() << "Trying to add as SSL-only friend a peer which PGP id is already a friend. This means the code is inconsistent. Not doing this!" << std::endl; + return false; + } + + if(pgp_id.isNull()) + { + RsErr() << "Null pgp id for friend added with skip_pgp_signature_validaiton flag. This is not allowed." << std::endl; + return false; + } + + pstate.gpg_id = pgp_id; + pstate.id = sslId; + + if(!dt.name.empty()) pstate.name = dt.name; + if(!dt.dyndns.empty()) pstate.dyndns = dt.dyndns; + pstate.hiddenNode = dt.isHiddenNode; + if(!dt.hiddenNodeAddress.empty()) + pstate.hiddenDomain = dt.hiddenNodeAddress; + if(dt.hiddenNodePort) pstate.hiddenPort = dt.hiddenNodePort; + if(dt.hiddenType) pstate.hiddenType = dt.hiddenType; + if(!dt.location.empty()) pstate.location = dt.location; + + pstate.skip_pgp_signature_validation = true; + + { RS_STACK_MUTEX(mPeerMtx); + + mFriendList[sslId] = pstate; + mStatusChanged = true; + + } // RS_STACK_MUTEX(mPeerMtx); + + IndicateConfigChanged(); + mLinkMgr->addFriend(sslId, dt.vs_dht != RS_VS_DHT_OFF); + + // To update IP addresses is much more confortable to use locators + if(!dt.isHiddenNode) + { + for(const std::string& locator : dt.ipAddressList) + addPeerLocator(sslId, locator); + + if(dt.extPort && !dt.extAddr.empty()) + { + RsUrl locator; + locator.setScheme("ipv4").setHost(dt.extAddr) + .setPort(dt.extPort); + addPeerLocator(sslId, locator); + } + + if(dt.localPort && !dt.localAddr.empty()) + { + RsUrl locator; + locator.setScheme("ipv4").setHost(dt.localAddr) + .setPort(dt.localPort); + addPeerLocator(sslId, locator); + } + } + + return true; +} + bool p3PeerMgrIMPL::removeFriend(const RsPgpId &id) { #ifdef PEER_DEBUG @@ -1059,7 +1187,7 @@ bool p3PeerMgrIMPL::removeFriend(const RsPgpId &id) sslid_toRemove.push_back(it->second.id); - mOthersList[it->second.id] = peer; + //mOthersList[it->second.id] = peer; mStatusChanged = true; //success = true; @@ -1134,7 +1262,7 @@ bool p3PeerMgrIMPL::removeFriend(const RsPeerId &id, bool removePgpId) if(removePgpId) pgpid_toRemove.push_back(it->second.gpg_id); - mOthersList[id] = peer; + //mOthersList[id] = peer; mStatusChanged = true; //success = true; @@ -1194,14 +1322,14 @@ void p3PeerMgrIMPL::printPeerLists(std::ostream &out) out << std::endl; } - out << "p3PeerMgrIMPL::printPeerLists() Others List"; - out << std::endl; - for(it = mOthersList.begin(); it != mOthersList.end(); ++it) - { - out << "\t SSL ID: " << it->second.id; - out << "\t GPG ID: " << it->second.gpg_id; - out << std::endl; - } +// out << "p3PeerMgrIMPL::printPeerLists() Others List"; +// out << std::endl; +// for(it = mOthersList.begin(); it != mOthersList.end(); ++it) +// { +// out << "\t SSL ID: " << it->second.id; +// out << "\t GPG ID: " << it->second.gpg_id; +// out << std::endl; +// } } return; @@ -1383,16 +1511,10 @@ bool p3PeerMgrIMPL::addPeerLocator(const RsPeerId &sslId, const RsUrl& locator) auto it = mFriendList.find(sslId); if (it == mFriendList.end()) { - it = mOthersList.find(sslId); - if (it == mOthersList.end()) - { #ifdef PEER_DEBUG - std::cerr << __PRETTY_FUNCTION__ << "cannot add address " - << "info, peer id: " << sslId << " not found in list" - << std::endl; + std::cerr << __PRETTY_FUNCTION__ << "cannot add address " << "info, peer id: " << sslId << " not found in list" << std::endl; #endif return false; - } } changed = it->second.ipAddrs.updateLocalAddrs(ip); @@ -1440,15 +1562,10 @@ bool p3PeerMgrIMPL::setLocalAddress( const RsPeerId &id, std::map::iterator it; if (mFriendList.end() == (it = mFriendList.find(id))) { - if (mOthersList.end() == (it = mOthersList.find(id))) - { #ifdef PEER_DEBUG - std::cerr << "p3PeerMgrIMPL::setLocalAddress() cannot add addres " - << "info : peer id not found in friend list id: " - << id << std::endl; + std::cerr << "p3PeerMgrIMPL::setLocalAddress() cannot add addres " << "info : peer id not found in friend list id: " << id << std::endl; #endif return false; - } } /* "it" points to peer */ @@ -1476,12 +1593,12 @@ bool p3PeerMgrIMPL::setExtAddress( const RsPeerId &id, bool changed = false; uint32_t check_res = 0; - if( rsBanList!=NULL && !rsBanList->isAddressAccepted( - addr, RSBANLIST_CHECKING_FLAGS_BLACKLIST, &check_res) ) + if(rsBanList && !rsBanList->isAddressAccepted( + addr, RSBANLIST_CHECKING_FLAGS_BLACKLIST, check_res )) { - std::cerr << "(SS) trying to set external contact address for peer " - << id << " to a banned address " - << sockaddr_storage_iptostring(addr) << std::endl; + RsErr() << __PRETTY_FUNCTION__ << " trying to set external contact " + << "address for peer: " << id << " to a banned address " << addr + << std::endl; return false; } @@ -1506,15 +1623,10 @@ bool p3PeerMgrIMPL::setExtAddress( const RsPeerId &id, std::map::iterator it; if (mFriendList.end() == (it = mFriendList.find(id))) { - if (mOthersList.end() == (it = mOthersList.find(id))) - { #ifdef PEER_DEBUG - std::cerr << "p3PeerMgrIMPL::setLocalAddress() cannot add addres " - << "info : peer id not found in friend list id: " << id - << std::endl; + std::cerr << "p3PeerMgrIMPL::setLocalAddress() cannot add addres " << "info : peer id not found in friend list id: " << id << std::endl; #endif return false; - } } /* "it" points to peer */ @@ -1561,13 +1673,10 @@ bool p3PeerMgrIMPL::setDynDNS(const RsPeerId &id, const std::string &dyndns) std::map::iterator it; if (mFriendList.end() == (it = mFriendList.find(id))) { - if (mOthersList.end() == (it = mOthersList.find(id))) - { #ifdef PEER_DEBUG - std::cerr << "p3PeerMgrIMPL::setDynDNS() cannot add dyn dns info : peer id not found in friend list id: " << id << std::endl; + std::cerr << "p3PeerMgrIMPL::setDynDNS() cannot add dyn dns info : peer id not found in friend list id: " << id << std::endl; #endif - return false; - } + return false; } /* "it" points to peer */ @@ -1602,7 +1711,7 @@ bool p3PeerMgrIMPL::addCandidateForOwnExternalAddress(const RsPeerId &from, cons sockaddr_storage_clear(addr_filtered) ; sockaddr_storage_copyip(addr_filtered,addr) ; -#ifdef PEER_DEBUG +#ifndef PEER_DEBUG std::cerr << "Own external address is " << sockaddr_storage_iptostring(addr_filtered) << ", as reported by friend " << from << std::endl; #endif @@ -1705,7 +1814,7 @@ bool p3PeerMgrIMPL::getExtAddressReportedByFriends(sockaddr_storage &addr, uint8 { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ - uint32_t count ; + uint32_t count =0; locked_computeCurrentBestOwnExtAddressCandidate(addr,count) ; @@ -1729,7 +1838,7 @@ static bool cleanIpList(std::list& lst,const RsPeerId& pid,p3LinkM /* remove unused parameter warnings */ (void) pid; #endif - if(!link_mgr->checkPotentialAddr( (*it2).mAddr,now - (*it2).mSeenTime)) + if(!link_mgr->checkPotentialAddr((*it2).mAddr)) { #ifdef PEER_DEBUG std::cerr << " (SS) Removing Banned/old IP address " << sockaddr_storage_iptostring( (*it2).mAddr) << " from peer " << pid << ", age = " << now - (*it2).mSeenTime << std::endl; @@ -1776,13 +1885,10 @@ bool p3PeerMgrIMPL::updateAddressList(const RsPeerId& id, const pqiIpAddrSet std::map::iterator it; if (mFriendList.end() == (it = mFriendList.find(id))) { - if (mOthersList.end() == (it = mOthersList.find(id))) - { #ifdef PEER_DEBUG - std::cerr << "p3PeerMgrIMPL::setLocalAddress() cannot add addres info : peer id not found in friend list. id: " << id << std::endl; + std::cerr << "p3PeerMgrIMPL::setLocalAddress() cannot add addres info : peer id not found in friend list. id: " << id << std::endl; #endif - return false; - } + return false; } /* "it" points to peer */ @@ -1821,11 +1927,8 @@ bool p3PeerMgrIMPL::updateCurrentAddress(const RsPeerId& id, const pqiIpAddre std::map::iterator it; if (mFriendList.end() == (it = mFriendList.find(id))) { - if (mOthersList.end() == (it = mOthersList.find(id))) - { std::cerr << "p3PeerMgrIMPL::updateCurrentAddress() ERROR peer id not found: " << id << std::endl; return false; - } } if (sockaddr_storage_isPrivateNet(addr.mAddr)) @@ -1868,11 +1971,8 @@ bool p3PeerMgrIMPL::updateLastContact(const RsPeerId& id) std::map::iterator it; if (mFriendList.end() == (it = mFriendList.find(id))) { - if (mOthersList.end() == (it = mOthersList.find(id))) - { std::cerr << "p3PeerMgrIMPL::updateLastContact() ERROR peer id not found: " << id << std::endl; return false; - } } it->second.lastcontact = time(NULL); @@ -1894,10 +1994,7 @@ bool p3PeerMgrIMPL::setNetworkMode(const RsPeerId &id, uint32_t netMode) std::map::iterator it; if (mFriendList.end() == (it = mFriendList.find(id))) { - if (mOthersList.end() == (it = mOthersList.find(id))) - { return false; - } } bool changed = false; @@ -1964,10 +2061,7 @@ bool p3PeerMgrIMPL::setVisState(const RsPeerId &id, uint16_t vs_disc, uint16_ std::map::iterator it; if (mFriendList.end() == (it = mFriendList.find(id))) { - if (mOthersList.end() == (it = mOthersList.find(id))) - { return false; - } } else { @@ -2344,7 +2438,20 @@ bool p3PeerMgrIMPL::loadList(std::list& load) #endif /* ************* */ // permission flags is used as a mask for the existing perms, so we set it to 0xffff - addFriend(peer_id, peer_pgp_id, pitem->netMode, pitem->vs_disc, pitem->vs_dht, pitem->lastContact, RS_NODE_PERM_ALL); + + RsPeerDetails det ; + if(!rsPeers->getGPGDetails(peer_pgp_id,det)) + { + // would be better to add flags into RsPeerNetItem so that we already have this information. However, it's possible that the PGP key + // has been added in the meantime, so the peer would be loaded with the right pGP key attached. + + RsInfo() << __PRETTY_FUNCTION__ << " loading SSL-only " << "friend: " << peer_id << " " << pitem->location << std::endl; + addSslOnlyFriend(peer_id,peer_pgp_id); + } + else if(!addFriend( peer_id, peer_pgp_id, pitem->netMode, pitem->vs_disc, pitem->vs_dht, pitem->lastContact, RS_NODE_PERM_ALL )) + { + RsInfo() << __PRETTY_FUNCTION__ << " cannot add friend friend: " << peer_id << " " << pitem->location << ". Somthing's wrong." << std::endl; + } setLocation(pitem->nodePeerId, pitem->location); } diff --git a/libretroshare/src/pqi/p3peermgr.h b/libretroshare/src/pqi/p3peermgr.h index 781dd6115..d5451eaa9 100644 --- a/libretroshare/src/pqi/p3peermgr.h +++ b/libretroshare/src/pqi/p3peermgr.h @@ -76,6 +76,13 @@ class peerState RsPeerId id; RsPgpId gpg_id; + // This flag is used when adding a single SSL cert as friend without adding its PGP key in the friend list. This allows to + // have short invites. However, because this represent a significant security risk, we perform multiple consistency checks + // whenever we use this flag, in particular: + // flat is true <==> friend SSL cert is in the friend list, but PGP id is not in the friend list + + bool skip_pgp_signature_validation; + uint32_t netMode; /* EXT / UPNP / UDP / HIDDEN / INVALID */ /* visState */ uint16_t vs_disc; @@ -127,8 +134,17 @@ public: rstime_t lastContact = 0, ServicePermissionFlags = ServicePermissionFlags(RS_NODE_PERM_DEFAULT) ) = 0; + virtual bool addSslOnlyFriend( + const RsPeerId& sslId, + const RsPgpId& pgpId, + const RsPeerDetails& details = RsPeerDetails() ) = 0; + + // Calling this removed the skip_pgp_signature_validation flag on all peers which PGP key is the one supplied. + virtual bool notifyPgpKeyReceived(const RsPgpId& pgp_key_id) = 0; + virtual bool removeFriend(const RsPeerId &ssl_id, bool removePgpId) = 0; virtual bool isFriend(const RsPeerId& ssl_id) = 0; + virtual bool isSslOnlyFriend(const RsPeerId &ssl_id)=0; virtual bool getAssociatedPeers(const RsPgpId &gpg_id, std::list &ids) = 0; virtual bool removeAllFriendLocations(const RsPgpId &gpgid) = 0; @@ -192,7 +208,6 @@ virtual bool UpdateOwnAddress(const struct sockaddr_storage &local_addr, cons virtual bool getOwnNetStatus(peerState &state) = 0; virtual bool getFriendNetStatus(const RsPeerId &id, peerState &state) = 0; -virtual bool getOthersNetStatus(const RsPeerId &id, peerState &state) = 0; virtual bool getPeerName(const RsPeerId &ssl_id, std::string &name) = 0; virtual bool getGpgId(const RsPeerId &sslId, RsPgpId &gpgId) = 0; @@ -242,10 +257,16 @@ public: virtual bool addFriend(const RsPeerId&ssl_id, const RsPgpId&gpg_id, uint32_t netMode = RS_NET_MODE_UDP, uint16_t vsDisc = RS_VS_DISC_FULL, uint16_t vsDht = RS_VS_DHT_FULL, rstime_t lastContact = 0,ServicePermissionFlags = ServicePermissionFlags(RS_NODE_PERM_DEFAULT)); + + bool addSslOnlyFriend(const RsPeerId& sslId, const RsPgpId &pgp_id, const RsPeerDetails& details = RsPeerDetails() ) override; + + virtual bool notifyPgpKeyReceived(const RsPgpId& pgp_key_id) override; + virtual bool removeFriend(const RsPeerId &ssl_id, bool removePgpId); virtual bool removeFriend(const RsPgpId &pgp_id); virtual bool isFriend(const RsPeerId &ssl_id); + virtual bool isSslOnlyFriend(const RsPeerId &ssl_id); virtual bool getAssociatedPeers(const RsPgpId &gpg_id, std::list &ids); virtual bool removeAllFriendLocations(const RsPgpId &gpgid); @@ -307,7 +328,6 @@ public: virtual bool getOwnNetStatus(peerState &state); virtual bool getFriendNetStatus(const RsPeerId &id, peerState &state); - virtual bool getOthersNetStatus(const RsPeerId &id, peerState &state); virtual bool getPeerName(const RsPeerId& ssl_id, std::string& name); virtual bool getGpgId(const RsPeerId& sslId, RsPgpId& gpgId); @@ -395,7 +415,6 @@ private: peerState mOwnState; std::map mFriendList; // - std::map mOthersList; std::map mReportedOwnAddresses ; diff --git a/libretroshare/src/pqi/p3servicecontrol.cc b/libretroshare/src/pqi/p3servicecontrol.cc index a8e3292ac..9bf3b3c62 100644 --- a/libretroshare/src/pqi/p3servicecontrol.cc +++ b/libretroshare/src/pqi/p3servicecontrol.cc @@ -28,6 +28,8 @@ #include "rsitems/rsnxsitems.h" #include "pqi/p3cfgmgr.h" #include "pqi/pqiservice.h" +#include "retroshare/rspeers.h" +#include "retroshare/rsevents.h" /*******************************/ // #define SERVICECONTROL_DEBUG 1 @@ -756,6 +758,11 @@ bool p3ServiceControl::updateFilterByPeer_locked(const RsPeerId &peerId) mPeerFilterMap[peerId] = peerFilter; } recordFilterChanges_locked(peerId, originalFilter, peerFilter); + + using Evt_t = RsPeerStateChangedEvent; + if(rsEvents) + rsEvents->postEvent(std::unique_ptr(new Evt_t(peerId))); + return true; } @@ -1392,29 +1399,6 @@ RsServiceInfo::RsServiceInfo() return; } -std::ostream &operator<<(std::ostream &out, const RsPeerServiceInfo &info) -{ - out << "RsPeerServiceInfo(" << info.mPeerId << ")"; - out << std::endl; - std::map::const_iterator it; - for(it = info.mServiceList.begin(); it != info.mServiceList.end(); ++it) - { - out << "\t Service:" << it->first << " : "; - out << it->second; - out << std::endl; - } - return out; -} - - -std::ostream &operator<<(std::ostream &out, const RsServiceInfo &info) -{ - out << "RsServiceInfo(" << info.mServiceType << "): " << info.mServiceName; - out << " Version(" << info.mVersionMajor << "," << info.mVersionMinor << ")"; - out << " MinVersion(" << info.mMinVersionMajor << "," << info.mMinVersionMinor << ")"; - return out; -} - std::ostream &operator<<(std::ostream &out, const ServicePeerFilter &filter) { out << "ServicePeerFilter DenyAll: " << filter.mDenyAll; diff --git a/libretroshare/src/pqi/pqissl.cc b/libretroshare/src/pqi/pqissl.cc index 2b9392ddf..a10e7853a 100644 --- a/libretroshare/src/pqi/pqissl.cc +++ b/libretroshare/src/pqi/pqissl.cc @@ -35,7 +35,7 @@ #include "pqi/pqissllistener.h" #include "pqi/p3linkmgr.h" -#include +#include "retroshare/rspeers.h" #include #include @@ -1115,9 +1115,6 @@ int pqissl::SSL_Connection_Complete() rslog(RSL_WARNING, pqisslzone, out); - // attempt real error. - Extract_Failed_SSL_Certificate(); - rslog(RSL_ALERT, pqisslzone, "pqissl::SSL_Connection_Complete() -> calling reset()"); reset_locked(); waiting = WAITING_FAIL_INTERFACE; @@ -1132,159 +1129,95 @@ int pqissl::SSL_Connection_Complete() return 1; } -int pqissl::Extract_Failed_SSL_Certificate() -{ - std::cerr << "pqissl::Extract_Failed_SSL_Certificate() FAILED Connection due to Security Issues"; - std::cerr << std::endl; - -#ifdef PQISSL_LOG_DEBUG - rslog(RSL_DEBUG_BASIC, pqisslzone, - "pqissl::Extract_Failed_SSL_Certificate()"); -#endif - - // Get the Peer Certificate.... - X509 *peercert = SSL_get_peer_certificate(ssl_connection); - - if (peercert == NULL) - { - rslog(RSL_WARNING, pqisslzone, - "pqissl::Extract_Failed_SSL_Certificate() Peer Didnt Give Cert"); - - std::cerr << "pqissl::Extract_Failed_SSL_Certificate() ERROR Peer Didn't Give Us Certificate"; - std::cerr << std::endl; - - return -1; - } - -#ifdef PQISSL_LOG_DEBUG - rslog(RSL_DEBUG_BASIC, pqisslzone, - "pqissl::Extract_Failed_SSL_Certificate() Have Peer Cert - Registering"); -#endif - - std::cerr << "pqissl::Extract_Failed_SSL_Certificate() Passing FAILED Cert to AuthSSL for analysis"; - std::cerr << std::endl; - - // save certificate... (and ip locations) - // false for outgoing.... - // we actually connected to remote_addr, - // which could be - // (pqissl's case) sslcert->serveraddr or sslcert->localaddr. - - RsPeerId sslid ; - getX509id(peercert, sslid) ; - -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) - RsPgpId gpgid(getX509CNString(peercert->cert_info->issuer)); - std::string sslcn = getX509CNString(peercert->cert_info->subject); -#else - RsPgpId gpgid(getX509CNString(X509_get_issuer_name(peercert))); - std::string sslcn = getX509CNString(X509_get_subject_name(peercert)); -#endif - - AuthSSL::getAuthSSL()->FailedCertificate(peercert, gpgid,sslid,sslcn,remote_addr, false); - mLinkMgr->notifyDeniedConnection(gpgid, sslid, sslcn, remote_addr, false); - - return 1; -} - - - - int pqissl::Authorise_SSL_Connection() { -#ifdef PQISSL_DEBUG - std::cerr << __PRETTY_FUNCTION__ << std::endl; -#endif + Dbg3() << __PRETTY_FUNCTION__ << std::endl; - if (time(NULL) > ssl_connect_timeout) + constexpr int failure = -1; + + if (time(nullptr) > ssl_connect_timeout) { - std::cerr << __PRETTY_FUNCTION__ << " Connection timed out reset!" - << std::endl; + RsInfo() << __PRETTY_FUNCTION__ << " Connection timed out reset!" + << std::endl; reset_locked(); } int err; if (0 >= (err = SSL_Connection_Complete())) return err; -#ifdef PQISSL_LOG_DEBUG - rslog(RSL_DEBUG_BASIC, pqisslzone, - "pqissl::Authorise_SSL_Connection() SSL_Connection_Complete"); -#endif + Dbg3() << __PRETTY_FUNCTION__ << "SSL_Connection_Complete success." + << std::endl; // reset switch. waiting = WAITING_NOT; - X509 *peercert = SSL_get_peer_certificate(ssl_connection); - - if (peercert == NULL) +#ifdef RS_PQISSL_AUTH_DOUBLE_CHECK + X509* peercert = SSL_get_peer_certificate(ssl_connection); + if (!peercert) { - rslog(RSL_WARNING, pqisslzone, - "pqissl::Authorise_SSL_Connection() Peer Didnt Give Cert"); - - rslog(RSL_ALERT, pqisslzone, "pqissl::Authorise_Connection_Complete() -> calling reset()"); - // Failed completely - reset_locked(); - return -1; + RsFatal() << __PRETTY_FUNCTION__ << " failed to retrieve peer " + << "certificate at this point this should never happen!" + << std::endl; + print_stacktrace(); + exit(failure); } - RsPeerId certPeerId; - getX509id(peercert, certPeerId); - if (RsPeerId(certPeerId) != PeerId()) { - rslog(RSL_WARNING, pqisslzone, - "pqissl::Authorise_SSL_Connection() the cert Id doesn't match the Peer id we're trying to connect to."); - - rslog(RSL_ALERT, pqisslzone, "pqissl::Authorise_Connection_Complete() -> calling reset()"); - // Failed completely - reset_locked(); - return -1; - } - -#ifdef PQISSL_LOG_DEBUG - rslog(RSL_DEBUG_BASIC, pqisslzone, - "pqissl::Authorise_SSL_Connection() Have Peer Cert"); -#endif - - // save certificate... (and ip locations) - // false for outgoing.... - // we actually connected to remote_addr, - // which could be - // (pqissl's case) sslcert->serveraddr or sslcert->localaddr. - - AuthSSL::getAuthSSL()->CheckCertificate(PeerId(), peercert); - bool certCorrect = true; /* WE know it okay already! */ - - uint32_t check_result ; - uint32_t checking_flags = RSBANLIST_CHECKING_FLAGS_BLACKLIST; - if (rsPeers->servicePermissionFlags(PeerId()) & RS_NODE_PERM_REQUIRE_WL) - checking_flags |= RSBANLIST_CHECKING_FLAGS_WHITELIST; - - if(rsBanList!=NULL && !rsBanList->isAddressAccepted(remote_addr,checking_flags,&check_result)) - { - std::cerr << "(SS) refusing connection attempt from IP address " << sockaddr_storage_iptostring(remote_addr) << ". Reason: " << - ((check_result == RSBANLIST_CHECK_RESULT_NOT_WHITELISTED)?"not whitelisted (peer requires whitelist)":"blacklisted") << std::endl; - - RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_IP_BLACKLISTED, PeerId().toStdString(), sockaddr_storage_iptostring(remote_addr), "", "", check_result); - reset_locked(); - return 0 ; - } - // check it's the right one. - if (certCorrect) + RsPeerId certPeerId = RsX509Cert::getCertSslId(*peercert); + if (RsPeerId(certPeerId) != PeerId()) { - // then okay... - rslog(RSL_WARNING, pqisslzone, "pqissl::Authorise_SSL_Connection() Accepting Conn. Peer: " + PeerId().toStdString()); + RsErr() << __PRETTY_FUNCTION__ << " the cert Id doesn't match the peer " + << "id we're trying to connect to." << std::endl; - //std::cerr << "pqissl::Authorise_SSL_Connection(): accepting connection from " << sockaddr_storage_iptostring(remote_addr) << std::endl; - accept_locked(ssl_connection, sockfd, remote_addr); - return 1; + /* TODO: Considering how difficult is managing to get a connection to a + * friend nowadays on the Internet because of evil NAT everywhere. + * If the cert is from a friend anyway we should find a way to make good + * use of this connection instead of throwing it away... */ + + X509_free(peercert); + reset_locked(); + return failure; } - rslog(RSL_WARNING, pqisslzone, "pqissl::Authorise_SSL_Connection() Something Wrong ... Shutdown. Peer: " + PeerId().toStdString()); + /* At this point the actual connection authentication has already been + * performed in AuthSSL::VerifyX509Callback, any furter authentication check + * like the followings are redundant. */ - // else shutdown ssl connection. - rslog(RSL_ALERT, pqisslzone, "pqissl::Authorise_Connection_Complete() -> calling reset()"); + bool isSslOnlyFriend = rsPeers->isSslOnlyFriend(certPeerId); - reset_locked(); - return 0; + uint32_t authErrCode = 0; + if( !isSslOnlyFriend && !AuthSSL::instance().AuthX509WithGPG(peercert,false, authErrCode) ) + { + RsFatal() << __PRETTY_FUNCTION__ << " failure verifying peer " + << "certificate signature. This should never happen at this " + << "point!" << std::endl; + print_stacktrace(); + + X509_free(peercert); // not needed but just in case we change to return + exit(failure); + } + + RsPgpId pgpId = RsX509Cert::getCertIssuer(*peercert); + if( !isSslOnlyFriend && pgpId != AuthGPG::getAuthGPG()->getGPGOwnId() && + !AuthGPG::getAuthGPG()->isGPGAccepted(pgpId) ) + { + RsFatal() << __PRETTY_FUNCTION__ << " pgpId: " << pgpId + << " is not friend. It is very unlikely to happen at this " + << "point! Either the user must have been so fast to deny " + << "friendship just after VerifyX509Callback have returned " + << "success and just before this code being executed, or " + << "something really fishy is happening! Share the full log " + << "with developers." << std::endl; + print_stacktrace(); + + X509_free(peercert); // not needed but just in case we change to return + exit(failure); + } +#endif // def RS_PQISSL_AUTH_REDUNDANT_CHECK + + Dbg2() << __PRETTY_FUNCTION__ << " Accepting connection to peer: " + << PeerId() << " with address: " << remote_addr << std::endl; + + return accept_locked(ssl_connection, sockfd, remote_addr); } @@ -1300,28 +1233,36 @@ int pqissl::accept( SSL *ssl, int fd, return accept_locked(ssl, fd, foreign_addr); } -int pqissl::accept_locked( SSL *ssl, int fd, +int pqissl::accept_locked( SSL *ssl, int fd, const sockaddr_storage &foreign_addr ) { -#ifdef PQISSL_DEBUG - std::cerr << __PRETTY_FUNCTION__ << std::endl; -#endif + Dbg3() << __PRETTY_FUNCTION__ << std::endl; + constexpr int failure = -1; + constexpr int success = 1; + +#ifdef RS_PQISSL_BANLIST_DOUBLE_CHECK + /* At this point, as we are actively attempting the connection, we decide + * the address to which to connect to, banned addresses should never get + * here as the filtering for banned addresses happens much before, this + * check is therefore redundant, and if it trigger something really fishy + * must be happening (a bug somewhere else in the code). */ uint32_t check_result; uint32_t checking_flags = RSBANLIST_CHECKING_FLAGS_BLACKLIST; if (rsPeers->servicePermissionFlags(PeerId()) & RS_NODE_PERM_REQUIRE_WL) checking_flags |= RSBANLIST_CHECKING_FLAGS_WHITELIST; - if( rsBanList && !rsBanList->isAddressAccepted( foreign_addr, - checking_flags, - &check_result ) ) + if(rsBanList && !rsBanList->isAddressAccepted( + foreign_addr, checking_flags, check_result )) { - std::cerr << __PRETTY_FUNCTION__ - << " (SS) refusing incoming SSL connection from blacklisted " - << "foreign address " - << sockaddr_storage_iptostring(foreign_addr) - << ". Reason: " << check_result << "." << std::endl; + RsErr() << __PRETTY_FUNCTION__ + << " Refusing incoming SSL connection from blacklisted " + << "foreign address " << foreign_addr + << ". Reason: " << check_result << ". This should never happen " + << "at this point! Please report full log to developers!" + << std::endl; + print_stacktrace(); RsServer::notify()->AddFeedItem( RS_FEED_ITEM_SEC_IP_BLACKLISTED, @@ -1329,14 +1270,15 @@ int pqissl::accept_locked( SSL *ssl, int fd, sockaddr_storage_iptostring(foreign_addr), "", "", check_result); reset_locked(); - return -1; + return failure; } +#endif //def RS_BANLIST_REDUNDANT_CHECK if (waiting != WAITING_NOT) { - std::cerr << __PRETTY_FUNCTION__ << " Peer: " << PeerId().toStdString() - << " - Two connections in progress - Shut 1 down!" - << std::endl; + RsInfo() << __PRETTY_FUNCTION__ << " Peer: " << PeerId() + << " - Two connections in progress - Shut 1 down!" + << std::endl; // outgoing connection in progress. // shut this baby down. @@ -1431,7 +1373,7 @@ int pqissl::accept_locked( SSL *ssl, int fd, waiting = WAITING_FAIL_INTERFACE; // failed completely. reset_locked(); - return -1; + return failure; } #ifdef PQISSL_DEBUG else std::cerr << __PRETTY_FUNCTION__ << " Socket made non-nlocking!" @@ -1456,7 +1398,7 @@ int pqissl::accept_locked( SSL *ssl, int fd, sockaddr_storage addr; sockaddr_storage_copy(remote_addr, addr); parent()->notifyEvent(this, NET_CONNECT_SUCCESS, addr); } - return 1; + return success; } /********** Implementation of BinInterface ************************** diff --git a/libretroshare/src/pqi/pqissl.h b/libretroshare/src/pqi/pqissl.h index 99408917c..6246145b7 100644 --- a/libretroshare/src/pqi/pqissl.h +++ b/libretroshare/src/pqi/pqissl.h @@ -3,8 +3,8 @@ * * * libretroshare: retroshare core library * * * - * Copyright 2004-2006 by Robert Fernie * - * Copyright (C) 2015-2018 Gioacchino Mazzurco * + * Copyright (C) 2004-2006 Robert Fernie * + * Copyright (C) 2015-2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -20,8 +20,7 @@ * along with this program. If not, see . * * * *******************************************************************************/ -#ifndef MRK_PQI_SSL_HEADER -#define MRK_PQI_SSL_HEADER +#pragma once // operating system specific network header. #include "pqi/pqinetwork.h" @@ -32,6 +31,11 @@ #include "pqi/pqi_base.h" #include "pqi/authssl.h" +#define RS_PQISSL_AUTH_DOUBLE_CHECK 1 + +#define RS_PQISSL_BANLIST_DOUBLE_CHECK 1 + + #define WAITING_NOT 0 #define WAITING_DELAY 1 #define WAITING_SOCK_CONNECT 2 @@ -159,8 +163,6 @@ int Initiate_SSL_Connection(); int SSL_Connection_Complete(); int Authorise_SSL_Connection(); -int Extract_Failed_SSL_Certificate(); // try to get cert anyway. - // check connection timeout. bool CheckConnectionTimeout(); @@ -207,9 +209,6 @@ bool CheckConnectionTimeout(); private: // ssl only fns. int connectInterface(const struct sockaddr_storage &addr); + + RS_SET_CONTEXT_DEBUG_LEVEL(1) }; - - - - -#endif // MRK_PQI_SSL_HEADER diff --git a/libretroshare/src/pqi/pqissllistener.cc b/libretroshare/src/pqi/pqissllistener.cc index a80e9b572..3d62db9ea 100644 --- a/libretroshare/src/pqi/pqissllistener.cc +++ b/libretroshare/src/pqi/pqissllistener.cc @@ -20,20 +20,20 @@ * along with this program. If not, see . * * * *******************************************************************************/ + #include "pqi/pqissl.h" #include "pqi/pqissllistener.h" #include "pqi/pqinetwork.h" #include "pqi/sslfns.h" - #include "pqi/p3peermgr.h" - -#include -#include - #include "util/rsdebug.h" #include "util/rsstring.h" #include "retroshare/rsbanlist.h" +#include "pqi/authgpg.h" + #include +#include +#include static struct RsLog::logInfo pqissllistenzoneInfo = {RsLog::Default, "p3peermgr"}; #define pqissllistenzone &pqissllistenzoneInfo @@ -486,9 +486,6 @@ int pqissllistenbase::continueSSL(IncomingSSLInfo& incoming_connexion_info, bool break; } - /* we have failed -> get certificate if possible */ - Extract_Failed_SSL_Certificate(incoming_connexion_info); - closeConnection(fd, incoming_connexion_info.ssl) ; pqioutput(PQL_WARNING, pqissllistenzone, "Read Error on the SSL Socket\nShutting it down!"); @@ -502,20 +499,11 @@ int pqissllistenbase::continueSSL(IncomingSSLInfo& incoming_connexion_info, bool // X509 *x509 = SSL_get_peer_certificate(incoming_connexion_info.ssl) ; -#ifdef DEBUG_LISTENNER - std::cerr << "Info from certificate: " << std::endl; -#endif - if(x509 != NULL) - { -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) - incoming_connexion_info.gpgid = RsPgpId(std::string(getX509CNString(x509->cert_info->issuer))); - incoming_connexion_info.sslcn = getX509CNString(x509->cert_info->subject); -#else - incoming_connexion_info.gpgid = RsPgpId(std::string(getX509CNString(X509_get_issuer_name(x509)))); - incoming_connexion_info.sslcn = getX509CNString(X509_get_subject_name(x509)); -#endif - - getX509id(x509,incoming_connexion_info.sslid); + if(x509) + { + incoming_connexion_info.gpgid = RsX509Cert::getCertIssuer(*x509); + incoming_connexion_info.sslcn = RsX509Cert::getCertName(*x509); + incoming_connexion_info.sslid = RsX509Cert::getCertSslId(*x509); #ifdef DEBUG_LISTENNER std::cerr << " Got PGP Id = " << incoming_connexion_info.gpgid << std::endl; @@ -571,61 +559,6 @@ int pqissllistenbase::closeConnection(int fd, SSL *ssl) return 1; } - - - -int pqissllistenbase::Extract_Failed_SSL_Certificate(const IncomingSSLInfo& info) -{ - pqioutput(PQL_DEBUG_BASIC, pqissllistenzone, "pqissllistenbase::Extract_Failed_SSL_Certificate()"); - - std::cerr << "pqissllistenbase::Extract_Failed_SSL_Certificate() FAILED CONNECTION due to security!"; - std::cerr << std::endl; - - // Get the Peer Certificate.... - X509 *peercert = SSL_get_peer_certificate(info.ssl); - - std::cerr << "Extract_Failed_SSL_Certificate: " << std::endl; - std::cerr << " SSL = " << (void*)info.ssl << std::endl; - std::cerr << " GPG id = " << info.gpgid << std::endl; - std::cerr << " SSL id = " << info.sslid << std::endl; - std::cerr << " SSL cn = " << info.sslcn << std::endl; - std::cerr << " addr+p = " << sockaddr_storage_tostring(info.addr) << std::endl; - - if (peercert == NULL) - { - std::string out; - out += "pqissllistenbase::Extract_Failed_SSL_Certificate() from: "; - out += sockaddr_storage_tostring(info.addr); - out += " ERROR Peer didn't give Cert!"; - std::cerr << out << std::endl; - AuthSSL::getAuthSSL()->FailedCertificate(peercert, info.gpgid,info.sslid,info.sslcn,info.addr, true); - - pqioutput(PQL_WARNING, pqissllistenzone, out); - return -1; - } - - pqioutput(PQL_DEBUG_BASIC, pqissllistenzone, - "pqissllistenbase::Extract_Failed_SSL_Certificate() Have Peer Cert - Registering"); - - { - std::string out; - out += "pqissllistenbase::Extract_Failed_SSL_Certificate() from: "; - out += sockaddr_storage_tostring(info.addr); - out += " Passing Cert to AuthSSL() for analysis"; - std::cerr << out << std::endl; - - pqioutput(PQL_WARNING, pqissllistenzone, out); - std::cerr << out << std::endl; - } - - // save certificate... (and ip locations) - // false for outgoing.... - AuthSSL::getAuthSSL()->FailedCertificate(peercert, info.gpgid,info.sslid,info.sslcn,info.addr, true); - - return 1; -} - - int pqissllistenbase::continueaccepts() { @@ -830,91 +763,76 @@ int pqissllistener::status() } int pqissllistener::completeConnection(int fd, IncomingSSLInfo& info) -{ +{ + constexpr int failure = -1; + constexpr int success = 1; // Get the Peer Certificate.... - X509 *peercert = SSL_get_peer_certificate(info.ssl); - - if (peercert == NULL) + X509* peercert = SSL_get_peer_certificate(info.ssl); + if(!peercert) { - pqioutput(PQL_WARNING, pqissllistenzone, - "pqissllistener::completeConnection() Peer Did Not Provide Cert!"); - - // failure -1, pending 0, sucess 1. - // pqissllistenbase will shutdown! - return -1; + RsFatal() << __PRETTY_FUNCTION__ << " failed to retrieve peer " + << "certificate at this point this should never happen!" + << std::endl; + print_stacktrace(); + exit(failure); } - // Check cert. - RsPeerId newPeerId; + RsPgpId pgpId = RsX509Cert::getCertIssuer(*peercert); + RsPeerId newPeerId = RsX509Cert::getCertSslId(*peercert); +#ifdef RS_PQISSL_AUTH_DOUBLE_CHECK + /* At this point the actual connection authentication has already been + * performed in AuthSSL::VerifyX509Callback, any furter authentication check + * like the followings are redundant. */ - /**** - * As the validation is actually done before this... - * we should only need to call CheckCertificate here! - ****/ + bool isSslOnlyFriend = rsPeers->isSslOnlyFriend(newPeerId); - bool certOk = AuthSSL::getAuthSSL()->ValidateCertificate(peercert, newPeerId); + uint32_t authErrCode = 0; + if( !isSslOnlyFriend && + !AuthSSL::instance().AuthX509WithGPG(peercert,false, authErrCode) ) + { + RsFatal() << __PRETTY_FUNCTION__ << " failure verifying peer " + << "certificate signature. This should never happen at this " + << "point!" << std::endl; + print_stacktrace(); + + X509_free(peercert); // not needed but just in case we change to return + exit(failure); + } + + if( !isSslOnlyFriend && pgpId != AuthGPG::getAuthGPG()->getGPGOwnId() && + !AuthGPG::getAuthGPG()->isGPGAccepted(pgpId) ) + { + RsFatal() << __PRETTY_FUNCTION__ << " pgpId: " << pgpId + << " is not friend. It is very unlikely to happen at this " + << "point! Either the user must have been so fast to deny " + << "friendship just after VerifyX509Callback have returned " + << "success and just before this code being executed, or " + << "something really fishy is happening! Share the full log " + << "with developers." << std::endl; + print_stacktrace(); + + X509_free(peercert); // not needed but just in case we change to return + exit(failure); + } +#endif //def RS_PQISSL_AUTH_REDUNDANT_CHECK bool found = false; - std::map::iterator it; - - // Let connected one through as well! if ((npc == NULL) || (npc -> Connected())) - if (!certOk) + for(auto it = listenaddr.begin(); !found && it != listenaddr.end(); ) { - pqioutput(PQL_WARNING, pqissllistenzone, - "pqissllistener::completeConnection() registerCertificate Failed!"); - - // bad - shutdown. - // pqissllistenbase will shutdown! - X509_free(peercert); - - return -1; + if (it -> first == newPeerId) found = true; + else ++it; } - else + + if (!found) { - std::string out = "pqissllistener::continueSSL()\nchecking: " + newPeerId.toStdString() + "\n"; - // check if cert is in our list..... - for(it = listenaddr.begin();(found!=true) && (it!=listenaddr.end());) - { - out + "\tagainst: " + it->first.toStdString() + "\n"; - if (it -> first == newPeerId) - { - // accept even if already connected. - out += "\t\tMatch!"; - found = true; - } - else - { - ++it; - } - } + Dbg1() << __PRETTY_FUNCTION__ << " got secure connection from address: " + << info.addr << " with previously unknown SSL certificate: " + << newPeerId << " signed by PGP friend: " << pgpId + << ". Adding the new location as SSL friend." << std::endl; - pqioutput(PQL_DEBUG_BASIC, pqissllistenzone, out); - } - - if (found == false) - { - std::string out = "No Matching Certificate for Connection:"; - out += sockaddr_storage_tostring(info.addr); - out += "\npqissllistenbase: Will shut it down!"; - pqioutput(PQL_WARNING, pqissllistenzone, out); - - // but as it passed the authentication step, - // we can add it into the AuthSSL, and mConnMgr. - - AuthSSL::getAuthSSL()->CheckCertificate(newPeerId, peercert); - - /* now need to get GPG id too */ -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) - RsPgpId pgpid(std::string(getX509CNString(peercert->cert_info->issuer))); -#else - RsPgpId pgpid(std::string(getX509CNString(X509_get_issuer_name(peercert)))); -#endif - mPeerMgr->addFriend(newPeerId, pgpid); - - X509_free(peercert); - return -1; + mPeerMgr->addFriend(newPeerId, pgpId); } // Cleanup cert. @@ -926,17 +844,14 @@ int pqissllistener::completeConnection(int fd, IncomingSSLInfo& info) as.mSSL = info.ssl; as.mPeerId = newPeerId; as.mAddr = info.addr; - as.mAcceptTS = time(NULL); + as.mAcceptTS = time(nullptr); accepted_ssl.push_back(as); - std::string out = "pqissllistener::completeConnection() Successful Connection with: " + newPeerId.toStdString(); - out += " for Connection:"; - out += sockaddr_storage_tostring(info.addr); - out += " Adding to WAIT-ACCEPT Queue"; - pqioutput(PQL_WARNING, pqissllistenzone, out); + Dbg1() << __PRETTY_FUNCTION__ << "Successful Connection with: " + << newPeerId << " with address: " << info.addr << std::endl; - return 1; + return success; } int pqissllistener::finaliseConnection(int fd, SSL *ssl, const RsPeerId& peerId, const struct sockaddr_storage &remote_addr) diff --git a/libretroshare/src/pqi/pqissllistener.h b/libretroshare/src/pqi/pqissllistener.h index 8b072d7c5..42ad0d0c2 100644 --- a/libretroshare/src/pqi/pqissllistener.h +++ b/libretroshare/src/pqi/pqissllistener.h @@ -19,21 +19,20 @@ * along with this program. If not, see . * * * *******************************************************************************/ -#ifndef MRK_PQI_SSL_LISTEN_HEADER -#define MRK_PQI_SSL_LISTEN_HEADER +#pragma once #include -// operating system specific network header. -#include "pqi/pqinetwork.h" - #include #include #include "pqi/pqi_base.h" #include "pqi/pqilistener.h" - #include "pqi/authssl.h" +#include "util/rsdebug.h" +#include "pqi/pqinetwork.h" + +#define RS_PQISSL_AUTH_DOUBLE_CHECK 1 /***************************** pqi Net SSL Interface ********************************* */ @@ -98,7 +97,7 @@ protected: p3PeerMgr *mPeerMgr; private: - int Extract_Failed_SSL_Certificate(const IncomingSSLInfo&); + bool active; int lsock; std::list incoming_ssl ; @@ -122,7 +121,6 @@ public: private: std::map listenaddr; + + RS_SET_CONTEXT_DEBUG_LEVEL(2) }; - - -#endif // MRK_PQI_SSL_LISTEN_HEADER diff --git a/libretroshare/src/pqi/sslfns.cc b/libretroshare/src/pqi/sslfns.cc index 59bdc884a..cb799ed86 100644 --- a/libretroshare/src/pqi/sslfns.cc +++ b/libretroshare/src/pqi/sslfns.cc @@ -31,6 +31,7 @@ #include "pqi/pqi_base.h" #include "util/rsdir.h" #include "util/rsstring.h" +#include "pqi/authssl.h" #include #include @@ -675,13 +676,6 @@ int pem_passwd_cb(char *buf, int size, int rwflag, void *password) return(strlen(buf)); } -/* XXX FIX */ -bool CheckX509Certificate(X509 */*x509*/) -{ - - return true; -} - uint64_t getX509SerialNumber(X509 *cert) { ASN1_INTEGER *serial = X509_get_serialNumber(cert); @@ -711,69 +705,6 @@ uint32_t getX509RetroshareCertificateVersion(X509 *cert) } } -// Not dependent on sslroot. load, and detroys the X509 memory. -int LoadCheckX509(const char *cert_file, RsPgpId& issuerName, std::string &location, RsPeerId &userId) -{ - /* This function loads the X509 certificate from the file, - * and checks the certificate - */ - - FILE *tmpfp = RsDirUtil::rs_fopen(cert_file, "r"); - if (tmpfp == NULL) - { -#ifdef AUTHSSL_DEBUG - std::cerr << "sslroot::LoadCheckAndGetX509Name()"; - std::cerr << " Failed to open Certificate File:" << cert_file; - std::cerr << std::endl; -#endif - return 0; - } - - // get xPGP certificate. - X509 *x509 = PEM_read_X509(tmpfp, NULL, NULL, NULL); - fclose(tmpfp); - - // check the certificate. - bool valid = false; - if (x509) - { - valid = CheckX509Certificate(x509); - if (valid) - { - valid = getX509id(x509, userId); - } - } - - if (valid) - { - // extract the name. -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) - issuerName = RsPgpId(std::string(getX509CNString(x509->cert_info->issuer))); - location = getX509LocString(x509->cert_info->subject); -#else - issuerName = RsPgpId(std::string(getX509CNString(X509_get_issuer_name(x509)))); - location = getX509LocString(X509_get_subject_name(x509)); -#endif - } - -#ifdef AUTHSSL_DEBUG - std::cout << getX509Info(x509) << std::endl ; -#endif - // clean up. - X509_free(x509); - - if (valid) - { - // happy! - return 1; - } - else - { - // something went wrong! - return 0; - } -} - std::string getX509NameString(X509_NAME *name) { std::string namestr; @@ -896,10 +827,9 @@ std::string getX509Info(X509 *cert) /********** SSL ERROR STUFF ******************************************/ -int printSSLError(SSL *ssl, int retval, int err, unsigned long err2, std::string &out) +int printSSLError( + SSL*, int retval, int err, unsigned long err2, std::string& out ) { - (void) ssl; /* remove unused parameter warnings */ - std::string reason; std::string mainreason = std::string("UNKNOWN ERROR CODE"); @@ -939,7 +869,18 @@ int printSSLError(SSL *ssl, int retval, int err, unsigned long err2, std::string { mainreason = std::string("SSL_ERROR_SSL"); } - rs_sprintf_append(out, "RetVal(%d) -> SSL Error: %s\n\t + ERR Error: %s\n", retval, mainreason.c_str(), ERR_error_string(err2, NULL)); + rs_sprintf_append( out, + "RetVal(%d) -> SSL Error: %s\n\t + ERR Error: %s\n", + retval, mainreason.c_str(), + ERR_error_string(err2, nullptr) ); return 1; } + +std::string sslErrorToString(int retval, int err, unsigned long err2) +{ + std::string ret; + // When printSSLError will be removed it's code will be moved here + printSSLError(nullptr, retval, err, err2, ret); + return ret; +} diff --git a/libretroshare/src/pqi/sslfns.h b/libretroshare/src/pqi/sslfns.h index 0a19904e1..c22076c51 100644 --- a/libretroshare/src/pqi/sslfns.h +++ b/libretroshare/src/pqi/sslfns.h @@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * libretroshare/src/pqi: sslfns.h * * * * libretroshare: retroshare core library * @@ -19,8 +19,7 @@ * along with this program. If not, see . * * * *******************************************************************************/ -#ifndef RS_PQI_SSL_HELPER_H -#define RS_PQI_SSL_HELPER_H +#pragma once /* Functions in this file are SSL only, * and have no dependence on SSLRoot() etc. @@ -32,9 +31,12 @@ #include #include -#include -#include #include +#include + +#include "util/rsdeprecate.h" +#include "retroshare/rstypes.h" + /**** * #define AUTHSSL_DEBUG 1 @@ -113,11 +115,6 @@ bool getX509id(X509 *x509, RsPeerId &xid); int pem_passwd_cb(char *buf, int size, int rwflag, void *password); -bool CheckX509Certificate(X509 *x509); -// Not dependent on sslroot. load, and detroys the X509 memory. -int LoadCheckX509(const char *cert_file, RsPgpId& issuer, std::string &location, RsPeerId& userId); - - std::string getX509NameString(X509_NAME *name); std::string getX509CNString(X509_NAME *name); std::string getX509TypeString(X509_NAME *name, const char *type, int len); @@ -131,7 +128,8 @@ uint32_t getX509RetroshareCertificateVersion(X509 *cert) ; /********** SSL ERROR STUFF ******************************************/ -int printSSLError(SSL *ssl, int retval, int err, unsigned long err2, std::string &out); - -#endif /* RS_PQI_SSL_HELPER_H */ +RS_DEPRECATED_FOR(sslErrorToString) +int printSSLError( + SSL* unused, int retval, int err, unsigned long err2, std::string& out); +std::string sslErrorToString(int retval, int err, unsigned long err2); diff --git a/libretroshare/src/retroshare/rsbanlist.h b/libretroshare/src/retroshare/rsbanlist.h index 194186b5f..c46ea0203 100644 --- a/libretroshare/src/retroshare/rsbanlist.h +++ b/libretroshare/src/retroshare/rsbanlist.h @@ -1,9 +1,9 @@ /******************************************************************************* - * libretroshare/src/retroshare: rsbanlist.h * + * IPv4 address filtering interface * * * * libretroshare: retroshare core library * * * - * Copyright 2011-2011 by Robert Fernie * + * Copyright (C) 2015 Cyril Soler * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -21,12 +21,21 @@ *******************************************************************************/ #pragma once +#include + #include "util/rsnet.h" #include "util/rstime.h" +#include "util/rsmemory.h" class RsBanList; -extern RsBanList *rsBanList ; +/** + * Pointer to global instance of RsBanList service implementation + * @jsonapi{development} + */ +extern RsBanList* rsBanList; + +// TODO: use enum class instead of defines #define RSBANLIST_ORIGIN_UNKNOWN 0 #define RSBANLIST_ORIGIN_SELF 1 #define RSBANLIST_ORIGIN_FRIEND 2 @@ -55,7 +64,7 @@ extern RsBanList *rsBanList ; #define RSBANLIST_TYPE_BLACKLIST 2 #define RSBANLIST_TYPE_WHITELIST 3 -class RsTlvBanListEntry ; +class RsTlvBanListEntry; class BanListPeer { @@ -78,42 +87,71 @@ public: class RsBanList { public: - virtual void enableIPFiltering(bool b) =0; - virtual bool ipFilteringEnabled() =0; + /** + * @brief Enable or disable IP filtering service + * @jsonapi{development} + * @param[in] enable pass true to enable, false to disable + */ + virtual void enableIPFiltering(bool enable) = 0; - // addIpRange()/removeIpRange() - // addr: full IPv4 address. Port is ignored. - // masked_bytes: 0=full IP, 1="/24", 2="/16" - // list_type: RSBANLIST_TYPE_WHITELIST or RSBANLIST_TYPE_BLACKLIST - // comment: anything, user-based. + /** + * @brief Get ip filtering service status + * @jsonapi{development} + * @return true if enabled, false if disabled + */ + virtual bool ipFilteringEnabled() = 0; - virtual bool addIpRange(const struct sockaddr_storage& addr,int masked_bytes,uint32_t list_type,const std::string& comment) =0; - virtual bool removeIpRange(const struct sockaddr_storage& addr,int masked_bytes,uint32_t list_type) =0; + /** + * @brief addIpRange + * @param addr full IPv4 address. Port is ignored. + * @param masked_bytes 0=full IP, 1="/24", 2="/16" + * @param list_type RSBANLIST_TYPE_WHITELIST or RSBANLIST_TYPE_BLACKLIST + * @param comment anything, user-based + * @return + */ + virtual bool addIpRange( + const sockaddr_storage& addr, int masked_bytes, uint32_t list_type, + const std::string& comment ) = 0; - // isAddressAccepted() - // addr: full IPv4 address. Port is ignored. - // checking flags: any combination of RSBANLIST_CHECKING_FLAGS_BLACKLIST and RSBANLIST_CHECKING_FLAGS_WHITELIST - // check_result: returned result of the check in RSBANLIST_CHECK_RESULT_* - // returned value: true=address is accepted, false=address is rejected. + /** + * @brief removeIpRange + * @param addr full IPv4 address. Port is ignored. + * @param masked_bytes 0=full IP, 1="/24", 2="/16" + * @param list_type RSBANLIST_TYPE_WHITELIST or RSBANLIST_TYPE_BLACKLIST + * @return + */ + virtual bool removeIpRange( + const sockaddr_storage& addr, int masked_bytes, uint32_t list_type + ) = 0; - virtual bool isAddressAccepted(const struct sockaddr_storage& addr,uint32_t checking_flags,uint32_t *check_result=NULL) =0; + /** + * @brief isAddressAccepted + * @param addr full IPv4 address. Port is ignored. + * @param checking_flags any combination of + * RSBANLIST_CHECKING_FLAGS_BLACKLIST and + * RSBANLIST_CHECKING_FLAGS_WHITELIST + * @param check_result returned result of the check in + * RSBANLIST_CHECK_RESULT_* + * @return true if address is accepted, false false if address is rejected. + */ + virtual bool isAddressAccepted( + const sockaddr_storage& addr, uint32_t checking_flags, + uint32_t& check_result = RS_DEFAULT_STORAGE_PARAM(uint32_t) ) = 0; - virtual void getBannedIps(std::list& list) =0; - virtual void getWhiteListedIps(std::list& list) =0; + virtual void getBannedIps(std::list& list) = 0; + virtual void getWhiteListedIps(std::list& list) = 0; - virtual bool autoRangeEnabled() =0; - virtual void enableAutoRange(bool b) =0 ; + virtual bool autoRangeEnabled() = 0; + virtual void enableAutoRange(bool b) = 0; - virtual int autoRangeLimit() =0; - virtual void setAutoRangeLimit(int n)=0; + virtual int autoRangeLimit() = 0; + virtual void setAutoRangeLimit(int n) = 0; - virtual void enableIPsFromFriends(bool b) =0; - virtual bool IPsFromFriendsEnabled() =0; + virtual void enableIPsFromFriends(bool b) = 0; + virtual bool IPsFromFriendsEnabled() = 0; - virtual void enableIPsFromDHT(bool b) =0; - virtual bool iPsFromDHTEnabled() =0; + virtual void enableIPsFromDHT(bool b) = 0; + virtual bool iPsFromDHTEnabled() = 0; + virtual ~RsBanList(); }; - - - diff --git a/libretroshare/src/retroshare/rsbroadcastdiscovery.h b/libretroshare/src/retroshare/rsbroadcastdiscovery.h new file mode 100644 index 000000000..36ffd4ff2 --- /dev/null +++ b/libretroshare/src/retroshare/rsbroadcastdiscovery.h @@ -0,0 +1,109 @@ +/******************************************************************************* + * RetroShare Broadcast Domain Discovery * + * * + * Copyright (C) 2019 Gioacchino Mazzurco * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ +#pragma once + +#include +#include +#include +#include + +#include "retroshare/rsids.h" +#include "retroshare/rstypes.h" +#include "serialiser/rsserializable.h" +#include "util/rstime.h" +#include "util/rsurl.h" +#include "util/rsmemory.h" +#include "retroshare/rsevents.h" + +class RsBroadcastDiscovery; + +/** + * Pointer to global instance of RsBroadcastDiscovery service implementation + * @jsonapi{development} + * + * TODO: this should become std::weak_ptr once we have a reasonable services + * management. + */ +extern std::shared_ptr rsBroadcastDiscovery; + + +struct RsBroadcastDiscoveryResult : RsSerializable +{ + RsPeerId mSslId; + std::string mProfileName; + RsUrl mLocator; + + /// @see RsSerializable + void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx) override + { + RS_SERIAL_PROCESS(mSslId); + RS_SERIAL_PROCESS(mProfileName); + RS_SERIAL_PROCESS(mLocator); + } + + RsBroadcastDiscoveryResult() = default; + RsBroadcastDiscoveryResult (const RsBroadcastDiscoveryResult&) = default; + ~RsBroadcastDiscoveryResult() override; +}; + + +/** + * @brief Event emitted when a non friend new peer is found in the local network + * @see RsEvents + */ +struct RsBroadcastDiscoveryPeerFoundEvent : RsEvent +{ + RsBroadcastDiscoveryPeerFoundEvent( + const RsBroadcastDiscoveryResult& eventData ) : + RsEvent(RsEventType::BROADCAST_DISCOVERY_PEER_FOUND), mData(eventData) {} + + RsBroadcastDiscoveryResult mData; + + /// @see RsSerializable + void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx) override + { + RsEvent::serial_process(j, ctx); + RS_SERIAL_PROCESS(mData); + } + + ~RsBroadcastDiscoveryPeerFoundEvent() override; +}; + + +/** + * Announce own RetroShare instace and look friends and peers in own broadcast + * domain (aka LAN). + * Emit event @see RsBroadcastDiscoveryPeerFoundEvent when a new peer (not + * friend yet) is found. + */ +class RsBroadcastDiscovery +{ +public: + /** + * @brief Get potential peers that have been discovered up until now + * @jsonapi{development} + * @return vector containing discovered peers, may be empty. + */ + virtual std::vector getDiscoveredPeers() = 0; + + virtual ~RsBroadcastDiscovery(); +}; diff --git a/libretroshare/src/retroshare/rsdisc.h b/libretroshare/src/retroshare/rsdisc.h index aedb5f9f7..06311be6c 100644 --- a/libretroshare/src/retroshare/rsdisc.h +++ b/libretroshare/src/retroshare/rsdisc.h @@ -1,9 +1,9 @@ /******************************************************************************* - * libretroshare/src/retroshare: rsdht.h * + * RetroShare gossip discovery - discovery2 retro-compatibility include * * * * libretroshare: retroshare core library * * * - * Copyright 2008-2008 by Robert Fernie * + * Copyright (C) 2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -19,66 +19,14 @@ * along with this program. If not, see . * * * *******************************************************************************/ -#ifndef RETROSHARE_DISC_GUI_INTERFACE_H -#define RETROSHARE_DISC_GUI_INTERFACE_H +#pragma once -#include -#include -#include -#include -#include +#include "retroshare/rsgossipdiscovery.h" +#include "util/rsdeprecate.h" -/* The Main Interface Class - for information about your Peers */ -class RsDisc; +#warning "Including retroshare/rsdisc.h is deprecated, \ +use retroshare/rsgossipdiscovery.h instead" -/** - * Pointer to global instance of RsDisc service implementation - * @jsonapi{development} - */ -extern RsDisc *rsDisc; +using RsDisc RS_DEPRECATED_FOR("RsGossipDiscovery") = RsGossipDiscovery; -class RsDisc -{ - public: - - RsDisc() {} - virtual ~RsDisc() {} - - /** - * @brief getDiscFriends get a list with all friends (ssl id) to a given friend (ssl id) - * @jsonapi{development} - * @param[in] id peer to get the friends of - * @param[out] friends list of friends (ssl id) - * @return true on success false otherwise - */ - virtual bool getDiscFriends(const RsPeerId &id, std::list& friends) = 0; - - /** - * @brief getDiscPgpFriends get a list with all friends (pgp id) to a given friend (pgp id) - * @jsonapi{development} - * @param[in] pgpid peer to get the friends of - * @param[out] gpg_friends list of friends (gpg id) - * @return true on success false otherwise - */ - virtual bool getDiscPgpFriends(const RsPgpId &pgpid, std::list& gpg_friends) = 0; - - /** - * @brief getPeerVersion get the version string of a peer. - * @jsonapi{development} - * @param[in] id peer to get the version string of - * @param[out] versions version string sent by the peer - * @return true on success false otherwise - */ - virtual bool getPeerVersion(const RsPeerId &id, std::string &versions) = 0; - - /** - * @brief getWaitingDiscCount get the number of queued discovery packets. - * @jsonapi{development} - * @param[out] sendCount number of queued outgoing packets - * @param[out] recvCount number of queued incoming packets - * @return true on success false otherwise - */ - virtual bool getWaitingDiscCount(size_t &sendCount, size_t &recvCount) = 0; -}; - -#endif +#define rsDisc rsGossipDiscovery.get() diff --git a/libretroshare/src/retroshare/rsevents.h b/libretroshare/src/retroshare/rsevents.h new file mode 100644 index 000000000..880cade56 --- /dev/null +++ b/libretroshare/src/retroshare/rsevents.h @@ -0,0 +1,169 @@ +/******************************************************************************* + * Retroshare events service * + * * + * libretroshare: retroshare core library * + * * + * Copyright (C) 2019 Gioacchino Mazzurco * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ +#pragma once + +#include +#include + +#include "util/rsmemory.h" +#include "serialiser/rsserializable.h" +#include "serialiser/rstypeserializer.h" + +class RsEvents; + +/** + * Pointer to global instance of RsEvents service implementation + * @jsonapi{development} + * + * TODO: this should become std::weak_ptr once we have a reasonable services + * management. + */ +extern RsEvents* rsEvents; + +/** + * @brief Events types. + * When creating a new type of event, add a new type here and use that to + * initialize mType in the constructor of your derivative of @see RsEvent + */ +enum class RsEventType : uint32_t +{ + NONE = 0, /// Used to detect uninitialized event + + /// @see RsBroadcastDiscovery + BROADCAST_DISCOVERY_PEER_FOUND = 1, + + /// @see RsDiscPendingPgpReceivedEvent + GOSSIP_DISCOVERY_INVITE_RECEIVED = 2, + + /// @see AuthSSL + AUTHSSL_CONNECTION_AUTENTICATION = 3, + + /// @see pqissl + REMOTE_PEER_REFUSED_CONNECTION = 4, + + /// @see RsGxsChanges + GXS_CHANGES = 5, + + /// Emitted when a peer state changes, @see RsPeers + PEER_STATE_CHANGED = 6, + + MAX /// Used to detect invalid event type passed +}; + +/** + * This struct is not meant to be used directly, you should create events type + * deriving from it. + */ +struct RsEvent : RsSerializable +{ +protected: + RsEvent(RsEventType type) : + mType(type), mTimePoint(std::chrono::system_clock::now()) {} + + RsEvent() = delete; + +public: + RsEventType mType; + std::chrono::system_clock::time_point mTimePoint; + + /** + * Derived types must call this method at beginning of their implementation + * of serial_process + * @see RsSerializable + */ + void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx) override + { + RS_SERIAL_PROCESS(mType); + + rstime_t mTime = std::chrono::system_clock::to_time_t(mTimePoint); + RS_SERIAL_PROCESS(mTime); + mTimePoint = std::chrono::system_clock::from_time_t(mTime); + } + + ~RsEvent() override; +}; + +typedef uint32_t RsEventsHandlerId_t; + +class RsEvents +{ +public: + /** + * @brief Post event to the event queue. + * @param[in] event + * @param[out] errorMessage Optional storage for error messsage, meaningful + * only on failure. + * @return False on error, true otherwise. + */ + virtual bool postEvent( + std::shared_ptr event, + std::string& errorMessage = RS_DEFAULT_STORAGE_PARAM(std::string) + ) = 0; + + /** + * @brief Send event directly to handlers. Blocking API + * The handlers get exectuded on the caller thread. + * @param[in] event + * @param[out] errorMessage Optional storage for error messsage, meaningful + * only on failure. + * @return False on error, true otherwise. + */ + virtual bool sendEvent( + std::shared_ptr event, + std::string& errorMessage = RS_DEFAULT_STORAGE_PARAM(std::string) + ) = 0; + + /** + * @brief Generate unique handler identifier + * @return generate Id + */ + virtual RsEventsHandlerId_t generateUniqueHandlerId() = 0; + + /** + * @brief Register events handler + * Every time an event is dispatced the registered events handlers will get + * their method handleEvent called with the event passed as paramether. + * @jsonapi{development,manualwrapper} + * @param multiCallback Function that will be called each time an event + * is dispatched. + * @param[inout] hId Optional storage for handler id, useful to + * eventually unregister the handler later. The + * value may be provided to the function call but + * must habe been generated with + * @see generateUniqueHandlerId() + * @return False on error, true otherwise. + */ + virtual bool registerEventsHandler( + std::function)> multiCallback, + RsEventsHandlerId_t& hId = RS_DEFAULT_STORAGE_PARAM(RsEventsHandlerId_t, 0) + ) = 0; + + /** + * @brief Unregister event handler + * @param[in] hId Id of the event handler to unregister + * @return True if the handler id has been found, false otherwise. + */ + virtual bool unregisterEventsHandler(RsEventsHandlerId_t hId) = 0; + + virtual ~RsEvents(); +}; diff --git a/libretroshare/src/retroshare/rsfiles.h b/libretroshare/src/retroshare/rsfiles.h index e1661d8df..47c464052 100644 --- a/libretroshare/src/retroshare/rsfiles.h +++ b/libretroshare/src/retroshare/rsfiles.h @@ -3,7 +3,8 @@ * * * libretroshare: retroshare core library * * * - * Copyright 2008-2008 by Robert Fernie * + * Copyright (C) 2008 Robert Fernie * + * Copyright (C) 2018-2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -208,7 +209,7 @@ public: virtual ~RsFiles() {} /** - * Provides file data for the gui, media streaming or rpc clients. + * @brief Provides file data for the gui, media streaming or rpc clients. * It may return unverified chunks. This allows streaming without having to * wait for hashes or completion of the file. * This function returns an unspecified amount of bytes. Either as much data @@ -224,7 +225,7 @@ public: * @param[in] offset where the desired block starts * @param[inout] requested_size size of pre-allocated data. Will be updated * by the function. - * @param data pre-allocated memory chunk of size 'requested_size' by the + * @param[out] data pre-allocated memory chunk of size 'requested_size' by the * client * @return Returns false in case * - the files is not available on the local node @@ -422,22 +423,47 @@ public: * @brief Get details about the upload with given hash * @jsonapi{development} * @param[in] hash file identifier - * @param[in] peer_id peer identifier + * @param[in] peerId peer identifier * @param[out] map storage for chunk info * @return true if file found, false otherwise */ virtual bool FileUploadChunksDetails( - const RsFileHash& hash, const RsPeerId& peer_id, + const RsFileHash& hash, const RsPeerId& peerId, CompressedChunkMap& map ) = 0; - /*** - * Extra List Access - ***/ - //virtual bool ExtraFileAdd(std::string fname, std::string hash, uint64_t size, uint32_t period, TransferRequestFlags flags) = 0; - virtual bool ExtraFileRemove(const RsFileHash& hash) = 0; - virtual bool ExtraFileHash(std::string localpath, uint32_t period, TransferRequestFlags flags) = 0; - virtual bool ExtraFileStatus(std::string localpath, FileInfo &info) = 0; - virtual bool ExtraFileMove(std::string fname, const RsFileHash& hash, uint64_t size, std::string destpath) = 0; + /** + * @brief Remove file from extra fila shared list + * @jsonapi{development} + * @param[in] hash hash of the file to remove + * @return return false on error, true otherwise + */ + virtual bool ExtraFileRemove(const RsFileHash& hash) = 0; + + /** + * @brief Add file to extra shared file list + * @jsonapi{development} + * @param[in] localpath path of the file + * @param[in] period how much time the file will be kept in extra list in + * seconds + * @param[in] flags sharing policy flags ex: RS_FILE_REQ_ANONYMOUS_ROUTING + * @return false on error, true otherwise + */ + virtual bool ExtraFileHash( + std::string localpath, rstime_t period, TransferRequestFlags flags + ) = 0; + + /** + * @brief Get extra file information + * @jsonapi{development} + * @param[in] localpath path of the file + * @param[out] info storage for the file information + * @return false on error, true otherwise + */ + virtual bool ExtraFileStatus(std::string localpath, FileInfo &info) = 0; + + virtual bool ExtraFileMove( + std::string fname, const RsFileHash& hash, uint64_t size, + std::string destpath ) = 0; /** * @brief Request directory details, subsequent multiple call may be used to diff --git a/libretroshare/src/retroshare/rsflags.h b/libretroshare/src/retroshare/rsflags.h index f6c97de10..51e91e9a1 100644 --- a/libretroshare/src/retroshare/rsflags.h +++ b/libretroshare/src/retroshare/rsflags.h @@ -1,6 +1,37 @@ +/******************************************************************************* + * libretroshare/src/retroshare: rsflags.h * + * * + * libretroshare: retroshare core library * + * * + * Copyright 2012-2019 by Retroshare Team * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ #pragma once -#include +#include + +/* G10h4ck: TODO we should redefine flags in a way that the flag declaration and + * the flags values (bit fields) would be strongly logically linked. + * A possible way is to take an enum class containing the names of each + * bitfield and corresponding value as template parameter, this way would also + * avoid the need of dumb template parameter that is used only to make the + * types incompatible but that doesn't help finding what are the possible values + * for a kind of flag. Another appealing approach seems the first one described + * here https://softwareengineering.stackexchange.com/questions/194412/using-scoped-enums-for-bit-flags-in-c + * a few simple macros could be used instead of the template class */ // This class provides a representation for flags that can be combined with bitwise // operations. However, because the class is templated with an id, it's not possible to diff --git a/libretroshare/src/retroshare/rsgossipdiscovery.h b/libretroshare/src/retroshare/rsgossipdiscovery.h new file mode 100644 index 000000000..c9dc9924a --- /dev/null +++ b/libretroshare/src/retroshare/rsgossipdiscovery.h @@ -0,0 +1,106 @@ +/******************************************************************************* + * RetroShare remote peers gossip discovery * + * * + * libretroshare: retroshare core library * + * * + * Copyright (C) 2008 Robert Fernie * + * Copyright (C) 2019 Gioacchino Mazzurco * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ +#pragma once + +#include +#include +#include +#include + +#include "retroshare/rstypes.h" +#include "retroshare/rsevents.h" +#include "util/rsmemory.h" + +class RsGossipDiscovery; + +/** + * Pointer to global instance of RsGossipDiscovery service implementation + * @jsonapi{development} + * + * TODO: this should become std::weak_ptr once we have a reasonable services + * management. + */ +extern std::shared_ptr rsGossipDiscovery; + +/** + * @brief Emitted when a pending PGP certificate is received + */ +struct RsGossipDiscoveryFriendInviteReceivedEvent : RsEvent +{ + RsGossipDiscoveryFriendInviteReceivedEvent( + const std::string& invite ); + + std::string mInvite; + + /// @see RsSerializable + virtual void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) + { + RsEvent::serial_process(j,ctx); + RS_SERIAL_PROCESS(mInvite); + } +}; + +class RsGossipDiscovery +{ +public: + virtual ~RsGossipDiscovery() = default; + + /** + * @brief getDiscFriends get a list of all friends of a given friend + * @jsonapi{development} + * @param[in] id peer to get the friends of + * @param[out] friends list of friends (ssl id) + * @return true on success false otherwise + */ + virtual bool getDiscFriends( const RsPeerId& id, + std::list& friends ) = 0; + + /** + * @brief getDiscPgpFriends get a list of all friends of a given friend + * @jsonapi{development} + * @param[in] pgpid peer to get the friends of + * @param[out] gpg_friends list of friends (gpg id) + * @return true on success false otherwise + */ + virtual bool getDiscPgpFriends( + const RsPgpId& pgpid, std::list& gpg_friends ) = 0; + + /** + * @brief getPeerVersion get the version string of a peer. + * @jsonapi{development} + * @param[in] id peer to get the version string of + * @param[out] version version string sent by the peer + * @return true on success false otherwise + */ + virtual bool getPeerVersion(const RsPeerId& id, std::string& version) = 0; + + /** + * @brief getWaitingDiscCount get the number of queued discovery packets. + * @jsonapi{development} + * @param[out] sendCount number of queued outgoing packets + * @param[out] recvCount number of queued incoming packets + * @return true on success false otherwise + */ + virtual bool getWaitingDiscCount(size_t& sendCount, size_t& recvCount) = 0; +}; diff --git a/libretroshare/src/retroshare/rsgxschannels.h b/libretroshare/src/retroshare/rsgxschannels.h index 9ff20cd11..1b90f7924 100644 --- a/libretroshare/src/retroshare/rsgxschannels.h +++ b/libretroshare/src/retroshare/rsgxschannels.h @@ -47,6 +47,8 @@ extern RsGxsChannels* rsGxsChannels; struct RsGxsChannelGroup : RsSerializable { + RsGxsChannelGroup() : mAutoDownload(false) {} + RsGroupMetaData mMeta; std::string mDescription; RsGxsImage mImage; @@ -140,10 +142,13 @@ public: * posted * @param[in] threadId Id of the post (that is a thread) in the channel * where the comment is placed + * @param[in] comment UTF-8 string containing the comment itself + * @param[in] authorId Id of the author of the comment * @param[in] parentId Id of the parent of the comment that is either a * channel post Id or the Id of another comment. - * @param[in] authorId Id of the author of the comment - * @param[in] comment UTF-8 string containing the comment itself + * @param[in] origCommentId If this is supposed to replace an already + * existent comment, the id of the old post. + * If left blank a new post will be created. * @param[out] commentMessageId Optional storage for the id of the comment * that was created, meaningful only on success. * @param[out] errorMessage Optional storage for error message, meaningful @@ -153,9 +158,10 @@ public: virtual bool createCommentV2( const RsGxsGroupId& channelId, const RsGxsMessageId& threadId, - const RsGxsMessageId& parentId, - const RsGxsId& authorId, const std::string& comment, + const RsGxsId& authorId, + const RsGxsMessageId& parentId = RsGxsMessageId(), + const RsGxsMessageId& origCommentId = RsGxsMessageId(), RsGxsMessageId& commentMessageId = RS_DEFAULT_STORAGE_PARAM(RsGxsMessageId), std::string& errorMessage = RS_DEFAULT_STORAGE_PARAM(std::string) ) = 0; diff --git a/libretroshare/src/retroshare/rsgxscircles.h b/libretroshare/src/retroshare/rsgxscircles.h index 83f8e840c..407871d80 100644 --- a/libretroshare/src/retroshare/rsgxscircles.h +++ b/libretroshare/src/retroshare/rsgxscircles.h @@ -3,8 +3,8 @@ * * * libretroshare: retroshare core library * * * - * Copyright (C) 2012 Robert Fernie * - * Copyright (C) 2018 Gioacchino Mazzurco * + * Copyright (C) 2012-2014 Robert Fernie * + * Copyright (C) 2018-2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -32,6 +32,7 @@ #include "retroshare/rsgxsifacehelper.h" #include "retroshare/rsidentity.h" #include "serialiser/rsserializable.h" +#include "util/rsmemory.h" class RsGxsCircles; @@ -74,8 +75,6 @@ static const uint32_t GXS_EXTERNAL_CIRCLE_FLAGS_ALLOWED = 0x0007 ;// user struct RsGxsCircleGroup : RsSerializable { - virtual ~RsGxsCircleGroup() {} - RsGroupMetaData mMeta; std::set mLocalFriends; @@ -95,17 +94,17 @@ struct RsGxsCircleGroup : RsSerializable RS_SERIAL_PROCESS(mInvitedMembers); RS_SERIAL_PROCESS(mSubCircles); } + + ~RsGxsCircleGroup() override; }; struct RsGxsCircleMsg : RsSerializable { - virtual ~RsGxsCircleMsg() {} - RsMsgMetaData mMeta; #ifndef V07_NON_BACKWARD_COMPATIBLE_CHANGE_UNNAMED /* This is horrible and should be changed into yet to be defined something - * reasonable in next non retrocompatible version */ + * reasonable in next non-retrocompatible version */ std::string stuff; #endif @@ -116,6 +115,8 @@ struct RsGxsCircleMsg : RsSerializable RS_SERIAL_PROCESS(mMeta); RS_SERIAL_PROCESS(stuff); } + + ~RsGxsCircleMsg() override; }; struct RsGxsCircleDetails : RsSerializable @@ -123,7 +124,7 @@ struct RsGxsCircleDetails : RsSerializable RsGxsCircleDetails() : mCircleType(static_cast(RsGxsCircleType::EXTERNAL)), mAmIAllowed(false) {} - ~RsGxsCircleDetails() override {} + ~RsGxsCircleDetails() override; RsGxsCircleId mCircleId; std::string mCircleName; @@ -162,16 +163,29 @@ class RsGxsCircles: public RsGxsIfaceHelper public: RsGxsCircles(RsGxsIface& gxs) : RsGxsIfaceHelper(gxs) {} - virtual ~RsGxsCircles() {} + virtual ~RsGxsCircles(); /** * @brief Create new circle * @jsonapi{development} - * @param[inout] cData input name and flags of the circle, storage for - * generated circle data id etc. + * @param[in] circleName String containing cirlce name + * @param[in] circleType Circle type + * @param[out] circleId Optional storage to output created circle id + * @param[in] restrictedId Optional id of a pre-existent circle that see the + * created circle. Meaningful only if circleType == EXTERNAL, must be null + * in all other cases. + * @param[in] authorId Optional author of the circle. + * @param[in] gxsIdMembers GXS ids of the members of the circle. + * @param[in] localMembers PGP ids of the members if the circle. * @return false if something failed, true otherwhise */ - virtual bool createCircle(RsGxsCircleGroup& cData) = 0; + virtual bool createCircle( + const std::string& circleName, RsGxsCircleType circleType, + RsGxsCircleId& circleId = RS_DEFAULT_STORAGE_PARAM(RsGxsCircleId), + const RsGxsCircleId& restrictedId = RsGxsCircleId(), + const RsGxsId& authorId = RsGxsId(), + const std::set& gxsIdMembers = std::set(), + const std::set& localMembers = std::set() ) = 0; /** * @brief Edit own existing circle diff --git a/libretroshare/src/retroshare/rsgxscommon.h b/libretroshare/src/retroshare/rsgxscommon.h index aded69f83..ad9d89ee2 100644 --- a/libretroshare/src/retroshare/rsgxscommon.h +++ b/libretroshare/src/retroshare/rsgxscommon.h @@ -142,19 +142,6 @@ struct RsGxsComment : RsSerializable RS_SERIAL_PROCESS(mOwnVote); RS_SERIAL_PROCESS(mVotes); } - - const std::ostream &print(std::ostream &out, std::string indent = "", std::string varName = "") const { - out << indent << varName << " of RsGxsComment Values ###################" << std::endl; - mMeta.print(out, indent + " ", "mMeta"); - out << indent << " mComment: " << mComment << std::endl; - out << indent << " mUpVotes: " << mUpVotes << std::endl; - out << indent << " mDownVotes: " << mDownVotes << std::endl; - out << indent << " mScore: " << mScore << std::endl; - out << indent << " mOwnVote: " << mOwnVote << std::endl; - out << indent << " mVotes.size(): " << mVotes.size() << std::endl; - out << indent << "######################################################" << std::endl; - return out; - } }; diff --git a/libretroshare/src/retroshare/rsgxsflags.h b/libretroshare/src/retroshare/rsgxsflags.h index ff6f164c2..261173af4 100644 --- a/libretroshare/src/retroshare/rsgxsflags.h +++ b/libretroshare/src/retroshare/rsgxsflags.h @@ -52,12 +52,11 @@ namespace GXS_SERV { static const uint32_t FLAG_AUTHOR_AUTHENTICATION_MASK = 0x0000ff00; static const uint32_t FLAG_AUTHOR_AUTHENTICATION_NONE = 0x00000000; static const uint32_t FLAG_AUTHOR_AUTHENTICATION_GPG = 0x00000100; // Anti-spam feature. Allows to ask higher reputation to anonymous IDs - static const uint32_t FLAG_AUTHOR_AUTHENTICATION_REQUIRED = 0x00000200; // unused + static const uint32_t FLAG_AUTHOR_AUTHENTICATION_REQUIRED = 0x00000200; static const uint32_t FLAG_AUTHOR_AUTHENTICATION_IFNOPUBSIGN = 0x00000400; // ??? static const uint32_t FLAG_AUTHOR_AUTHENTICATION_TRACK_MESSAGES = 0x00000800; // not used anymore static const uint32_t FLAG_AUTHOR_AUTHENTICATION_GPG_KNOWN = 0x00001000; // Anti-spam feature. Allows to ask higher reputation to unknown IDs and anonymous IDs - // These are *not used* static const uint32_t FLAG_GROUP_SIGN_PUBLISH_MASK = 0x000000ff; static const uint32_t FLAG_GROUP_SIGN_PUBLISH_ENCRYPTED = 0x00000001; static const uint32_t FLAG_GROUP_SIGN_PUBLISH_ALLSIGNED = 0x00000002; // unused diff --git a/libretroshare/src/retroshare/rsgxsforums.h b/libretroshare/src/retroshare/rsgxsforums.h index 1c95bed87..3be38691d 100644 --- a/libretroshare/src/retroshare/rsgxsforums.h +++ b/libretroshare/src/retroshare/rsgxsforums.h @@ -3,8 +3,8 @@ * * * libretroshare: retroshare core library * * * - * Copyright (C) 2012 by Robert Fernie * - * Copyright (C) 2018 Gioacchino Mazzurco * + * Copyright (C) 2012-2014 Robert Fernie * + * Copyright (C) 2018-2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -30,9 +30,9 @@ #include "retroshare/rsgxsifacehelper.h" #include "serialiser/rstlvidset.h" #include "serialiser/rsserializable.h" +#include "retroshare/rsgxscircles.h" -/* The Main Interface Class - for information about your Peers */ class RsGxsForums; /** @@ -43,8 +43,10 @@ extern RsGxsForums* rsGxsForums; /** Forum Service message flags, to be used in RsMsgMetaData::mMsgFlags - * Gxs imposes to use the first two bytes (lower bytes) of mMsgFlags for + * Gxs imposes to use the first two bytes (lower bytes) of mMsgFlags for * private forum flags, the upper bytes being used for internal GXS stuff. + * @todo mixing service level flags and GXS level flag into the same member is + * prone to confusion, use separated members for those things */ static const uint32_t RS_GXS_FORUM_MSG_FLAGS_MASK = 0x0000000f; static const uint32_t RS_GXS_FORUM_MSG_FLAGS_MODERATED = 0x00000001; @@ -54,46 +56,52 @@ static const uint32_t RS_GXS_FORUM_MSG_FLAGS_MODERATED = 0x00000001; struct RsGxsForumGroup : RsSerializable { - virtual ~RsGxsForumGroup() {} - + /** Forum GXS metadata */ RsGroupMetaData mMeta; + + /** @brief Forum desciption */ std::string mDescription; - /* What's below is optional, and handled by the serialiser - * TODO: run away from TLV old serializables as those types are opaque to - * JSON API! */ + /** @brief List of forum moderators ids + * @todo run away from TLV old serializables as those types are opaque to + * JSON API! */ RsTlvGxsIdSet mAdminList; + + /** @brief List of forum pinned posts, those are usually displayed on top + * @todo run away from TLV old serializables as those types are opaque to + * JSON API! */ RsTlvGxsMsgIdSet mPinnedPosts; /// @see RsSerializable - virtual void serial_process( RsGenericSerializer::SerializeJob j, - RsGenericSerializer::SerializeContext& ctx ) - { - RS_SERIAL_PROCESS(mMeta); - RS_SERIAL_PROCESS(mDescription); - RS_SERIAL_PROCESS(mAdminList); - RS_SERIAL_PROCESS(mPinnedPosts); - } + virtual void serial_process( + RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) override; - // utility functions + ~RsGxsForumGroup() override; - bool canEditPosts(const RsGxsId& id) const { return mAdminList.ids.find(id) != mAdminList.ids.end() || id == mMeta.mAuthorId; } + /* G10h4ck: We should avoid actual methods in this contexts as they are + * invisible to JSON API */ + bool canEditPosts(const RsGxsId& id) const; }; struct RsGxsForumMsg : RsSerializable { - virtual ~RsGxsForumMsg() {} - + /** @brief Forum post GXS metadata */ RsMsgMetaData mMeta; + + /** @brief Forum post content */ std::string mMsg; /// @see RsSerializable - virtual void serial_process( RsGenericSerializer::SerializeJob j, - RsGenericSerializer::SerializeContext& ctx ) + virtual void serial_process( + RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) override { RS_SERIAL_PROCESS(mMeta); RS_SERIAL_PROCESS(mMsg); } + + ~RsGxsForumMsg() override; }; @@ -101,23 +109,67 @@ class RsGxsForums: public RsGxsIfaceHelper { public: explicit RsGxsForums(RsGxsIface& gxs) : RsGxsIfaceHelper(gxs) {} - virtual ~RsGxsForums() {} + virtual ~RsGxsForums(); /** - * @brief Create forum. Blocking API. + * @brief Create forum. * @jsonapi{development} - * @param[inout] forum Forum data (name, description...) - * @return false on error, true otherwise + * @param[in] name Name of the forum + * @param[in] description Optional description of the forum + * @param[in] authorId Optional id of the froum owner author + * @param[in] moderatorsIds Optional list of forum moderators + * @param[in] circleType Optional visibility rule, default public. + * @param[in] circleId If the forum is not public specify the id of + * the circle who can see the forum. Depending on + * the value you pass for circleType this should + * be a circle if EXTERNAL is passed, a local + * friends group id if NODES_GROUP is passed, + * empty otherwise. + * @param[out] forumId Optional storage for the id of the created + * forum, meaningful only if creations succeeds. + * @param[out] errorMessage Optional storage for error messsage, meaningful + * only if creation fail. + * @return False on error, true otherwise. */ - virtual bool createForum(RsGxsForumGroup& forum) = 0; + virtual bool createForumV2( + const std::string& name, const std::string& description, + const RsGxsId& authorId = RsGxsId(), + const std::set& moderatorsIds = std::set(), + RsGxsCircleType circleType = RsGxsCircleType::PUBLIC, + const RsGxsCircleId& circleId = RsGxsCircleId(), + RsGxsGroupId& forumId = RS_DEFAULT_STORAGE_PARAM(RsGxsGroupId), + std::string& errorMessage = RS_DEFAULT_STORAGE_PARAM(std::string) + ) = 0; /** - * @brief Create forum message. Blocking API. + * @brief Create a post on the given forum. * @jsonapi{development} - * @param[inout] message + * @param[in] forumId Id of the forum in which the post is to be + * submitted + * @param[in] title UTF-8 string containing the title of the post + * @param[in] mBody UTF-8 string containing the text of the post + * @param[in] authorId Id of the author of the comment + * @param[in] parentId Optional Id of the parent post if this post is a + * reply to another post, empty otherwise. + * @param[in] origPostId If this is supposed to replace an already + * existent post, the id of the old post. + * If left blank a new post will be created. + * @param[out] postMsgId Optional storage for the id of the created, + * meaningful only on success. + * @param[out] errorMessage Optional storage for error message, meaningful + * only on failure. * @return false on error, true otherwise */ - virtual bool createMessage(RsGxsForumMsg& message) = 0; + virtual bool createPost( + const RsGxsGroupId& forumId, + const std::string& title, + const std::string& mBody, + const RsGxsId& authorId, + const RsGxsMessageId& parentId = RsGxsMessageId(), + const RsGxsMessageId& origPostId = RsGxsMessageId(), + RsGxsMessageId& postMsgId = RS_DEFAULT_STORAGE_PARAM(RsGxsMessageId), + std::string& errorMessage = RS_DEFAULT_STORAGE_PARAM(std::string) + ) = 0; /** * @brief Edit forum details. @@ -167,7 +219,7 @@ public: */ virtual bool getForumContent( const RsGxsGroupId& forumId, - std::set& msgsIds, + const std::set& msgsIds, std::vector& msgs) = 0; /** @@ -189,6 +241,26 @@ public: virtual bool subscribeToForum( const RsGxsGroupId& forumId, bool subscribe ) = 0; + /** + * @brief Create forum. Blocking API. + * @jsonapi{development} + * @param[inout] forum Forum data (name, description...) + * @return false on error, true otherwise + * @deprecated @see createForumV2 + */ + RS_DEPRECATED_FOR(createForumV2) + virtual bool createForum(RsGxsForumGroup& forum) = 0; + + /** + * @brief Create forum message. Blocking API. + * @jsonapi{development} + * @param[inout] message + * @return false on error, true otherwise + * @deprecated @see createPost + */ + RS_DEPRECATED_FOR(createPost) + virtual bool createMessage(RsGxsForumMsg& message) = 0; + /* Specific Service Data */ RS_DEPRECATED_FOR("getForumsSummaries, getForumsInfo") virtual bool getGroupData(const uint32_t &token, std::vector &groups) = 0; @@ -203,4 +275,3 @@ public: RS_DEPRECATED_FOR(editForum) virtual bool updateGroup(uint32_t &token, RsGxsForumGroup &group) = 0; }; - diff --git a/libretroshare/src/retroshare/rsgxsiface.h b/libretroshare/src/retroshare/rsgxsiface.h index 268c8cc75..c230c06fa 100644 --- a/libretroshare/src/retroshare/rsgxsiface.h +++ b/libretroshare/src/retroshare/rsgxsiface.h @@ -3,7 +3,8 @@ * * * libretroshare: retroshare core library * * * - * Copyright 2012 by Christopher Evi-Parker * + * Copyright (C) 2012 Christopher Evi-Parker * + * Copyright (C) 2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -19,9 +20,7 @@ * along with this program. If not, see . * * * *******************************************************************************/ - -#ifndef RSGXSIFACE_H_ -#define RSGXSIFACE_H_ +#pragma once #include "retroshare/rsreputations.h" #include "retroshare/rsgxsservice.h" @@ -29,6 +28,8 @@ #include "retroshare/rsgxsifacetypes.h" #include "util/rsdeprecate.h" #include "serialiser/rsserializable.h" +#include "rsitems/rsserviceids.h" +#include "retroshare/rsevents.h" /*! * This structure is used to transport group summary information when a GXS @@ -71,17 +72,35 @@ struct RsGxsGroupSummary : RsSerializable /*! - * Stores ids of changed gxs groups and messages. It is used to notify the GUI about changes. + * Stores ids of changed gxs groups and messages. + * It is used to notify about GXS changes. */ -struct RsGxsChanges +struct RsGxsChanges : RsEvent { - RsGxsChanges(): mService(0){} - RsTokenService *mService; - std::map > mMsgs; - std::map > mMsgsMeta; - std::list mGrps; - std::list mGrpsMeta; - std::list mDistantSearchReqs; + RsGxsChanges(); + + /// Type of the service + RsServiceType mServiceType; + std::map > mMsgs; + std::map > mMsgsMeta; + std::list mGrps; + std::list mGrpsMeta; + std::list mDistantSearchReqs; + + /// @see RsSerializable + void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx) override + { + RsEvent::serial_process(j,ctx); + RS_SERIAL_PROCESS(mServiceType); + RS_SERIAL_PROCESS(mMsgs); + RS_SERIAL_PROCESS(mMsgsMeta); + RS_SERIAL_PROCESS(mGrps); + RS_SERIAL_PROCESS(mGrpsMeta); + RS_SERIAL_PROCESS(mDistantSearchReqs); + } + + RsTokenService* mService; /// Weak pointer, not serialized }; /*! @@ -220,7 +239,3 @@ struct RsGxsIface virtual RsReputationLevel minReputationForForwardingMessages( uint32_t group_sign_flags,uint32_t identity_flags ) = 0; }; - - - -#endif /* RSGXSIFACE_H_ */ diff --git a/libretroshare/src/retroshare/rsgxsifacetypes.h b/libretroshare/src/retroshare/rsgxsifacetypes.h index d5a9d8d7d..d0e6e0372 100644 --- a/libretroshare/src/retroshare/rsgxsifacetypes.h +++ b/libretroshare/src/retroshare/rsgxsifacetypes.h @@ -34,10 +34,7 @@ #include "serialiser/rstypeserializer.h" #include "util/rstime.h" -typedef GXSGroupId RsGxsGroupId; typedef Sha1CheckSum RsGxsMessageId; -typedef GXSId RsGxsId; -typedef GXSCircleId RsGxsCircleId; typedef std::map > GxsMsgIdResult; typedef std::pair RsGxsGrpMsgIdPair; @@ -143,14 +140,20 @@ struct RsMsgMetaData : RsSerializable std::string mMsgName; rstime_t mPublishTs; - /// the lower 16 bits for service, upper 16 bits for GXS - uint32_t mMsgFlags; + /** the lower 16 bits for service, upper 16 bits for GXS + * @todo mixing service level flags and GXS level flag into the same member + * is prone to confusion, use separated members for those things, this could + * be done without breaking network retro-compatibility */ + uint32_t mMsgFlags; // BELOW HERE IS LOCAL DATA, THAT IS NOT FROM MSG. // normally READ / UNREAD flags. LOCAL Data. - /// the first 16 bits for service, last 16 for GXS - uint32_t mMsgStatus; + /** the first 16 bits for service, last 16 for GXS + * @todo mixing service level flags and GXS level flag into the same member + * is prone to confusion, use separated members for those things, this could + * be done without breaking network retro-compatibility */ + uint32_t mMsgStatus; rstime_t mChildTs; std::string mServiceString; // Service Specific Free-Form extra storage. @@ -172,25 +175,6 @@ struct RsMsgMetaData : RsSerializable RS_SERIAL_PROCESS(mChildTs); RS_SERIAL_PROCESS(mServiceString); } - - const std::ostream &print(std::ostream &out, std::string indent = "", std::string varName = "") const { - out - << indent << varName << " of RsMsgMetaData Values ###################" << std::endl - << indent << " mGroupId: " << mGroupId.toStdString() << std::endl - << indent << " mMsgId: " << mMsgId.toStdString() << std::endl - << indent << " mThreadId: " << mThreadId.toStdString() << std::endl - << indent << " mParentId: " << mParentId.toStdString() << std::endl - << indent << " mOrigMsgId: " << mOrigMsgId.toStdString() << std::endl - << indent << " mAuthorId: " << mAuthorId.toStdString() << std::endl - << indent << " mMsgName: " << mMsgName << std::endl - << indent << " mPublishTs: " << mPublishTs << std::endl - << indent << " mMsgFlags: " << std::hex << mMsgFlags << std::dec << std::endl - << indent << " mMsgStatus: " << std::hex << mMsgStatus << std::dec << std::endl - << indent << " mChildTs: " << mChildTs << std::endl - << indent << " mServiceString: " << mServiceString << std::endl - << indent << "######################################################" << std::endl; - return out; - } }; class GxsGroupStatistic diff --git a/libretroshare/src/retroshare/rsgxstrans.h b/libretroshare/src/retroshare/rsgxstrans.h index bee1e11ec..a491f7bfe 100644 --- a/libretroshare/src/retroshare/rsgxstrans.h +++ b/libretroshare/src/retroshare/rsgxstrans.h @@ -1,3 +1,23 @@ +/******************************************************************************* + * libretroshare/src/retroshare: rsgxstrans.h * + * * + * libretroshare: retroshare core library * + * * + * Copyright (C) 2016-2019 Gioacchino Mazzurco * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License version 3 as * + * published by the Free Software Foundation. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ #pragma once #include "retroshare/rstokenservice.h" @@ -41,7 +61,8 @@ enum class GxsTransSendStatus : uint8_t /// Records with status >= RECEIPT_RECEIVED get deleted RECEIPT_RECEIVED = 0x0a, FAILED_RECEIPT_SIGNATURE = 0xf0, - FAILED_ENCRYPTION = 0xf1 + FAILED_ENCRYPTION = 0xf1, + FAILED_TIMED_OUT = 0xf2 }; typedef uint64_t RsGxsTransId; @@ -79,6 +100,7 @@ struct RsGxsTransOutgoingRecord RsGxsGroupId group_id ; }; +/// RetroShare GxsTrans asyncronous redundant small mail trasport on top of GXS class RsGxsTrans: public RsGxsIfaceHelper { public: diff --git a/libretroshare/src/retroshare/rsgxstunnel.h b/libretroshare/src/retroshare/rsgxstunnel.h index 239816f38..125a7c9a9 100644 --- a/libretroshare/src/retroshare/rsgxstunnel.h +++ b/libretroshare/src/retroshare/rsgxstunnel.h @@ -29,8 +29,6 @@ class RsGxsTunnelService { public: - typedef GXSTunnelId RsGxsTunnelId ; - enum { RS_GXS_TUNNEL_ERROR_NO_ERROR = 0x0000, RS_GXS_TUNNEL_ERROR_UNKNOWN_GXS_ID = 0x0001 diff --git a/libretroshare/src/retroshare/rsidentity.h b/libretroshare/src/retroshare/rsidentity.h index 8be685d24..5abdfb47b 100644 --- a/libretroshare/src/retroshare/rsidentity.h +++ b/libretroshare/src/retroshare/rsidentity.h @@ -151,11 +151,9 @@ struct RsGxsIdGroup : RsSerializable RsGenericSerializer::SerializeContext& ctx ) override; }; -std::ostream &operator<<(std::ostream &out, const RsGxsIdGroup &group); - // DATA TYPE FOR EXTERNAL INTERFACE. -struct RsRecognTag +struct RS_DEPRECATED RsRecognTag { RsRecognTag(uint16_t tc, uint16_t tt, bool v) : tag_class(tc), tag_type(tt), valid(v) {} @@ -166,7 +164,7 @@ struct RsRecognTag }; -struct RsRecognTagDetails +struct RS_DEPRECATED RsRecognTagDetails { RsRecognTagDetails() : valid_from(0), valid_to(0), tag_class(0), tag_type(0), is_valid(false), @@ -246,14 +244,22 @@ struct RsIdentityUsage : RsSerializable CIRCLE_MEMBERSHIP_CHECK = 0x13 } ; + RS_DEPRECATED RsIdentityUsage( uint16_t service, const RsIdentityUsage::UsageCode& code, const RsGxsGroupId& gid = RsGxsGroupId(), const RsGxsMessageId& mid = RsGxsMessageId(), uint64_t additional_id=0, const std::string& comment = std::string() ); + RsIdentityUsage( RsServiceType service, + RsIdentityUsage::UsageCode code, + const RsGxsGroupId& gid = RsGxsGroupId(), + const RsGxsMessageId& mid = RsGxsMessageId(), + uint64_t additional_id=0, + const std::string& comment = std::string() ); + /// Id of the service using that identity, as understood by rsServiceControl - uint16_t mServiceId; + RsServiceType mServiceId; /** Specific code to use. Will allow forming the correct translated message * in the GUI if necessary. */ @@ -382,6 +388,7 @@ struct RsIdentity : RsGxsIfaceHelper /** * @brief Get identity details, from the cache + * @jsonapi{development} * @param[in] id Id of the identity * @param[out] details Storage for the identity details * @return false on error, true otherwise @@ -402,7 +409,7 @@ struct RsIdentity : RsGxsIfaceHelper * @param[out] ids storage for the ids * @return false on error, true otherwise */ - virtual bool getOwnSignedIds(std::vector ids) = 0; + virtual bool getOwnSignedIds(std::vector& ids) = 0; /** * @brief Get own pseudonimous (unsigned) ids @@ -410,7 +417,7 @@ struct RsIdentity : RsGxsIfaceHelper * @param[out] ids storage for the ids * @return false on error, true otherwise */ - virtual bool getOwnPseudonimousIds(std::vector ids) = 0; + virtual bool getOwnPseudonimousIds(std::vector& ids) = 0; /** * @brief Check if an id is own @@ -470,6 +477,7 @@ struct RsIdentity : RsGxsIfaceHelper /** * @brief Set/unset identity as contact + * @jsonapi{development} * @param[in] id Id of the identity * @param[in] isContact true to set, false to unset * @return false on error, true otherwise @@ -505,6 +513,14 @@ struct RsIdentity : RsGxsIfaceHelper */ virtual void setDeleteBannedNodesThreshold(uint32_t days) = 0; + /** + * @brief request details of a not yet known identity to the network + * @jsonapi{development} + * @param[in] id id of the identity to request + * @return false on error, true otherwise + */ + virtual bool requestIdentity(const RsGxsId& id) = 0; + RS_DEPRECATED virtual bool getGroupSerializedData( diff --git a/libretroshare/src/retroshare/rsids.h b/libretroshare/src/retroshare/rsids.h index 3f0deaca9..8c2cdc51e 100644 --- a/libretroshare/src/retroshare/rsids.h +++ b/libretroshare/src/retroshare/rsids.h @@ -3,7 +3,8 @@ * * * libretroshare: retroshare core library * * * - * Copyright 2013 by Cyril Soler * + * Copyright (C) 2013 Cyril Soler * + * Copyright (C) 2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -19,35 +20,6 @@ * along with this program. If not, see . * * * *******************************************************************************/ - -// This class aims at defining a generic ID type that is a list of bytes. It -// can be converted into a hexadecial string for printing, mainly) or for -// compatibility with old methods. -// -// To use this class, derive your own ID type from it. Examples include: -// -// class RsPgpId: public t_RsGenericIdType<8> -// { -// [..] -// }; -// -// class PGPFingerprintType: public t_RsGenericIdType<20> -// { -// [..] -// }; -// -// With this, there is no implicit conversion between subtypes, and therefore ID mixup -// is impossible. -// -// A simpler way to make ID types is to -// typedef t_RsGenericIdType MyType ; -// -// ID Types with different lengths will be incompatible on compilation. -// -// Warning: never store references to a t_RsGenericIdType accross threads, since the -// cached string convertion is not thread safe. -// - #pragma once #include @@ -55,125 +27,213 @@ #include #include #include -#include -#include +#include #include #include #include +#include -template class t_RsGenericIdType +#include "util/rsdebug.h" +#include "util/rsrandom.h" +#include "util/stacktrace.h" + +/** + * RsGenericIdType values might be random, but must be different, in order to + * make the various IDs incompatible with each other. + */ +enum class RsGenericIdType { - public: - - typedef std::list > std_list; - typedef std::vector > std_vector; - typedef std::set > std_set; - - t_RsGenericIdType() - { - memset(bytes,0,ID_SIZE_IN_BYTES) ; // by default, ids are set to null() - } - virtual ~t_RsGenericIdType() {} - - // Explicit constructor from a hexadecimal string - // - explicit t_RsGenericIdType(const std::string& hex_string) ; - - // Explicit constructor from a byte array. The array should have size at least ID_SIZE_IN_BYTES - // - explicit t_RsGenericIdType(const unsigned char bytes[]) ; - - // Explicit constructor from a different type, checking that the sizes are compatible. - // This is used for conversions such as - // - // GroupId -> CircleId - // GroupId -> GxsId - // - template - explicit t_RsGenericIdType(const t_RsGenericIdType& id) - { - memcpy(bytes,id.toByteArray(),ID_SIZE_IN_BYTES) ; - } - - // Random initialization. Can be useful for testing and to generate new ids. - // - static t_RsGenericIdType random() - { - t_RsGenericIdType id ; - - RSRandom::random_bytes(id.bytes,ID_SIZE_IN_BYTES) ; - - return id ; - } - - inline void clear() { memset(bytes,0,SIZE_IN_BYTES) ; } - - // Converts to a std::string using cached value. - // - const unsigned char *toByteArray() const { return &bytes[0] ; } - static const uint32_t SIZE_IN_BYTES = ID_SIZE_IN_BYTES ; - - inline bool operator==(const t_RsGenericIdType& fp) const { return !memcmp(bytes,fp.bytes,ID_SIZE_IN_BYTES) ; } - inline bool operator!=(const t_RsGenericIdType& fp) const { return !!memcmp(bytes,fp.bytes,ID_SIZE_IN_BYTES); } - inline bool operator< (const t_RsGenericIdType& fp) const { return (memcmp(bytes,fp.bytes,ID_SIZE_IN_BYTES) < 0) ; } - inline t_RsGenericIdType - operator~ () const - { - t_RsGenericIdType ret; - for(uint32_t i=0; i < ID_SIZE_IN_BYTES; ++i) - ret.bytes[i] = ~bytes[i]; - return ret; - } - inline t_RsGenericIdType - operator| (const t_RsGenericIdType& fp) const - { - t_RsGenericIdType ret; - for(uint32_t i=0; i < ID_SIZE_IN_BYTES; ++i) - ret.bytes[i] = bytes[i] | fp.bytes[i]; - return ret; - } - - inline bool isNull() const - { - for(uint32_t i=0;i& id) - { - return out << id.toStdString(UPPER_CASE) ; - } - - inline std::string toStdString() const { return toStdString(UPPER_CASE) ; } - - inline static uint32_t serial_size() { return SIZE_IN_BYTES ; } - bool serialise(void *data,uint32_t pktsize,uint32_t& offset) const - { - if(offset + SIZE_IN_BYTES > pktsize) - return false ; - - memcpy(&((uint8_t*)data)[offset],bytes,SIZE_IN_BYTES) ; - offset += SIZE_IN_BYTES ; - return true ; - } - bool deserialise(const void *data,uint32_t pktsize,uint32_t& offset) - { - if(offset + SIZE_IN_BYTES > pktsize) - return false ; - - memcpy(bytes,&((uint8_t*)data)[offset],SIZE_IN_BYTES) ; - offset += SIZE_IN_BYTES ; - return true ; - } - private: - std::string toStdString(bool upper_case) const ; - - unsigned char bytes[ID_SIZE_IN_BYTES] ; + SSL, + PGP_ID, + SHA1, + PGP_FINGERPRINT, + GXS_GROUP, + GXS_ID, + GXS_MSG, + GXS_CIRCLE, + GROUTER, + GXS_TUNNEL, + DISTANT_CHAT, + NODE_GROUP, + SHA256, + BIAS_20_BYTES }; -template std::string t_RsGenericIdType::toStdString(bool upper_case) const +/** + * This class aims at defining a generic ID type that is a list of bytes. It + * can be converted into a hexadecial string for printing, mainly) or for + * compatibility with old methods. + * + * To use this class, derive your own ID type from it. + * @see RsPpgFingerprint as an example. + * + * Take care to define and use a different @see RsGenericIdType for each ne type + * of ID you create, to avoid implicit conversion between subtypes, and + * therefore accidental ID mixup is impossible. + * + * ID Types with different lengths are not convertible even using explicit + * constructor and compilation would fail if that is attempted. + * + * Warning: never store references to a t_RsGenericIdType accross threads, since + * the cached string convertion is not thread safe. + */ +template +struct t_RsGenericIdType +{ + using Id_t = t_RsGenericIdType; + using std_list = std::list; + using std_vector = std::vector; + using std_set = std::set; + + /// by default, ids are set to null() + t_RsGenericIdType() { memset(bytes, 0, ID_SIZE_IN_BYTES); } + + /// Explicit constructor from a hexadecimal string + explicit t_RsGenericIdType(const std::string& hex_string); + + /** + * @brief Construct from a buffer of at least the size of SIZE_IN_BYTES + * This is dangerous if used without being absolutely sure of buffer size, + * nothing prevent a buffer of wrong size being passed at runtime! + * @param[in] buff pointer to the buffer + * @return empty id on failure, an id initialized from the bytes in the + * buffer + */ + static Id_t fromBufferUnsafe(const uint8_t* buff) + { + Id_t ret; + + if(!buff) + { + RsErr() << __PRETTY_FUNCTION__ << " invalid paramethers buff: " + << buff << std::endl; + print_stacktrace(); + return ret; + } + + memmove(ret.bytes, buff, SIZE_IN_BYTES); + return ret; + } + + /** + * Explicit constructor from a different type but with same size. + * + * This is used for conversions such as + * GroupId -> CircleId + * GroupId -> GxsId + */ + template + explicit t_RsGenericIdType( + const t_RsGenericIdType& + id ) + { memmove(bytes, id.toByteArray(), ID_SIZE_IN_BYTES); } + + /// Random initialization. Can be useful for testing and to generate new ids. + static Id_t random() + { + Id_t id; + RsRandom::random_bytes(id.bytes, ID_SIZE_IN_BYTES); + return id; + } + + inline void clear() { memset(bytes, 0, SIZE_IN_BYTES); } + + /// Converts to a std::string using cached value. + const uint8_t* toByteArray() const { return &bytes[0]; } + + static constexpr uint32_t SIZE_IN_BYTES = ID_SIZE_IN_BYTES; + + inline bool operator==(const Id_t& fp) const + { return !memcmp(bytes, fp.bytes, ID_SIZE_IN_BYTES); } + + inline bool operator!=(const Id_t& fp) const + { return !!memcmp(bytes, fp.bytes, ID_SIZE_IN_BYTES); } + + inline bool operator< (const Id_t& fp) const + { return (memcmp(bytes, fp.bytes, ID_SIZE_IN_BYTES) < 0); } + + inline Id_t operator~ () const + { + Id_t ret; + for(uint32_t i=0; i < ID_SIZE_IN_BYTES; ++i) + ret.bytes[i] = ~bytes[i]; + return ret; + } + + inline Id_t operator| (const Id_t& fp) const + { + Id_t ret; + for(uint32_t i=0; i < ID_SIZE_IN_BYTES; ++i) + ret.bytes[i] = bytes[i] | fp.bytes[i]; + return ret; + } + + inline bool isNull() const + { + for(uint32_t i=0; i < SIZE_IN_BYTES; ++i) + if(bytes[i] != 0) return false; + return true; + } + + friend std::ostream& operator<<(std::ostream& out, const Id_t& id) + { + switch (UNIQUE_IDENTIFIER) + { + case RsGenericIdType::PGP_FINGERPRINT: + { + uint8_t index = 0; + for(char c : id.toStdString()) + { + out << c; + if(++index % 4 == 0 && index < id.SIZE_IN_BYTES*2) out << ' '; + } + } + break; + default: out << id.toStdString(UPPER_CASE); break; + } + + return out; + } + + inline std::string toStdString() const { return toStdString(UPPER_CASE); } + + inline static uint32_t serial_size() { return SIZE_IN_BYTES; } + + bool serialise(void* data,uint32_t pktsize,uint32_t& offset) const + { + if(offset + SIZE_IN_BYTES > pktsize) return false; + memmove( &(reinterpret_cast(data))[offset], + bytes, SIZE_IN_BYTES ); + offset += SIZE_IN_BYTES; + return true; + } + + bool deserialise(const void* data, uint32_t pktsize, uint32_t& offset) + { + if(offset + SIZE_IN_BYTES > pktsize) return false; + memmove( bytes, + &(reinterpret_cast(data))[offset], + SIZE_IN_BYTES ); + offset += SIZE_IN_BYTES; + return true; + } + + /** Explicit constructor from a byte array. The array must have size at + * least ID_SIZE_IN_BYTES + * @deprecated This is too dangerous! + * Nothing prevent a buffer of wrong size being passed at runtime! + */ + RS_DEPRECATED_FOR("fromBufferUnsafe(const uint8_t* buff)") + explicit t_RsGenericIdType(const uint8_t bytes[]); + +private: + std::string toStdString(bool upper_case) const; + uint8_t bytes[ID_SIZE_IN_BYTES]; +}; + +template +std::string t_RsGenericIdType +::toStdString(bool upper_case) const { static const char outh[16] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' } ; static const char outl[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' } ; @@ -195,14 +255,20 @@ template s return res ; } -template t_RsGenericIdType::t_RsGenericIdType(const std::string& s) +template +t_RsGenericIdType +::t_RsGenericIdType(const std::string& s) { - int n=0; + std::string::size_type n = 0; if(s.length() != ID_SIZE_IN_BYTES*2) { if(!s.empty()) - std::cerr << "t_RsGenericIdType<>::t_RsGenericIdType(std::string&): supplied string in constructor has wrong size. Expected ID size=" << ID_SIZE_IN_BYTES*2 << " String=\"" << s << "\" = " << s.length() << std::endl; - + { + RsErr() << __PRETTY_FUNCTION__ << " supplied string in constructor " + << "has wrong size. Expected ID size=" << ID_SIZE_IN_BYTES*2 + << " String=\"" << s << "\" = " << s.length() << std::endl; + print_stacktrace(); + } clear(); return; } @@ -221,58 +287,52 @@ template t bytes[i] += (b-'a'+10) << 4*(1-k) ; else if(b >= '0' && b <= '9') bytes[i] += (b-'0') << 4*(1-k) ; - else { - std::cerr << "t_RsGenericIdType<>::t_RsGenericIdType(std::string&): supplied string is not purely hexadecimal: s=\"" << s << "\"" << std::endl; - clear(); + else + { + RsErr() << __PRETTY_FUNCTION__ << "supplied string is not " + << "purely hexadecimal: s=\"" << s << "\"" << std::endl; + clear(); return; } } } } -template t_RsGenericIdType::t_RsGenericIdType(const unsigned char *mem) +template +RS_DEPRECATED_FOR("t_RsGenericIdType::fromBuffer(...)") +t_RsGenericIdType:: +t_RsGenericIdType(const uint8_t mem[]) /// @deprecated Too dangerous! { - if(mem == NULL) - memset(bytes,0,ID_SIZE_IN_BYTES) ; - else - memcpy(bytes,mem,ID_SIZE_IN_BYTES) ; + if(mem == nullptr) memset(bytes, 0, ID_SIZE_IN_BYTES); + else memcpy(bytes, mem, ID_SIZE_IN_BYTES); } -static const int SSL_ID_SIZE = 16 ; // = CERTSIGNLEN -static const int CERT_SIGN_LEN = 16 ; // = CERTSIGNLEN -static const int PGP_KEY_ID_SIZE = 8 ; -static const int PGP_KEY_FINGERPRINT_SIZE = 20 ; -static const int SHA1_SIZE = 20 ; -static const int SHA256_SIZE = 32 ; +/** + * This constants are meant to be used only inside this file. + * Use @see t_RsGenericIdType::SIZE_IN_BYTES in other places. + */ +namespace _RsIdSize +{ +constexpr uint32_t SSL_ID = 16; // = CERT_SIGN +constexpr uint32_t CERT_SIGN = 16; // = SSL_ID +constexpr uint32_t PGP_ID = 8; +constexpr uint32_t PGP_FINGERPRINT = 20; +constexpr uint32_t SHA1 = 20; +constexpr uint32_t SHA256 = 32; +} -// These constants are random, but should be different, in order to make the various IDs incompatible with each other. -// -static const uint32_t RS_GENERIC_ID_SSL_ID_TYPE = 0x0001 ; -static const uint32_t RS_GENERIC_ID_PGP_ID_TYPE = 0x0002 ; -static const uint32_t RS_GENERIC_ID_SHA1_ID_TYPE = 0x0003 ; -static const uint32_t RS_GENERIC_ID_PGP_FINGERPRINT_TYPE = 0x0004 ; -static const uint32_t RS_GENERIC_ID_GXS_GROUP_ID_TYPE = 0x0005 ; -static const uint32_t RS_GENERIC_ID_GXS_ID_TYPE = 0x0006 ; -static const uint32_t RS_GENERIC_ID_GXS_MSG_ID_TYPE = 0x0007 ; -static const uint32_t RS_GENERIC_ID_GXS_CIRCLE_ID_TYPE = 0x0008 ; -static const uint32_t RS_GENERIC_ID_GROUTER_ID_TYPE = 0x0009 ; -static const uint32_t RS_GENERIC_ID_GXS_TUNNEL_ID_TYPE = 0x0010 ; -static const uint32_t RS_GENERIC_ID_GXS_DISTANT_CHAT_ID_TYPE = 0x0011 ; -static const uint32_t RS_GENERIC_ID_NODE_GROUP_ID_TYPE = 0x0012 ; -static const uint32_t RS_GENERIC_ID_SHA256_ID_TYPE = 0x0013 ; -static const uint32_t RS_GENERIC_ID_20_BYTES_UNTYPED = 0x0014 ; - -typedef t_RsGenericIdType< SSL_ID_SIZE , false, RS_GENERIC_ID_SSL_ID_TYPE> SSLIdType ; -typedef t_RsGenericIdType< PGP_KEY_ID_SIZE , true, RS_GENERIC_ID_PGP_ID_TYPE> PGPIdType ; -typedef t_RsGenericIdType< SHA1_SIZE , false, RS_GENERIC_ID_SHA1_ID_TYPE> Sha1CheckSum ; -typedef t_RsGenericIdType< SHA256_SIZE , false, RS_GENERIC_ID_SHA256_ID_TYPE> Sha256CheckSum ; -typedef t_RsGenericIdType< PGP_KEY_FINGERPRINT_SIZE, true, RS_GENERIC_ID_PGP_FINGERPRINT_TYPE> PGPFingerprintType ; -typedef t_RsGenericIdType< SHA1_SIZE , true, RS_GENERIC_ID_20_BYTES_UNTYPED> Bias20Bytes ; - -typedef t_RsGenericIdType< CERT_SIGN_LEN , false, RS_GENERIC_ID_GXS_GROUP_ID_TYPE > GXSGroupId ; -typedef t_RsGenericIdType< CERT_SIGN_LEN , false, RS_GENERIC_ID_GXS_ID_TYPE > GXSId ; -typedef t_RsGenericIdType< CERT_SIGN_LEN , false, RS_GENERIC_ID_GXS_CIRCLE_ID_TYPE > GXSCircleId ; -typedef t_RsGenericIdType< SSL_ID_SIZE , false, RS_GENERIC_ID_GXS_TUNNEL_ID_TYPE > GXSTunnelId ; -typedef t_RsGenericIdType< SSL_ID_SIZE , false, RS_GENERIC_ID_GXS_DISTANT_CHAT_ID_TYPE > DistantChatPeerId ; -typedef t_RsGenericIdType< CERT_SIGN_LEN , false, RS_GENERIC_ID_NODE_GROUP_ID_TYPE > RsNodeGroupId ; +using RsPeerId = t_RsGenericIdType<_RsIdSize::SSL_ID , false, RsGenericIdType::SSL >; +using RsPgpId = t_RsGenericIdType<_RsIdSize::PGP_ID , true, RsGenericIdType::PGP_ID >; +using Sha1CheckSum = t_RsGenericIdType<_RsIdSize::SHA1 , false, RsGenericIdType::SHA1 >; +using Sha256CheckSum = t_RsGenericIdType<_RsIdSize::SHA256 , false, RsGenericIdType::SHA256 >; +using RsPgpFingerprint = t_RsGenericIdType<_RsIdSize::PGP_FINGERPRINT, true, RsGenericIdType::PGP_FINGERPRINT>; +using Bias20Bytes = t_RsGenericIdType<_RsIdSize::SHA1 , true, RsGenericIdType::BIAS_20_BYTES >; +using RsGxsGroupId = t_RsGenericIdType<_RsIdSize::CERT_SIGN , false, RsGenericIdType::GXS_GROUP >; +using RsGxsId = t_RsGenericIdType<_RsIdSize::CERT_SIGN , false, RsGenericIdType::GXS_ID >; +using RsGxsCircleId = t_RsGenericIdType<_RsIdSize::CERT_SIGN , false, RsGenericIdType::GXS_CIRCLE >; +using RsGxsTunnelId = t_RsGenericIdType<_RsIdSize::SSL_ID , false, RsGenericIdType::GXS_TUNNEL >; +using DistantChatPeerId = t_RsGenericIdType<_RsIdSize::SSL_ID , false, RsGenericIdType::DISTANT_CHAT >; +using RsNodeGroupId = t_RsGenericIdType<_RsIdSize::CERT_SIGN , false, RsGenericIdType::NODE_GROUP >; +/// @deprecated Ugly name kept temporarly only because it is used in many places +using PGPFingerprintType RS_DEPRECATED_FOR(RsPpgFingerprint) = RsPgpFingerprint; diff --git a/libretroshare/src/retroshare/rsinit.h b/libretroshare/src/retroshare/rsinit.h index 2e8009b3c..5c2064030 100644 --- a/libretroshare/src/retroshare/rsinit.h +++ b/libretroshare/src/retroshare/rsinit.h @@ -1,9 +1,8 @@ /******************************************************************************* * libretroshare/src/retroshare: rsinit.h * * * - * libretroshare: retroshare core library * - * * - * Copyright 2004-2006 by Robert Fernie * + * Copyright (C) 2004-2014 Robert Fernie * + * Copyright (C) 2016-2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -19,8 +18,10 @@ * along with this program. If not, see . * * * *******************************************************************************/ -#ifndef RETROSHARE_INIT_INTERFACE_H -#define RETROSHARE_INIT_INTERFACE_H +#pragma once + +/// RetroShare initialization and login API + // Initialize ok, result >= 0 #define RS_INIT_OK 0 // Initialize ok @@ -29,13 +30,7 @@ #define RS_INIT_AUTH_FAILED -1 // AuthGPG::InitAuth failed #define RS_INIT_BASE_DIR_ERROR -2 // AuthGPG::InitAuth failed #define RS_INIT_NO_KEYRING -3 // Keyring is empty. Need to import it. - - -/**** - * #define RS_USE_PGPSSL 1 - ***/ - -#define RS_USE_PGPSSL 1 +#define RS_INIT_NO_EXECUTABLE -4 // executable path hasn't been set in config options #include #include @@ -43,7 +38,7 @@ #include #include -struct RsLoginHelper; +class RsLoginHelper; /** * Pointer to global instance of RsLoginHelper @@ -51,6 +46,38 @@ struct RsLoginHelper; */ extern RsLoginHelper* rsLoginHelper; +/** + * @brief The RsInitConfig struct + * This class contains common configuration options, that executables using libretroshare may want to + * set using e.g. commandline options. To be passed to RsInit::InitRetroShare(). + */ +struct RsConfigOptions +{ + RsConfigOptions(); + + // required + + std::string main_executable_path;/* this should be set to argv[0] */ + + // Optional. Only change if needed. + + bool autoLogin; /* try auto-login */ + + bool udpListenerOnly; /* only listen to udp */ + std::string forcedInetAddress; /* inet address to use.*/ + uint16_t forcedPort; /* port to listen to */ + + bool outStderr; + int debugLevel; + std::string logfname; /* output filename for log */ + + std::string opModeStr; /* operating mode. Acceptable values: "Full", "NoTurtle", "Gaming", "Minimal" */ + std::string optBaseDir; /* base directory where to find profiles, etc */ + + uint16_t jsonApiPort; /* port to use fo Json API */ + std::string jsonApiBindAddress; /* bind address for Json API */ +}; + /*! * Initialisation Class (not publicly disclosed to RsIFace) @@ -63,7 +90,7 @@ public: OK, /// Everything go as expected, no error occurred ERR_ALREADY_RUNNING, /// Another istance is running already ERR_CANT_ACQUIRE_LOCK, /// Another istance is already running? - ERR_UNKOWN /// Unkown error, maybe password is wrong? + ERR_UNKNOWN /// Unkown error, maybe password is wrong? }; /* reorganised RsInit system */ @@ -83,12 +110,19 @@ public: * invalid argument passed and vice versa * @return RS_INIT_... */ - static int InitRetroShare(int argc, char **argv, bool strictCheck=true); + static int InitRetroShare(const RsConfigOptions&); static bool isPortable(); static bool isWindowsXP(); static bool collectEntropy(uint32_t bytes) ; + /*! + * \brief lockFilePath + * \return + * full path for the lock file. Can be used to warn the user about a non deleted lock that would prevent to start. + */ + static std::string lockFilePath(); + /* * Setup Hidden Location; */ @@ -276,8 +310,10 @@ extern RsAccounts* rsAccounts; * This helper class have been implemented because there was not reasonable way * to login in the API that could be exposed via JSON API */ -struct RsLoginHelper +class RsLoginHelper { +public: + RsLoginHelper() {} /** * @brief Normal way to attempt login * @jsonapi{development,manualwrapper} @@ -301,7 +337,7 @@ struct RsLoginHelper RsPeerId mLocationId; RsPgpId mPgpId; std::string mLocationName; - std::string mPpgName; + std::string mPgpName; /// @see RsSerializable::serial_process void serial_process( RsGenericSerializer::SerializeJob j, @@ -340,5 +376,3 @@ struct RsLoginHelper */ bool isLoggedIn(); }; - -#endif diff --git a/libretroshare/src/retroshare/rsmsgs.h b/libretroshare/src/retroshare/rsmsgs.h index f1e42c4c3..f56312659 100644 --- a/libretroshare/src/retroshare/rsmsgs.h +++ b/libretroshare/src/retroshare/rsmsgs.h @@ -470,6 +470,8 @@ public: std::map gxs_ids ; // list of non direct friend who participate. Used to display only. rstime_t last_activity ; // last recorded activity. Useful for removing dead lobbies. + virtual void clear() { gxs_ids.clear(); lobby_id = 0; lobby_name.clear(); lobby_topic.clear(); participating_friends.clear(); } + // RsSerializable interface public: void serial_process(RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext &ctx) { @@ -485,14 +487,13 @@ public: } }; -std::ostream &operator<<(std::ostream &out, const Rs::Msgs::MessageInfo &info); class RsMsgs; /** * @brief Pointer to retroshare's message service * @jsonapi{development} */ -extern RsMsgs *rsMsgs; +extern RsMsgs* rsMsgs; class RsMsgs { @@ -521,6 +522,7 @@ public: * @return true on success */ virtual bool getMessage(const std::string &msgId, Rs::Msgs::MessageInfo &msg) = 0; + /** * @brief getMessageCount * @jsonapi{development} @@ -832,6 +834,13 @@ virtual void getOwnAvatarData(unsigned char *& data,int& size) = 0 ; */ virtual void unsubscribeChatLobby(const ChatLobbyId &lobby_id) = 0; + /** + * @brief sendLobbyStatusPeerLeaving notify friend nodes that we're leaving a subscribed lobby + * @jsonapi{development} + * @param[in] lobby_id lobby to leave + */ + virtual void sendLobbyStatusPeerLeaving(const ChatLobbyId& lobby_id) = 0; + /** * @brief setIdentityForChatLobby set the chat identit * @jsonapi{development} diff --git a/libretroshare/src/retroshare/rsnotify.h b/libretroshare/src/retroshare/rsnotify.h index d2077e7f0..894d1f30d 100644 --- a/libretroshare/src/retroshare/rsnotify.h +++ b/libretroshare/src/retroshare/rsnotify.h @@ -19,8 +19,7 @@ * along with this program. If not, see . * * * *******************************************************************************/ -#ifndef RS_NOTIFY_GUI_INTERFACE_H -#define RS_NOTIFY_GUI_INTERFACE_H +#pragma once #include #include @@ -30,6 +29,7 @@ #include "rsturtle.h" #include "rsgxsifacetypes.h" +#include "util/rsdeprecate.h" class ChatId; class ChatMessage; @@ -148,7 +148,7 @@ const uint32_t NOTIFY_HASHTYPE_FINISH = 2; /* Finish */ const uint32_t NOTIFY_HASHTYPE_HASH_FILE = 3; /* Hashing file */ const uint32_t NOTIFY_HASHTYPE_SAVE_FILE_INDEX = 4; /* Hashing file */ -class RsFeedItem +class RS_DEPRECATED RsFeedItem { public: RsFeedItem(uint32_t type, const std::string& id1, const std::string& id2, const std::string& id3, const std::string& id4, uint32_t result1) @@ -181,9 +181,9 @@ class RsFeedItem // This mechanism can be used in plugins, new services, etc. // -class NotifyClient; +class RS_DEPRECATED NotifyClient; -class RsNotify +class RS_DEPRECATED_FOR(RsEvents) RsNotify { public: /* registration of notifies clients */ @@ -206,12 +206,14 @@ class RsNotify virtual bool setDisableAskPassword (const bool /*bValue*/) { return false ; } }; -class NotifyClient +class RS_DEPRECATED NotifyClient { public: NotifyClient() {} virtual ~NotifyClient() {} + virtual void notifyPeerConnected (const std::string& /* peer_id */) {} + virtual void notifyPeerDisconnected (const std::string& /* peer_id */) {} virtual void notifyListPreChange (int /* list */, int /* type */) {} virtual void notifyListChange (int /* list */, int /* type */) {} virtual void notifyErrorMsg (int /* list */, int /* sev */, std::string /* msg */) {} @@ -223,8 +225,6 @@ public: virtual void notifyCustomState (const std::string& /* peer_id */, const std::string& /* status_string */) {} virtual void notifyHashingInfo (uint32_t /* type */, const std::string& /* fileinfo */) {} virtual void notifyTurtleSearchResult (const RsPeerId& /* pid */, uint32_t /* search_id */, const std::list& /* files */) {} -#warning MISSING CODE HERE - // virtual void notifyTurtleSearchResult (uint32_t /* search_id */, const std::list& /* groups */) {} virtual void notifyPeerHasNewAvatar (std::string /* peer_id */) {} virtual void notifyOwnAvatarChanged () {} virtual void notifyOwnStatusMessageChanged () {} @@ -245,4 +245,3 @@ public: virtual bool askForPassword (const std::string& /* title */, const std::string& /* key_details */, bool /* prev_is_bad */, std::string& /* password */,bool& /* cancelled */ ) { return false ;} virtual bool askForPluginConfirmation (const std::string& /* plugin_filename */, const std::string& /* plugin_file_hash */,bool /* first_time */) { return false ;} }; -#endif diff --git a/libretroshare/src/retroshare/rspeers.h b/libretroshare/src/retroshare/rspeers.h index 2d1263043..b4b0a64d0 100644 --- a/libretroshare/src/retroshare/rspeers.h +++ b/libretroshare/src/retroshare/rspeers.h @@ -31,6 +31,7 @@ #include "util/rsurl.h" #include "util/rsdeprecate.h" #include "util/rstime.h" +#include "retroshare/rsevents.h" class RsPeers; @@ -73,7 +74,7 @@ const uint32_t RS_HIDDEN_TYPE_I2P = 0x0004; /* mask to match all valid hidden types */ const uint32_t RS_HIDDEN_TYPE_MASK = RS_HIDDEN_TYPE_I2P | RS_HIDDEN_TYPE_TOR; -/* Visibility */ +/* Visibility parameter for discovery */ const uint32_t RS_VS_DISC_OFF = 0x0000; const uint32_t RS_VS_DISC_MINIMAL = 0x0001; const uint32_t RS_VS_DISC_FULL = 0x0002; @@ -129,6 +130,8 @@ const uint32_t CERTIFICATE_PARSING_ERROR_CHECKSUM_ERROR = 0x16 ; const uint32_t CERTIFICATE_PARSING_ERROR_UNKNOWN_SECTION_PTAG = 0x17 ; const uint32_t CERTIFICATE_PARSING_ERROR_MISSING_CHECKSUM = 0x18 ; const uint32_t CERTIFICATE_PARSING_ERROR_WRONG_VERSION = 0x19 ; +const uint32_t CERTIFICATE_PARSING_ERROR_MISSING_PGP_FINGERPRINT = 0x1a ; +const uint32_t CERTIFICATE_PARSING_ERROR_MISSING_LOCATION_ID = 0x1b ; const uint32_t PGP_KEYRING_REMOVAL_ERROR_NO_ERROR = 0x20 ; const uint32_t PGP_KEYRING_REMOVAL_ERROR_CANT_REMOVE_SECRET_KEYS = 0x21 ; @@ -139,40 +142,40 @@ const uint32_t PGP_KEYRING_REMOVAL_ERROR_DATA_INCONSISTENCY = 0x24 ; /* LinkType Flags */ // CONNECTION -const uint32_t RS_NET_CONN_TRANS_MASK = 0x0000ffff; -const uint32_t RS_NET_CONN_TRANS_TCP_MASK = 0x0000000f; -const uint32_t RS_NET_CONN_TRANS_TCP_UNKNOWN = 0x00000001; -const uint32_t RS_NET_CONN_TRANS_TCP_LOCAL = 0x00000002; -const uint32_t RS_NET_CONN_TRANS_TCP_EXTERNAL = 0x00000004; +const uint32_t RS_NET_CONN_TRANS_MASK = 0x0000ffff; +const uint32_t RS_NET_CONN_TRANS_TCP_MASK = 0x0000000f; +const uint32_t RS_NET_CONN_TRANS_TCP_UNKNOWN = 0x00000001; +const uint32_t RS_NET_CONN_TRANS_TCP_LOCAL = 0x00000002; +const uint32_t RS_NET_CONN_TRANS_TCP_EXTERNAL = 0x00000004; -const uint32_t RS_NET_CONN_TRANS_UDP_MASK = 0x000000f0; -const uint32_t RS_NET_CONN_TRANS_UDP_UNKNOWN = 0x00000010; -const uint32_t RS_NET_CONN_TRANS_UDP_DIRECT = 0x00000020; -const uint32_t RS_NET_CONN_TRANS_UDP_PROXY = 0x00000040; -const uint32_t RS_NET_CONN_TRANS_UDP_RELAY = 0x00000080; +const uint32_t RS_NET_CONN_TRANS_UDP_MASK = 0x000000f0; +const uint32_t RS_NET_CONN_TRANS_UDP_UNKNOWN = 0x00000010; +const uint32_t RS_NET_CONN_TRANS_UDP_DIRECT = 0x00000020; +const uint32_t RS_NET_CONN_TRANS_UDP_PROXY = 0x00000040; +const uint32_t RS_NET_CONN_TRANS_UDP_RELAY = 0x00000080; -const uint32_t RS_NET_CONN_TRANS_OTHER_MASK = 0x00000f00; +const uint32_t RS_NET_CONN_TRANS_OTHER_MASK = 0x00000f00; -const uint32_t RS_NET_CONN_TRANS_UNKNOWN = 0x00001000; +const uint32_t RS_NET_CONN_TRANS_UNKNOWN = 0x00001000; -const uint32_t RS_NET_CONN_SPEED_MASK = 0x000f0000; -const uint32_t RS_NET_CONN_SPEED_UNKNOWN = 0x00000000; -const uint32_t RS_NET_CONN_SPEED_TRICKLE = 0x00010000; -const uint32_t RS_NET_CONN_SPEED_LOW = 0x00020000; -const uint32_t RS_NET_CONN_SPEED_NORMAL = 0x00040000; -const uint32_t RS_NET_CONN_SPEED_HIGH = 0x00080000; +const uint32_t RS_NET_CONN_SPEED_MASK = 0x000f0000; +const uint32_t RS_NET_CONN_SPEED_UNKNOWN = 0x00000000; +const uint32_t RS_NET_CONN_SPEED_TRICKLE = 0x00010000; +const uint32_t RS_NET_CONN_SPEED_LOW = 0x00020000; +const uint32_t RS_NET_CONN_SPEED_NORMAL = 0x00040000; +const uint32_t RS_NET_CONN_SPEED_HIGH = 0x00080000; -const uint32_t RS_NET_CONN_QUALITY_MASK = 0x00f00000; -const uint32_t RS_NET_CONN_QUALITY_UNKNOWN = 0x00000000; +const uint32_t RS_NET_CONN_QUALITY_MASK = 0x00f00000; +const uint32_t RS_NET_CONN_QUALITY_UNKNOWN = 0x00000000; // THIS INFO MUST BE SUPPLIED BY PEERMGR.... -const uint32_t RS_NET_CONN_TYPE_MASK = 0x0f000000; -const uint32_t RS_NET_CONN_TYPE_UNKNOWN = 0x00000000; -const uint32_t RS_NET_CONN_TYPE_ACQUAINTANCE = 0x01000000; -const uint32_t RS_NET_CONN_TYPE_FRIEND = 0x02000000; -const uint32_t RS_NET_CONN_TYPE_SERVER = 0x04000000; -const uint32_t RS_NET_CONN_TYPE_CLIENT = 0x08000000; +const uint32_t RS_NET_CONN_TYPE_MASK = 0x0f000000; +const uint32_t RS_NET_CONN_TYPE_UNKNOWN = 0x00000000; +const uint32_t RS_NET_CONN_TYPE_ACQUAINTANCE = 0x01000000; +const uint32_t RS_NET_CONN_TYPE_FRIEND = 0x02000000; +const uint32_t RS_NET_CONN_TYPE_SERVER = 0x04000000; +const uint32_t RS_NET_CONN_TYPE_CLIENT = 0x08000000; // working state of proxy @@ -204,6 +207,14 @@ std::string RsPeerNetModeString(uint32_t netModel); std::string RsPeerLastConnectString(uint32_t lastConnect); +/* We should definitely split this into 2 sub-structures: + * PGP info (or profile info) with all info related to PGP keys + * peer info: all network related information + * + * Plus top level information: + * isOnlyPgpDetail (this could be obsolete if the methods to query about PGP info is a different function) + * peer Id + */ struct RsPeerDetails : RsSerializable { RsPeerDetails(); @@ -220,13 +231,14 @@ struct RsPeerDetails : RsSerializable RsPgpId issuer; - PGPFingerprintType fpr; /* pgp fingerprint */ + RsPgpFingerprint fpr; /* pgp fingerprint */ std::string authcode; // TODO: 2015/12/31 (cyril) what is this used for ????? std::list gpgSigners; uint32_t trustLvl; uint32_t validLvl; + bool skip_pgp_signature_validation; bool ownsign; /* we have signed the remote peer GPG key */ bool hasSignedMe; /* the remote peer has signed my GPG key */ @@ -358,7 +370,22 @@ struct RsGroupInfo : RsSerializable } }; -std::ostream &operator<<(std::ostream &out, const RsPeerDetails &detail); +/** Event emitted when a peer change state */ +struct RsPeerStateChangedEvent : RsEvent +{ + /// @param[in] sslId is of the peer which changed state + RsPeerStateChangedEvent(RsPeerId sslId); + + /// Storage fot the id of the peer that changed state + RsPeerId mSslId; + + void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx) override + { + RsEvent::serial_process(j, ctx); + RS_SERIAL_PROCESS(mSslId); + } +}; /** The Main Interface Class - for information about your Peers * A peer is another RS instance, means associated with an SSL certificate @@ -436,6 +463,16 @@ public: */ virtual bool isPgpFriend(const RsPgpId& pgpId) = 0; + /** + * @brief Check if given peer is a trusted SSL node pending PGP approval + * Peers added through short invite remain in this state as long as their + * PGP key is not received and verified/approved by the user. + * @jsonapi{development} + * @param[in] sslId id of the peer to check + * @return true if the node is trusted, false otherwise + */ + virtual bool isSslOnlyFriend(const RsPeerId& sslId) = 0; + virtual std::string getPeerName(const RsPeerId &ssl_id) = 0; virtual std::string getGPGName(const RsPgpId& gpg_id) = 0; @@ -462,12 +499,17 @@ public: virtual RsPgpId getGPGId(const RsPeerId& sslId) = 0; virtual bool isKeySupported(const RsPgpId& gpg_ids) = 0; virtual bool getGPGAcceptedList(std::list &gpg_ids) = 0; - virtual bool getGPGSignedList(std::list &gpg_ids) = 0;//friends that we accpet to connect with but we don't want to sign their gpg key - virtual bool getGPGValidList(std::list &gpg_ids) = 0; - virtual bool getGPGAllList(std::list &gpg_ids) = 0; + virtual bool getGPGSignedList(std::list &gpg_ids) = 0;// keys signed by our own PGP key. + virtual bool getGPGValidList(std::list &gpg_ids) = 0;// all PGP keys without filtering + virtual bool getGPGAllList(std::list &gpg_ids) = 0;// all PGP keys as well virtual bool getAssociatedSSLIds(const RsPgpId& gpg_id, std::list& ids) = 0; virtual bool gpgSignData(const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen, std::string reason = "") = 0; + virtual RsPgpId pgpIdFromFingerprint(const RsPgpFingerprint& fpr) = 0; + + // Note: the two methods below could be unified. The fact that one of them can take an optional RsPeerDetails struct as parameter + // seems quite inconsistent. + /** * @brief Add trusted node * @jsonapi{development} @@ -476,8 +518,26 @@ public: * @param[in] flags service permissions flag * @return false if error occurred, true otherwise */ - virtual bool addFriend( const RsPeerId &sslId, const RsPgpId& gpgId, - ServicePermissionFlags flags = RS_NODE_PERM_DEFAULT ) = 0; + virtual bool addFriend( + const RsPeerId& sslId, const RsPgpId& gpgId, + ServicePermissionFlags flags = RS_NODE_PERM_DEFAULT ) = 0; + + /** + * @brief Add SSL-only trusted node + * When adding an SSL-only node, it is authorized to connect. Every time a + * connection is established the user is notified about the need to verify + * the PGP fingerprint, until she does, at that point the node become a full + * SSL+PGP friend. + * @jsonapi{development} + * @param[in] sslId SSL id of the node to add + * @param[in] pgpId PGP id of the node to add. Will be used for validation when the key is available. + * @param[in] details Optional extra details known about the node to add + * @return false if error occurred, true otherwise + */ + virtual bool addSslOnlyFriend( + const RsPeerId& sslId, + const RsPgpId& pgpId, + const RsPeerDetails& details = RsPeerDetails() ) = 0; /** * @brief Revoke connection trust from to node @@ -599,6 +659,38 @@ public: bool includeSignatures = false, bool includeExtraLocators = true ) = 0; + /** + * @brief Get RetroShare short invite of the given peer + * @jsonapi{development} + * @param[out] invite storage for the generated invite + * @param[in] sslId Id of the peer of which we want to generate an invite, + * a null id (all 0) is passed, an invite for own node is returned. + * @param[in] formatRadix true to get in base64 format false to get URL. + * @param[in] bareBones true to get smallest invite, which miss also + * the information necessary to attempt an outgoing connection, but still + * enough to accept an incoming one. + * @param[in] baseUrl URL into which to sneak in the RetroShare invite + * radix, this is primarly useful to trick other applications into making + * the invite clickable, or to disguise the RetroShare invite into a + * "normal" looking web link. Used only if formatRadix is false. + * @return false if error occurred, true otherwise + */ + virtual bool getShortInvite( + std::string& invite, const RsPeerId& sslId = RsPeerId(), + bool formatRadix = false, bool bareBones = false, + const std::string& baseUrl = "https://retroshare.me/" ) = 0; + + /** + * @brief Parse the give short invite to extract contained information + * @jsonapi{development} + * @param[in] invite string containing the short invite to parse + * @param[out] details storage for the extracted information, consider it + * @param[out] err_code storage for the error code + * @return false if error occurred, true otherwise + */ + virtual bool parseShortInvite( + const std::string& invite, RsPeerDetails& details,uint32_t& err_code ) = 0; + /** * @brief Add trusted node from invite * @jsonapi{development} @@ -642,8 +734,13 @@ public: const std::string& cert, RsPeerDetails& certDetails, uint32_t& errorCode ) = 0; + virtual bool loadPgpKeyFromBinaryData( const unsigned char *bin_key_data, + uint32_t bin_key_len, + RsPgpId& gpg_id, + std::string& error_string )=0; + // Certificate utils - virtual bool cleanCertificate(const std::string &certstr, std::string &cleanCert,int& error_code) = 0; + virtual bool cleanCertificate(const std::string &certstr, std::string &cleanCert,bool& is_short_format,uint32_t& error_code) = 0; virtual bool saveCertificateToFile(const RsPeerId& id, const std::string &fname) = 0; virtual std::string saveCertificateToString(const RsPeerId &id) = 0; @@ -751,6 +848,3 @@ public: RS_DEPRECATED_FOR(isPgpFriend) virtual bool isGPGAccepted(const RsPgpId &gpg_id_is_friend) = 0; }; - - - diff --git a/libretroshare/src/retroshare/rsplugin.h b/libretroshare/src/retroshare/rsplugin.h index 49ad98f0b..1efa70399 100644 --- a/libretroshare/src/retroshare/rsplugin.h +++ b/libretroshare/src/retroshare/rsplugin.h @@ -30,6 +30,7 @@ #include "retroshare/rsfiles.h" #include "retroshare/rsversion.h" #include "util/rsinitedptr.h" +#include "retroshare/rsdisc.h" class RsPluginHandler ; extern RsPluginHandler *rsPlugins ; @@ -40,7 +41,6 @@ class RsReputations ; class RsTurtle ; class RsGxsTunnelService ; class RsDht ; -class RsDisc ; class RsMsgs ; class RsGxsForums; class RsGxsChannels; diff --git a/libretroshare/src/retroshare/rsservicecontrol.h b/libretroshare/src/retroshare/rsservicecontrol.h index f588e9719..4946f5247 100644 --- a/libretroshare/src/retroshare/rsservicecontrol.h +++ b/libretroshare/src/retroshare/rsservicecontrol.h @@ -88,10 +88,6 @@ struct RsPeerServiceInfo : RsSerializable } }; -std::ostream &operator<<(std::ostream &out, const RsPeerServiceInfo &info); -std::ostream &operator<<(std::ostream &out, const RsServiceInfo &info); - - struct RsServicePermissions : RsSerializable { RsServicePermissions(); diff --git a/libretroshare/src/retroshare/rstokenservice.h b/libretroshare/src/retroshare/rstokenservice.h index 515579a07..bea291e25 100644 --- a/libretroshare/src/retroshare/rstokenservice.h +++ b/libretroshare/src/retroshare/rstokenservice.h @@ -107,9 +107,6 @@ struct RsTokReqOptions rstime_t mAfter; }; -std::ostream &operator<<(std::ostream &out, const RsGroupMetaData &meta); -std::ostream &operator<<(std::ostream &out, const RsMsgMetaData &meta); - /*! * A proxy class for requesting generic service data for GXS * This seperates the request mechanism from the actual retrieval of data diff --git a/libretroshare/src/retroshare/rstypes.h b/libretroshare/src/retroshare/rstypes.h index cec7034ba..52495b664 100644 --- a/libretroshare/src/retroshare/rstypes.h +++ b/libretroshare/src/retroshare/rstypes.h @@ -37,15 +37,6 @@ #define USE_NEW_CHUNK_CHECKING_CODE -// This adds a level of indirection to types, so we can easily change them if needed -// -//typedef std::string RsCertId; // unused -//typedef std::string RsChanId; -//typedef std::string RsMsgId; -//typedef std::string RsAuthId; - -typedef SSLIdType RsPeerId ; -typedef PGPIdType RsPgpId ; typedef Sha1CheckSum RsFileHash ; typedef Sha1CheckSum RsMessageId ; @@ -257,8 +248,6 @@ struct FileInfo : RsSerializable } }; -std::ostream &operator<<(std::ostream &out, const FileInfo& info); - /** * Pointers in this class have no real meaning as pointers, they are used as * indexes, internally by retroshare. @@ -379,8 +368,6 @@ struct DirDetails : RsSerializable } }; -std::ostream &operator<<(std::ostream &out, const DirDetails& details); - class FileDetail { public: diff --git a/libretroshare/src/upnp/UPnPBase.cpp b/libretroshare/src/rs_upnp/UPnPBase.cpp similarity index 84% rename from libretroshare/src/upnp/UPnPBase.cpp rename to libretroshare/src/rs_upnp/UPnPBase.cpp index 75421b2f7..2f79dc7b1 100644 --- a/libretroshare/src/upnp/UPnPBase.cpp +++ b/libretroshare/src/rs_upnp/UPnPBase.cpp @@ -6,6 +6,7 @@ * Copyright (c) 2004-2009 Marcelo Roberto Jimenez ( phoenix@amule.org ) * * Copyright (c) 2006-2009 aMule Team ( admin@amule.org / http://www.amule.org)* * Copyright (c) 2009-2010 Retroshare Team * + * Copyright (C) 2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -25,12 +26,14 @@ #define UPNP_C #include "UPnPBase.h" + #include #include #include // for std::istringstream - #include // For transform() + #include "util/rsstring.h" +#include "rs_upnp/upnp18_retrocompat.h" #ifdef __GNUC__ #if __GNUC__ >= 4 @@ -115,7 +118,7 @@ std::string CUPnPLib::processUPnPErrorMessage( const std::string &message, int errorCode, const DOMString errorString, - IXML_Document *doc) const + const IXML_Document* doc) const { /* remove unused parameter warnings */ (void) message; @@ -159,7 +162,7 @@ std::string CUPnPLib::processUPnPErrorMessage( void CUPnPLib::ProcessActionResponse( - IXML_Document *RespDoc, + const IXML_Document* RespDoc, const std::string &actionName) const { /* remove unused parameter warnings */ @@ -196,11 +199,11 @@ void CUPnPLib::ProcessActionResponse( * \brief Returns the root node of a given document. */ IXML_Element *CUPnPLib::Element_GetRootElement( - IXML_Document *doc) const + const IXML_Document* doc) const { - IXML_Element *root = REINTERPRET_CAST(IXML_Element *)( + IXML_Element* root = REINTERPRET_CAST(IXML_Element *)( ixmlNode_getFirstChild( - REINTERPRET_CAST(IXML_Node *)(doc))); + REINTERPRET_CAST(IXML_Node *)(const_cast(doc)))); return root; } @@ -344,12 +347,12 @@ const std::string CUPnPLib::Element_GetAttributeByTag( CUPnPError::CUPnPError( - const CUPnPLib &upnpLib, - IXML_Document *errorDoc) -: -m_root (upnpLib.Element_GetRootElement(errorDoc)), -m_ErrorCode (upnpLib.Element_GetChildValueByTag(m_root, "errorCode")), -m_ErrorDescription(upnpLib.Element_GetChildValueByTag(m_root, "errorDescription")) + const CUPnPLib &upnpLib, + const IXML_Document *errorDoc) + : + m_root (upnpLib.Element_GetRootElement(errorDoc)), + m_ErrorCode (upnpLib.Element_GetChildValueByTag(m_root, "errorCode")), + m_ErrorDescription(upnpLib.Element_GetChildValueByTag(m_root, "errorDescription")) { } @@ -485,7 +488,8 @@ m_timeout(1801), m_SCPD(NULL) { int errcode; - + m_SID[0]=0; + std::vector vscpdURL(URLBase.length() + m_SCPDURL.length() + 1); char *scpdURL = &vscpdURL[0]; errcode = UpnpResolveURL( @@ -748,7 +752,7 @@ bool CUPnPService::Execute( GetAbsControlURL().c_str(), GetServiceType().c_str(), NULL, ActionDoc, - static_cast(&CUPnPControlPoint::Callback), + reinterpret_cast(&CUPnPControlPoint::Callback), NULL); return true; } @@ -948,7 +952,7 @@ m_WanService(NULL) #endif ret = UpnpRegisterClient( - static_cast(&CUPnPControlPoint::Callback), + reinterpret_cast(&CUPnPControlPoint::Callback), &m_UPnPClientHandle, &m_UPnPClientHandle); if (ret != UPNP_E_SUCCESS) { @@ -1295,185 +1299,149 @@ bool CUPnPControlPoint::PrivateGetExternalIpAdress() // This function is static -int CUPnPControlPoint::Callback(Upnp_EventType EventType, void *Event, void * /*Cookie*/) +int CUPnPControlPoint::Callback( + Upnp_EventType EventType, const void* Event, void * /*Cookie*/ ) { + if(!Event) return 0; + std::string msg; std::string msg2; - // Somehow, this is unreliable. UPNP_DISCOVERY_ADVERTISEMENT_ALIVE events - // happen with a wrong cookie and... boom! - // CUPnPControlPoint *upnpCP = static_cast(Cookie); - CUPnPControlPoint *upnpCP = CUPnPControlPoint::s_CtrlPoint ; - if (upnpCP == NULL) - return 0; - - //fprintf(stderr, "Callback: %d, Cookie: %p\n", EventType, Cookie); - switch (EventType) { - case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE: -#ifdef UPNP_DEBUG - std::cerr << "CUPnPControlPoint::Callback() UPNP_DISCOVERY_ADVERTISEMENT_ALIVE: "; -#endif - goto upnpDiscovery; - case UPNP_DISCOVERY_SEARCH_RESULT: { -#ifdef UPNP_DEBUG - std::cerr << "UPNP_DISCOVERY_SEARCH_RESULT: "; -#endif - // UPnP Discovery -upnpDiscovery: - struct Upnp_Discovery *d_event = (struct Upnp_Discovery *)Event; - IXML_Document *doc = NULL; - int ret; - if (d_event->ErrCode != UPNP_E_SUCCESS) { -#ifdef UPNP_DEBUG - std::cerr << upnpCP->m_upnpLib.GetUPnPErrorMessage(d_event->ErrCode) << "." << std::endl; -#endif - } -#ifdef UPNP_DEBUG - std::cerr << "CUPnPControlPoint::Callback() URetrieving device description from " << - d_event->Location << "." << std::endl; -#endif + CUPnPControlPoint* upnpCP = CUPnPControlPoint::s_CtrlPoint; + if (!upnpCP) return 0; + + switch (EventType) + { + case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE: /*fallthrough*/ + case UPNP_DISCOVERY_SEARCH_RESULT: + { + const UpnpDiscovery* d_event = static_cast(Event); + // Get the XML tree device description in doc - ret = UpnpDownloadXmlDoc(d_event->Location, &doc); - if (ret != UPNP_E_SUCCESS) { + IXML_Document* doc = nullptr; + UpnpDownloadXmlDoc(UpnpDiscovery_get_Location_cstr(d_event), &doc); + if (!doc) break; + + IXML_Element* root = upnpCP->m_upnpLib.Element_GetRootElement(doc); + + // Extract the URLBase + const std::string urlBase = upnpCP->m_upnpLib. + Element_GetChildValueByTag(root, "URLBase"); + // Get the root device + IXML_Element *rootDevice = upnpCP->m_upnpLib. + Element_GetFirstChildByTag(root, "device"); + // Extract the deviceType + std::string devType(upnpCP->m_upnpLib. + Element_GetChildValueByTag(rootDevice, "deviceType")); + #ifdef UPNP_DEBUG - std::cerr << "CUPnPControlPoint::Callback() UError retrieving device description from " << - d_event->Location << ": " << - upnpCP->m_upnpLib.GetUPnPErrorMessage(ret) << "."; + std::cerr << "CUPnPControlPoint::Callback() EventType==UPNP_DISCOVERY_SEARCH_RESULT" << std::endl + << "urlBase:" << urlBase << std::endl + << "devType:" << devType << std::endl; #endif - } else { -#ifdef UPNP_DEBUG - std::cerr << "CUPnPControlPoint::Callback() URetrieving device description from " << - d_event->Location << "." << std::endl; + + // Only add device if it is an InternetGatewayDevice + if (stdStringIsEqualCI(devType, upnpCP->m_upnpLib.UPNP_DEVICE_IGW)) + { + // This condition can be used to auto-detect + // the UPnP device we are interested in. + // Obs.: Don't block the entry here on this + // condition! There may be more than one device, + // and the first that enters may not be the one + // we are interested in! + upnpCP->SetIGWDeviceDetected(true); + // Log it if not UPNP_DISCOVERY_ADVERTISEMENT_ALIVE, + // we don't want to spam our logs. + //if (EventType != UPNP_DISCOVERY_ADVERTISEMENT_ALIVE) { + // Add the root device to our list + upnpCP->AddRootDevice( + rootDevice, urlBase, + UpnpDiscovery_get_Location_cstr(d_event), + UpnpDiscovery_get_Expires(d_event) ); + +#if (UPNP_VERSION > 10624) && (UPNP_VERSION < 10800) + upnpCP->m_WaitForSearchTimeoutMutex.unlock(); #endif } - if (doc) { - // Get the root node - IXML_Element *root = - upnpCP->m_upnpLib.Element_GetRootElement(doc); - // Extract the URLBase - const std::string urlBase = upnpCP->m_upnpLib. - Element_GetChildValueByTag(root, "URLBase"); - // Get the root device - IXML_Element *rootDevice = upnpCP->m_upnpLib. - Element_GetFirstChildByTag(root, "device"); - // Extract the deviceType - std::string devType(upnpCP->m_upnpLib. - Element_GetChildValueByTag(rootDevice, "deviceType")); - // Only add device if it is an InternetGatewayDevice - if (stdStringIsEqualCI(devType, upnpCP->m_upnpLib.UPNP_DEVICE_IGW)) { - // This condition can be used to auto-detect - // the UPnP device we are interested in. - // Obs.: Don't block the entry here on this - // condition! There may be more than one device, - // and the first that enters may not be the one - // we are interested in! - upnpCP->SetIGWDeviceDetected(true); - // Log it if not UPNP_DISCOVERY_ADVERTISEMENT_ALIVE, - // we don't want to spam our logs. - //if (EventType != UPNP_DISCOVERY_ADVERTISEMENT_ALIVE) { -#ifdef UPNP_DEBUG - std::cerr << "Internet Gateway Device Detected." << std::endl; -#endif - //} -#ifdef UPNP_DEBUG - std::cerr << "CUPnPControlPoint::Callback() UGetting root device desc." << std::endl; -#endif - // Add the root device to our list - upnpCP->AddRootDevice(rootDevice, urlBase, - d_event->Location, d_event->Expires); -#ifdef UPNP_DEBUG - std::cerr << "CUPnPControlPoint::Callback() UFinishing getting root device desc." << std::endl; -#endif - } - // Free the XML doc tree - ixmlDocument_free(doc); - } + + // Free the XML doc tree + ixmlDocument_free(doc); break; } - case UPNP_DISCOVERY_SEARCH_TIMEOUT: { - //fprintf(stderr, "Callback: UPNP_DISCOVERY_SEARCH_TIMEOUT\n"); - // Search timeout -#ifdef UPNP_DEBUG - std::cerr << "CUPnPControlPoint::Callback() UUPNP_DISCOVERY_SEARCH_TIMEOUT : unlocking mutex." << std::endl; + case UPNP_DISCOVERY_SEARCH_TIMEOUT: + { +#if (UPNP_VERSION > 10624) && (UPNP_VERSION < 10800) + std::cerr << "********************************************************************************" << std::endl + << "*** THIS SHOULD NOT HAPPEN !!! TELL IT TO DEVS ***" << std::endl + << "*** UPnPBase.cpp CUPnPControlPoint::Callback() UPNP_DISCOVERY_SEARCH_TIMEOUT ***" << std::endl + << "********************************************************************************" << std::endl; #endif // Unlock the search timeout mutex upnpCP->m_WaitForSearchTimeoutMutex.unlock(); - break; } - case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE: { - //fprintf(stderr, "Callback: UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE\n"); - // UPnP Device Removed - struct Upnp_Discovery *dab_event = (struct Upnp_Discovery *)Event; - if (dab_event->ErrCode != UPNP_E_SUCCESS) { -#ifdef UPNP_DEBUG - std::cerr << "CUPnPControlPoint::Callback() Uerror(UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE): " << - upnpCP->m_upnpLib.GetUPnPErrorMessage(dab_event->ErrCode) << - "." << std::endl; -#endif - } - std::string devType = dab_event->DeviceType; + case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE: // UPnP Device Removed + { + const UpnpDiscovery* dab_event = static_cast(Event); + if(!dab_event) break; + + std::string devType = UpnpDiscovery_get_DeviceType_cstr(dab_event); + // Check for an InternetGatewayDevice and removes it from the list std::transform(devType.begin(), devType.end(), devType.begin(), tolower); - if (stdStringIsEqualCI(devType, upnpCP->m_upnpLib.UPNP_DEVICE_IGW)) { - upnpCP->RemoveRootDevice(dab_event->DeviceId); - } + if (stdStringIsEqualCI(devType, upnpCP->m_upnpLib.UPNP_DEVICE_IGW)) + upnpCP->RemoveRootDevice( + UpnpDiscovery_get_DeviceID_cstr(dab_event) ); break; } - case UPNP_EVENT_RECEIVED: { -#ifdef UPNP_DEBUG - fprintf(stderr, "Callback: UPNP_EVENT_RECEIVED\n"); -#endif + case UPNP_EVENT_RECEIVED: + { // Event reveived - struct Upnp_Event *e_event = (struct Upnp_Event *)Event; - const std::string Sid = e_event->Sid; + const UpnpEvent* e_event = static_cast(Event); + + const std::string Sid = UpnpEvent_get_SID_cstr(e_event); + // Parses the event - upnpCP->OnEventReceived(Sid, e_event->EventKey, e_event->ChangedVariables); + upnpCP->OnEventReceived( Sid, + UpnpEvent_get_EventKey(e_event), + UpnpEvent_get_ChangedVariables(e_event) ); break; } case UPNP_EVENT_SUBSCRIBE_COMPLETE: - //fprintf(stderr, "Callback: UPNP_EVENT_SUBSCRIBE_COMPLETE\n"); msg += "error(UPNP_EVENT_SUBSCRIBE_COMPLETE): "; goto upnpEventRenewalComplete; case UPNP_EVENT_UNSUBSCRIBE_COMPLETE: - //fprintf(stderr, "Callback: UPNP_EVENT_UNSUBSCRIBE_COMPLETE\n"); msg += "error(UPNP_EVENT_UNSUBSCRIBE_COMPLETE): "; goto upnpEventRenewalComplete; - case UPNP_EVENT_RENEWAL_COMPLETE: { - //fprintf(stderr, "Callback: UPNP_EVENT_RENEWAL_COMPLETE\n"); + case UPNP_EVENT_RENEWAL_COMPLETE: + { msg += "error(UPNP_EVENT_RENEWAL_COMPLETE): "; upnpEventRenewalComplete: - struct Upnp_Event_Subscribe *es_event = - (struct Upnp_Event_Subscribe *)Event; - if (es_event->ErrCode != UPNP_E_SUCCESS) { + const UpnpEventSubscribe* es_event = + static_cast(Event); + + if (UpnpEventSubscribe_get_ErrCode(es_event) != UPNP_E_SUCCESS) + { msg += "Error in Event Subscribe Callback"; upnpCP->m_upnpLib.processUPnPErrorMessage( - msg, es_event->ErrCode, NULL, NULL); - } else { -#if 0 - TvCtrlPointHandleSubscribeUpdate( - es_event->PublisherUrl, - es_event->Sid, - es_event->TimeOut ); -#endif + msg, UpnpEventSubscribe_get_ErrCode(es_event), + nullptr, nullptr ); } break; } - case UPNP_EVENT_AUTORENEWAL_FAILED: - //fprintf(stderr, "Callback: UPNP_EVENT_AUTORENEWAL_FAILED\n"); msg += "CUPnPControlPoint::Callback() error(UPNP_EVENT_AUTORENEWAL_FAILED): "; msg2 += "UPNP_EVENT_AUTORENEWAL_FAILED: "; goto upnpEventSubscriptionExpired; case UPNP_EVENT_SUBSCRIPTION_EXPIRED: { - //fprintf(stderr, "Callback: UPNP_EVENT_SUBSCRIPTION_EXPIRED\n"); msg += "CUPnPControlPoint::Callback() error(UPNP_EVENT_SUBSCRIPTION_EXPIRED): "; msg2 += "UPNP_EVENT_SUBSCRIPTION_EXPIRED: "; upnpEventSubscriptionExpired: - struct Upnp_Event_Subscribe *es_event = - (struct Upnp_Event_Subscribe *)Event; + const UpnpEventSubscribe* es_event = + static_cast(Event); + Upnp_SID newSID; int TimeOut = 1801; int ret = UpnpSubscribe( @@ -1481,20 +1449,25 @@ upnpEventSubscriptionExpired: #ifdef PATCHED_LIBUPNP UpnpString_get_String(es_event->PublisherUrl), #else - es_event->PublisherUrl, + UpnpEventSubscribe_get_PublisherUrl_cstr(es_event), #endif &TimeOut, newSID); - if (ret != UPNP_E_SUCCESS) { + if (ret != UPNP_E_SUCCESS) + { msg += "Error Subscribing to EventURL"; upnpCP->m_upnpLib.processUPnPErrorMessage( - msg, es_event->ErrCode, NULL, NULL); - } else { + msg, UpnpEventSubscribe_get_ErrCode(es_event), + nullptr, nullptr ); + } + else + { ServiceMap::iterator it = #ifdef PATCHED_LIBUPNP upnpCP->m_ServiceMap.find(UpnpString_get_String(es_event->PublisherUrl)); #else - upnpCP->m_ServiceMap.find(es_event->PublisherUrl); + upnpCP->m_ServiceMap.find( + UpnpEventSubscribe_get_PublisherUrl_cstr(es_event) ); #endif if (it != upnpCP->m_ServiceMap.end()) { CUPnPService &service = *(it->second); @@ -1504,7 +1477,7 @@ upnpEventSubscriptionExpired: #ifdef PATCHED_LIBUPNP UpnpString_get_String(es_event->PublisherUrl) << #else - es_event->PublisherUrl << + UpnpEventSubscribe_get_PublisherUrl_cstr(es_event) << #endif "' with SID == '" << newSID << "'." << std::endl; @@ -1512,7 +1485,9 @@ upnpEventSubscriptionExpired: // service is the same. But here we only have one // service, so... upnpCP->RefreshPortMappings(); - } else { + } + else + { #ifdef UPNP_DEBUG std::cerr << "CUPnPControlPoint::Callback() Error: did not find service " << newSID << " in the service map." << std::endl; @@ -1521,41 +1496,49 @@ upnpEventSubscriptionExpired: } break; } - case UPNP_CONTROL_ACTION_COMPLETE: { - //fprintf(stderr, "Callback: UPNP_CONTROL_ACTION_COMPLETE\n"); + case UPNP_CONTROL_ACTION_COMPLETE: + { // This is here if we choose to do this asynchronously - struct Upnp_Action_Complete *a_event = - (struct Upnp_Action_Complete *)Event; - if (a_event->ErrCode != UPNP_E_SUCCESS) { + const UpnpActionComplete* a_event = + static_cast(Event); + if(UpnpActionComplete_get_ErrCode(a_event) != UPNP_E_SUCCESS) + { upnpCP->m_upnpLib.processUPnPErrorMessage( - "UpnpSendActionAsync", - a_event->ErrCode, NULL, - a_event->ActionResult); - } else { + "UpnpSendActionAsync", + UpnpActionComplete_get_ErrCode(a_event), nullptr, + UpnpActionComplete_get_ActionResult(a_event) ); + } + else + { // Check the response document upnpCP->m_upnpLib.ProcessActionResponse( - a_event->ActionResult, - ""); + UpnpActionComplete_get_ActionResult(a_event), + "" ); } /* No need for any processing here, just print out results. * Service state table updates are handled by events. */ break; } - case UPNP_CONTROL_GET_VAR_COMPLETE: { -#ifdef UPNP_DEBUG - fprintf(stderr, "CUPnPControlPoint::Callback() Callback: UPNP_CONTROL_GET_VAR_COMPLETE\n"); -#endif + case UPNP_CONTROL_GET_VAR_COMPLETE: + { msg += "CUPnPControlPoint::Callback() error(UPNP_CONTROL_GET_VAR_COMPLETE): "; - struct Upnp_State_Var_Complete *sv_event = - (struct Upnp_State_Var_Complete *)Event; - if (sv_event->ErrCode != UPNP_E_SUCCESS) { + const UpnpStateVarComplete* sv_event = + static_cast(Event); + if (UpnpStateVarComplete_get_ErrCode(sv_event) != UPNP_E_SUCCESS) + { msg += "m_UpnpGetServiceVarStatusAsync"; upnpCP->m_upnpLib.processUPnPErrorMessage( - msg, sv_event->ErrCode, NULL, NULL); - } else { - //add the variable to the wanservice property map - (upnpCP->m_WanService->propertyMap)[std::string(sv_event->StateVarName)] = std::string(sv_event->CurrentVal); + msg, UpnpStateVarComplete_get_ErrCode(sv_event), + nullptr, nullptr ); + } + else + { + //add the variable to the wanservice property map + (upnpCP->m_WanService->propertyMap)[ + std::string( + UpnpStateVarComplete_get_StateVarName_cstr(sv_event) ) ] + = std::string(UpnpStateVarComplete_get_CurrentVal_cstr(sv_event)); } break; } @@ -1603,7 +1586,7 @@ eventSubscriptionRequest: void CUPnPControlPoint::OnEventReceived( const std::string &Sid, int EventKey, - IXML_Document *ChangedVariablesDoc) + const IXML_Document* ChangedVariablesDoc) { /* remove unused parameter warnings */ (void) EventKey; diff --git a/libretroshare/src/upnp/UPnPBase.h b/libretroshare/src/rs_upnp/UPnPBase.h similarity index 96% rename from libretroshare/src/upnp/UPnPBase.h rename to libretroshare/src/rs_upnp/UPnPBase.h index 59057c7e1..e1c41fb83 100644 --- a/libretroshare/src/upnp/UPnPBase.h +++ b/libretroshare/src/rs_upnp/UPnPBase.h @@ -43,6 +43,7 @@ extern std::string stdEmptyString; #endif // UPNP_C +//#define UPNP_DEBUG 1 /** * Case insensitive std::string comparison @@ -113,20 +114,18 @@ public: // Convenience function to avoid repetitive processing of error // messages - std::string processUPnPErrorMessage( - const std::string &messsage, - int code, - const DOMString errorString, - IXML_Document *doc) const; + std::string processUPnPErrorMessage(const std::string &messsage, + int code, + const DOMString errorString, + const IXML_Document* doc) const; // Processing response to actions void ProcessActionResponse( - IXML_Document *RespDoc, - const std::string &actionName) const; + const IXML_Document* RespDoc, + const std::string& actionName ) const; // IXML_Element - IXML_Element *Element_GetRootElement( - IXML_Document *doc) const; + IXML_Element* Element_GetRootElement(const IXML_Document* doc) const; IXML_Element *Element_GetFirstChild( IXML_Element *parent) const; IXML_Element *Element_GetNextSibling( @@ -257,7 +256,7 @@ private: public: CUPnPError( const CUPnPLib &upnpLib, - IXML_Document *errorDoc); + const IXML_Document *errorDoc); ~CUPnPError() {} const std::string &getErrorCode() const { return m_ErrorCode; } @@ -597,13 +596,10 @@ public: // Callback function static int Callback( - Upnp_EventType EventType, - void* Event, - void* Cookie); - void OnEventReceived( - const std::string &Sid, - int EventKey, - IXML_Document *ChangedVariables); + Upnp_EventType EventType, const void* Event, void* Cookie ); + void OnEventReceived(const std::string &Sid, + int EventKey, + const IXML_Document* ChangedVariables); private: void AddRootDevice( diff --git a/libretroshare/src/rs_upnp/upnp18_retrocompat.h b/libretroshare/src/rs_upnp/upnp18_retrocompat.h new file mode 100644 index 000000000..26fb0a524 --- /dev/null +++ b/libretroshare/src/rs_upnp/upnp18_retrocompat.h @@ -0,0 +1,82 @@ +/******************************************************************************* + * libupnp-1.8.x -> libupnp-1.6.x retrocompatibility header * + * * + * Copyright (C) 2019 Gioacchino Mazzurco * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ +#pragma once + +#include + + +#if UPNP_VERSION < 10800 + +using UpnpDiscovery = Upnp_Discovery; +using UpnpEvent = Upnp_Event; +using UpnpEventSubscribe = Upnp_Event_Subscribe; +using UpnpActionComplete = Upnp_Action_Complete; +using UpnpStateVarComplete = Upnp_State_Var_Complete; + +static inline const char* UpnpStateVarComplete_get_CurrentVal_cstr( + const UpnpStateVarComplete* esvc) noexcept { return esvc->CurrentVal; } + +#endif // UPNP_VERSION < 10800 + +#if UPNP_VERSION < 10624 + +static inline int UpnpDiscovery_get_Expires(const Upnp_Discovery* disc) noexcept +{ return disc->Expires; } + +static inline const char* UpnpDiscovery_get_DeviceID_cstr( + const Upnp_Discovery* disc ) noexcept +{ return disc->DeviceId; } + +static inline const char* UpnpDiscovery_get_DeviceType_cstr( + const Upnp_Discovery* disc ) noexcept +{ return disc->DeviceType; } + +static inline const char* UpnpDiscovery_get_Location_cstr( + const Upnp_Discovery* disc ) noexcept +{ return disc->Location; } + +static inline const char* UpnpEvent_get_SID_cstr(const UpnpEvent* ev) noexcept +{ return ev->Sid; } + +static inline int UpnpEvent_get_EventKey(const UpnpEvent* ev) noexcept +{ return ev->EventKey; } + +static inline const IXML_Document* UpnpEvent_get_ChangedVariables( + const UpnpEvent* ev) noexcept { return ev->ChangedVariables; } + +static inline int UpnpEventSubscribe_get_ErrCode(const UpnpEventSubscribe* evs) +noexcept { return evs->ErrCode; } + +static inline const char* UpnpEventSubscribe_get_PublisherUrl_cstr( + const UpnpEventSubscribe* evs ) noexcept { return evs->PublisherUrl; } + +static inline int UpnpActionComplete_get_ErrCode(const UpnpActionComplete* evc) +noexcept { return evc->ErrCode; } + +static inline const IXML_Document* UpnpActionComplete_get_ActionResult( + const UpnpActionComplete* evc ) noexcept { return evc->ActionResult; } + +static inline int UpnpStateVarComplete_get_ErrCode( + const UpnpStateVarComplete* esvc) noexcept { return esvc->ErrCode; } + +static inline const char* UpnpStateVarComplete_get_StateVarName_cstr( + const UpnpStateVarComplete* esvc) noexcept { return esvc->StateVarName; } + +#endif // UPNP_VERSION < 10624 diff --git a/libretroshare/src/upnp/upnphandler_linux.cc b/libretroshare/src/rs_upnp/upnphandler_linux.cc similarity index 99% rename from libretroshare/src/upnp/upnphandler_linux.cc rename to libretroshare/src/rs_upnp/upnphandler_linux.cc index 943e62d7a..df9bc66e9 100644 --- a/libretroshare/src/upnp/upnphandler_linux.cc +++ b/libretroshare/src/rs_upnp/upnphandler_linux.cc @@ -28,7 +28,7 @@ extern "C" { #endif /* This stuff is actually C */ -#include "upnp/upnphandler_linux.h" +#include "rs_upnp/upnphandler_linux.h" #include "util/rsnet.h" diff --git a/libretroshare/src/upnp/upnphandler_linux.h b/libretroshare/src/rs_upnp/upnphandler_linux.h similarity index 99% rename from libretroshare/src/upnp/upnphandler_linux.h rename to libretroshare/src/rs_upnp/upnphandler_linux.h index 13aa83335..dc5207a7c 100644 --- a/libretroshare/src/upnp/upnphandler_linux.h +++ b/libretroshare/src/rs_upnp/upnphandler_linux.h @@ -31,7 +31,7 @@ #include "util/rsthreads.h" #include -#include "upnp/UPnPBase.h" +#include "rs_upnp/UPnPBase.h" #define RS_UPNP_S_UNINITIALISED 0 #define RS_UPNP_S_UNAVAILABLE 1 diff --git a/libretroshare/src/upnp/upnphandler_miniupnp.cc b/libretroshare/src/rs_upnp/upnphandler_miniupnp.cc similarity index 99% rename from libretroshare/src/upnp/upnphandler_miniupnp.cc rename to libretroshare/src/rs_upnp/upnphandler_miniupnp.cc index 316e23748..97b972cf1 100644 --- a/libretroshare/src/upnp/upnphandler_miniupnp.cc +++ b/libretroshare/src/rs_upnp/upnphandler_miniupnp.cc @@ -31,8 +31,8 @@ extern "C" { #endif /* This stuff is actually C */ -#include "upnp/upnphandler_miniupnp.h" -#include "upnp/upnputil.h" +#include "rs_upnp/upnphandler_miniupnp.h" +#include "rs_upnp/upnputil.h" class uPnPConfigData { diff --git a/libretroshare/src/upnp/upnphandler_miniupnp.h b/libretroshare/src/rs_upnp/upnphandler_miniupnp.h similarity index 100% rename from libretroshare/src/upnp/upnphandler_miniupnp.h rename to libretroshare/src/rs_upnp/upnphandler_miniupnp.h diff --git a/libretroshare/src/upnp/upnptest.cc b/libretroshare/src/rs_upnp/upnptest.cc similarity index 98% rename from libretroshare/src/upnp/upnptest.cc rename to libretroshare/src/rs_upnp/upnptest.cc index c6f55e787..80d98e4e5 100644 --- a/libretroshare/src/upnp/upnptest.cc +++ b/libretroshare/src/rs_upnp/upnptest.cc @@ -1,6 +1,6 @@ //this file use miniupnp -#include "upnp/upnphandler.h" +#include int main(int argc, char **argv) diff --git a/libretroshare/src/upnp/upnputil.c b/libretroshare/src/rs_upnp/upnputil.c similarity index 99% rename from libretroshare/src/upnp/upnputil.c rename to libretroshare/src/rs_upnp/upnputil.c index 0ee6bec42..28b0c4de6 100644 --- a/libretroshare/src/upnp/upnputil.c +++ b/libretroshare/src/rs_upnp/upnputil.c @@ -23,7 +23,7 @@ //this file uses miniupnp //From https://github.com/miniupnp/miniupnp/blob/master/miniupnpc/upnpc.c -#include "upnp/upnputil.h" +#include "rs_upnp/upnputil.h" #if MINIUPNPC_API_VERSION >= -4//1.0 2008/02/18 #include "util/rstime.h" diff --git a/libretroshare/src/upnp/upnputil.h b/libretroshare/src/rs_upnp/upnputil.h similarity index 100% rename from libretroshare/src/upnp/upnputil.h rename to libretroshare/src/rs_upnp/upnputil.h diff --git a/libretroshare/src/rsitems/rsgxsiditems.h b/libretroshare/src/rsitems/rsgxsiditems.h index bfcca0946..440247403 100644 --- a/libretroshare/src/rsitems/rsgxsiditems.h +++ b/libretroshare/src/rsitems/rsgxsiditems.h @@ -67,11 +67,9 @@ public: // Avatar RsTlvImage mImage ; }; -class RsGxsIdLocalInfoItem : public RsGxsIdItem + +struct RsGxsIdLocalInfoItem : public RsGxsIdItem { - -public: - RsGxsIdLocalInfoItem(): RsGxsIdItem(RS_PKT_SUBTYPE_GXSID_LOCAL_INFO_ITEM) {} virtual ~RsGxsIdLocalInfoItem() {} @@ -83,39 +81,6 @@ public: std::set mContacts ; }; -#if 0 -class RsGxsIdOpinionItem : public RsGxsMsgItem -{ -public: - - RsGxsIdOpinionItem(): RsGxsMsgItem(RS_SERVICE_GXS_TYPE_GXSID, - RS_PKT_SUBTYPE_GXSID_OPINION_ITEM) {return; } - virtual ~RsGxsIdOpinionItem() { return;} - void clear(); - virtual bool serialise(void *data,uint32_t& size) = 0 ; - virtual uint32_t serial_size() = 0 ; - - std::ostream &print(std::ostream &out, uint16_t indent = 0); - RsGxsIdOpinion opinion; -}; - -class RsGxsIdCommentItem : public RsGxsMsgItem -{ -public: - - RsGxsIdCommentItem(): RsGxsMsgItem(RS_SERVICE_GXS_TYPE_GXSID, - RS_PKT_SUBTYPE_GXSID_COMMENT_ITEM) { return; } - virtual ~RsGxsIdCommentItem() { return; } - void clear(); - virtual bool serialise(void *data,uint32_t& size) = 0 ; - virtual uint32_t serial_size() = 0 ; - - std::ostream &print(std::ostream &out, uint16_t indent = 0); - RsGxsIdComment comment; - -}; -#endif - class RsGxsIdSerialiser : public RsServiceSerializer { public: diff --git a/libretroshare/src/rsitems/rsgxsitems.cc b/libretroshare/src/rsitems/rsgxsitems.cc index d8f96555b..22c379f9e 100644 --- a/libretroshare/src/rsitems/rsgxsitems.cc +++ b/libretroshare/src/rsitems/rsgxsitems.cc @@ -61,31 +61,10 @@ this->mCircleType = rGxsMeta.mCircleType; this->mInternalCircle = rGxsMeta.mInternalCircle; this->mOriginator = rGxsMeta.mOriginator; - this->mAuthenFlags = rGxsMeta.mAuthenFlags; - // std::cout << "rGxsMeta.mParentGrpId= " <mParentGrpId= " <mParentGrpId<<"\n"; + this->mAuthenFlags = rGxsMeta.mAuthenFlags; this->mParentGrpId = rGxsMeta.mParentGrpId; } -std::ostream &operator<<(std::ostream &out, const RsGroupMetaData &meta) -{ - out << "[ GroupId: " << meta.mGroupId << " Name: " << meta.mGroupName << " ]"; - return out; -} - -std::ostream &operator<<(std::ostream &out, const RsMsgMetaData &meta) -{ - out << "[ GroupId: " << meta.mGroupId << " MsgId: " << meta.mMsgId; - out << " Name: " << meta.mMsgName; - out << " OrigMsgId: " << meta.mOrigMsgId; - out << " ThreadId: " << meta.mThreadId; - out << " ParentId: " << meta.mParentId; - out << " AuthorId: " << meta.mAuthorId; - out << " Name: " << meta.mMsgName << " ]"; - return out; -} - template<> uint32_t RsTypeSerializer::serial_size(const TurtleGxsInfo& i) { uint32_t s = 0 ; diff --git a/libretroshare/src/rsitems/rsgxsitems.h b/libretroshare/src/rsitems/rsgxsitems.h index efc11afbb..9b47d5d6d 100644 --- a/libretroshare/src/rsitems/rsgxsitems.h +++ b/libretroshare/src/rsitems/rsgxsitems.h @@ -28,9 +28,6 @@ #include "util/rstime.h" #include "retroshare/rsgxsifacetypes.h" -std::ostream &operator<<(std::ostream &out, const RsGroupMetaData &meta); -std::ostream &operator<<(std::ostream &out, const RsMsgMetaData &meta); - class RsGxsGrpItem : public RsItem { diff --git a/libretroshare/src/rsitems/rsserviceids.h b/libretroshare/src/rsitems/rsserviceids.h index 69ec0962c..3f690cf45 100644 --- a/libretroshare/src/rsitems/rsserviceids.h +++ b/libretroshare/src/rsitems/rsserviceids.h @@ -3,7 +3,8 @@ * * * libretroshare: retroshare core library * * * - * Copyright 2007-2008 by Robert Fernie * + * Copyright (C) 2007-2008 Robert Fernie * + * Copyright (C) 2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -19,144 +20,129 @@ * along with this program. If not, see . * * * *******************************************************************************/ -#ifndef RS_SERVICE_IDS_H -#define RS_SERVICE_IDS_H +#pragma once -#include +#include "util/rsdeprecate.h" -/* Single place for Cache/Service Ids (uint16_t) - * to 64K of them.... - * - * Some Services/Caches are only msgs or caches... - * but they need to be combined so that the messages/caches - * can easily be aligned. - * - */ +#include -/* These are Cache Only */ -const uint16_t RS_SERVICE_TYPE_FILE_INDEX = 0x0001; +enum class RsServiceType : uint16_t +{ + NONE = 0, /// To detect non-initialized reads + GOSSIP_DISCOVERY = 0x0011, + CHAT = 0x0012, + MSG = 0x0013, + TURTLE = 0x0014, + TUNNEL = 0x0015, + HEARTBEAT = 0x0016, + FILE_TRANSFER = 0x0017, + GROUTER = 0x0018, + FILE_DATABASE = 0x0019, + SERVICEINFO = 0x0020, + BANDWIDTH_CONTROL = 0x0021, + MAIL = 0x0022, + DIRECT_MAIL = 0x0023, + DISTANT_MAIL = 0x0024, + GWEMAIL_MAIL = 0x0025, + SERVICE_CONTROL = 0x0026, + DISTANT_CHAT = 0x0027, + GXS_TUNNEL = 0x0028, + BANLIST = 0x0101, + STATUS = 0x0102, + NXS = 0x0200, + GXSID = 0x0211, + PHOTO = 0x0212, + WIKI = 0x0213, + WIRE = 0x0214, + FORUMS = 0x0215, + POSTED = 0x0216, + CHANNELS = 0x0217, + GXSCIRCLE = 0x0218, + /// not gxs, but used with identities. + REPUTATION = 0x0219, + GXS_RECOGN = 0x0220, + GXS_TRANS = 0x0230, + JSONAPI = 0x0240, + FORUMS_CONFIG = 0x0315, + CHANNELS_CONFIG = 0x0317, + RTT = 0x1011, /// Round Trip Time -/* These are Services only */ -const uint16_t RS_SERVICE_TYPE_DISC = 0x0011; -const uint16_t RS_SERVICE_TYPE_CHAT = 0x0012; -const uint16_t RS_SERVICE_TYPE_MSG = 0x0013; -const uint16_t RS_SERVICE_TYPE_TURTLE = 0x0014; -const uint16_t RS_SERVICE_TYPE_TUNNEL = 0x0015; -const uint16_t RS_SERVICE_TYPE_HEARTBEAT = 0x0016; -const uint16_t RS_SERVICE_TYPE_FILE_TRANSFER = 0x0017; -const uint16_t RS_SERVICE_TYPE_GROUTER = 0x0018; -const uint16_t RS_SERVICE_TYPE_FILE_DATABASE = 0x0019; -const uint16_t RS_SERVICE_TYPE_SERVICEINFO = 0x0020; -/* Bandwidth Control */ -const uint16_t RS_SERVICE_TYPE_BWCTRL = 0x0021; -// New Mail Service (replace old Msg Service) -const uint16_t RS_SERVICE_TYPE_MAIL = 0x0022; -const uint16_t RS_SERVICE_TYPE_DIRECT_MAIL = 0x0023; -const uint16_t RS_SERVICE_TYPE_DISTANT_MAIL = 0x0024; -const uint16_t RS_SERVICE_TYPE_GWEMAIL_MAIL = 0x0025; -const uint16_t RS_SERVICE_TYPE_SERVICE_CONTROL= 0x0026; -const uint16_t RS_SERVICE_TYPE_DISTANT_CHAT = 0x0027; -const uint16_t RS_SERVICE_TYPE_GXS_TUNNEL = 0x0028; + /***************** IDS ALLOCATED FOR PLUGINS ******************/ + // 2000+ + PLUGIN_ARADO_ID = 0x2001, + PLUGIN_QCHESS_ID = 0x2002, + PLUGIN_FEEDREADER = 0x2003, -// Non essential services. -const uint16_t RS_SERVICE_TYPE_BANLIST = 0x0101; -const uint16_t RS_SERVICE_TYPE_STATUS = 0x0102; + /// Reserved for packet slicing probes. + PACKET_SLICING_PROBE = 0xAABB, - /* New Cache Services */ -/* Rs Network Exchange Service */ -const uint16_t RS_SERVICE_TYPE_NXS = 0x0200; + // Nabu's experimental services. + PLUGIN_FIDO_GW = 0xF1D0, + PLUGIN_ZERORESERVE = 0xBEEF +}; -const uint16_t RS_SERVICE_GXS_TYPE_GXSID = 0x0211; -const uint16_t RS_SERVICE_GXS_TYPE_PHOTO = 0x0212; -const uint16_t RS_SERVICE_GXS_TYPE_WIKI = 0x0213; -const uint16_t RS_SERVICE_GXS_TYPE_WIRE = 0x0214; -const uint16_t RS_SERVICE_GXS_TYPE_FORUMS = 0x0215; -const uint16_t RS_SERVICE_GXS_TYPE_POSTED = 0x0216; -const uint16_t RS_SERVICE_GXS_TYPE_CHANNELS = 0x0217; -const uint16_t RS_SERVICE_GXS_TYPE_GXSCIRCLE = 0x0218; -// not gxs, but used with identities. -const uint16_t RS_SERVICE_GXS_TYPE_REPUTATION = 0x0219; -const uint16_t RS_SERVICE_TYPE_GXS_RECOGN = 0x0220; -const uint16_t RS_SERVICE_TYPE_GXS_TRANS = 0x0230; -const uint16_t RS_SERVICE_TYPE_JSONAPI = 0x0240; -const uint16_t RS_SERVICE_GXS_TYPE_FORUMS_CONFIG = 0x0315; -const uint16_t RS_SERVICE_GXS_TYPE_CHANNELS_CONFIG = 0x0317; + +// TODO: Port all services types to RsServiceType + +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_FILE_INDEX = 0x0001; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_DISC = 0x0011; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_CHAT = 0x0012; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_MSG = 0x0013; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_TURTLE = 0x0014; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_TUNNEL = 0x0015; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_HEARTBEAT = 0x0016; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_FILE_TRANSFER = 0x0017; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_GROUTER = 0x0018; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_FILE_DATABASE = 0x0019; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_SERVICEINFO = 0x0020; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_BWCTRL = 0x0021; /// Bandwidth Control +/// New Mail Service (replace old Msg Service) +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_MAIL = 0x0022; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_DIRECT_MAIL = 0x0023; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_DISTANT_MAIL = 0x0024; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_GWEMAIL_MAIL = 0x0025; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_SERVICE_CONTROL= 0x0026; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_DISTANT_CHAT = 0x0027; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_GXS_TUNNEL = 0x0028; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_BANLIST = 0x0101; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_STATUS = 0x0102; +/// Rs Network Exchange Service +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_NXS = 0x0200; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_GXS_TYPE_GXSID = 0x0211; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_GXS_TYPE_PHOTO = 0x0212; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_GXS_TYPE_WIKI = 0x0213; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_GXS_TYPE_WIRE = 0x0214; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_GXS_TYPE_FORUMS = 0x0215; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_GXS_TYPE_POSTED = 0x0216; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_GXS_TYPE_CHANNELS = 0x0217; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_GXS_TYPE_GXSCIRCLE = 0x0218; +/// not gxs, but used with identities. +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_GXS_TYPE_REPUTATION = 0x0219; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_GXS_RECOGN = 0x0220; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_GXS_TRANS = 0x0230; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_JSONAPI = 0x0240; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_GXS_TYPE_FORUMS_CONFIG = 0x0315; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_GXS_TYPE_CHANNELS_CONFIG = 0x0317; // Experimental Services. /* DSDV Testing at the moment - Service Only */ -const uint16_t RS_SERVICE_TYPE_DSDV = 0x1010; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_DSDV = 0x1010; /* Latency RTT Measurements */ -const uint16_t RS_SERVICE_TYPE_RTT = 0x1011; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_RTT = 0x1011; /***************** IDS ALLOCATED FOR PLUGINS ******************/ // 2000+ -const uint16_t RS_SERVICE_TYPE_PLUGIN_ARADO_ID = 0x2001; -const uint16_t RS_SERVICE_TYPE_PLUGIN_QCHESS_ID = 0x2002; -const uint16_t RS_SERVICE_TYPE_PLUGIN_FEEDREADER = 0x2003; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_PLUGIN_ARADO_ID = 0x2001; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_PLUGIN_QCHESS_ID = 0x2002; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_PLUGIN_FEEDREADER = 0x2003; // Reserved for packet slicing probes. -const uint16_t RS_SERVICE_TYPE_PACKET_SLICING_PROBE = 0xAABB; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_PACKET_SLICING_PROBE = 0xAABB; // Nabu's services. -const uint16_t RS_SERVICE_TYPE_PLUGIN_FIDO_GW = 0xF1D0; -const uint16_t RS_SERVICE_TYPE_PLUGIN_ZERORESERVE = 0xBEEF; - -/****************** BELOW ARE ONLY THEORETICAL (CAN BE CHANGED) *****/ -/* - * If you are planning on making a new service.... - * Test it out with an ID in the range from 0xf000 - 0xffff - * And Change the ID everytime you make significant changes to the - * data structures... - * - * eg. - * const uint16_t RS_SERVICE_TYPE_DISTRIB_O1 = 0xf110; // First Revision. - * const uint16_t RS_SERVICE_TYPE_DISTRIB_O2 = 0xf111; // Second Revision. - * const uint16_t RS_SERVICE_TYPE_DISTRIB = 0xf112; // Final Revision. - * - * This minimises the chances of your new serialisers messing with - * other existing, older, or proposed services. - * - * ONLY MOVE your Id once the service has been finalised. - * - */ - - /*! for Qblog service (Cache Only) */ -//const uint16_t RS_SERVICE_TYPE_QBLOG = 0xf010; - -/* TEST VOIP - Service only */ -// NOT SURE WHATS HAPPENING WITH THIS ONE? -// SHOULD BE DEFINED IN PLUGIN SECTION! -//const uint16_t RS_SERVICE_TYPE_VOIP = 0xf011; - - /* Proxy - Service only */ -//const uint16_t RS_SERVICE_TYPE_PROXY = 0xf030; - -/* Games/External Apps - Service Only */ -//const uint16_t RS_SERVICE_TYPE_GAME_LAUNCHER = 0xf200; -//const uint16_t RS_SERVICE_TYPE_PORT = 0xf201; - -/* Example Games (NOT USED YET!) */ -/* Board Games */ -//const uint16_t RS_SERVICE_TYPE_GAME_QTCHESS = 0xf211; -//const uint16_t RS_SERVICE_TYPE_GAME_QGO = 0xf212; - -/* Card Games */ -//const uint16_t RS_SERVICE_TYPE_GAME_BIGTWO = 0xf213; -//const uint16_t RS_SERVICE_TYPE_GAME_POKER = 0xf214; - -/***************** IDS ALLOCATED FOR PLUGINS ******************/ - -//const uint16_t RS_SERVICE_TYPE_PLUGIN_ARADO_TEST_ID1 = 0xf401; -//const uint16_t RS_SERVICE_TYPE_PLUGIN_QCHESS_TEST_ID1 = 0xf402; - -// test -//const uint16_t RS_SERVICE_TYPE_PLUGIN_SIMPLE_FORUM = 0xf403; - - -#endif /* RS_SERVICE_IDS_H */ - - +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_PLUGIN_FIDO_GW = 0xF1D0; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_PLUGIN_ZERORESERVE = 0xBEEF; diff --git a/libretroshare/src/rsserver/p3face-info.cc b/libretroshare/src/rsserver/p3face-info.cc index 2b027e15b..18fdc40aa 100644 --- a/libretroshare/src/rsserver/p3face-info.cc +++ b/libretroshare/src/rsserver/p3face-info.cc @@ -26,18 +26,16 @@ #include #ifdef NO_SQLCIPHER -#include +# include #else -#include +# include #endif -#ifndef RS_ENABLE_ZCNATASSIST #ifdef RS_USE_LIBUPNP -#include "upnp/upnpconfig.h" -#else -#include "miniupnpc/miniupnpc.h" -#endif // RS_USE_LIBUPNP -#endif // RS_ENABLE_ZCNATASSIST +# include +#elif defined(RS_USE_LIBMINIUPNPC) +# include +#endif // def RS_USE_LIBUPNP std::string RsServer::getSQLCipherVersion() { @@ -88,12 +86,12 @@ void RsServer::getLibraries(std::list &libraries) #ifndef NO_SQLCIPHER libraries.push_back(RsLibraryInfo("SQLCipher", getSQLCipherVersion())); #endif -#ifndef RS_ENABLE_ZCNATASSIST + #ifdef RS_USE_LIBUPNP libraries.push_back(RsLibraryInfo("UPnP (libupnp)", UPNP_VERSION_STRING)); -#else +#elif defined(RS_USE_LIBMINIUPNPC) libraries.push_back(RsLibraryInfo("UPnP (MiniUPnP)", MINIUPNPC_VERSION)); -#endif // RS_USE_LIBUPNP -#endif // RS_ENABLE_ZCNATASSIST +#endif // def RS_USE_LIBUPNP + libraries.push_back(RsLibraryInfo("Zlib", ZLIB_VERSION)); } diff --git a/libretroshare/src/rsserver/p3face-server.cc b/libretroshare/src/rsserver/p3face-server.cc index 40bc1c452..d8114cc12 100644 --- a/libretroshare/src/rsserver/p3face-server.cc +++ b/libretroshare/src/rsserver/p3face-server.cc @@ -35,10 +35,11 @@ #include "pqi/p3linkmgr.h" #include "pqi/p3netmgr.h" -int rsserverzone = 101; - #include "util/rsdebug.h" +#include "retroshare/rsevents.h" +#include "services/rseventsservice.h" + /**** #define DEBUG_TICK 1 @@ -81,6 +82,12 @@ RsServer::RsServer() : coreMutex("RsServer"), mShutdownCallback([](int){}), coreReady(false) { + { + RsEventsService* tmpRsEvtPtr = new RsEventsService(); + rsEvents = tmpRsEvtPtr; + startServiceThread(tmpRsEvtPtr, "RsEventsService"); + } + // This is needed asap. // mNotify = new p3Notify() ; @@ -262,8 +269,6 @@ void RsServer::data_tick() std::string out; rs_sprintf(out, "RsServer::run() WARNING Excessively Long Cycle Time: %g secs => Please DEBUG", cycleTime); std::cerr << out << std::endl; - - rslog(RSL_ALERT, rsserverzone, out); } #endif } diff --git a/libretroshare/src/rsserver/p3msgs.cc b/libretroshare/src/rsserver/p3msgs.cc index 4c4e08116..3f987af49 100644 --- a/libretroshare/src/rsserver/p3msgs.cc +++ b/libretroshare/src/rsserver/p3msgs.cc @@ -453,6 +453,10 @@ void p3Msgs::invitePeerToLobby(const ChatLobbyId& lobby_id, const RsPeerId& peer { mChatSrv->invitePeerToLobby(lobby_id,peer_id) ; } +void p3Msgs::sendLobbyStatusPeerLeaving(const ChatLobbyId& lobby_id) +{ + mChatSrv->sendLobbyStatusPeerLeaving(lobby_id) ; +} void p3Msgs::unsubscribeChatLobby(const ChatLobbyId& lobby_id) { mChatSrv->unsubscribeChatLobby(lobby_id) ; diff --git a/libretroshare/src/rsserver/p3msgs.h b/libretroshare/src/rsserver/p3msgs.h index 7e092c51d..b567ab48f 100644 --- a/libretroshare/src/rsserver/p3msgs.h +++ b/libretroshare/src/rsserver/p3msgs.h @@ -147,6 +147,7 @@ class p3Msgs: public RsMsgs virtual void denyLobbyInvite(const ChatLobbyId& id) ; virtual void getPendingChatLobbyInvites(std::list& invites) ; virtual void unsubscribeChatLobby(const ChatLobbyId& lobby_id) ; + virtual void sendLobbyStatusPeerLeaving(const ChatLobbyId& lobby_id); virtual bool setIdentityForChatLobby(const ChatLobbyId& lobby_id,const RsGxsId&) ; virtual bool getIdentityForChatLobby(const ChatLobbyId&,RsGxsId& nick) ; virtual bool setDefaultIdentityForChatLobby(const RsGxsId&) ; diff --git a/libretroshare/src/rsserver/p3peers.cc b/libretroshare/src/rsserver/p3peers.cc index 02365d7bf..18d245663 100644 --- a/libretroshare/src/rsserver/p3peers.cc +++ b/libretroshare/src/rsserver/p3peers.cc @@ -41,15 +41,8 @@ #include #include -const std::string CERT_SSL_ID = "--SSLID--"; -const std::string CERT_LOCATION = "--LOCATION--"; -const std::string CERT_LOCAL_IP = "--LOCAL--"; -const std::string CERT_EXT_IP = "--EXT--"; -const std::string CERT_DYNDNS = "--DYNDNS--"; - //static const int MAX_TIME_KEEP_LOCATION_WITHOUT_CONTACT = 30*24*3600 ; // 30 days. - #include "pqi/authssl.h" @@ -137,11 +130,12 @@ bool p3Peers::hasExportMinimal() } /* Updates ... */ -bool p3Peers::FriendsChanged() +bool p3Peers::FriendsChanged(bool add) { #ifdef P3PEERS_DEBUG std::cerr << "p3Peers::FriendsChanged()" << std::endl; #endif + RsServer::notify()->notifyListChange(NOTIFY_LIST_FRIENDS, add? NOTIFY_TYPE_ADD : NOTIFY_TYPE_DEL); /* TODO */ return false; @@ -295,7 +289,18 @@ bool p3Peers::getPeerDetails(const RsPeerId& id, RsPeerDetails &d) /* get from gpg (first), to fill in the sign and trust details */ /* don't return now, we've got fill in the ssl and connection info */ - getGPGDetails(ps.gpg_id, d); + + if(!getGPGDetails(ps.gpg_id, d)) + { + if(!ps.skip_pgp_signature_validation) + return false; + + d.gpg_id = ps.gpg_id ; + d.skip_pgp_signature_validation = true; + } + else + d.skip_pgp_signature_validation = false; + d.isOnlyGPGdetail = false; //get the ssl details @@ -570,6 +575,22 @@ std::string p3Peers::getGPGName(const RsPgpId &gpg_id) bool p3Peers::isPgpFriend(const RsPgpId& pgpId) { return AuthGPG::getAuthGPG()->isGPGAccepted(pgpId); } +bool p3Peers::isSslOnlyFriend(const RsPeerId& sslId) +{ + bool has_ssl_only_flag = mPeerMgr->isSslOnlyFriend(sslId) ; + + if(has_ssl_only_flag) + { + if(isPgpFriend(getGPGId(sslId))) + { + RsErr() << __PRETTY_FUNCTION__ << ": Peer " << sslId << " has SSL-friend-only flag but his PGP id is in the list of friends. This is inconsistent (Bug in the code). Returning false for security reasons." << std::endl; + return false; + } + return true; + } + return false; +} + bool p3Peers::isGPGAccepted(const RsPgpId &gpg_id_is_friend) { return isPgpFriend(gpg_id_is_friend); } @@ -650,6 +671,11 @@ bool p3Peers::gpgSignData(const void *data, const uint32_t len, unsigned char return AuthGPG::getAuthGPG()->SignDataBin(data,len,sign,signlen, reason); } +RsPgpId p3Peers::pgpIdFromFingerprint(const RsPgpFingerprint& fpr) +{ + return PGPHandler::pgpIdFromFingerprint(fpr); +} + bool p3Peers::getGPGDetails(const RsPgpId &pgp_id, RsPeerDetails &d) { #ifdef P3PEERS_DEBUG @@ -687,9 +713,8 @@ RsPgpId p3Peers::getGPGId(const RsPeerId& sslid) return AuthGPG::getAuthGPG()->getGPGOwnId(); } peerState pcs; - if (mPeerMgr->getFriendNetStatus(sslid, pcs) || mPeerMgr->getOthersNetStatus(sslid, pcs)) { + if (mPeerMgr->getFriendNetStatus(sslid, pcs)) return pcs.gpg_id; - } return RsPgpId(); } @@ -741,7 +766,9 @@ bool p3Peers::addFriend(const RsPeerId &ssl_id, const RsPgpId &gpg_id,ServicePe return true; } - /* otherwise - we install as ssl_id..... + FriendsChanged(true); + + /* otherwise - we install as ssl_id..... * If we are adding an SSL certificate. we flag lastcontact as now. * This will cause the SSL certificate to be retained for 30 days... and give the person a chance to connect! * */ @@ -749,6 +776,17 @@ bool p3Peers::addFriend(const RsPeerId &ssl_id, const RsPgpId &gpg_id,ServicePe return mPeerMgr->addFriend(ssl_id, gpg_id, RS_NET_MODE_UDP, RS_VS_DISC_FULL, RS_VS_DHT_FULL, now, perm_flags); } +bool p3Peers::addSslOnlyFriend( const RsPeerId& sslId, const RsPgpId& pgp_id,const RsPeerDetails& details ) +{ + if( mPeerMgr->addSslOnlyFriend(sslId, pgp_id,details)) + { + FriendsChanged(true); + return true; + } + else + return false; +} + bool p3Peers::removeKeysFromPGPKeyring(const std::set& pgp_ids,std::string& backup_file,uint32_t& error_code) { return AuthGPG::getAuthGPG()->removeKeysFromPGPKeyring(pgp_ids,backup_file,error_code) ; @@ -1104,6 +1142,274 @@ bool p3Peers::GetPGPBase64StringAndCheckSum( const RsPgpId& gpg_id, return true ; } +enum class RsShortInviteFieldType : uint8_t +{ + SSL_ID = 0x00, + PEER_NAME = 0x01, + LOCATOR = 0x02, + PGP_FINGERPRINT = 0x03, + + /* The following will be deprecated, and ported to LOCATOR when generic + * trasport layer will be implemented */ + HIDDEN_LOCATOR = 0x90, + DNS_LOCATOR = 0x91, + EXT4_LOCATOR = 0x92 +}; + +static void addPacketHeader(RsShortInviteFieldType ptag, size_t size, unsigned char *& buf, uint32_t& offset, uint32_t& buf_size) +{ + // Check that the buffer has sufficient size. If not, increase it. + + while(offset + size + 6 >= buf_size) + { + unsigned char *newbuf = new unsigned char[2*buf_size] ; + + memcpy(newbuf, buf, buf_size) ; + buf_size *= 2 ; + delete[] buf ; + buf = newbuf ; + } + + // Write ptag and size + + buf[offset] = static_cast(ptag) ; + offset += 1 ; + + offset += PGPKeyParser::write_125Size(&buf[offset],size) ; +} + +bool p3Peers::getShortInvite( + std::string& invite, const RsPeerId& _sslId, bool formatRadix, + bool bareBones, const std::string& baseUrl ) +{ + RsPeerId sslId = _sslId; + if(sslId.isNull()) sslId = getOwnId(); + + RsPeerDetails tDetails; + if(!getPeerDetails(sslId, tDetails)) return false; + + uint32_t buf_size = 100; + uint32_t offset = 0; + unsigned char *buf = (unsigned char*)malloc(buf_size); + + addPacketHeader(RsShortInviteFieldType::SSL_ID,RsPeerId::SIZE_IN_BYTES,buf,offset,buf_size); + sslId.serialise(buf,buf_size,offset); + + addPacketHeader(RsShortInviteFieldType::PGP_FINGERPRINT,RsPgpFingerprint::SIZE_IN_BYTES,buf,offset,buf_size); + tDetails.fpr.serialise(buf,buf_size,offset); + + addPacketHeader(RsShortInviteFieldType::PEER_NAME,tDetails.name.size(),buf,offset,buf_size); + memcpy(&buf[offset],tDetails.name.c_str(),tDetails.name.size()); + offset += tDetails.name.size(); + + if(!bareBones) + { + /* If is hidden use hidden address and port as locator, else if we have + * a valid dyndns and extPort use that as locator, else if we have a + * valid extAddr and extPort use that as locator, otherwise use most + * recently known locator */ + sockaddr_storage tExt; + if(tDetails.isHiddenNode) + { + addPacketHeader(RsShortInviteFieldType::HIDDEN_LOCATOR,4 + 2 + tDetails.hiddenNodeAddress.size(),buf,offset,buf_size); + + buf[offset+0] = (uint8_t)((tDetails.hiddenType >> 24) & 0xff); + buf[offset+1] = (uint8_t)((tDetails.hiddenType >> 16) & 0xff); + buf[offset+2] = (uint8_t)((tDetails.hiddenType >> 8) & 0xff); + buf[offset+3] = (uint8_t)((tDetails.hiddenType ) & 0xff); + + buf[offset+4] = (uint8_t)((tDetails.hiddenNodePort >> 8) & 0xff); + buf[offset+5] = (uint8_t)((tDetails.hiddenNodePort ) & 0xff); + + memcpy(&buf[offset+6],tDetails.hiddenNodeAddress.c_str(),tDetails.hiddenNodeAddress.size()); + offset += 4 + 2 + tDetails.hiddenNodeAddress.size(); + } + else if( !tDetails.dyndns.empty() && (tDetails.extPort || tDetails.localPort) ) + { + uint16_t tPort = tDetails.extPort ? tDetails.extPort : tDetails.localPort; + + addPacketHeader(RsShortInviteFieldType::DNS_LOCATOR, 2 + tDetails.dyndns.size(),buf,offset,buf_size); + + buf[offset+0] = (uint8_t)((tPort >> 8) & 0xff); + buf[offset+1] = (uint8_t)((tPort ) & 0xff); + + memcpy(&buf[offset+2],tDetails.dyndns.c_str(),tDetails.dyndns.size()); + offset += 2 + tDetails.dyndns.size(); + } + else if( sockaddr_storage_inet_pton(tExt, tDetails.extAddr) && + sockaddr_storage_isValidNet(tExt) && + sockaddr_storage_ipv6_to_ipv4(tExt) && + tDetails.extPort ) + { + uint32_t t4Addr = reinterpret_cast(tExt).sin_addr.s_addr; + + addPacketHeader(RsShortInviteFieldType::EXT4_LOCATOR, 4 + 2,buf,offset,buf_size); + + buf[offset+0] = (uint8_t)((t4Addr >> 24) & 0xff); + buf[offset+1] = (uint8_t)((t4Addr >> 16) & 0xff); + buf[offset+2] = (uint8_t)((t4Addr >> 8) & 0xff); + buf[offset+3] = (uint8_t)((t4Addr ) & 0xff); + + buf[offset+4] = (uint8_t)((tDetails.extPort >> 8) & 0xff); + buf[offset+5] = (uint8_t)((tDetails.extPort ) & 0xff); + + offset += 4+2; + } + else if(!tDetails.ipAddressList.empty()) + { + const std::string& tLc = tDetails.ipAddressList.front(); + std::string tLocator = tLc.substr(0, tLc.find_first_of(" ")-1); + + addPacketHeader(RsShortInviteFieldType::LOCATOR, tLocator.size(),buf,offset,buf_size); + memcpy(&buf[offset],tLocator.c_str(),tLocator.size()); + + offset += tLocator.size(); + } + } + + Radix64::encode(buf, static_cast(offset), invite); + + if(!formatRadix) + { + RsUrl inviteUrl(baseUrl); + inviteUrl.setQueryKV("rsInvite", invite); + invite = inviteUrl.toString(); + } + + return true; +} + +bool p3Peers::parseShortInvite(const std::string& inviteStrUrl, RsPeerDetails& details, uint32_t &err_code ) +{ + if(inviteStrUrl.empty()) + { + RsErr() << __PRETTY_FUNCTION__ << " can't parse empty invite" + << std::endl; + return false; + } + std::string rsInvite = inviteStrUrl; + + RsUrl inviteUrl(inviteStrUrl); + + if(inviteUrl.hasQueryK("rsInvite")) + rsInvite = *inviteUrl.getQueryV("rsInvite"); + + std::vector bf = Radix64::decode(rsInvite); + size_t size = bf.size(); + + unsigned char* buf = bf.data(); + size_t total_s = 0; + + while(total_s < size) + { + RsShortInviteFieldType ptag = RsShortInviteFieldType(buf[0]); + buf = &buf[1]; + + unsigned char *buf2 = buf; + uint32_t s = 0; + + try { s = PGPKeyParser::read_125Size(buf); } + catch (...) + { + err_code = CERTIFICATE_PARSING_ERROR_SIZE_ERROR; + return false; + } + + total_s += 1 + ( reinterpret_cast(buf) - reinterpret_cast(buf2) ); + + if(total_s > size) + { + err_code = CERTIFICATE_PARSING_ERROR_SIZE_ERROR; + return false; + } + + Dbg3() << __PRETTY_FUNCTION__ << " Read ptag: " + << static_cast(ptag) + << ", size " << s << ", total_s = " << total_s + << ", expected total = " << size << std::endl; + + switch(ptag) + { + case RsShortInviteFieldType::SSL_ID: + details.id = RsPeerId::fromBufferUnsafe(buf) ; + break; + + case RsShortInviteFieldType::PEER_NAME: + details.name = std::string((char*)buf,s); + break; + + case RsShortInviteFieldType::PGP_FINGERPRINT: + details.fpr = RsPgpFingerprint::fromBufferUnsafe(buf); + details.gpg_id = PGPHandler::pgpIdFromFingerprint(details.fpr); + break; + + case RsShortInviteFieldType::LOCATOR: + { + std::string locatorStr((char*)buf,s); + details.ipAddressList.push_back(locatorStr); + } + break; + + case RsShortInviteFieldType::DNS_LOCATOR: + details.extPort = (((int)buf[0]) << 8) + buf[1]; + details.dyndns = std::string((char*)&buf[2],s-2); + break; + + case RsShortInviteFieldType::EXT4_LOCATOR: + { + uint32_t t4Addr = (((uint32_t)buf[0]) << 24)+(((uint32_t)buf[1])<<16)+(((uint32_t)buf[2])<<8) + (uint32_t)buf[3]; + sockaddr_in tExtAddr; + tExtAddr.sin_addr.s_addr = t4Addr; + + details.extAddr = rs_inet_ntoa(tExtAddr.sin_addr); + details.extPort = (((uint32_t)buf[4])<<8) + (uint32_t)buf[5]; + } + break; + + case RsShortInviteFieldType::HIDDEN_LOCATOR: + details.hiddenType = (((uint32_t)buf[0]) << 24)+(((uint32_t)buf[1])<<16)+(((uint32_t)buf[2])<<8) + (uint32_t)buf[3]; + details.hiddenNodePort = (((uint32_t)buf[4]) << 8)+ (uint32_t)buf[5]; + + details.hiddenNodeAddress = std::string((char*)&buf[6],s-6); + break; + + } + + buf = &buf[s]; + total_s += s; + } + + // now check if the PGP key is available. If so, add it in the PeerDetails: + + RsPeerDetails pgp_det ; + if(getGPGDetails(PGPHandler::pgpIdFromFingerprint(details.fpr),pgp_det) && pgp_det.fpr == details.fpr) + { + details.issuer = pgp_det.issuer; + details.gpg_id = pgp_det.gpg_id; + details.gpgSigners = pgp_det.gpgSigners; + details.trustLvl = pgp_det.trustLvl; + details.validLvl = pgp_det.validLvl; + details.ownsign = pgp_det.ownsign; + details.hasSignedMe = pgp_det.hasSignedMe; + details.accept_connection = pgp_det.accept_connection; + } + else + details.skip_pgp_signature_validation = true; + + if(details.gpg_id.isNull()) + { + err_code = CERTIFICATE_PARSING_ERROR_MISSING_PGP_FINGERPRINT; + return false; + } + if(details.id.isNull()) + { + err_code = CERTIFICATE_PARSING_ERROR_MISSING_LOCATION_ID; + return false; + } + err_code = CERTIFICATE_PARSING_ERROR_NO_ERROR; + return true; +} + bool p3Peers::acceptInvite( const std::string& invite, ServicePermissionFlags flags ) { @@ -1217,9 +1523,10 @@ bool p3Peers::loadCertificateFromString( const std::string& cert, RsPeerId& ssl_id, RsPgpId& gpg_id, std::string& error_string ) { - RsCertificate crt; uint32_t errNum = 0; - if(!crt.initializeFromString(cert,errNum)) + auto crt = RsCertificate::fromString(cert, errNum); + + if(!crt) { error_string = "RsCertificate failed with errno: " + std::to_string(errNum) + " parsing: " + cert; @@ -1227,11 +1534,27 @@ bool p3Peers::loadCertificateFromString( } RsPgpId gpgid; - bool res = AuthGPG::getAuthGPG()-> - LoadCertificateFromString(crt.armouredPGPKey(), gpgid,error_string); + bool res = AuthGPG::getAuthGPG()->LoadCertificateFromString( crt->armouredPGPKey(), gpgid, error_string ); gpg_id = gpgid; - ssl_id = crt.sslid(); + ssl_id = crt->sslid(); + + // now get all friends who declare this key ID to be the one needed to check connections, and clear their "skip_pgp_signature_validation" flag + + if(res) + { + mPeerMgr->notifyPgpKeyReceived(gpgid); + FriendsChanged(true); + } + + return res; +} +bool p3Peers::loadPgpKeyFromBinaryData( const unsigned char *bin_key_data,uint32_t bin_key_len, RsPgpId& gpg_id, std::string& error_string ) +{ + bool res = AuthGPG::getAuthGPG()->LoadPGPKeyFromBinaryData( bin_key_data,bin_key_len, gpg_id, error_string ); + + if(res) + mPeerMgr->notifyPgpKeyReceived(gpg_id); return res; } @@ -1240,70 +1563,69 @@ bool p3Peers::loadDetailsFromStringCert( const std::string &certstr, RsPeerDetails &pd, uint32_t& error_code ) { -#ifdef P3PEERS_DEBUG - std::cerr << "p3Peers::LoadCertificateFromString() " << std::endl; -#endif - //parse the text to get ip address - try - { - RsCertificate cert(certstr) ; + Dbg3() << __PRETTY_FUNCTION__ << std::endl; - if(!AuthGPG::getAuthGPG()->getGPGDetailsFromBinaryBlock(cert.pgp_key(),cert.pgp_key_size(), pd.gpg_id,pd.name,pd.gpgSigners)) - return false; + auto certPtr = RsCertificate::fromString(certstr, error_code); + if(!certPtr) return false; -#ifdef P3PEERS_DEBUG - std::cerr << "Parsing cert for sslid, location, ext and local address details. : " << certstr << std::endl; -#endif + RsCertificate& cert = *certPtr; - pd.id = cert.sslid() ; - pd.location = cert.location_name_string(); - - pd.isOnlyGPGdetail = pd.id.isNull(); - pd.service_perm_flags = RS_NODE_PERM_DEFAULT ; - - if (!cert.hidden_node_string().empty()) - { - pd.isHiddenNode = true; - - std::string domain; - uint16_t port; - if (splitAddressString(cert.hidden_node_string(), domain, port)) - { - pd.hiddenNodeAddress = domain; - pd.hiddenNodePort = port; - pd.hiddenType = mPeerMgr->hiddenDomainToHiddenType(domain); - } - } - else - { - pd.isHiddenNode = false; - pd.localAddr = cert.loc_ip_string(); - pd.localPort = cert.loc_port_us(); - pd.extAddr = cert.ext_ip_string(); - pd.extPort = cert.ext_port_us(); - pd.dyndns = cert.dns_string(); - for(const RsUrl& locator : cert.locators()) - pd.ipAddressList.push_back(locator.toString()); - } - } - catch(uint32_t e) - { - std::cerr << "ConnectFriendWizard : Parse ip address error :" << e << std::endl; - error_code = e; - return false ; - } - - if (pd.gpg_id.isNull()) + if(!AuthGPG::getAuthGPG()->getGPGDetailsFromBinaryBlock( + cert.pgp_key(), cert.pgp_key_size(), + pd.gpg_id, pd.name, pd.gpgSigners )) return false; - else - return true; + + Dbg4() << __PRETTY_FUNCTION__ << " Parsing cert for sslid, location, ext " + << " and local address details. : " << certstr << std::endl; + + pd.id = cert.sslid(); + pd.location = cert.location_name_string(); + + pd.isOnlyGPGdetail = pd.id.isNull(); + pd.service_perm_flags = RS_NODE_PERM_DEFAULT; + + if (!cert.hidden_node_string().empty()) + { + pd.isHiddenNode = true; + + std::string domain; + uint16_t port; + if (splitAddressString(cert.hidden_node_string(), domain, port)) + { + pd.hiddenNodeAddress = domain; + pd.hiddenNodePort = port; + pd.hiddenType = mPeerMgr->hiddenDomainToHiddenType(domain); + } + } + else + { + pd.isHiddenNode = false; + pd.localAddr = cert.loc_ip_string(); + pd.localPort = cert.loc_port_us(); + pd.extAddr = cert.ext_ip_string(); + pd.extPort = cert.ext_port_us(); + pd.dyndns = cert.dns_string(); + for(const RsUrl& locator : cert.locators()) + pd.ipAddressList.push_back(locator.toString()); + } + + return true; } -bool p3Peers::cleanCertificate(const std::string &certstr, std::string &cleanCert,int& error_code) +bool p3Peers::cleanCertificate(const std::string &certstr, std::string &cleanCert,bool& is_short_format,uint32_t& error_code) { RsCertificate::Format format ; - return RsCertificate::cleanCertificate(certstr,cleanCert,format,error_code,true) ; + bool res = RsCertificate::cleanCertificate(certstr,cleanCert,format,error_code,true) ; + + if(format == RsCertificate::RS_CERTIFICATE_RADIX) + is_short_format = false; + else if(format == RsCertificate::RS_CERTIFICATE_SHORT_RADIX) + is_short_format = true; + else + return false ; + + return res; } bool p3Peers::saveCertificateToFile(const RsPeerId &id, const std::string &/*fname*/) @@ -1484,7 +1806,7 @@ RsPeerDetails::RsPeerDetails() :isOnlyGPGdetail(false), name(""),email(""),location(""), org(""),authcode(""), - trustLvl(0), validLvl(0),ownsign(false), + trustLvl(0), validLvl(0),skip_pgp_signature_validation(false),ownsign(false), hasSignedMe(false),accept_connection(false), state(0),actAsServer(false), connectPort(0), @@ -1495,63 +1817,9 @@ RsPeerDetails::RsPeerDetails() lastConnect(0),lastUsed(0),connectState(0),connectStateString(""), connectPeriod(0), foundDHT(false), wasDeniedConnection(false), deniedTS(0), - linkType ( RS_NET_CONN_TRANS_TCP_UNKNOWN) -{ -} + linkType ( RS_NET_CONN_TRANS_TCP_UNKNOWN) {} -std::ostream &operator<<(std::ostream &out, const RsPeerDetails &detail) -{ - out << "RsPeerDetail: " << detail.name << " <" << detail.id << ">"; - out << std::endl; - - out << " email: " << detail.email; - out << " location:" << detail.location; - out << " org: " << detail.org; - out << std::endl; - - out << " fpr: " << detail.fpr; - out << " authcode:" << detail.authcode; - out << std::endl; - - out << " signers:"; - out << std::endl; - - std::list::const_iterator it; - for(it = detail.gpgSigners.begin(); - it != detail.gpgSigners.end(); ++it) - { - out << "\t" << *it; - out << std::endl; - } - out << std::endl; - - out << " trustLvl: " << detail.trustLvl; - out << " ownSign: " << detail.ownsign; - out << std::endl; - - out << " state: " << detail.state; - out << " netMode: " << detail.netMode; - out << std::endl; - - out << " localAddr: " << detail.localAddr; - out << ":" << detail.localPort; - out << std::endl; - out << " extAddr: " << detail.extAddr; - out << ":" << detail.extPort; - out << std::endl; - - - out << " lastConnect: " << detail.lastConnect; - out << " connectPeriod: " << detail.connectPeriod; - out << std::endl; - - return out; -} - -RsGroupInfo::RsGroupInfo() -{ - flag = 0; -} +RsGroupInfo::RsGroupInfo() : flag(0) {} ServicePermissionFlags p3Peers::servicePermissionFlags(const RsPeerId& ssl_id) { @@ -1566,4 +1834,5 @@ void p3Peers::setServicePermissionFlags(const RsPgpId& gpg_id,const ServicePermi mPeerMgr->setServicePermissionFlags(gpg_id,flags) ; } - +RsPeerStateChangedEvent::RsPeerStateChangedEvent(RsPeerId sslId) : + RsEvent(RsEventType::PEER_STATE_CHANGED), mSslId(sslId) {} diff --git a/libretroshare/src/rsserver/p3peers.h b/libretroshare/src/rsserver/p3peers.h index 02389128f..e44e7d23a 100644 --- a/libretroshare/src/rsserver/p3peers.h +++ b/libretroshare/src/rsserver/p3peers.h @@ -33,6 +33,7 @@ #include "retroshare/rspeers.h" #include "util/rsurl.h" #include "util/rsdeprecate.h" +#include "util/rsdebug.h" class p3LinkMgr; class p3PeerMgr; @@ -47,7 +48,7 @@ public: virtual ~p3Peers() {} /* Updates ... */ - virtual bool FriendsChanged(); + virtual bool FriendsChanged(bool add); virtual bool OthersChanged(); /* Peer Details (Net & Auth) */ @@ -68,6 +69,9 @@ public: virtual bool isFriend(const RsPeerId &id); virtual bool isPgpFriend(const RsPgpId& pgpId); + /// @see RsPeers + bool isSslOnlyFriend(const RsPeerId& sslId) override; + RS_DEPRECATED_FOR(isPgpFriend) virtual bool isGPGAccepted(const RsPgpId &gpg_id_is_friend); @@ -87,8 +91,17 @@ public: virtual bool getAssociatedSSLIds(const RsPgpId& gpg_id, std::list &ids); virtual bool gpgSignData(const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen, std::string reason = "") ; + virtual RsPgpId pgpIdFromFingerprint(const RsPgpFingerprint& fpr) override; + /* Add/Remove Friends */ virtual bool addFriend(const RsPeerId &ssl_id, const RsPgpId &gpg_id,ServicePermissionFlags flags = RS_NODE_PERM_DEFAULT); + + /// @see RsPeers + bool addSslOnlyFriend( + const RsPeerId& sslId, + const RsPgpId& pgp_id, + const RsPeerDetails& details = RsPeerDetails() ) override; + virtual bool removeFriend(const RsPgpId& gpgid); virtual bool removeFriendLocation(const RsPeerId& sslId); @@ -127,6 +140,15 @@ public: virtual bool GetPGPBase64StringAndCheckSum(const RsPgpId& gpg_id,std::string& gpg_base64_string,std::string& gpg_base64_checksum); + /// @see RsPeers + bool getShortInvite( + std::string& invite, const RsPeerId& sslId = RsPeerId(), + bool formatRadix = false, bool bareBones = false, + const std::string& baseUrl = "https://retroshare.me/" ) override; + + /// @see RsPeers + bool parseShortInvite(const std::string& invite, RsPeerDetails& details, uint32_t &err_code ) override; + /// @see RsPeers::acceptInvite virtual bool acceptInvite( const std::string& invite, @@ -135,9 +157,10 @@ public: virtual bool hasExportMinimal(); virtual bool loadCertificateFromString(const std::string& cert, RsPeerId& ssl_id,RsPgpId& pgp_id, std::string& error_string); + virtual bool loadPgpKeyFromBinaryData( const unsigned char *bin_key_data,uint32_t bin_key_len, RsPgpId& gpg_id, std::string& error_string ); virtual bool loadDetailsFromStringCert(const std::string &cert, RsPeerDetails &pd, uint32_t& error_code); - virtual bool cleanCertificate(const std::string &certstr, std::string &cleanCert,int& error_code); + virtual bool cleanCertificate(const std::string &certstr, std::string &cleanCert, bool &is_short_format, uint32_t& error_code) override; virtual bool saveCertificateToFile(const RsPeerId &id, const std::string &fname); virtual std::string saveCertificateToString(const RsPeerId &id); @@ -170,6 +193,8 @@ private: p3LinkMgr *mLinkMgr; p3PeerMgr *mPeerMgr; p3NetMgr *mNetMgr; + + RS_SET_CONTEXT_DEBUG_LEVEL(1) }; #endif diff --git a/libretroshare/src/rsserver/rsaccounts.cc b/libretroshare/src/rsserver/rsaccounts.cc index 1203a63a2..8be56073c 100644 --- a/libretroshare/src/rsserver/rsaccounts.cc +++ b/libretroshare/src/rsserver/rsaccounts.cc @@ -686,7 +686,8 @@ static bool checkAccount(const std::string &accountdir, AccountDetails &account, bool ret = false; /* check against authmanagers private keys */ - if (LoadCheckX509(cert_name.c_str(), account.mPgpId, account.mLocation, account.mSslId)) + if(AuthSSL::instance().parseX509DetailsFromFile( + cert_name, account.mSslId, account.mPgpId, account.mLocation )) { // new locations store the name in an extra file if(account.mLocation == "") @@ -1117,8 +1118,11 @@ bool RsAccountsDetail::GenerateSSLCertificate(const RsPgpId& pgp_id, const s std::string location; RsPgpId pgpid_retrieved; - if (LoadCheckX509(cert_name.c_str(), pgpid_retrieved, location, sslId) == 0) { - std::cerr << "RsInit::GenerateSSLCertificate() Cannot check own signature, maybe the files are corrupted." << std::endl; + if(!AuthSSL::instance().parseX509DetailsFromFile( + cert_name, sslId, pgpid_retrieved, location )) + { + RsErr() << __PRETTY_FUNCTION__ << " Cannot check own signature, maybe " + << "the files are corrupted." << std::endl; return false; } diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index 86e26c55b..e8e2b518f 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -1,9 +1,8 @@ /******************************************************************************* * libretroshare/src/retroshare: rsinit.cc * * * - * libretroshare: retroshare core library * - * * - * Copyright 2004-2006 by Robert Fernie * + * Copyright (C) 2004-2014 Robert Fernie * + * Copyright (C) 2016-2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -20,8 +19,7 @@ * * *******************************************************************************/ -/* This is an updated startup class. Class variables are hidden from - * the GUI / External via a hidden class */ +/// RetroShare initialization and login API implementation #include @@ -34,7 +32,7 @@ #ifdef __ANDROID__ # include // To install bdboot.txt -# include // for String::fromStdString(...) +# include // for QString::fromStdString(...) #endif #include "util/argstream.h" @@ -44,6 +42,8 @@ #include "util/folderiterator.h" #include "util/rsstring.h" #include "retroshare/rsinit.h" +#include "retroshare/rsnotify.h" +#include "retroshare/rsiface.h" #include "plugins/pluginmanager.h" #include "rsserver/rsloginhandler.h" @@ -98,6 +98,11 @@ RsDht *rsDht = NULL ; # include "jsonapi/jsonapi.h" #endif +#ifdef RS_BROADCAST_DISCOVERY +# include "retroshare/rsbroadcastdiscovery.h" +# include "services/broadcastdiscoveryservice.h" +#endif // def RS_BROADCAST_DISCOVERY + // #define GPG_DEBUG // #define AUTHSSL_DEBUG // #define FIM_DEBUG @@ -109,9 +114,30 @@ RsLoginHelper* rsLoginHelper = nullptr; RsAccounts* rsAccounts = nullptr; +RsConfigOptions::RsConfigOptions() + : + autoLogin(false), + udpListenerOnly(false), + forcedInetAddress("127.0.0.1"), /* inet address to use.*/ + forcedPort(0), + outStderr(false), + debugLevel(5) +#ifdef RS_JSONAPI + ,jsonApiPort(0) // JSonAPI server is enabled in each main() + ,jsonApiBindAddress("127.0.0.1") +#endif +{ +} + + struct RsInitConfig { - RsInitConfig() : jsonApiPort(0), jsonApiBindAddress("127.0.0.1") {} + RsInitConfig() +#ifdef RS_JSONAPI + : jsonApiPort(JsonApiServer::DEFAULT_PORT), + jsonApiBindAddress("127.0.0.1") +#endif + {} RsFileHash main_executable_hash; @@ -152,6 +178,7 @@ struct RsInitConfig bool udpListenerOnly; std::string opModeStr; + std::string optBaseDir; uint16_t jsonApiPort; std::string jsonApiBindAddress; @@ -240,14 +267,6 @@ void RsInit::InitRsConfig() setOutputLevel(RsLog::Warning); } -/******** - * LOCALNET_TESTING - allows port restrictions - * - * #define LOCALNET_TESTING 1 - * - ********/ - - #ifdef LOCALNET_TESTING std::string portRestrictions; @@ -261,166 +280,117 @@ bool doPortRestrictions = false; #endif #endif -int RsInit::InitRetroShare(int argc, char **argv, bool /* strictCheck */) +/******** + * LOCALNET_TESTING - allows port restrictions + * + * #define LOCALNET_TESTING 1 + * + ********/ +int RsInit::InitRetroShare(const RsConfigOptions& conf) { -#ifdef DEBUG_RSINIT - for(int i=0; iautoLogin = conf.autoLogin; + rsInitConfig->outStderr = conf.outStderr; + rsInitConfig->logfname = conf.logfname ; + rsInitConfig->inet = conf.forcedInetAddress ; + rsInitConfig->port = conf.forcedPort ; + rsInitConfig->debugLevel = conf.debugLevel; + rsInitConfig->optBaseDir = conf.optBaseDir; + rsInitConfig->jsonApiPort = conf.jsonApiPort; + rsInitConfig->jsonApiBindAddress = conf.jsonApiBindAddress; #ifdef PTW32_STATIC_LIB // for static PThreads under windows... we need to init the library... pthread_win32_process_attach_np(); #endif - - std::string prefUserString = ""; - std::string opt_base_dir; - -#ifdef __APPLE__ - // TODO: is this still needed with argstream? - /* HACK to avoid stupid OSX Finder behaviour - * remove the commandline arguments - if we detect we are launched from Finder, - * and we have the unparsable "-psn_0_12332" option. - * this is okay, as you cannot pass commandline arguments via Finder anyway - */ - if ((argc >= 2) && (0 == strncmp(argv[1], "-psn", 4))) argc = 1; + if( rsInitConfig->autoLogin) rsInitConfig->startMinimised = true ; + if( rsInitConfig->outStderr) rsInitConfig->haveLogFile = false ; + if(!rsInitConfig->logfname.empty()) rsInitConfig->haveLogFile = true; + if( rsInitConfig->inet != "127.0.0.1") rsInitConfig->forceLocalAddr = true; + if( rsInitConfig->port != 0) rsInitConfig->forceExtPort = true; +#ifdef LOCALNET_TESTING + if(!portRestrictions.empty()) doPortRestrictions = true; #endif + setOutputLevel((RsLog::logLvl)rsInitConfig->debugLevel); - argstream as(argc,argv); - as >> option('m',"minimized" ,rsInitConfig->startMinimised ,"Start minimized." ) - >> option('s',"stderr" ,rsInitConfig->outStderr ,"output to stderr instead of log file." ) - >> option('u',"udp" ,rsInitConfig->udpListenerOnly,"Only listen to UDP." ) - >> option('e',"external-port" ,rsInitConfig->forceExtPort ,"Use a forwarded external port." ) - >> parameter('l',"log-file" ,rsInitConfig->logfname ,"logfile" ,"Set Log filename." ,false) - >> parameter('d',"debug-level" ,rsInitConfig->debugLevel ,"level" ,"Set debug level." ,false) - >> parameter('i',"ip-address" ,rsInitConfig->inet ,"nnn.nnn.nnn.nnn", "Force IP address to use (if cannot be detected)." ,false) - >> parameter('o',"opmode" ,rsInitConfig->opModeStr ,"opmode" ,"Set Operating mode (Full, NoTurtle, Gaming, Minimal)." ,false) - >> parameter('p',"port" ,rsInitConfig->port ,"port", "Set listenning port to use." ,false) - >> parameter('c',"base-dir" ,opt_base_dir ,"directory", "Set base directory." ,false) - >> parameter('U',"user-id" ,prefUserString ,"ID", "[ocation Id] Sets Account to Use, Useful when Autologin is enabled.",false); + // set the debug file. + if (rsInitConfig->haveLogFile) + setDebugFile(rsInitConfig->logfname.c_str()); -#ifdef RS_JSONAPI - as >> parameter( - "jsonApiPort", rsInitConfig->jsonApiPort, "jsonApiPort", - "Enable JSON API on the specified port", false ) - >> parameter( - "jsonApiBindAddress", rsInitConfig->jsonApiBindAddress, - "jsonApiBindAddress", "JSON API Bind Address.", false); -#endif // ifdef RS_JSONAPI - -#ifdef LOCALNET_TESTING - as >> parameter('R',"restrict-port" ,portRestrictions ,"port1-port2","Apply port restriction" ,false); -#endif // ifdef LOCALNET_TESTING - -#ifdef RS_AUTOLOGIN - as >> option('a',"auto-login" ,rsInitConfig->autoLogin ,"AutoLogin (Windows Only) + StartMinimised"); -#endif // ifdef RS_AUTOLOGIN - - as >> help('h',"help","Display this Help"); - as.defaultErrorHandling(true,true); - - if(rsInitConfig->autoLogin) rsInitConfig->startMinimised = true ; - if(rsInitConfig->outStderr) rsInitConfig->haveLogFile = false ; - if(!rsInitConfig->logfname.empty()) rsInitConfig->haveLogFile = true; - if(rsInitConfig->inet != "127.0.0.1") rsInitConfig->forceLocalAddr = true; -#ifdef LOCALNET_TESTING - if(!portRestrictions.empty()) doPortRestrictions = true; -#endif - - setOutputLevel((RsLog::logLvl)rsInitConfig->debugLevel); - - // set the debug file. - if (rsInitConfig->haveLogFile) - setDebugFile(rsInitConfig->logfname.c_str()); - - /******************************** WINDOWS/UNIX SPECIFIC PART ******************/ + /******************************** WINDOWS/UNIX SPECIFIC PART ******************/ #ifndef WINDOWS_SYS - /********************************** WINDOWS/UNIX SPECIFIC PART ******************/ + /********************************** WINDOWS/UNIX SPECIFIC PART ******************/ #else - // Windows Networking Init. - WORD wVerReq = MAKEWORD(2,2); - WSADATA wsaData; + // Windows Networking Init. + WORD wVerReq = MAKEWORD(2,2); + WSADATA wsaData; - if (0 != WSAStartup(wVerReq, &wsaData)) - { - std::cerr << "Failed to Startup Windows Networking"; - std::cerr << std::endl; - } - else - { - std::cerr << "Started Windows Networking"; - std::cerr << std::endl; - } + if (0 != WSAStartup(wVerReq, &wsaData)) + { + std::cerr << "Failed to Startup Windows Networking"; + std::cerr << std::endl; + } + else + { + std::cerr << "Started Windows Networking"; + std::cerr << std::endl; + } #endif - /********************************** WINDOWS/UNIX SPECIFIC PART ******************/ - // SWITCH off the SIGPIPE - kills process on Linux. - /******************************** WINDOWS/UNIX SPECIFIC PART ******************/ + /********************************** WINDOWS/UNIX SPECIFIC PART ******************/ + // SWITCH off the SIGPIPE - kills process on Linux. + /******************************** WINDOWS/UNIX SPECIFIC PART ******************/ #ifndef WINDOWS_SYS - struct sigaction sigact; - sigact.sa_handler = SIG_IGN; - sigact.sa_flags = 0; + struct sigaction sigact; + sigact.sa_handler = SIG_IGN; + sigact.sa_flags = 0; - sigset_t set; - sigemptyset(&set); - //sigaddset(&set, SIGINT); // or whatever other signal - sigact.sa_mask = set; + sigset_t set; + sigemptyset(&set); + //sigaddset(&set, SIGINT); // or whatever other signal + sigact.sa_mask = set; - if (0 == sigaction(SIGPIPE, &sigact, NULL)) - { - std::cerr << "RetroShare:: Successfully installed the SIGPIPE Block" << std::endl; - } - else - { - std::cerr << "RetroShare:: Failed to install the SIGPIPE Block" << std::endl; - } + if (0 == sigaction(SIGPIPE, &sigact, NULL)) + { + std::cerr << "RetroShare:: Successfully installed the SIGPIPE Block" << std::endl; + } + else + { + std::cerr << "RetroShare:: Failed to install the SIGPIPE Block" << std::endl; + } #endif - /******************************** WINDOWS/UNIX SPECIFIC PART ******************/ + /******************************** WINDOWS/UNIX SPECIFIC PART ******************/ - // Hash the main executable. + // Hash the main executable. - uint64_t tmp_size ; + uint64_t tmp_size ; - if(!RsDirUtil::getFileHash(argv[0],rsInitConfig->main_executable_hash,tmp_size,NULL)) - std::cerr << "Cannot hash executable! Plugins will not be loaded correctly." << std::endl; - else - std::cerr << "Hashed main executable: " << rsInitConfig->main_executable_hash << std::endl; + if(conf.main_executable_path.empty()) + { + std::cerr << "Executable path is unknown. It should normally have been set in passed RsConfigOptions structure" << std::endl; + return 1; + } + if(!RsDirUtil::getFileHash(conf.main_executable_path,rsInitConfig->main_executable_hash,tmp_size,NULL)) + std::cerr << "Cannot hash executable! Plugins will not be loaded correctly." << std::endl; + else + std::cerr << "Hashed main executable: " << rsInitConfig->main_executable_hash << std::endl; - /* At this point we want to. + /* At this point we want to. * 1) Load up Dase Directory. * 3) Get Prefered Id. * 2) Get List of Available Accounts. * 4) Get List of GPG Accounts. */ - /* create singletons */ - AuthSSL::AuthSSLInit(); - AuthSSL::getAuthSSL() -> InitAuth(NULL, NULL, NULL, ""); + /* Initialize AuthSSL */ + AuthSSL::instance().InitAuth(nullptr, nullptr, nullptr, ""); - rsLoginHelper = new RsLoginHelper; + rsLoginHelper = new RsLoginHelper; - int error_code ; + int error_code ; - if(!RsAccounts::init(opt_base_dir,error_code)) - return error_code ; + if(!RsAccounts::init(rsInitConfig->optBaseDir,error_code)) + return error_code ; - // choose alternative account. - if(prefUserString != "") - { - RsPeerId ssl_id(prefUserString); - - if(ssl_id.isNull()) - { - std::cerr << "Invalid User location id: not found in list"; - std::cerr << std::endl; - return RS_INIT_AUTH_FAILED ; - } - - if(RsAccounts::SelectAccount(ssl_id)) - { - std::cerr << "Auto-selectng account ID " << ssl_id << std::endl; - return RS_INIT_HAVE_ACCOUNT; - } - } #ifdef RS_AUTOLOGIN /* check that we have selected someone */ @@ -441,9 +411,7 @@ int RsInit::InitRetroShare(int argc, char **argv, bool /* strictCheck */) #ifdef RS_JSONAPI if(rsInitConfig->jsonApiPort) { - jsonApiServer = new JsonApiServer( - rsInitConfig->jsonApiPort, - rsInitConfig->jsonApiBindAddress ); + jsonApiServer = new JsonApiServer( rsInitConfig->jsonApiPort, rsInitConfig->jsonApiBindAddress ); jsonApiServer->start("JSON API Server"); } #endif // ifdef RS_JSONAPI @@ -475,7 +443,7 @@ RsInit::LoadCertificateStatus RsInit::LockConfigDirectory( case 0: return RsInit::OK; case 1: return RsInit::ERR_ALREADY_RUNNING; case 2: return RsInit::ERR_CANT_ACQUIRE_LOCK; - default: return RsInit::ERR_UNKOWN; + default: return RsInit::ERR_UNKNOWN; } } @@ -508,27 +476,32 @@ bool RsInit::LoadPassword(const std::string& inPwd) return true; } +std::string RsInit::lockFilePath() +{ + return RsAccounts::AccountDirectory() + "/lock" ; +} + RsInit::LoadCertificateStatus RsInit::LockAndLoadCertificates( bool autoLoginNT, std::string& lockFilePath ) { try { if (!RsAccounts::lockPreferredAccount()) - throw RsInit::ERR_UNKOWN; // invalid PreferredAccount. + throw RsInit::ERR_UNKNOWN; // invalid PreferredAccount. // Logic that used to be external to RsInit... RsPeerId accountId; if (!RsAccounts::GetPreferredAccountId(accountId)) - throw RsInit::ERR_UNKOWN; // invalid PreferredAccount; + throw RsInit::ERR_UNKNOWN; // invalid PreferredAccount; RsPgpId pgpId; std::string pgpName, pgpEmail, location; if(!RsAccounts::GetAccountDetails(accountId, pgpId, pgpName, pgpEmail, location)) - throw RsInit::ERR_UNKOWN; // invalid PreferredAccount; + throw RsInit::ERR_UNKNOWN; // invalid PreferredAccount; if(0 == AuthGPG::getAuthGPG() -> GPGInit(pgpId)) - throw RsInit::ERR_UNKOWN; // PGP Error. + throw RsInit::ERR_UNKNOWN; // PGP Error. LoadCertificateStatus retVal = LockConfigDirectory(RsAccounts::AccountDirectory(), lockFilePath); @@ -539,7 +512,7 @@ RsInit::LoadCertificateStatus RsInit::LockAndLoadCertificates( if(LoadCertificates(autoLoginNT) != 1) { UnlockConfigDirectory(); - throw RsInit::ERR_UNKOWN; + throw RsInit::ERR_UNKNOWN; } return RsInit::OK; @@ -728,19 +701,11 @@ RsGRouter *rsGRouter = NULL ; #include "util/rsdir.h" #include "util/rsrandom.h" -#ifdef RS_ENABLE_ZEROCONF - #include "zeroconf/p3zeroconf.h" -#endif - -#ifdef RS_ENABLE_ZCNATASSIST - #include "zeroconf/p3zcnatassist.h" -#else - #ifdef RS_USE_LIBUPNP - #include "upnp/upnphandler_linux.h" - #else - #include "upnp/upnphandler_miniupnp.h" - #endif -#endif +#ifdef RS_USE_LIBUPNP +# include "rs_upnp/upnphandler_linux.h" +#else // def RS_USE_LIBUPNP +# include "rs_upnp/upnphandler_miniupnp.h" +#endif // def RS_USE_LIBUPNP #include "services/autoproxy/p3i2pbob.h" #include "services/autoproxy/rsautoproxymonitor.h" @@ -748,7 +713,7 @@ RsGRouter *rsGRouter = NULL ; #include "services/p3gxsreputation.h" #include "services/p3serviceinfo.h" #include "services/p3heartbeat.h" -#include "services/p3discovery2.h" +#include "gossipdiscovery/p3gossipdiscovery.h" #include "services/p3msgservice.h" #include "services/p3statusservice.h" @@ -1216,7 +1181,8 @@ int RsServer::StartupRetroShare() plugins_directories.push_back(extensions_dir) ; if(!RsDirUtil::checkCreateDirectory(extensions_dir)) - std::cerr << "(EE) Cannot create extensions directory " + extensions_dir + ". This is not mandatory, but you probably have a permission problem." << std::endl; + std::cerr << "(EE) Cannot create extensions directory " << extensions_dir + << ". This is not mandatory, but you probably have a permission problem." << std::endl; #ifdef DEBUG_PLUGIN_SYSTEM plugins_directories.push_back(".") ; // this list should be saved/set to some correct value. @@ -1462,6 +1428,12 @@ int RsServer::StartupRetroShare() mHistoryMgr, *mGxsTrans ); mStatusSrv = new p3StatusService(serviceCtrl); +#ifdef RS_BROADCAST_DISCOVERY + rsBroadcastDiscovery.reset(new BroadcastDiscoveryService(*rsPeers)); + BroadcastDiscoveryService& tBroadcastDiscoveryService = + static_cast(*rsBroadcastDiscovery); +#endif // def RS_BROADCAST_DISCOVERY + #ifdef ENABLE_GROUTER p3GRouter *gr = new p3GRouter(serviceCtrl,mGxsIdService) ; rsGRouter = gr ; @@ -1481,7 +1453,7 @@ int RsServer::StartupRetroShare() mGxsNetTunnel->connectToTurtleRouter(tr) ; - rsDisc = mDisc; + rsGossipDiscovery.reset(mDisc); rsMsgs = new p3Msgs(msgSrv, chatSrv); // connect components to turtle router. @@ -1583,23 +1555,11 @@ int RsServer::StartupRetroShare() mNetMgr->addNetListener(mProxyStack); #endif -#ifdef RS_ENABLE_ZEROCONF - p3ZeroConf *mZeroConf = new p3ZeroConf( - AuthGPG::getAuthGPG()->getGPGOwnId(), ownId, - mLinkMgr, mNetMgr, mPeerMgr); - mNetMgr->addNetAssistConnect(2, mZeroConf); - mNetMgr->addNetListener(mZeroConf); -#endif - -#ifdef RS_ENABLE_ZCNATASSIST - // Apple's UPnP & NAT-PMP assistance. - p3zcNatAssist *mZcNatAssist = new p3zcNatAssist(); - mNetMgr->addNetAssistFirewall(1, mZcNatAssist); -#else +#if defined(RS_USE_LIBMINIUPNPC) || defined(RS_USE_LIBUPNP) // Original UPnP Interface. pqiNetAssistFirewall *mUpnpMgr = new upnphandler(); mNetMgr->addNetAssistFirewall(1, mUpnpMgr); -#endif +#endif // defined(RS_USE_LIBMINIUPNPC) || defined(RS_USE_LIBUPNP) } /**************************************************************************/ @@ -1804,7 +1764,7 @@ int RsServer::StartupRetroShare() /* Add AuthGPG services */ /**************************************************************************/ - AuthGPG::getAuthGPG()->addService(mDisc); + //AuthGPG::getAuthGPG()->addService(mDisc); /**************************************************************************/ /* Force Any Last Configuration Options */ @@ -1863,10 +1823,14 @@ int RsServer::StartupRetroShare() # ifdef RS_GXS_TRANS startServiceThread(mGxsTrans, "gxs trans"); startServiceThread(gxstrans_ns, "gxs trans ns"); -# endif // RS_GXS_TRANS +# endif // def RS_GXS_TRANS #endif // RS_ENABLE_GXS +#ifdef RS_BROADCAST_DISCOVERY + startServiceThread(&tBroadcastDiscoveryService, "Broadcast Discovery"); +#endif // def RS_BROADCAST_DISCOVERY + ftserver->StartupThreads(); ftserver->ResumeTransfers(); @@ -1917,21 +1881,24 @@ int RsServer::StartupRetroShare() return 1; } -RsInit::LoadCertificateStatus RsLoginHelper::attemptLogin( - const RsPeerId& account, const std::string& password) +RsInit::LoadCertificateStatus RsLoginHelper::attemptLogin(const RsPeerId& account, const std::string& password) { if(isLoggedIn()) return RsInit::ERR_ALREADY_RUNNING; - if(!rsNotify->cachePgpPassphrase(password)) return RsInit::ERR_UNKOWN; - if(!rsNotify->setDisableAskPassword(true)) return RsInit::ERR_UNKOWN; - if(!RsAccounts::SelectAccount(account)) return RsInit::ERR_UNKOWN; + + if(!password.empty()) + { + if(!rsNotify->cachePgpPassphrase(password)) return RsInit::ERR_UNKNOWN; + if(!rsNotify->setDisableAskPassword(true)) return RsInit::ERR_UNKNOWN; + } + if(!RsAccounts::SelectAccount(account)) return RsInit::ERR_UNKNOWN; std::string _ignore_lockFilePath; - RsInit::LoadCertificateStatus ret = - RsInit::LockAndLoadCertificates(false, _ignore_lockFilePath); - if(!rsNotify->setDisableAskPassword(false)) return RsInit::ERR_UNKOWN; - if(!rsNotify->clearPgpPassphrase()) return RsInit::ERR_UNKOWN; + RsInit::LoadCertificateStatus ret = RsInit::LockAndLoadCertificates(false, _ignore_lockFilePath); + + if(!rsNotify->setDisableAskPassword(false)) return RsInit::ERR_UNKNOWN; + if(!rsNotify->clearPgpPassphrase()) return RsInit::ERR_UNKNOWN; if(ret != RsInit::OK) return ret; if(RsControl::instance()->StartupRetroShare() == 1) return RsInit::OK; - return RsInit::ERR_UNKOWN; + return RsInit::ERR_UNKNOWN; } /*static*/ bool RsLoginHelper::collectEntropy(uint32_t bytes) @@ -1947,7 +1914,7 @@ void RsLoginHelper::getLocations(std::vector& store) { Location l; l.mLocationId = locId; std::string discardPgpMail; - RsAccounts::GetAccountDetails( locId, l.mPgpId, l.mPpgName, + RsAccounts::GetAccountDetails( locId, l.mPgpId, l.mPgpName, discardPgpMail, l.mLocationName ); store.push_back(l); } @@ -1965,14 +1932,14 @@ bool RsLoginHelper::createLocation( return false; } - if(l.mPgpId.isNull() && l.mPpgName.empty()) + if(l.mPgpId.isNull() && l.mPgpName.empty()) { errorMessage = "Either PGP name or PGP id is needed"; return false; } if(l.mPgpId.isNull() && !RsAccounts::GeneratePGPCertificate( - l.mPpgName, "", password, l.mPgpId, 4096, errorMessage) ) + l.mPgpName, "", password, l.mPgpId, 4096, errorMessage) ) { errorMessage = "Failure creating PGP key: " + errorMessage; return false; @@ -2007,7 +1974,7 @@ void RsLoginHelper::Location::serial_process( RS_SERIAL_PROCESS(mLocationId); RS_SERIAL_PROCESS(mPgpId); RS_SERIAL_PROCESS(mLocationName); - RS_SERIAL_PROCESS(mPpgName); + RS_SERIAL_PROCESS(mPgpName); } /*static*/ bool RsAccounts::getCurrentAccountId(RsPeerId& id) diff --git a/libretroshare/src/rsserver/rstypes.cc b/libretroshare/src/rsserver/rstypes.cc deleted file mode 100644 index 0dd06b956..000000000 --- a/libretroshare/src/rsserver/rstypes.cc +++ /dev/null @@ -1,72 +0,0 @@ -/******************************************************************************* - * libretroshare/src/rsserver: rstypes.cc * - * * - * libretroshare: retroshare core library * - * * - * Copyright 2004-2006 by Robert Fernie * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License as * - * published by the Free Software Foundation, either version 3 of the * - * License, or (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public License * - * along with this program. If not, see . * - * * - *******************************************************************************/ - -/* Insides of RetroShare interface. - * only prints stuff out at the moment - */ - -#include "retroshare/rstypes.h" -#include -#include -#include "util/rstime.h" - - -/********************************************************************** - * NOTE NOTE NOTE ...... XXX - * BUG in MinGW .... %hhx in sscanf overwrites 32bits, instead of 8bits. - * this means that scanf(.... &(data[15])) is running off the - * end of the buffer, and hitting data[15-18]... - * To work around this bug we are reading into proper int32s - * and then copying the data over... - * -**********************************************************************/ - -std::ostream &operator<<(std::ostream &out, const DirDetails& d) -{ - std::cerr << "====DIR DETAILS====" << std::endl; - std::cerr << " parent pointer: " << d.parent << std::endl; - std::cerr << " current pointer: " << d.ref << std::endl; - std::cerr << " parent row : " << d.prow << std::endl; - std::cerr << " type : " << (int)d.type << std::endl; - std::cerr << " PeerId : " << d.id << std::endl; - std::cerr << " Name : " << d.name << std::endl; - std::cerr << " Hash : " << d.hash << std::endl; - std::cerr << " Path : " << d.path << std::endl; - std::cerr << " Count : " << d.count << std::endl; - std::cerr << " Age : " << time(NULL) - (int)d.mtime << std::endl; - std::cerr << " Min age : " << time(NULL) - (int)d.max_mtime << std::endl; - std::cerr << " Flags : " << d.flags << std::endl; - std::cerr << " Parent groups : " ; for(std::list::const_iterator it(d.parent_groups.begin());it!=d.parent_groups.end();++it) std::cerr << (*it) << " "; std::cerr << std::endl; - std::cerr << " Children : " ; for(uint32_t i=0;i * - * Copyright (C) 2018 Gioacchino Mazzurco * + * Copyright (C) 2017 Cyril Soler * + * Copyright (C) 2018-2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -39,8 +39,7 @@ #include #endif // HAS_RAPIDJSON -//static const uint32_t MAX_SERIALIZED_ARRAY_SIZE = 500 ; -static const uint32_t MAX_SERIALIZED_CHUNK_SIZE = 10*1024*1024 ; // 10 MB. +static constexpr uint32_t MAX_SERIALIZED_CHUNK_SIZE = 10*1024*1024 ; // 10 MB. #ifdef RSSERIAL_DEBUG # define SAFE_GET_JSON_V() \ @@ -63,6 +62,61 @@ static const uint32_t MAX_SERIALIZED_CHUNK_SIZE = 10*1024*1024 ; // 10 MB. #endif // ifdef RSSERIAL_DEBUG +//============================================================================// +// std::string // +//============================================================================// + +template<> uint32_t RsTypeSerializer::serial_size(const std::string& str) +{ + return getRawStringSize(str); +} +template<> bool RsTypeSerializer::serialize( uint8_t data[], uint32_t size, + uint32_t& offset, + const std::string& str ) +{ + return setRawString(data, size, &offset, str); +} +template<> bool RsTypeSerializer::deserialize( const uint8_t data[], + uint32_t size, uint32_t &offset, + std::string& str ) +{ + return getRawString(data, size, &offset, str); +} +template<> void RsTypeSerializer::print_data( const std::string& n, + const std::string& str ) +{ + std::cerr << " [std::string] " << n << ": " << str << std::endl; +} +template<> /*static*/ +bool RsTypeSerializer::to_JSON( const std::string& membername, + const std::string& member, RsJson& jDoc ) +{ + rapidjson::Document::AllocatorType& allocator = jDoc.GetAllocator(); + + rapidjson::Value key; + key.SetString( membername.c_str(), + static_cast(membername.length()), + allocator ); + + rapidjson::Value value; + value.SetString( member.c_str(), + static_cast(member.length()), + allocator ); + + jDoc.AddMember(key, value, allocator); + + return true; +} +template<> /*static*/ +bool RsTypeSerializer::from_JSON( const std::string& memberName, + std::string& member, RsJson& jDoc ) +{ + SAFE_GET_JSON_V(); + ret = ret && v.IsString(); + if(ret) member = v.GetString(); + return ret; +} + //============================================================================// // Integer types // //============================================================================// @@ -199,7 +253,9 @@ template<> bool RsTypeSerializer::to_JSON( const std::string& memberName, \ rapidjson::Document::AllocatorType& allocator = jDoc.GetAllocator(); \ \ rapidjson::Value key; \ - key.SetString(memberName.c_str(), memberName.length(), allocator); \ + key.SetString( memberName.c_str(), \ + static_cast(memberName.length()), \ + allocator ); \ \ rapidjson::Value value(member); \ \ @@ -210,12 +266,39 @@ template<> bool RsTypeSerializer::to_JSON( const std::string& memberName, \ SIMPLE_TO_JSON_DEF(bool) SIMPLE_TO_JSON_DEF(int32_t) -SIMPLE_TO_JSON_DEF(rstime_t) SIMPLE_TO_JSON_DEF(uint8_t) SIMPLE_TO_JSON_DEF(uint16_t) SIMPLE_TO_JSON_DEF(uint32_t) -SIMPLE_TO_JSON_DEF(uint64_t) + +/** Be very careful in changing this constant as it would break 64 bit integers + * members JSON string representation retrocompatibility */ +static constexpr char strReprSuffix[] = "_sixtyfour_str"; + +/** While JSON doesn't have problems representing 64 bit integers JavaScript + * standard represents numbers in a double-like format thus it is not capable to + * handle safely integers outside the range [-(2^53 - 1), 2^53 - 1], so we add + * to JSON also the string representation for this types as a workaround for the + * sake of JavaScript clients @see https://stackoverflow.com/a/34989371 + */ +#define SIXTYFOUR_INTEGERS_TO_JSON_DEF(T) \ +template<> bool RsTypeSerializer::to_JSON( const std::string& memberName, \ + const T& member, RsJson& jDoc ) \ +{ \ + rapidjson::Document::AllocatorType& allocator = jDoc.GetAllocator(); \ + \ + rapidjson::Value key; \ + key.SetString( memberName.c_str(), \ + static_cast(memberName.length()), \ + allocator ); \ + rapidjson::Value value(member); \ + jDoc.AddMember(key, value, allocator); \ + \ + return to_JSON(memberName + strReprSuffix, std::to_string(member), jDoc); \ +} + +SIXTYFOUR_INTEGERS_TO_JSON_DEF(int64_t); +SIXTYFOUR_INTEGERS_TO_JSON_DEF(uint64_t); template<> /*static*/ bool RsTypeSerializer::from_JSON( const std::string& memberName, bool& member, @@ -237,23 +320,13 @@ bool RsTypeSerializer::from_JSON( const std::string& memberName, return ret; } -template<> /*static*/ -bool RsTypeSerializer::from_JSON( const std::string& memberName, rstime_t& member, - RsJson& jDoc ) -{ - SAFE_GET_JSON_V(); - ret = ret && v.IsInt64(); - if(ret) member = v.GetInt64(); - return ret; -} - template<> /*static*/ bool RsTypeSerializer::from_JSON( const std::string& memberName, uint8_t& member, RsJson& jDoc ) { SAFE_GET_JSON_V(); ret = ret && v.IsUint(); - if(ret) member = v.GetUint(); + if(ret) member = static_cast(v.GetUint()); return ret; } @@ -263,7 +336,7 @@ bool RsTypeSerializer::from_JSON( const std::string& memberName, { SAFE_GET_JSON_V(); ret = ret && v.IsUint(); - if(ret) member = v.GetUint(); + if(ret) member = static_cast(v.GetUint()); return ret; } @@ -277,14 +350,98 @@ bool RsTypeSerializer::from_JSON( const std::string& memberName, return ret; } +/** While JSON doesn't have problems representing 64 bit integers JavaScript + * standard represents numbers in a double-like format thus it is not capable to + * handle safely integers outside the range [-(2^53 - 1), 2^53 - 1], so we look + * for the string representation in the JSON for this types as a workaround for + * the sake of JavaScript clients @see https://stackoverflow.com/a/34989371 + */ template<> /*static*/ -bool RsTypeSerializer::from_JSON( const std::string& memberName, - uint64_t& member, RsJson& jDoc ) +bool RsTypeSerializer::from_JSON( + const std::string& memberName, int64_t& member, RsJson& jDoc ) { - SAFE_GET_JSON_V(); - ret = ret && v.IsUint64(); - if(ret) member = v.GetUint64(); - return ret; + const char* mName = memberName.c_str(); + if(jDoc.HasMember(mName)) + { + rapidjson::Value& v = jDoc[mName]; + if(v.IsInt64()) + { + member = v.GetInt64(); + return true; + } + } + + Dbg4() << __PRETTY_FUNCTION__ << " int64_t " << memberName << " not found " + << "in JSON then attempt to look for string representation" + << std::endl; + + const std::string str_key = memberName + strReprSuffix; + std::string str_value; + if(from_JSON(str_key, str_value, jDoc)) + { + try { member = std::stoll(str_value); } + catch (...) + { + RsErr() << __PRETTY_FUNCTION__ << " cannot convert " + << str_value << " to int64_t" << std::endl; + return false; + } + + return true; + } + + Dbg3() << __PRETTY_FUNCTION__ << " neither " << memberName << " nor its " + << "string representation " << str_key << " has been found " + << "in JSON" << std::endl; + + return false; +} + +/** While JSON doesn't have problems representing 64 bit integers JavaScript + * standard represents numbers in a double-like format thus it is not capable to + * handle safely integers outside the range [-(2^53 - 1), 2^53 - 1], so we look + * for the string representation in the JSON for this types as a workaround for + * the sake of JavaScript clients @see https://stackoverflow.com/a/34989371 + */ +template<> /*static*/ +bool RsTypeSerializer::from_JSON( + const std::string& memberName, uint64_t& member, RsJson& jDoc ) +{ + const char* mName = memberName.c_str(); + if(jDoc.HasMember(mName)) + { + rapidjson::Value& v = jDoc[mName]; + if(v.IsUint64()) + { + member = v.GetUint64(); + return true; + } + } + + Dbg4() << __PRETTY_FUNCTION__ << " uint64_t " << memberName << " not found " + << "in JSON then attempt to look for string representation" + << std::endl; + + const std::string str_key = memberName + strReprSuffix; + std::string str_value; + if(from_JSON(str_key, str_value, jDoc)) + { + try { member = std::stoull(str_value); } + catch (...) + { + RsErr() << __PRETTY_FUNCTION__ << " cannot convert " + << str_value << " to uint64_t" << std::endl; + return false; + } + + return true; + } + + Dbg3() << __PRETTY_FUNCTION__ << " neither " << memberName << " nor its " + << "string representation " << str_key << " has been found " + << "in JSON" << std::endl; + + return false; } @@ -363,59 +520,6 @@ bool RsTypeSerializer::from_JSON( const std::string& memberName, } -//============================================================================// -// std::string // -//============================================================================// - -template<> uint32_t RsTypeSerializer::serial_size(const std::string& str) -{ - return getRawStringSize(str); -} -template<> bool RsTypeSerializer::serialize( uint8_t data[], uint32_t size, - uint32_t& offset, - const std::string& str ) -{ - return setRawString(data, size, &offset, str); -} -template<> bool RsTypeSerializer::deserialize( const uint8_t data[], - uint32_t size, uint32_t &offset, - std::string& str ) -{ - return getRawString(data, size, &offset, str); -} -template<> void RsTypeSerializer::print_data( const std::string& n, - const std::string& str ) -{ - std::cerr << " [std::string] " << n << ": " << str << std::endl; -} -template<> /*static*/ -bool RsTypeSerializer::to_JSON( const std::string& membername, - const std::string& member, RsJson& jDoc ) -{ - rapidjson::Document::AllocatorType& allocator = jDoc.GetAllocator(); - - rapidjson::Value key; - key.SetString(membername.c_str(), membername.length(), allocator); - - rapidjson::Value value;; - value.SetString(member.c_str(), member.length(), allocator); - - jDoc.AddMember(key, value, allocator); - - return true; -} -template<> /*static*/ -bool RsTypeSerializer::from_JSON( const std::string& memberName, - std::string& member, RsJson& jDoc ) -{ - SAFE_GET_JSON_V(); - ret = ret && v.IsString(); - if(ret) member = v.GetString(); - return ret; -} - - - //============================================================================// // TlvString with subtype // //============================================================================// @@ -628,11 +732,13 @@ bool RsTypeSerializer::to_JSON( rapidjson::Document::AllocatorType& allocator = jDoc.GetAllocator(); rapidjson::Value key; - key.SetString(memberName.c_str(), memberName.length(), allocator); + key.SetString( memberName.c_str(), + static_cast(memberName.length()), + allocator ); std::string encodedValue; Radix64::encode( reinterpret_cast(member.first), - member.second, encodedValue ); + static_cast(member.second), encodedValue ); rapidjson::Value value; value.SetString(encodedValue.data(), allocator); diff --git a/libretroshare/src/serialiser/rstypeserializer.h b/libretroshare/src/serialiser/rstypeserializer.h index 768194a06..550b89f07 100644 --- a/libretroshare/src/serialiser/rstypeserializer.h +++ b/libretroshare/src/serialiser/rstypeserializer.h @@ -3,8 +3,8 @@ * * * libretroshare: retroshare core library * * * - * Copyright (C) 2017 Cyril Soler * - * Copyright (C) 2018 Gioacchino Mazzurco * + * Copyright (C) 2017 Cyril Soler * + * Copyright (C) 2018-2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -32,6 +32,7 @@ #include "serialiser/rsserializer.h" #include "serialiser/rsserializable.h" #include "util/rsjson.h" +#include "util/rsdebug.h" #include // for typeid #include @@ -844,36 +845,36 @@ protected: // t_RsGenericId<...> declarations // //============================================================================// - template + template static bool serialize( uint8_t data[], uint32_t size, uint32_t &offset, - const t_RsGenericIdType& member ); + const t_RsGenericIdType& member ); - template + template static bool deserialize( const uint8_t data[], uint32_t size, uint32_t &offset, - t_RsGenericIdType& member ); + t_RsGenericIdType& member ); - template + template static uint32_t serial_size( const t_RsGenericIdType< - ID_SIZE_IN_BYTES,UPPER_CASE,UNIQUE_IDENTIFIER>& member ); + ID_SIZE_IN_BYTES, UPPER_CASE, UNIQUE_IDENTIFIER>& member ); - template + template static void print_data( const std::string& name, const t_RsGenericIdType& member ); - template + template static bool to_JSON( const std::string& membername, - const t_RsGenericIdType& member, + const t_RsGenericIdType& member, RsJson& jVal ); - template + template static bool from_JSON( const std::string& memberName, - t_RsGenericIdType& member, + t_RsGenericIdType& member, RsJson& jDoc ); //============================================================================// @@ -907,6 +908,8 @@ protected: static bool from_JSON( const std::string& memberName, t_RsTlvList& member, RsJson& jDoc ); + + RS_SET_CONTEXT_DEBUG_LEVEL(1) }; @@ -914,41 +917,43 @@ protected: // t_RsGenericId<...> // //============================================================================// -template +template bool RsTypeSerializer::serialize ( uint8_t data[], uint32_t size, uint32_t &offset, const t_RsGenericIdType< - ID_SIZE_IN_BYTES,UPPER_CASE,UNIQUE_IDENTIFIER>& member ) + ID_SIZE_IN_BYTES, UPPER_CASE, UNIQUE_IDENTIFIER>& member ) { return (*const_cast *>(&member) - ).serialise(data,size,offset); + ID_SIZE_IN_BYTES, UPPER_CASE, UNIQUE_IDENTIFIER> *>(&member) + ).serialise(data, size, offset); } -template +template bool RsTypeSerializer::deserialize( const uint8_t data[], uint32_t size, uint32_t &offset, - t_RsGenericIdType& member ) -{ return member.deserialise(data,size,offset); } + t_RsGenericIdType& member ) +{ return member.deserialise(data, size, offset); } -template +template uint32_t RsTypeSerializer::serial_size( - const t_RsGenericIdType& member ) + const t_RsGenericIdType& member ) { return member.serial_size(); } -template +template void RsTypeSerializer::print_data( const std::string& /*name*/, - const t_RsGenericIdType& member ) + const t_RsGenericIdType& member ) { - std::cerr << " [RsGenericId<" << std::hex << UNIQUE_IDENTIFIER << ">] : " + std::cerr << " [RsGenericId<" << std::hex + << static_cast(UNIQUE_IDENTIFIER) << ">] : " << member << std::endl; } -template -bool RsTypeSerializer::to_JSON( const std::string& memberName, - const t_RsGenericIdType& member, - RsJson& jDoc ) +template +bool RsTypeSerializer::to_JSON( + const std::string& memberName, + const t_RsGenericIdType& member, + RsJson& jDoc ) { rapidjson::Document::AllocatorType& allocator = jDoc.GetAllocator(); @@ -964,10 +969,11 @@ bool RsTypeSerializer::to_JSON( const std::string& memberName, return true; } -template -bool RsTypeSerializer::from_JSON( const std::string& membername, - t_RsGenericIdType& member, - RsJson& jVal ) +template +bool RsTypeSerializer::from_JSON( + const std::string& membername, + t_RsGenericIdType& member, + RsJson& jVal ) { const char* mName = membername.c_str(); bool ret = jVal.HasMember(mName); @@ -975,7 +981,9 @@ bool RsTypeSerializer::from_JSON( const std::string& membername, { rapidjson::Value& v = jVal[mName]; ret = ret && v.IsString(); - if(ret) member = t_RsGenericIdType(std::string(v.GetString())); + if(ret) member = + t_RsGenericIdType( + std::string(v.GetString()) ); } return ret; } diff --git a/libretroshare/src/services/autoproxy/rsautoproxymonitor.cc b/libretroshare/src/services/autoproxy/rsautoproxymonitor.cc index aef160590..d198bd207 100644 --- a/libretroshare/src/services/autoproxy/rsautoproxymonitor.cc +++ b/libretroshare/src/services/autoproxy/rsautoproxymonitor.cc @@ -258,6 +258,7 @@ void rsAutoProxyMonitor::taskDone(taskTicket *t, autoProxyStatus::autoProxyStatu if (cleanUp) { if (t->data) { std::cerr << "(WW) rsAutoProxyMonitor::taskFinish will try to delete void pointer!" << std::endl; +#pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdelete-incomplete" delete t->data; #pragma GCC diagnostic pop @@ -290,6 +291,7 @@ void rsAutoProxyMonitor::taskFinished(taskTicket *&ticket) // clean up if (ticket->data) { std::cerr << "rsAutoProxyMonitor::taskFinished data set. Will try to delete void pointer" << std::endl; +#pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdelete-incomplete" delete ticket->data; #pragma GCC diagnostic pop diff --git a/libretroshare/src/services/broadcastdiscoveryservice.cc b/libretroshare/src/services/broadcastdiscoveryservice.cc new file mode 100644 index 000000000..bbcaa307d --- /dev/null +++ b/libretroshare/src/services/broadcastdiscoveryservice.cc @@ -0,0 +1,204 @@ +/******************************************************************************* + * RetroShare Broadcast Domain Discovery * + * * + * Copyright (C) 2019 Gioacchino Mazzurco * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "services/broadcastdiscoveryservice.h" +#include "retroshare/rspeers.h" +#include "serialiser/rsserializable.h" +#include "serialiser/rsserializer.h" +#include "retroshare/rsevents.h" + +/*extern*/ std::shared_ptr rsBroadcastDiscovery(nullptr); +RsBroadcastDiscovery::~RsBroadcastDiscovery() { /* Beware of Rs prefix! */ } +RsBroadcastDiscoveryResult::~RsBroadcastDiscoveryResult() {} +RsBroadcastDiscoveryPeerFoundEvent::~RsBroadcastDiscoveryPeerFoundEvent() {} + +struct BroadcastDiscoveryPack : RsSerializable +{ + BroadcastDiscoveryPack() : mLocalPort(0) {} + + RsPeerId mSslId; + uint16_t mLocalPort; + std::string mProfileName; + + void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) override + { + RS_SERIAL_PROCESS(mSslId); + RS_SERIAL_PROCESS(mLocalPort); + RS_SERIAL_PROCESS(mProfileName); + } + + static BroadcastDiscoveryPack fromPeerDetails(const RsPeerDetails& pd) + { + BroadcastDiscoveryPack bdp; + bdp.mSslId = pd.id; + bdp.mLocalPort = pd.localPort; + bdp.mProfileName = pd.name; + return bdp; + } + + static BroadcastDiscoveryPack fromSerializedString(const std::string& st) + { + RsGenericSerializer::SerializeContext ctx( + reinterpret_cast(const_cast(st.data())), + static_cast(st.size()) ); + BroadcastDiscoveryPack bdp; + bdp.serial_process(RsGenericSerializer::DESERIALIZE, ctx); + return bdp; + } + + std::string serializeToString() + { + /* After some experiments it seems very unlikely that UDP broadcast + * packets bigger then this could get trought a network */ + std::vector buffer(512, 0); + RsGenericSerializer::SerializeContext ctx( + buffer.data(), static_cast(buffer.size()) ); + serial_process(RsGenericSerializer::SERIALIZE, ctx); + return std::string(reinterpret_cast(buffer.data()), ctx.mOffset); + } + + BroadcastDiscoveryPack(const BroadcastDiscoveryPack&) = default; + ~BroadcastDiscoveryPack() override; +}; + +BroadcastDiscoveryPack::~BroadcastDiscoveryPack() {}; + +BroadcastDiscoveryService::BroadcastDiscoveryService( + RsPeers& pRsPeers ) : + mDiscoveredDataMutex("BroadcastDiscoveryService discovered data mutex"), + mRsPeers(pRsPeers) +{ + if(mRsPeers.isHiddenNode(mRsPeers.getOwnId())) return; + + mUdcParameters.set_can_discover(true); + mUdcParameters.set_can_be_discovered(true); + mUdcParameters.set_port(port); + mUdcParameters.set_application_id(appId); + + mUdcPeer.Start(mUdcParameters, ""); + updatePublishedData(); +} + +BroadcastDiscoveryService::~BroadcastDiscoveryService() +{ mUdcPeer.Stop(true); } + +std::vector +BroadcastDiscoveryService::getDiscoveredPeers() +{ + std::vector ret; + + RS_STACK_MUTEX(mDiscoveredDataMutex); + for(auto&& pp: mDiscoveredData) + ret.push_back(createResult(pp.first, pp.second)); + + return ret; +} + +void BroadcastDiscoveryService::updatePublishedData() +{ + RsPeerDetails od; + mRsPeers.getPeerDetails(mRsPeers.getOwnId(), od); + mUdcPeer.SetUserData( + BroadcastDiscoveryPack::fromPeerDetails(od).serializeToString()); +} + +void BroadcastDiscoveryService::data_tick() +{ + auto nextRunAt = std::chrono::system_clock::now() + std::chrono::seconds(5); + + if( mUdcParameters.can_discover() && + !mRsPeers.isHiddenNode(mRsPeers.getOwnId()) ) + { + auto currentEndpoints = mUdcPeer.ListDiscovered(); + std::map currentMap; + std::map updateMap; + + mDiscoveredDataMutex.lock(); + for(auto&& dEndpoint: currentEndpoints) + { + currentMap[dEndpoint.ip_port()] = dEndpoint.user_data(); + + auto findIt = mDiscoveredData.find(dEndpoint.ip_port()); + if( !dEndpoint.user_data().empty() && ( + findIt == mDiscoveredData.end() || + findIt->second != dEndpoint.user_data() ) ) + updateMap[dEndpoint.ip_port()] = dEndpoint.user_data(); + } + mDiscoveredData = currentMap; + mDiscoveredDataMutex.unlock(); + + if(!updateMap.empty()) + { + for (auto&& pp : updateMap) + { + RsBroadcastDiscoveryResult rbdr = + createResult(pp.first, pp.second); + + const bool isFriend = mRsPeers.isFriend(rbdr.mSslId); + if( isFriend && rbdr.mLocator.hasPort() && + !mRsPeers.isOnline(rbdr.mSslId) ) + { + mRsPeers.setLocalAddress( + rbdr.mSslId, rbdr.mLocator.host(), + rbdr.mLocator.port() ); + mRsPeers.connectAttempt(rbdr.mSslId); + } + else if(!isFriend) + { + typedef RsBroadcastDiscoveryPeerFoundEvent Evt_t; + if(rsEvents) + rsEvents->postEvent( + std::shared_ptr(new Evt_t(rbdr)) ); + } + } + } + } + + /* Probably this would be better if done only on actual change */ + if( mUdcParameters.can_be_discovered() && + !mRsPeers.isHiddenNode(mRsPeers.getOwnId()) ) updatePublishedData(); + + std::this_thread::sleep_until(nextRunAt); +} + +RsBroadcastDiscoveryResult BroadcastDiscoveryService::createResult( + const udpdiscovery::IpPort& ipp, const std::string& uData ) +{ + BroadcastDiscoveryPack bdp = + BroadcastDiscoveryPack::fromSerializedString(uData); + + RsBroadcastDiscoveryResult rbdr; + rbdr.mSslId = bdp.mSslId; + rbdr.mProfileName = bdp.mProfileName; + rbdr.mLocator. + setScheme("ipv4"). + setHost(UDC::IpToString(ipp.ip())). + setPort(bdp.mLocalPort); + + return rbdr; +} diff --git a/libretroshare/src/services/broadcastdiscoveryservice.h b/libretroshare/src/services/broadcastdiscoveryservice.h new file mode 100644 index 000000000..17129c995 --- /dev/null +++ b/libretroshare/src/services/broadcastdiscoveryservice.h @@ -0,0 +1,66 @@ +/******************************************************************************* + * RetroShare Broadcast Domain Discovery * + * * + * Copyright (C) 2019 Gioacchino Mazzurco * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ +#pragma once + +#include +#include +#include +#include +#include + +#include + +#include "retroshare/rsbroadcastdiscovery.h" +#include "util/rsthreads.h" + +namespace UDC = udpdiscovery; +class RsPeers; + +class BroadcastDiscoveryService : + public RsBroadcastDiscovery, public RsTickingThread +{ +public: + // TODO: std::shared_ptr mRsPeers; + BroadcastDiscoveryService(RsPeers& pRsPeers); + virtual ~BroadcastDiscoveryService() override; + + /// @see RsBroadcastDiscovery + std::vector getDiscoveredPeers() override; + + /// @see RsTickingThread + void data_tick() override; + +protected: + constexpr static uint16_t port = 36405; + constexpr static uint32_t appId = 904571; + + void updatePublishedData(); + + UDC::PeerParameters mUdcParameters; + UDC::Peer mUdcPeer; + + std::map mDiscoveredData; + RsMutex mDiscoveredDataMutex; + + RsPeers& mRsPeers; // TODO: std::shared_ptr mRsPeers; + + RsBroadcastDiscoveryResult createResult( + const UDC::IpPort& ipp, const std::string& uData ); +}; diff --git a/libretroshare/src/services/p3banlist.cc b/libretroshare/src/services/p3banlist.cc index f55343889..a257d2772 100644 --- a/libretroshare/src/services/p3banlist.cc +++ b/libretroshare/src/services/p3banlist.cc @@ -62,7 +62,7 @@ p3BanList::p3BanList(p3ServiceControl *sc, p3NetMgr */*nm*/) : p3Service(), mBanMtx("p3BanList"), mServiceCtrl(sc) , mSentListTime(0), mLastDhtInfoRequest(0) // default number of IPs in same range to trigger a complete IP /24 filter. - , mAutoRangeLimit(100), mAutoRangeIps(false) + , mAutoRangeLimit(2), mAutoRangeIps(true) , mIPFilteringEnabled(true) , mIPFriendGatheringEnabled(false) , mIPDHTGatheringEnabled(false) @@ -306,15 +306,23 @@ bool p3BanList::acceptedBanRanges_locked(const BanListPeer& blp) } return false ; } -bool p3BanList::isAddressAccepted(const sockaddr_storage &dAddr, uint32_t checking_flags,uint32_t *check_result) + +bool p3BanList::isAddressAccepted( + const sockaddr_storage& dAddr, uint32_t checking_flags, + uint32_t& check_result ) { + check_result = RSBANLIST_CHECK_RESULT_NOCHECK; + sockaddr_storage addr; sockaddr_storage_copy(dAddr, addr); - if(!mIPFilteringEnabled) return true; - if(check_result != NULL) *check_result = RSBANLIST_CHECK_RESULT_NOCHECK; if(!sockaddr_storage_ipv6_to_ipv4(addr)) return true; if(sockaddr_storage_isLoopbackNet(addr)) return true; + + RS_STACK_MUTEX(mBanMtx); + + if(!mIPFilteringEnabled) return true; + #ifdef DEBUG_BANLIST std::cerr << "isAddressAccepted(): tested addr=" << sockaddr_storage_iptostring(addr) << ", checking flags=" << checking_flags ; #endif @@ -332,9 +340,8 @@ bool p3BanList::isAddressAccepted(const sockaddr_storage &dAddr, uint32_t checki white_list_found = white_list_found || (mWhiteListedRanges.find(addr_32) != mWhiteListedRanges.end()) ; if(white_list_found) - { - if(check_result != NULL) - *check_result = RSBANLIST_CHECK_RESULT_ACCEPTED ; + { + check_result = RSBANLIST_CHECK_RESULT_ACCEPTED; #ifdef DEBUG_BANLIST std::cerr << ". Address is in whitelist. Accepting" << std::endl; #endif @@ -342,9 +349,8 @@ bool p3BanList::isAddressAccepted(const sockaddr_storage &dAddr, uint32_t checki } if(checking_flags & RSBANLIST_CHECKING_FLAGS_WHITELIST) - { - if(check_result != NULL) - *check_result = RSBANLIST_CHECK_RESULT_NOT_WHITELISTED ; + { + check_result = RSBANLIST_CHECK_RESULT_NOT_WHITELISTED; #ifdef DEBUG_BANLIST std::cerr << ". Address is not whitelist, and whitelist is required. Rejecting" << std::endl; #endif @@ -356,8 +362,7 @@ bool p3BanList::isAddressAccepted(const sockaddr_storage &dAddr, uint32_t checki #ifdef DEBUG_BANLIST std::cerr << ". No blacklisting required. Accepting." << std::endl; #endif - if(check_result != NULL) - *check_result = RSBANLIST_CHECK_RESULT_ACCEPTED ; + check_result = RSBANLIST_CHECK_RESULT_ACCEPTED; return true; } @@ -369,8 +374,7 @@ bool p3BanList::isAddressAccepted(const sockaddr_storage &dAddr, uint32_t checki #ifdef DEBUG_BANLIST std::cerr << " found in blacklisted range " << sockaddr_storage_iptostring(it->first) << "/16. returning false. attempts=" << it->second.connect_attempts << std::endl; #endif - if(check_result != NULL) - *check_result = RSBANLIST_CHECK_RESULT_BLACKLISTED ; + check_result = RSBANLIST_CHECK_RESULT_BLACKLISTED; return false ; } @@ -380,8 +384,7 @@ bool p3BanList::isAddressAccepted(const sockaddr_storage &dAddr, uint32_t checki #ifdef DEBUG_BANLIST std::cerr << " found in blacklisted range " << sockaddr_storage_iptostring(it->first) << "/24. returning false. attempts=" << it->second.connect_attempts << std::endl; #endif - if(check_result != NULL) - *check_result = RSBANLIST_CHECK_RESULT_BLACKLISTED ; + check_result = RSBANLIST_CHECK_RESULT_BLACKLISTED; return false ; } @@ -391,8 +394,7 @@ bool p3BanList::isAddressAccepted(const sockaddr_storage &dAddr, uint32_t checki #ifdef DEBUG_BANLIST std::cerr << " found in blacklisted range " << sockaddr_storage_iptostring(it->first) << "/32. returning false. attempts=" << it->second.connect_attempts << std::endl; #endif - if(check_result != NULL) - *check_result = RSBANLIST_CHECK_RESULT_BLACKLISTED ; + check_result = RSBANLIST_CHECK_RESULT_BLACKLISTED; return false ; } @@ -402,18 +404,17 @@ bool p3BanList::isAddressAccepted(const sockaddr_storage &dAddr, uint32_t checki #ifdef DEBUG_BANLIST std::cerr << "found as blacklisted address " << sockaddr_storage_iptostring(it->first) << ". returning false. attempts=" << it->second.connect_attempts << std::endl; #endif - if(check_result != NULL) - *check_result = RSBANLIST_CHECK_RESULT_BLACKLISTED ; + check_result = RSBANLIST_CHECK_RESULT_BLACKLISTED; return false ; } #ifdef DEBUG_BANLIST std::cerr << " not blacklisted. Accepting." << std::endl; #endif - if(check_result != NULL) - *check_result = RSBANLIST_CHECK_RESULT_ACCEPTED ; + check_result = RSBANLIST_CHECK_RESULT_ACCEPTED; return true ; } + void p3BanList::getWhiteListedIps(std::list &lst) { RS_STACK_MUTEX(mBanMtx) ; @@ -587,11 +588,6 @@ int p3BanList::tick() return 0; } -int p3BanList::status() -{ - return 1; -} - void p3BanList::getDhtInfo() { // Get the list of masquerading peers from the DHT. Add them as potential IPs to be banned. @@ -1202,7 +1198,7 @@ void p3BanList::sendBanLists() } } - +// Send all manually banned ranges to friends int p3BanList::sendBanSet(const RsPeerId& peerid) { @@ -1304,4 +1300,4 @@ int p3BanList::printBanSources_locked(std::ostream &out) return true ; } - +RsBanList::~RsBanList() = default; diff --git a/libretroshare/src/services/p3banlist.h b/libretroshare/src/services/p3banlist.h index eac722cda..b61b7cb71 100644 --- a/libretroshare/src/services/p3banlist.h +++ b/libretroshare/src/services/p3banlist.h @@ -56,9 +56,11 @@ public: /***** overloaded from RsBanList *****/ - virtual bool isAddressAccepted( const sockaddr_storage& addr, - uint32_t checking_flags, - uint32_t *check_result=NULL ); + /// @see RsBanList + virtual bool isAddressAccepted( + const sockaddr_storage& addr, uint32_t checking_flags, + uint32_t& check_result = RS_DEFAULT_STORAGE_PARAM(uint32_t) + ) override; virtual void getBannedIps(std::list& list) ; virtual void getWhiteListedIps(std::list& list) ; @@ -103,7 +105,6 @@ public: */ virtual int tick(); - virtual int status(); int sendPackets(); bool processIncoming(); diff --git a/libretroshare/src/services/p3discovery2.h b/libretroshare/src/services/p3discovery2.h deleted file mode 100644 index 5a88f9e92..000000000 --- a/libretroshare/src/services/p3discovery2.h +++ /dev/null @@ -1,153 +0,0 @@ -/******************************************************************************* - * libretroshare/src/services: p3discovery2.h * - * * - * libretroshare: retroshare core library * - * * - * Copyright 2004-2013 Robert Fernie * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License as * - * published by the Free Software Foundation, either version 3 of the * - * License, or (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public License * - * along with this program. If not, see . * - * * - *******************************************************************************/ -#ifndef MRK_SERVICES_DISCOVERY2_H -#define MRK_SERVICES_DISCOVERY2_H - -// Discovery2: Improved discovery service. - -#include "retroshare/rsdisc.h" - -#include "pqi/p3peermgr.h" -#include "pqi/p3linkmgr.h" -#include "pqi/p3netmgr.h" - -#include "pqi/pqiservicemonitor.h" -#include "rsitems/rsdiscovery2items.h" -#include "services/p3service.h" -#include "pqi/authgpg.h" -#include "gxs/rsgixs.h" - -class p3ServiceControl; - - -typedef RsPgpId PGPID; -typedef RsPeerId SSLID; - -class DiscSslInfo -{ - public: - DiscSslInfo() { mDiscStatus = 0; } - uint16_t mDiscStatus; -}; - -class DiscPeerInfo -{ - public: - DiscPeerInfo() {} - - std::string mVersion; - //uint32_t mStatus; -}; - -class DiscPgpInfo -{ - public: - DiscPgpInfo() {} - -void mergeFriendList(const std::set &friends); - - //PGPID mPgpId; - std::set mFriendSet; - std::map mSslIds; -}; - - - -class p3discovery2: public RsDisc, public p3Service, public pqiServiceMonitor, public AuthGPGService -{ - public: - - p3discovery2(p3PeerMgr *peerMgr, p3LinkMgr *linkMgr, p3NetMgr *netMgr, p3ServiceControl *sc,RsGixs *gixs); -virtual ~p3discovery2(); - -virtual RsServiceInfo getServiceInfo(); - - /************* from pqiServiceMonitor *******************/ - virtual void statusChange(const std::list &plist); - /************* from pqiServiceMonitor *******************/ - - int tick(); - - /* external interface */ - bool getDiscFriends(const RsPeerId &id, std::list &friends); - bool getDiscPgpFriends(const RsPgpId &pgpid, std::list &gpg_friends); - bool getPeerVersion(const RsPeerId &id, std::string &version); - bool getWaitingDiscCount(size_t &sendCount, size_t &recvCount); - /************* from AuthGPService ****************/ -virtual AuthGPGOperation *getGPGOperation(); -virtual void setGPGOperation(AuthGPGOperation *operation); - - - private: - - PGPID getPGPId(const SSLID &id); - - int handleIncoming(); - void updatePgpFriendList(); - - void addFriend(const SSLID &sslId); - void removeFriend(const SSLID &sslId); - - void updatePeerAddresses(const RsDiscContactItem *item); - void updatePeerAddressList(const RsDiscContactItem *item); - - void sendOwnContactInfo(const SSLID &sslid); - void recvOwnContactInfo(const SSLID &fromId, const RsDiscContactItem *item); - - void sendPGPList(const SSLID &toId); - void processPGPList(const SSLID &fromId, const RsDiscPgpListItem *item); - - void processContactInfo(const SSLID &fromId, const RsDiscContactItem *info); - - void requestPGPCertificate(const PGPID &aboutId, const SSLID &toId); - void recvPGPCertificateRequest(const SSLID &fromId, const RsDiscPgpListItem *item); - void sendPGPCertificate(const PGPID &aboutId, const SSLID &toId); - void recvPGPCertificate(const SSLID &fromId, RsDiscPgpCertItem *item); - void recvIdentityList(const RsPeerId& pid,const std::list& ids); - - bool setPeerVersion(const SSLID &peerId, const std::string &version); - - private: - - p3PeerMgr *mPeerMgr; - p3LinkMgr *mLinkMgr; - p3NetMgr *mNetMgr; - p3ServiceControl *mServiceCtrl; - RsGixs *mGixs ; - - /* data */ - RsMutex mDiscMtx; - - void updatePeers_locked(const SSLID &aboutId); - void sendContactInfo_locked(const PGPID &aboutId, const SSLID &toId); - - rstime_t mLastPgpUpdate; - - std::map mFriendList; - std::map mLocationMap; - - std::list mPendingDiscPgpCertInList; - std::list mPendingDiscPgpCertOutList; -}; - - -#endif // MRK_SERVICES_DISCOVERY2_H diff --git a/libretroshare/src/services/p3gxschannels.cc b/libretroshare/src/services/p3gxschannels.cc index 367023cad..f09f4d98c 100644 --- a/libretroshare/src/services/p3gxschannels.cc +++ b/libretroshare/src/services/p3gxschannels.cc @@ -1433,13 +1433,15 @@ bool p3GxsChannels::createPostV2( return false; } -bool p3GxsChannels::createCommentV2(const RsGxsGroupId& channelId, - const RsGxsMessageId& threadId, - const RsGxsMessageId& parentId, - const RsGxsId& authorId, - const std::string& comment, - RsGxsMessageId& commentMessageId, - std::string& errorMessage) +bool p3GxsChannels::createCommentV2( + const RsGxsGroupId& channelId, + const RsGxsMessageId& threadId, + const std::string& comment, + const RsGxsId& authorId, + const RsGxsMessageId& parentId, + const RsGxsMessageId& origCommentId, + RsGxsMessageId& commentMessageId, + std::string& errorMessage ) { std::vector channelsInfo; if(!getChannelsInfo(std::list({channelId}),channelsInfo)) @@ -1476,6 +1478,7 @@ bool p3GxsChannels::createCommentV2(const RsGxsGroupId& channelId, } if(!parentId.isNull()) + { if(!getChannelContent( // does the post thread exist? channelId,std::set({parentId}),posts,comments )) { @@ -1485,17 +1488,50 @@ bool p3GxsChannels::createCommentV2(const RsGxsGroupId& channelId, << std::endl; return false; } - else if(comments.size() != 1 || comments[0].mMeta.mParentId.isNull()) - { // is the comment parent actually a comment? - errorMessage = "You cannot comment post " + parentId.toStdString() - + " of channel with Id " + channelId.toStdString() + - ": supplied mParentMsgId is not a comment Id!"; - std::cerr << __PRETTY_FUNCTION__ << " Error: " << errorMessage - << std::endl; + else + { + if(comments.size() != 1 || comments[0].mMeta.mParentId.isNull()) + { // is the comment parent actually a comment? + errorMessage = "You cannot comment post " + + parentId.toStdString() + + " of channel with Id " + channelId.toStdString() + + ": supplied mParentMsgId is not a comment Id!"; + std::cerr << __PRETTY_FUNCTION__ << " Error: " << errorMessage + << std::endl; + return false; + } + } + } + + if(!origCommentId.isNull()) + { + std::set s({origCommentId}); + std::vector posts; + std::vector comments; + + if( !getChannelContent(channelId, s, posts, comments) || + comments.size() != 1 ) + { + errorMessage = "You cannot edit comment " + + origCommentId.toStdString() + + " of channel with Id " + channelId.toStdString() + + ": this post does not exist locally!"; + RsErr() << __PRETTY_FUNCTION__ << " " << errorMessage << std::endl; return false; } - if(!rsIdentity->isOwnId(authorId)) // is the voter ID actually ours? + const RsGxsId& commentAuthor = comments[0].mMeta.mAuthorId; + if(commentAuthor != authorId) + { + errorMessage = "Editor identity and creator doesn't match " + + authorId.toStdString() + " != " + + commentAuthor.toStdString(); + RsErr() << __PRETTY_FUNCTION__ << " " << errorMessage << std::endl; + return false; + } + } + + if(!rsIdentity->isOwnId(authorId)) // is the author ID actually ours? { errorMessage = "You cannot comment to channel with Id " + channelId.toStdString() + " with identity " + @@ -1511,6 +1547,7 @@ bool p3GxsChannels::createCommentV2(const RsGxsGroupId& channelId, cmt.mMeta.mThreadId = threadId; cmt.mMeta.mParentId = parentId; cmt.mMeta.mAuthorId = authorId; + cmt.mMeta.mOrigMsgId = origCommentId; cmt.mComment = comment; uint32_t token; @@ -1852,12 +1889,8 @@ bool p3GxsChannels::ExtraFileHash(const std::string& path) } -bool p3GxsChannels::ExtraFileRemove(const RsFileHash &hash) -{ - //TransferRequestFlags tflags = RS_FILE_REQ_ANONYMOUS_ROUTING | RS_FILE_REQ_EXTRA; - RsFileHash fh = RsFileHash(hash); - return rsFiles->ExtraFileRemove(fh); -} +bool p3GxsChannels::ExtraFileRemove(const RsFileHash& hash) +{ return rsFiles->ExtraFileRemove(hash); } /********************************************************************************************/ diff --git a/libretroshare/src/services/p3gxschannels.h b/libretroshare/src/services/p3gxschannels.h index dffc73c32..766049624 100644 --- a/libretroshare/src/services/p3gxschannels.h +++ b/libretroshare/src/services/p3gxschannels.h @@ -28,7 +28,7 @@ #include "gxs/rsgenexchange.h" #include "gxs/gxstokenqueue.h" #include "util/rsmemory.h" - +#include "util/rsdebug.h" #include "util/rstickevent.h" #include @@ -213,11 +213,14 @@ virtual bool ExtraFileRemove(const RsFileHash &hash); /// Implementation of @see RsGxsChannels::createComment virtual bool createCommentV2( - const RsGxsGroupId& channelId, const RsGxsMessageId& threadId, - const RsGxsMessageId& parentId, const RsGxsId& authorId, + const RsGxsGroupId& channelId, + const RsGxsMessageId& threadId, const std::string& comment, - RsGxsMessageId& commentMessageId = RS_DEFAULT_STORAGE_PARAM(RsGxsMessageId), - std::string& errorMessage = RS_DEFAULT_STORAGE_PARAM(std::string) + const RsGxsId& authorId, + const RsGxsMessageId& parentId = RsGxsMessageId(), + const RsGxsMessageId& origCommentId = RsGxsMessageId(), + RsGxsMessageId& commentMessageId = RS_DEFAULT_STORAGE_PARAM(RsGxsMessageId), + std::string& errorMessage = RS_DEFAULT_STORAGE_PARAM(std::string) ) override; /// Implementation of @see RsGxsChannels::editChannel diff --git a/libretroshare/src/services/p3gxscircles.cc b/libretroshare/src/services/p3gxscircles.cc index ed5dc74ff..3087fe4c6 100644 --- a/libretroshare/src/services/p3gxscircles.cc +++ b/libretroshare/src/services/p3gxscircles.cc @@ -3,7 +3,8 @@ * * * libretroshare: retroshare core library * * * - * Copyright 2012-2012 Robert Fernie * + * Copyright (C) 2012-2014 Robert Fernie * + * Copyright (C) 2018-2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -27,7 +28,7 @@ #include "util/rsdir.h" #include "util/radix64.h" #include "util/rsstring.h" - +#include "util/rsdebug.h" #include "pgp/pgpauxutils.h" #include "retroshare/rsgxscircles.h" #include "retroshare/rspeers.h" @@ -40,7 +41,7 @@ * #define DEBUG_CIRCLES 1 ****/ -RsGxsCircles *rsGxsCircles = NULL; +/*extern*/ RsGxsCircles* rsGxsCircles = nullptr; /****** * @@ -153,8 +154,76 @@ RsServiceInfo p3GxsCircles::getServiceInfo() GXS_CIRCLES_MIN_MINOR_VERSION); } -bool p3GxsCircles::createCircle(RsGxsCircleGroup& cData) +bool p3GxsCircles::createCircle( + const std::string& circleName, RsGxsCircleType circleType, + RsGxsCircleId& circleId, const RsGxsCircleId& restrictedId, + const RsGxsId& authorId, const std::set& gxsIdMembers, + const std::set& localMembers ) { + if(circleName.empty()) + { + RsErr() << __PRETTY_FUNCTION__ << " Circle name is empty" << std::endl; + return false; + } + + switch(circleType) + { + case RsGxsCircleType::PUBLIC: + if(!restrictedId.isNull()) + { + RsErr() << __PRETTY_FUNCTION__ << " restrictedId: " << restrictedId + << " must be null with RsGxsCircleType::PUBLIC" + << std::endl; + return false; + } + break; + case RsGxsCircleType::EXTERNAL: + if(restrictedId.isNull()) + { + RsErr() << __PRETTY_FUNCTION__ << " restrictedId can't be null " + << "with RsGxsCircleType::EXTERNAL" << std::endl; + return false; + } + break; + case RsGxsCircleType::NODES_GROUP: + if(localMembers.empty()) + { + RsErr() << __PRETTY_FUNCTION__ << " localMembers can't be empty " + << "with RsGxsCircleType::NODES_GROUP" << std::endl; + return false; + } + break; + case RsGxsCircleType::LOCAL: + break; + case RsGxsCircleType::EXT_SELF: + if(!restrictedId.isNull()) + { + RsErr() << __PRETTY_FUNCTION__ << " restrictedId: " << restrictedId + << " must be null with RsGxsCircleType::EXT_SELF" + << std::endl; + return false; + } + if(gxsIdMembers.empty()) + { + RsErr() << __PRETTY_FUNCTION__ << " gxsIdMembers can't be empty " + << "with RsGxsCircleType::EXT_SELF" << std::endl; + return false; + } + break; + case RsGxsCircleType::YOUR_EYES_ONLY: + break; + default: + RsErr() << __PRETTY_FUNCTION__ << " Invalid circle type: " + << static_cast(circleType) << std::endl; + return false; + } + + RsGxsCircleGroup cData; + cData.mMeta.mGroupName = circleName; + cData.mMeta.mAuthorId = authorId; + cData.mMeta.mCircleType = static_cast(circleType); + cData.mMeta.mGroupFlags = GXS_SERV::FLAG_PRIVACY_PUBLIC; + uint32_t token; createGroup(token, cData); @@ -172,8 +241,9 @@ bool p3GxsCircles::createCircle(RsGxsCircleGroup& cData) return false; } + circleId = static_cast(cData.mMeta.mGroupId); return true; -} +}; bool p3GxsCircles::editCircle(RsGxsCircleGroup& cData) { @@ -1858,47 +1928,6 @@ void p3GxsCircles::generateDummyCircle() createGroup(dummyToken, group); } - -/************************************************************************************/ -/************************************************************************************/ -/************************************************************************************/ -/************************************************************************************/ - - -std::ostream &operator<<(std::ostream &out, const RsGxsCircleGroup &grp) -{ - out << "RsGxsCircleGroup: Meta: " << grp.mMeta; - out << "InvitedMembers: "; - out << std::endl; - - std::set::const_iterator it; - std::set::const_iterator sit; - for(it = grp.mInvitedMembers.begin(); - it != grp.mInvitedMembers.begin(); ++it) - { - out << "\t" << *it; - out << std::endl; - } - - for(sit = grp.mSubCircles.begin(); - sit != grp.mSubCircles.begin(); ++sit) - { - out << "\t" << *it; - out << std::endl; - } - return out; -} - -std::ostream &operator<<(std::ostream &out, const RsGxsCircleMsg &msg) -{ - out << "RsGxsCircleMsg: Meta: " << msg.mMeta; - out << std::endl; - - return out; -} - - - // Overloaded from GxsTokenQueue for Request callbacks. void p3GxsCircles::handleResponse(uint32_t token, uint32_t req_type) { @@ -1921,22 +1950,13 @@ void p3GxsCircles::handleResponse(uint32_t token, uint32_t req_type) case CIRCLEREQ_CACHELOAD: cache_load_for_token(token); break; - -#if 0 - case CIRCLEREQ_CACHETEST: - cachetest_handlerequest(token); - break; -#endif - - default: - /* error */ - std::cerr << "p3GxsCircles::handleResponse() Unknown Request Type: " << req_type; - std::cerr << std::endl; - break; + default: + RsErr() << __PRETTY_FUNCTION__ << " Unknown Request Type: " + << req_type << std::endl; + break; } } - // Overloaded from RsTickEvent for Event callbacks. void p3GxsCircles::handle_event(uint32_t event_type, const std::string &elabel) { @@ -1960,14 +1980,7 @@ void p3GxsCircles::handle_event(uint32_t event_type, const std::string &elabel) cache_reloadids(RsGxsCircleId(elabel)); break; -#if 0 - case CIRCLE_EVENT_CACHETEST: - cachetest_getlist(); - break; -#endif - - - case CIRCLE_EVENT_DUMMYSTART: + case CIRCLE_EVENT_DUMMYSTART: generateDummyData(); break; @@ -1979,11 +1992,10 @@ void p3GxsCircles::handle_event(uint32_t event_type, const std::string &elabel) generateDummyCircle(); break; - default: - /* error */ - std::cerr << "p3GxsCircles::handle_event() Unknown Event Type: " << event_type; - std::cerr << std::endl; - break; + default: + RsErr() << __PRETTY_FUNCTION__ << " Unknown Event Type: " << event_type + << std::endl; + break; } } @@ -2215,3 +2227,8 @@ bool p3GxsCircles::processMembershipRequests(uint32_t token) return true ; } + +RsGxsCircles::~RsGxsCircles() = default; +RsGxsCircleMsg::~RsGxsCircleMsg() = default; +RsGxsCircleDetails::~RsGxsCircleDetails() = default; +RsGxsCircleGroup::~RsGxsCircleGroup() = default; diff --git a/libretroshare/src/services/p3gxscircles.h b/libretroshare/src/services/p3gxscircles.h index a23ecbd88..48129a9ba 100644 --- a/libretroshare/src/services/p3gxscircles.h +++ b/libretroshare/src/services/p3gxscircles.h @@ -3,7 +3,8 @@ * * * libretroshare: retroshare core library * * * - * Copyright 2012-2012 Robert Fernie * + * Copyright (C) 2012-2014 Robert Fernie * + * Copyright (C) 2018-2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -19,8 +20,7 @@ * along with this program. If not, see . * * * *******************************************************************************/ -#ifndef P3_CIRCLES_SERVICE_HEADER -#define P3_CIRCLES_SERVICE_HEADER +#pragma once #include "retroshare/rsgxscircles.h" // External Interfaces. @@ -180,7 +180,14 @@ virtual RsServiceInfo getServiceInfo(); /*********** External Interface ***************/ /// @see RsGxsCircles - bool createCircle(RsGxsCircleGroup& cData) override; + bool createCircle( + const std::string& circleName, RsGxsCircleType circleType, + RsGxsCircleId& circleId = RS_DEFAULT_STORAGE_PARAM(RsGxsCircleId), + const RsGxsCircleId& restrictedId = RsGxsCircleId(), + const RsGxsId& authorId = RsGxsId(), + const std::set& gxsIdMembers = std::set(), + const std::set& localMembers = std::set() + ) override; /// @see RsGxsCircles bool editCircle(RsGxsCircleGroup& cData) override; @@ -315,5 +322,3 @@ virtual RsServiceInfo getServiceInfo(); std::list mDummyPgpLinkedIds; std::list mDummyOwnIds; }; - -#endif // P3_CIRCLES_SERVICE_HEADER diff --git a/libretroshare/src/services/p3gxsforums.cc b/libretroshare/src/services/p3gxsforums.cc index 07f91e33f..787ea22e1 100644 --- a/libretroshare/src/services/p3gxsforums.cc +++ b/libretroshare/src/services/p3gxsforums.cc @@ -3,7 +3,8 @@ * * * libretroshare: retroshare core library * * * - * Copyright 2012-2012 Robert Fernie * + * Copyright (C) 2012-2014 Robert Fernie * + * Copyright (C) 2018-2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -21,8 +22,8 @@ *******************************************************************************/ #include "services/p3gxsforums.h" #include "rsitems/rsgxsforumitems.h" - -#include +#include "retroshare/rspeers.h" +#include "retroshare/rsidentity.h" #include "rsserver/p3face.h" #include "retroshare/rsnotify.h" @@ -384,6 +385,165 @@ bool p3GxsForums::getMsgData(const uint32_t &token, std::vector & /********************************************************************************************/ +bool p3GxsForums::createForumV2( + const std::string& name, const std::string& description, + const RsGxsId& authorId, const std::set& moderatorsIds, + RsGxsCircleType circleType, const RsGxsCircleId& circleId, + RsGxsGroupId& forumId, std::string& errorMessage ) +{ + auto createFail = [&](std::string mErr) + { + errorMessage = mErr; + RsErr() << __PRETTY_FUNCTION__ << " " << errorMessage << std::endl; + return false; + }; + + if(name.empty()) return createFail("Forum name is required"); + + if(!authorId.isNull() && !rsIdentity->isOwnId(authorId)) + return createFail("Author must be iether null or and identity owned by " + "this node"); + + switch(circleType) + { + case RsGxsCircleType::PUBLIC: // fallthrough + case RsGxsCircleType::LOCAL: // fallthrough + case RsGxsCircleType::YOUR_EYES_ONLY: + break; + case RsGxsCircleType::EXTERNAL: + if(circleId.isNull()) + return createFail("circleType is EXTERNAL but circleId is null"); + break; + case RsGxsCircleType::NODES_GROUP: + { + RsGroupInfo ginfo; + if(!rsPeers->getGroupInfo(RsNodeGroupId(circleId), ginfo)) + return createFail("circleType is NODES_GROUP but circleId does not " + "correspond to an actual group of friends"); + break; + } + default: return createFail("circleType has invalid value"); + } + + // Create a consistent channel group meta from the information supplied + RsGxsForumGroup forum; + + forum.mMeta.mGroupName = name; + forum.mMeta.mAuthorId = authorId; + forum.mMeta.mCircleType = static_cast(circleType); + + forum.mMeta.mSignFlags = GXS_SERV::FLAG_GROUP_SIGN_PUBLISH_NONEREQ + | GXS_SERV::FLAG_AUTHOR_AUTHENTICATION_REQUIRED; + + forum.mMeta.mGroupFlags = GXS_SERV::FLAG_PRIVACY_PUBLIC; + + forum.mMeta.mCircleId.clear(); + forum.mMeta.mInternalCircle.clear(); + + switch(circleType) + { + case RsGxsCircleType::NODES_GROUP: + forum.mMeta.mInternalCircle = circleId; break; + case RsGxsCircleType::EXTERNAL: + forum.mMeta.mCircleId = circleId; break; + default: break; + } + + forum.mDescription = description; + forum.mAdminList.ids = moderatorsIds; + + uint32_t token; + if(!createGroup(token, forum)) + return createFail("Failed creating GXS group."); + + // wait for the group creation to complete. + RsTokenService::GxsRequestStatus wSt = + waitToken( token, std::chrono::milliseconds(5000), + std::chrono::milliseconds(20) ); + if(wSt != RsTokenService::COMPLETE) + return createFail( "GXS operation waitToken failed with: " + + std::to_string(wSt) ); + + if(!RsGenExchange::getPublishedGroupMeta(token, forum.mMeta)) + return createFail("Failure getting updated group data."); + + forumId = forum.mMeta.mGroupId; + + return true; +} + +bool p3GxsForums::createPost( + const RsGxsGroupId& forumId, const std::string& title, + const std::string& mBody, + const RsGxsId& authorId, const RsGxsMessageId& parentId, + const RsGxsMessageId& origPostId, RsGxsMessageId& postMsgId, + std::string& errorMessage ) +{ + RsGxsForumMsg post; + + auto failure = [&](std::string errMsg) + { + errorMessage = errMsg; + RsErr() << __PRETTY_FUNCTION__ << " " << errorMessage << std::endl; + return false; + }; + + if(title.empty()) return failure("Title is required"); + + if(authorId.isNull()) return failure("Author id is needed"); + + if(!rsIdentity->isOwnId(authorId)) + return failure( "Author id: " + authorId.toStdString() + " is not of" + "own identity" ); + + if(!parentId.isNull()) + { + std::vector msgs; + if( getForumContent(forumId, std::set({parentId}), msgs) + && msgs.size() == 1 ) + { + post.mMeta.mParentId = parentId; + post.mMeta.mThreadId = msgs[0].mMeta.mThreadId; + } + else return failure("Parent post " + parentId.toStdString() + + " doesn't exists locally"); + } + + std::vector forumInfo; + if(!getForumsInfo(std::list({forumId}), forumInfo)) + return failure( "Forum with Id " + forumId.toStdString() + + " does not exist locally." ); + + if(!origPostId.isNull()) + { + std::vector msgs; + if( getForumContent( forumId, + std::set({origPostId}), msgs) + && msgs.size() == 1 ) + post.mMeta.mOrigMsgId = origPostId; + else return failure("Original post " + origPostId.toStdString() + + " doesn't exists locally"); + } + + post.mMeta.mGroupId = forumId; + post.mMeta.mMsgName = title; + post.mMeta.mAuthorId = authorId; + post.mMsg = mBody; + + uint32_t token; + if( !createMsg(token, post) + || waitToken( + token, + std::chrono::milliseconds(5000) ) != RsTokenService::COMPLETE ) + return failure("Failure creating GXS message"); + + if(!RsGenExchange::getPublishedMsgMeta(token, post.mMeta)) + return failure("Failure getting created GXS message metadata"); + + postMsgId = post.mMeta.mMsgId; + return true; +} + bool p3GxsForums::createForum(RsGxsForumGroup& forum) { uint32_t token; @@ -461,8 +621,9 @@ bool p3GxsForums::getForumsInfo( } bool p3GxsForums::getForumContent( - const RsGxsGroupId& forumId, std::set& msgs_to_request, - std::vector& msgs ) + const RsGxsGroupId& forumId, + const std::set& msgs_to_request, + std::vector& msgs ) { uint32_t token; RsTokReqOptions opts; @@ -813,3 +974,37 @@ void p3GxsForums::handle_event(uint32_t event_type, const std::string &/*elabel* break; } } + +void RsGxsForumGroup::serial_process( + RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) +{ + RS_SERIAL_PROCESS(mMeta); + RS_SERIAL_PROCESS(mDescription); + + /* Work around to have usable JSON API, without breaking binary + * serialization retrocompatibility */ + switch (j) + { + case RsGenericSerializer::TO_JSON: // fallthrough + case RsGenericSerializer::FROM_JSON: + RsTypeSerializer::serial_process( j, ctx, + mAdminList.ids, "mAdminList" ); + RsTypeSerializer::serial_process( j, ctx, + mPinnedPosts.ids, "mPinnedPosts" ); + break; + default: + RS_SERIAL_PROCESS(mAdminList); + RS_SERIAL_PROCESS(mPinnedPosts); + } +} + +bool RsGxsForumGroup::canEditPosts(const RsGxsId& id) const +{ + return mAdminList.ids.find(id) != mAdminList.ids.end() || + id == mMeta.mAuthorId; +} + +RsGxsForumGroup::~RsGxsForumGroup() = default; +RsGxsForumMsg::~RsGxsForumMsg() = default; +RsGxsForums::~RsGxsForums() = default; diff --git a/libretroshare/src/services/p3gxsforums.h b/libretroshare/src/services/p3gxsforums.h index 5b08efd6b..910daff8d 100644 --- a/libretroshare/src/services/p3gxsforums.h +++ b/libretroshare/src/services/p3gxsforums.h @@ -3,7 +3,8 @@ * * * libretroshare: retroshare core library * * * - * Copyright 2012-2012 Robert Fernie * + * Copyright (C) 2012-2014 Robert Fernie * + * Copyright (C) 2018-2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -19,21 +20,17 @@ * along with this program. If not, see . * * * *******************************************************************************/ -#ifndef P3_GXSFORUMS_SERVICE_HEADER -#define P3_GXSFORUMS_SERVICE_HEADER - - -#include "retroshare/rsgxsforums.h" -#include "gxs/rsgenexchange.h" - -#include "util/rstickevent.h" +#pragma once #include #include -/* - * - */ +#include "retroshare/rsgxsforums.h" +#include "gxs/rsgenexchange.h" +#include "retroshare/rsgxscircles.h" +#include "util/rstickevent.h" +#include "util/rsdebug.h" + class p3GxsForums: public RsGenExchange, public RsGxsForums, public p3Config, public RsTickEvent /* only needed for testing - remove after */ @@ -55,14 +52,39 @@ protected: virtual bool loadList(std::list& loadList); // @see p3Config::loadList(std::list&) public: - /// @see RsGxsForums::createForum + /// @see RsGxsForums::createForumV2 + bool createForumV2( + const std::string& name, const std::string& description, + const RsGxsId& authorId = RsGxsId(), + const std::set& moderatorsIds = std::set(), + RsGxsCircleType circleType = RsGxsCircleType::PUBLIC, + const RsGxsCircleId& circleId = RsGxsCircleId(), + RsGxsGroupId& forumId = RS_DEFAULT_STORAGE_PARAM(RsGxsGroupId), + std::string& errorMessage = RS_DEFAULT_STORAGE_PARAM(std::string) + ) override; + + /// @see RsGxsForums::createPost + bool createPost( + const RsGxsGroupId& forumId, + const std::string& title, + const std::string& mBody, + const RsGxsId& authorId, + const RsGxsMessageId& parentId = RsGxsMessageId(), + const RsGxsMessageId& origPostId = RsGxsMessageId(), + RsGxsMessageId& postMsgId = RS_DEFAULT_STORAGE_PARAM(RsGxsMessageId), + std::string& errorMessage = RS_DEFAULT_STORAGE_PARAM(std::string) + ) override; + + /// @see RsGxsForums::createForum @deprecated + RS_DEPRECATED_FOR(createForumV2) virtual bool createForum(RsGxsForumGroup& forum); - /// @see RsGxsForums::createMessage + /// @see RsGxsForums::createMessage @deprecated + RS_DEPRECATED_FOR(createPost) virtual bool createMessage(RsGxsForumMsg& message); /// @see RsGxsForums::editForum - virtual bool editForum(RsGxsForumGroup& forum); + virtual bool editForum(RsGxsForumGroup& forum) override; /// @see RsGxsForums::getForumsSummaries virtual bool getForumsSummaries(std::list& forums); @@ -78,7 +100,7 @@ public: /// @see RsGxsForums::getForumContent virtual bool getForumContent( const RsGxsGroupId& forumId, - std::set& msgs_to_request, + const std::set& msgs_to_request, std::vector& msgs ); /// @see RsGxsForums::markRead @@ -130,5 +152,3 @@ bool generateGroup(uint32_t &token, std::string groupName); std::map mKnownForums ; }; - -#endif diff --git a/libretroshare/src/services/p3idservice.cc b/libretroshare/src/services/p3idservice.cc index e6f820b89..95adf0b96 100644 --- a/libretroshare/src/services/p3idservice.cc +++ b/libretroshare/src/services/p3idservice.cc @@ -1,10 +1,8 @@ /******************************************************************************* * libretroshare/src/services: p3idservice.cc * * * - * libretroshare: retroshare core library * - * * - * Copyright 2012-2012 Robert Fernie * - * Copyright (C) 2018 Gioacchino Mazzurco * + * Copyright (C) 2012-2014 Robert Fernie * + * Copyright (C) 2017-2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -20,8 +18,14 @@ * along with this program. If not, see . * * * *******************************************************************************/ + +/// RetroShare GXS identities service + + #include #include +#include +#include #include "services/p3idservice.h" #include "pgp/pgpauxutils.h" @@ -36,15 +40,9 @@ #include "crypto/hashstream.h" #include "gxs/gxssecurity.h" #include "retroshare/rspeers.h" +#include "retroshare/rsnotify.h" -//#include "pqi/authgpg.h" - -//#include - -#include -#include - /**** * #define DEBUG_IDS 1 * #define DEBUG_RECOGN 1 @@ -71,7 +69,7 @@ static const uint32_t MAX_DELAY_BEFORE_CLEANING= 1800 ; // clean old keys eve static const uint32_t MAX_SERIALISED_IDENTITY_AGE = 600 ; // after 10 mins, a serialised identity record must be renewed. -RsIdentity *rsIdentity = NULL; +RsIdentity* rsIdentity = nullptr; /****** * Some notes: @@ -757,7 +755,7 @@ bool p3IdService::isOwnId(const RsGxsId& id) } -bool p3IdService::getOwnSignedIds(std::vector ids) +bool p3IdService::getOwnSignedIds(std::vector& ids) { ids.clear(); @@ -769,27 +767,29 @@ bool p3IdService::getOwnSignedIds(std::vector ids) if(ownIdsAreLoaded()) { RS_STACK_MUTEX(mIdMtx); - ids.reserve(mOwnSignedIds.size()); - ids.insert(ids.end(), mOwnSignedIds.begin(), mOwnSignedIds.end()); + ids.resize(mOwnSignedIds.size()); + std::copy(mOwnSignedIds.begin(), mOwnSignedIds.end(), ids.begin()); return true; } return false; } -bool p3IdService::getOwnPseudonimousIds(std::vector ids) +bool p3IdService::getOwnPseudonimousIds(std::vector& ids) { ids.clear(); std::vector signedV; // this implicitely ensure ids are already loaded ;) if(!getOwnSignedIds(signedV)) return false; + std::set signedS(signedV.begin(), signedV.end()); { RS_STACK_MUTEX(mIdMtx); - std::copy_if(mOwnIds.begin(), mOwnIds.end(), ids.end(), - [&](const RsGxsId& id) {return !signedS.count(id);}); + ids.resize(mOwnIds.size() - signedV.size()); + std::copy_if( mOwnIds.begin(), mOwnIds.end(), ids.begin(), + [&](const RsGxsId& id) {return !signedS.count(id);} ); } return true; @@ -908,40 +908,80 @@ bool p3IdService::createIdentity( const std::string& name, const RsGxsImage& avatar, bool pseudonimous, const std::string& pgpPassword) { - if(!pgpPassword.empty()) - std::cerr<< __PRETTY_FUNCTION__ << " Warning! PGP Password handling " - << "not implemented yet!" << std::endl; - + bool ret = true; RsIdentityParameters params; + uint32_t token = 0; + RsGroupMetaData meta; + RsTokenService::GxsRequestStatus wtStatus = RsTokenService::CANCELLED; + + if(!pseudonimous && !pgpPassword.empty()) + { + if(!rsNotify->cachePgpPassphrase(pgpPassword)) + { + RsErr() << __PRETTY_FUNCTION__ << " Failure caching password" + << std::endl; + ret = false; + goto LabelCreateIdentityCleanup; + } + + if(!rsNotify->setDisableAskPassword(true)) + { + RsErr() << __PRETTY_FUNCTION__ << " Failure disabling password user" + << " request" << std::endl; + ret = false; + goto LabelCreateIdentityCleanup; + } + } + params.isPgpLinked = !pseudonimous; params.nickname = name; params.mImage = avatar; - uint32_t token; if(!createIdentity(token, params)) { - std::cerr << __PRETTY_FUNCTION__ << " Error! Failed creating group." - << std::endl; - return false; + RsErr() << __PRETTY_FUNCTION__ << " Failed creating GXS group." + << std::endl; + ret = false; + goto LabelCreateIdentityCleanup; } - if(waitToken(token) != RsTokenService::COMPLETE) + /* Use custom timeout for waitToken because creating identities involves + * creating multiple signatures, which can take a lot of time expecially on + * slow hardware like phones or embedded devices */ + if( (wtStatus = waitToken( + token, std::chrono::seconds(10), std::chrono::milliseconds(20) )) + != RsTokenService::COMPLETE ) { - std::cerr << __PRETTY_FUNCTION__ << " Error! GXS operation failed." - << std::endl; - return false; + RsErr() << __PRETTY_FUNCTION__ << " waitToken("<< token + << ") failed with: " << wtStatus << std::endl; + ret = false; + goto LabelCreateIdentityCleanup; } - RsGroupMetaData meta; if(!RsGenExchange::getPublishedGroupMeta(token, meta)) { - std::cerr << __PRETTY_FUNCTION__ << "Error! Failure getting updated " - << " group data." << std::endl; - return false; + RsErr() << __PRETTY_FUNCTION__ << " Failure getting updated group data." + << std::endl; + ret = false; + goto LabelCreateIdentityCleanup; } id = RsGxsId(meta.mGroupId); - return true; + + { + RS_STACK_MUTEX(mIdMtx); + mOwnIds.push_back(id); + if(!pseudonimous) mOwnSignedIds.push_back(id); + } + +LabelCreateIdentityCleanup: + if(!pseudonimous && !pgpPassword.empty()) + { + rsNotify->setDisableAskPassword(false); + rsNotify->clearPgpPassphrase(); + } + + return ret; } bool p3IdService::createIdentity(uint32_t& token, RsIdentityParameters ¶ms) @@ -1151,6 +1191,16 @@ static void mergeIds(std::map >& idmap,const RsGxsId old_peers.push_back(*it) ; } +bool p3IdService::requestIdentity(const RsGxsId& id) +{ + RsIdentityUsage usageInfo( RsServiceType::GXSID, + RsIdentityUsage::IDENTITY_DATA_UPDATE ); + std::list onlinePeers; + + return rsPeers && rsPeers->getOnlineList(onlinePeers) + && requestKey(id, onlinePeers, usageInfo); +} + bool p3IdService::requestKey(const RsGxsId &id, const std::list& peers,const RsIdentityUsage& use_info) { if(id.isNull()) @@ -2991,7 +3041,7 @@ bool p3IdService::cache_request_ownids() RsGenExchange::getTokenService()->requestGroupInfo(token, ansType, opts); GxsTokenQueue::queueRequest(token, GXSIDREQ_CACHEOWNIDS); - return 1; + return true; } @@ -3297,13 +3347,10 @@ static void calcPGPHash(const RsGxsId &id, const PGPFingerprintType &pgp, Sha1Ch // Must Use meta. -RsGenExchange::ServiceCreate_Return p3IdService::service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet& keySet) +RsGenExchange::ServiceCreate_Return p3IdService::service_CreateGroup( + RsGxsGrpItem* grpItem, RsTlvSecurityKeySet& keySet ) { - -#ifdef DEBUG_IDS - std::cerr << "p3IdService::service_CreateGroup()"; - std::cerr << std::endl; -#endif // DEBUG_IDS + Dbg2() << __PRETTY_FUNCTION__ << std::endl; RsGxsIdGroupItem *item = dynamic_cast(grpItem); if (!item) @@ -3313,30 +3360,23 @@ RsGenExchange::ServiceCreate_Return p3IdService::service_CreateGroup(RsGxsGrpIte return SERVICE_CREATE_FAIL; } -#ifdef DEBUG_IDS - std::cerr << "p3IdService::service_CreateGroup() Item is:"; - std::cerr << std::endl; - item->print(std::cerr); - std::cerr << std::endl; -#endif // DEBUG_IDS - item->meta.mGroupId.clear(); /********************* TEMP HACK UNTIL GXS FILLS IN GROUP_ID *****************/ - // find private admin key - for(std::map::iterator mit = keySet.private_keys.begin();mit != keySet.private_keys.end(); ++mit) - if(mit->second.keyFlags == (RSTLV_KEY_DISTRIB_ADMIN | RSTLV_KEY_TYPE_FULL)) + // find private admin key + for( std::map::iterator mit = + keySet.private_keys.begin(); mit != keySet.private_keys.end(); ++mit ) + if(mit->second.keyFlags == (RSTLV_KEY_DISTRIB_ADMIN | RSTLV_KEY_TYPE_FULL)) { item->meta.mGroupId = RsGxsGroupId(mit->second.keyId); break; } - if(item->meta.mGroupId.isNull()) - { - std::cerr << "p3IdService::service_CreateGroup() ERROR no admin key"; - std::cerr << std::endl; - return SERVICE_CREATE_FAIL; - } + if(item->meta.mGroupId.isNull()) + { + RsErr() << __PRETTY_FUNCTION__ << " missing admin key!" << std::endl; + return SERVICE_CREATE_FAIL; + } mKeysTS[RsGxsId(item->meta.mGroupId)].TS = time(NULL) ; /********************* TEMP HACK UNTIL GXS FILLS IN GROUP_ID *****************/ @@ -3384,8 +3424,7 @@ RsGenExchange::ServiceCreate_Return p3IdService::service_CreateGroup(RsGxsGrpIte /* create the hash */ Sha1CheckSum hash; - /* */ - PGPFingerprintType ownFinger; + RsPgpFingerprint ownFinger; RsPgpId ownId(mPgpUtils->getPGPOwnId()); #ifdef DEBUG_IDS @@ -3400,12 +3439,12 @@ RsGenExchange::ServiceCreate_Return p3IdService::service_CreateGroup(RsGxsGrpIte // } #endif - if (!mPgpUtils->getKeyFingerprint(ownId,ownFinger)) - { - std::cerr << "p3IdService::service_CreateGroup() ERROR Own Finger is stuck"; - std::cerr << std::endl; - return SERVICE_CREATE_FAIL; // abandon attempt! - } + if(!mPgpUtils->getKeyFingerprint(ownId,ownFinger)) + { + RsErr() << __PRETTY_FUNCTION__ + << " failure retriving own PGP fingerprint" << std::endl; + return SERVICE_CREATE_FAIL; // abandon attempt! + } #ifdef DEBUG_IDS std::cerr << "p3IdService::service_CreateGroup() OwnFingerprint: " << ownFinger.toStdString(); @@ -3427,60 +3466,69 @@ RsGenExchange::ServiceCreate_Return p3IdService::service_CreateGroup(RsGxsGrpIte #define MAX_SIGN_SIZE 2048 uint8_t signarray[MAX_SIGN_SIZE]; - unsigned int sign_size = MAX_SIGN_SIZE; - int result ; - + unsigned int sign_size = MAX_SIGN_SIZE; memset(signarray,0,MAX_SIGN_SIZE) ; // just in case. - mPgpUtils->askForDeferredSelfSignature((void *) hash.toByteArray(), hash.SIZE_IN_BYTES, signarray, &sign_size,result, "p3IdService::service_CreateGroup()") ; + /* -10 is never returned by askForDeferredSelfSignature therefore we can + * use it to properly detect and handle the case libretroshare is being + * used outside retroshare-gui */ + int result = -10; - /* error */ - switch(result) - { - case SELF_SIGNATURE_RESULT_PENDING : createStatus = SERVICE_CREATE_FAIL_TRY_LATER; - std::cerr << "p3IdService::service_CreateGroup() signature still pending" << std::endl; - break ; - default: - case SELF_SIGNATURE_RESULT_FAILED: return SERVICE_CREATE_FAIL ; - std::cerr << "p3IdService::service_CreateGroup() signature failed" << std::endl; - break ; + /* This method is DEPRECATED we call it only for retrocompatibility with + * retroshare-gui, when called from something different then + * retroshare-gui for example retroshare-service it miserably fail! */ + mPgpUtils->askForDeferredSelfSignature( + static_cast(hash.toByteArray()), + hash.SIZE_IN_BYTES, signarray, &sign_size, result, + __PRETTY_FUNCTION__ ); - case SELF_SIGNATURE_RESULT_SUCCESS: - { - // Additional consistency checks. + /* If askForDeferredSelfSignature left result untouched it means + * libretroshare is being used by something different then + * retroshare-gui so try calling AuthGPG::getAuthGPG()->SignDataBin + * directly */ + if( result == -10 ) + result = AuthGPG::getAuthGPG()->SignDataBin( + static_cast(hash.toByteArray()), + hash.SIZE_IN_BYTES, signarray, &sign_size, + __PRETTY_FUNCTION__ ) + ? + SELF_SIGNATURE_RESULT_SUCCESS : + SELF_SIGNATURE_RESULT_FAILED; - if(sign_size == MAX_SIGN_SIZE) - { - std::cerr << "Inconsistent result. Signature uses full buffer. This is probably an error." << std::endl; - return SERVICE_CREATE_FAIL; // abandon attempt! - } -#ifdef DEBUG_IDS - std::cerr << "p3IdService::service_CreateGroup() Signature: "; - std::string strout; -#endif - /* push binary into string -> really bad! */ - item->mPgpIdSign = ""; - for(unsigned int i = 0; i < sign_size; i++) - { -#ifdef DEBUG_IDS - rs_sprintf_append(strout, "%02x", (uint32_t) signarray[i]); -#endif - item->mPgpIdSign += signarray[i]; - } - createStatus = SERVICE_CREATE_SUCCESS; + switch(result) + { + case SELF_SIGNATURE_RESULT_PENDING: + createStatus = SERVICE_CREATE_FAIL_TRY_LATER; + Dbg1() << __PRETTY_FUNCTION__ << " signature still pending" + << std::endl; + break; + case SELF_SIGNATURE_RESULT_SUCCESS: + { + // Additional consistency checks. + if(sign_size == MAX_SIGN_SIZE) + { + RsErr() << __PRETTY_FUNCTION__ << "Inconsistent result. " + << "Signature uses full buffer. This is probably an " + << "error." << std::endl; + return SERVICE_CREATE_FAIL; + } -#ifdef DEBUG_IDS - std::cerr << strout; - std::cerr << std::endl; -#endif - } - } - /* done! */ - } - else - { - createStatus = SERVICE_CREATE_SUCCESS; - } + /* push binary into string -> really bad! */ + item->mPgpIdSign = ""; + for(unsigned int i = 0; i < sign_size; i++) + item->mPgpIdSign += static_cast(signarray[i]); + + createStatus = SERVICE_CREATE_SUCCESS; + break; + } + case SELF_SIGNATURE_RESULT_FAILED: /* fall-through */ + default: + RsErr() << __PRETTY_FUNCTION__ << " signature failed with: " + << result << std::endl; + return SERVICE_CREATE_FAIL; + } + } + else createStatus = SERVICE_CREATE_SUCCESS; // Enforce no AuthorId. item->meta.mAuthorId.clear() ; @@ -3491,17 +3539,18 @@ RsGenExchange::ServiceCreate_Return p3IdService::service_CreateGroup(RsGxsGrpIte // do it like p3gxscircles: save the new grp id // this allows the user interface // to see the grp id on the list of ownIds immediately after the group was created - { - RsStackMutex stack(mIdMtx); + { + RS_STACK_MUTEX(mIdMtx); RsGxsId gxsId(item->meta.mGroupId); if (std::find(mOwnIds.begin(), mOwnIds.end(), gxsId) == mOwnIds.end()) { - mOwnIds.push_back(gxsId); - mKeysTS[gxsId].TS = time(NULL) ; + mOwnIds.push_back(gxsId); + mKeysTS[gxsId].TS = time(nullptr); } } - return createStatus; + Dbg2() << __PRETTY_FUNCTION__ << " returns: " << createStatus << std::endl; + return createStatus; } @@ -4542,65 +4591,6 @@ std::string rsIdTypeToString(uint32_t idtype) * */ - -/************************************************************************************/ -/* - * Scoring system. - * -100 to 100 is expected range. - * - * - * Each Lobby has a publish threshold. - * - As part of Lobby definition. ??? - * - Locally Set. - * - * Threshold: - * 50 VIP List. - * 20 Dress Code - * 10 Limit Riffraff. - * 0 Accept All. - * - * Implicit Scores: - * +50 for known PGP - * +10 for unknown PGP (want to encourage usage). - * +5 for Anon ID. - * - * Own Scores: - * +1000 Accepted - * +50 Friend - * +10 Interesting - * 0 Mostly Harmless - * -10 Annoying. - * -50 Troll - * -1000 Total Banned - * - * - * - - - -Processing Algorithm: - * - Grab all Groups which have received messages. - * (opt 1)-> grab latest msgs for each of these and process => score. - * (opt 2)-> try incremental system (people probably won't change opinions often -> just set them once) - * --> if not possible, fallback to full calculation. - * - * - */ - - - - -std::ostream &operator<<(std::ostream &out, const RsGxsIdGroup &grp) -{ - out << "RsGxsIdGroup: Meta: " << grp.mMeta; - out << " PgpIdHash: " << grp.mPgpIdHash; - out << " PgpIdSign: [binary]"; // << grp.mPgpIdSign; - out << std::endl; - - return out; -} - - void p3IdService::checkPeerForIdentities() { RsStackMutex stack(mIdMtx); @@ -4737,12 +4727,34 @@ void RsGxsIdGroup::serial_process( RS_SERIAL_PROCESS(mReputation); } +RsIdentityUsage::RsIdentityUsage( + RsServiceType service, RsIdentityUsage::UsageCode code, + const RsGxsGroupId& gid, const RsGxsMessageId& mid, + uint64_t additional_id, const std::string& comment ) : + mServiceId(service), mUsageCode(code), mGrpId(gid), mMsgId(mid), + mAdditionalId(additional_id), mComment(comment) +{ + /* This is a hack, since it will hash also mHash, but because it is + * initialized to 0, and only computed in the constructor here, it should + * be ok. */ + librs::crypto::HashStream hs(librs::crypto::HashStream::SHA1); + + hs << static_cast(service); // G10h4ck: Why uint32 if it's 16 bits? + hs << static_cast(code); + hs << gid; + hs << mid; + hs << static_cast(additional_id); + hs << comment; + + mHash = hs.hash(); +} + RsIdentityUsage::RsIdentityUsage( uint16_t service, const RsIdentityUsage::UsageCode& code, const RsGxsGroupId& gid, const RsGxsMessageId& mid, uint64_t additional_id,const std::string& comment ) : - mServiceId(service), mUsageCode(code), mGrpId(gid), mMsgId(mid), - mAdditionalId(additional_id), mComment(comment) + mServiceId(static_cast(service)), mUsageCode(code), + mGrpId(gid), mMsgId(mid), mAdditionalId(additional_id), mComment(comment) { #ifdef DEBUG_IDS std::cerr << "New identity usage: " << std::endl; @@ -4759,7 +4771,7 @@ RsIdentityUsage::RsIdentityUsage( * be ok. */ librs::crypto::HashStream hs(librs::crypto::HashStream::SHA1) ; - hs << (uint32_t)service ; + hs << (uint32_t)service ; // G10h4ck: Why uint32 if it's 16 bits? hs << (uint8_t)code ; hs << gid ; hs << mid ; @@ -4774,4 +4786,5 @@ RsIdentityUsage::RsIdentityUsage( } RsIdentityUsage::RsIdentityUsage() : - mServiceId(0), mUsageCode(UNKNOWN_USAGE), mAdditionalId(0) {} + mServiceId(RsServiceType::NONE), mUsageCode(UNKNOWN_USAGE), mAdditionalId(0) +{} diff --git a/libretroshare/src/services/p3idservice.h b/libretroshare/src/services/p3idservice.h index f585804a9..4e22698b6 100644 --- a/libretroshare/src/services/p3idservice.h +++ b/libretroshare/src/services/p3idservice.h @@ -1,9 +1,8 @@ /******************************************************************************* * libretroshare/src/services: p3idservice.h * * * - * libretroshare: retroshare core library * - * * - * Copyright 2012-2012 Robert Fernie * + * Copyright (C) 2012-2014 Robert Fernie * + * Copyright (C) 2017-2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -19,51 +18,28 @@ * along with this program. If not, see . * * * *******************************************************************************/ -#ifndef P3_IDENTITY_SERVICE_HEADER -#define P3_IDENTITY_SERVICE_HEADER +#pragma once +/// RetroShare GXS identities service -#include "retroshare/rsidentity.h" // External Interfaces. -#include "gxs/rsgenexchange.h" // GXS service. -#include "gxs/rsgixs.h" // Internal Interfaces. - -#include "gxs/gxstokenqueue.h" -#include "rsitems/rsgxsiditems.h" #include #include +#include "retroshare/rsidentity.h" // External Interfaces. +#include "gxs/rsgenexchange.h" // GXS service. +#include "gxs/rsgixs.h" // Internal Interfaces. +#include "util/rsdebug.h" +#include "gxs/gxstokenqueue.h" +#include "rsitems/rsgxsiditems.h" #include "util/rsmemcache.h" #include "util/rstickevent.h" #include "util/rsrecogn.h" - #include "pqi/authgpg.h" - #include "rsitems/rsgxsrecognitems.h" class PgpAuxUtils; -/* - * Identity Service - * - */ - -#if 0 -class GxsReputation -{ - public: - GxsReputation(); - - bool updateIdScore(bool pgpLinked, bool pgpKnown); - bool update(); // checks ranges and calculates overall score. - int mOverallScore; - int mIdScore; // PGP, Known, etc. - int mOwnOpinion; - int mPeerOpinion; -}; - -#endif - class OpinionRequest { public: @@ -312,10 +288,10 @@ public: /**************** RsGixs Implementation ***************/ /// @see RsIdentity - bool getOwnSignedIds(std::vector ids) override; + bool getOwnSignedIds(std::vector& ids) override; /// @see RsIdentity - bool getOwnPseudonimousIds(std::vector ids) override; + bool getOwnPseudonimousIds(std::vector& ids) override; virtual bool getOwnIds(std::list &ownIds, bool signed_only = false); @@ -392,6 +368,9 @@ public: virtual bool deserialiseIdentityFromMemory(const std::string& radix_string, RsGxsId* id = nullptr); + /// @see RsIdentity + bool requestIdentity(const RsGxsId& id) override; + /**************** RsGixsReputation Implementation ****************/ // get Reputation. @@ -641,9 +620,6 @@ private: bool mAutoAddFriendsIdentitiesAsContacts; uint32_t mMaxKeepKeysBanned ; + + RS_SET_CONTEXT_DEBUG_LEVEL(1) }; - -#endif // P3_IDENTITY_SERVICE_HEADER - - - diff --git a/libretroshare/src/services/rseventsservice.cc b/libretroshare/src/services/rseventsservice.cc new file mode 100644 index 000000000..b970e26e7 --- /dev/null +++ b/libretroshare/src/services/rseventsservice.cc @@ -0,0 +1,177 @@ +/******************************************************************************* + * Retroshare events service * + * * + * libretroshare: retroshare core library * + * * + * Copyright (C) 2019 Gioacchino Mazzurco * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +#include + +#include "services/rseventsservice.h" + + +/*extern*/ RsEvents* rsEvents = nullptr; +RsEvent::~RsEvent() {}; +RsEvents::~RsEvents() {}; + +bool isEventValid( + std::shared_ptr event, std::string& errorMessage ) +{ + if(!event) + { + errorMessage = "Event is null!"; + return false; + } + + if(event->mType <= RsEventType::NONE) + { + errorMessage = "Event has type NONE: " + + std::to_string( + static_cast::type >( + event->mType ) ); + return false; + } + + if(event->mType >= RsEventType::MAX) + { + errorMessage = "Event has type >= RsEventType::MAX: " + + std::to_string( + static_cast::type >( + event->mType ) ); + } + + return true; +} + +bool RsEventsService::postEvent( std::shared_ptr event, + std::string& errorMessage ) +{ + if(!isEventValid(event, errorMessage)) + { + std::cerr << __PRETTY_FUNCTION__ << " Error: "<< errorMessage + << std::endl; + return false; + } + + RS_STACK_MUTEX(mEventQueueMtx); + mEventQueue.push_back(event); + return true; +} + +bool RsEventsService::sendEvent( std::shared_ptr event, + std::string& errorMessage ) +{ + if(!isEventValid(event, errorMessage)) + { + RsErr() << __PRETTY_FUNCTION__ << " "<< errorMessage << std::endl; + return false; + } + + handleEvent(event); + return true; +} + +RsEventsHandlerId_t RsEventsService::generateUniqueHandlerId() +{ + RS_STACK_MUTEX(mHandlerMapMtx); + return generateUniqueHandlerId_unlocked(); +} + +RsEventsHandlerId_t RsEventsService::generateUniqueHandlerId_unlocked() +{ + if(++mLastHandlerId) return mLastHandlerId; // Avoid 0 after overflow + return 1; +} + +bool RsEventsService::registerEventsHandler( + std::function)> multiCallback, + RsEventsHandlerId_t& hId ) +{ + RS_STACK_MUTEX(mHandlerMapMtx); + if(!hId) hId = generateUniqueHandlerId_unlocked(); + mHandlerMap[hId] = multiCallback; + return true; +} + +bool RsEventsService::unregisterEventsHandler(RsEventsHandlerId_t hId) +{ + RS_STACK_MUTEX(mHandlerMapMtx); + auto it = mHandlerMap.find(hId); + if(it == mHandlerMap.end()) return false; + mHandlerMap.erase(it); + return true; +} + +void RsEventsService::data_tick() +{ + auto nextRunAt = std::chrono::system_clock::now() + + std::chrono::milliseconds(1); + + std::shared_ptr eventPtr(nullptr); + size_t futureEventsCounter = 0; + +dispatchEventFromQueueLock: + mEventQueueMtx.lock(); + if(mEventQueue.size() > futureEventsCounter) + { + eventPtr = mEventQueue.front(); + mEventQueue.pop_front(); + + if(eventPtr->mTimePoint >= nextRunAt) + { + mEventQueue.push_back(eventPtr); + ++futureEventsCounter; + } + } + mEventQueueMtx.unlock(); + + if(eventPtr) + { + /* It is relevant that this stays out of mEventQueueMtx */ + handleEvent(eventPtr); + eventPtr = nullptr; // ensure refcounter is decremented before sleep + goto dispatchEventFromQueueLock; + } + + std::this_thread::sleep_until(nextRunAt); +} + +void RsEventsService::handleEvent(std::shared_ptr event) +{ + std::function)> mCallback; + + mHandlerMapMtx.lock(); + auto cbpt = mHandlerMap.begin(); + mHandlerMapMtx.unlock(); + +getHandlerFromMapLock: + mHandlerMapMtx.lock(); + if(cbpt != mHandlerMap.end()) + { + mCallback = cbpt->second; + ++cbpt; + } + mHandlerMapMtx.unlock(); + + if(mCallback) + { + mCallback(event); // It is relevant that this happens outside mutex + mCallback = std::function)>(nullptr); + goto getHandlerFromMapLock; + } +} diff --git a/libretroshare/src/services/rseventsservice.h b/libretroshare/src/services/rseventsservice.h new file mode 100644 index 000000000..05fff772e --- /dev/null +++ b/libretroshare/src/services/rseventsservice.h @@ -0,0 +1,81 @@ +/******************************************************************************* + * Retroshare events service * + * * + * libretroshare: retroshare core library * + * * + * Copyright (C) 2019 Gioacchino Mazzurco * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ +#pragma once + +#include +#include +#include + +#include "retroshare/rsevents.h" +#include "util/rsthreads.h" +#include "util/rsdebug.h" + +class RsEventsService : + public RsEvents, public RsTickingThread +{ +public: + RsEventsService(): + mHandlerMapMtx("RsEventsService::mHandlerMapMtx"), mLastHandlerId(1), + mEventQueueMtx("RsEventsService::mEventQueueMtx") {} + + /// @see RsEvents + bool postEvent( + std::shared_ptr event, + std::string& errorMessage = RS_DEFAULT_STORAGE_PARAM(std::string) + ) override; + + /// @see RsEvents + bool sendEvent( + std::shared_ptr event, + std::string& errorMessage = RS_DEFAULT_STORAGE_PARAM(std::string) + ) override; + + /// @see RsEvents + RsEventsHandlerId_t generateUniqueHandlerId() override; + + /// @see RsEvents + bool registerEventsHandler( + std::function)> multiCallback, + RsEventsHandlerId_t& hId = RS_DEFAULT_STORAGE_PARAM(RsEventsHandlerId_t, 0) + ) override; + + /// @see RsEvents + bool unregisterEventsHandler(RsEventsHandlerId_t hId) override; + +protected: + RsMutex mHandlerMapMtx; + RsEventsHandlerId_t mLastHandlerId; + std::map< + RsEventsHandlerId_t, + std::function)> > mHandlerMap; + + RsMutex mEventQueueMtx; + std::deque< std::shared_ptr > mEventQueue; + + /// @see RsTickingThread + void data_tick() override; + + void handleEvent(std::shared_ptr event); + RsEventsHandlerId_t generateUniqueHandlerId_unlocked(); + + RS_SET_CONTEXT_DEBUG_LEVEL(3) +}; diff --git a/libretroshare/src/tcponudp/bss_tou.c b/libretroshare/src/tcponudp/bss_tou.cc similarity index 79% rename from libretroshare/src/tcponudp/bss_tou.c rename to libretroshare/src/tcponudp/bss_tou.cc index 5a4b53983..b5b4693aa 100644 --- a/libretroshare/src/tcponudp/bss_tou.c +++ b/libretroshare/src/tcponudp/bss_tou.cc @@ -3,8 +3,9 @@ * * * libretroshare: retroshare core library * * * - * Copyright 2004-2006 by Robert Fernie * - * Copyright 1995-1998 Eric Young (eay@cryptsoft.com) * + * Copyright (C) 1995-1998 Eric Young * + * Copyright (C) 2004-2006 Robert Fernie * + * Copyright (C) 2018-2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -25,19 +26,17 @@ #include "bio_tou.h" -// STUFF defined in the header....... -//int BIO_tou_socket_should_retry(int s, int e); -//int BIO_tou_socket_non_fatal_error(int error); -//#define BIO_TYPE_TOU_SOCKET (30|0x0400|0x0100) /* NEW rmfern type */ -//BIO_METHOD *BIO_s_tou_socket(void); - #include #include -#define USE_SOCKETS -//#include "cryptlib.h" -#include #include /* for strlen() */ +#define USE_SOCKETS +#include + +#include "tou.h" +#include "util/rsdebug.h" + +RS_SET_CONTEXT_DEBUG_LEVEL(0); static int tou_socket_write(BIO *h, const char *buf, int num); static int tou_socket_read(BIO *h, char *buf, int size); @@ -48,13 +47,12 @@ static int tou_socket_free(BIO *data); static int get_last_tou_socket_error(int s); static int clear_tou_socket_error(int s); -#include "tou.h" - #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) static int BIO_get_init(BIO *a) { return a->init; } -#if (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000) || (!defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x10100000L) +#if (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000) \ + || (!defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x10100000L) static int BIO_get_shutdown(BIO *a) { return a->shutdown; } static void BIO_set_init(BIO *a,int i) { a->init=i; } @@ -62,7 +60,8 @@ static void BIO_set_data(BIO *a,void *p) { a->ptr = p; } long (*BIO_meth_get_ctrl(const BIO_METHOD* biom)) (BIO*, int, long, void*) { return biom->ctrl; } -#endif +#endif /* (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000) \ +|| (!defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x10100000L) */ static BIO_METHOD methods_tou_sockp = { @@ -71,22 +70,20 @@ static BIO_METHOD methods_tou_sockp = tou_socket_write, tou_socket_read, tou_socket_puts, - NULL, /* tou_gets, */ + nullptr, // bgets tou_socket_ctrl, tou_socket_new, tou_socket_free, - NULL, + nullptr, // callback_ctrl }; BIO_METHOD* BIO_s_tou_socket(void) { -#ifdef DEBUG_TOU_BIO - fprintf(stderr, "BIO_s_tou_socket(void)\n"); -#endif + Dbg2() << __PRETTY_FUNCTION__ << std::endl; return(&methods_tou_sockp); } -#else +#else // OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) BIO_METHOD* BIO_s_tou_socket(void) { @@ -106,46 +103,28 @@ BIO_METHOD* BIO_s_tou_socket(void) return methods_tou_sockp_ptr; } -#endif - -BIO *BIO_new_tou_socket(int fd, int close_flag) - { - BIO *ret; -#ifdef DEBUG_TOU_BIO - fprintf(stderr, "BIO_new_tou_socket(%d)\n", fd); -#endif - - ret=BIO_new(BIO_s_tou_socket()); - if (ret == NULL) return(NULL); - BIO_set_fd(ret,fd,close_flag); - return(ret); - } +#endif // OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) static int tou_socket_new(BIO *bi) - { -#ifdef DEBUG_TOU_BIO - fprintf(stderr, "tou_socket_new()\n"); -#endif +{ + Dbg2() << __PRETTY_FUNCTION__ << std::endl; + BIO_set_init(bi,0) ; - BIO_set_data(bi,NULL) ; // sets bi->ptr + BIO_set_data(bi, nullptr); // sets bi->ptr BIO_set_flags(bi,0) ; BIO_set_fd(bi,0,0) ; return(1); - } +} static int tou_socket_free(BIO *a) - { -#ifdef DEBUG_TOU_BIO - fprintf(stderr, "tou_socket_free()\n"); -#endif - if (a == NULL) return(0); +{ + Dbg2() << __PRETTY_FUNCTION__ << std::endl; + + if (!a) return(0); if(BIO_get_shutdown(a)) { - if(BIO_get_init(a)) - { - tou_close(BIO_get_fd(a,NULL)); - } + if(BIO_get_init(a)) tou_close(static_cast(BIO_get_fd(a, nullptr))); BIO_set_init(a,0) ; BIO_set_flags(a,0) ; } @@ -153,13 +132,12 @@ static int tou_socket_free(BIO *a) } static int tou_socket_read(BIO *b, char *out, int outl) - { - int ret=0; -#ifdef DEBUG_TOU_BIO - fprintf(stderr, "tou_socket_read(%p,%p,%d)\n",b,out,outl); -#endif +{ + Dbg2() << __PRETTY_FUNCTION__ << std::endl; - if (out != NULL) + int ret=0; + + if (!out) { clear_tou_socket_error(BIO_get_fd(b,NULL)); /* call tou library */ @@ -312,69 +290,66 @@ int BIO_tou_socket_should_retry(int s, int i) } int BIO_tou_socket_non_fatal_error(int err) - { - switch (err) - { -#if defined(OPENSSL_SYS_WINDOWS) -# if defined(WSAEWOULDBLOCK) - case WSAEWOULDBLOCK: -# endif +{ + constexpr int fatalError = 0; + constexpr int nonFatalError = 1; -# if 0 /* This appears to always be an error */ -# if defined(WSAENOTCONN) - case WSAENOTCONN: -# endif -# endif -#endif + switch (err) + { +#if defined(OPENSSL_SYS_WINDOWS) +# if defined(WSAEWOULDBLOCK) + case WSAEWOULDBLOCK: +# endif // defined(WSAEWOULDBLOCK) +#endif // defined(OPENSSL_SYS_WINDOWS) #ifdef EWOULDBLOCK -# ifdef WSAEWOULDBLOCK -# if WSAEWOULDBLOCK != EWOULDBLOCK +# ifdef WSAEWOULDBLOCK +# if WSAEWOULDBLOCK != EWOULDBLOCK case EWOULDBLOCK: -# endif -# else +# endif // WSAEWOULDBLOCK != EWOULDBLOCK +# else // def WSAEWOULDBLOCK case EWOULDBLOCK: -# endif +# endif // def WSAEWOULDBLOCK #endif #if defined(ENOTCONN) case ENOTCONN: -#endif +#endif // defined(ENOTCONN) #ifdef EINTR case EINTR: -#endif +#endif // def EINTR #ifdef EAGAIN -#if EWOULDBLOCK != EAGAIN +# if EWOULDBLOCK != EAGAIN case EAGAIN: -# endif -#endif +# endif // EWOULDBLOCK != EAGAIN +#endif // def EAGAIN #ifdef EPROTO case EPROTO: -#endif +#endif // def EPROTO #ifdef EINPROGRESS case EINPROGRESS: -#endif +#endif // def EINPROGRESS #ifdef EALREADY case EALREADY: -#endif +#endif // def EALREADY + Dbg2() << __PRETTY_FUNCTION__ << " err: " << err + << " return nonFatalError " << nonFatalError << std::endl; + return nonFatalError; -#ifdef DEBUG_TOU_BIO - fprintf(stderr, "BIO_tou_socket_non_fatal_error(%d) = 1\n", err); -#endif - return(1); - /* break; */ default: break; - } -#ifdef DEBUG_TOU_BIO - fprintf(stderr, "BIO_tou_socket_non_fatal_error(%d) = 0\n", err); -#endif - return(0); } -#endif + + Dbg2() << __PRETTY_FUNCTION__ << " err: " << err << " return fatalError " + << fatalError << std::endl; + + return fatalError; +} + +#endif // ndef OPENSSL_NO_SOCK diff --git a/libretroshare/src/turtle/p3turtle.h b/libretroshare/src/turtle/p3turtle.h index ad60cf7f2..a80025c28 100644 --- a/libretroshare/src/turtle/p3turtle.h +++ b/libretroshare/src/turtle/p3turtle.h @@ -444,7 +444,7 @@ class p3turtle: public p3Service, public RsTurtle, public p3Config std::list _online_peers; /// used to force digging new tunnels - bool _force_digg_new_tunnels ; + //bool _force_digg_new_tunnels ; /// used as a bias to introduce randomness in a consistent way, for /// altering tunnel request depths, and tunnel re-routing actions. diff --git a/libretroshare/src/use_libretroshare.pri b/libretroshare/src/use_libretroshare.pri index d3dbb0e45..9a74d209c 100644 --- a/libretroshare/src/use_libretroshare.pri +++ b/libretroshare/src/use_libretroshare.pri @@ -15,13 +15,16 @@ # You should have received a copy of the GNU Lesser General Public License # # along with this program. If not, see . # ################################################################################ -DEPENDPATH *= $$clean_path($${PWD}/../../libretroshare/src/) -INCLUDEPATH *= $$clean_path($${PWD}/../../libretroshare/src) -LIBS *= -L$$clean_path($${OUT_PWD}/../../libretroshare/src/lib/) -lretroshare +RS_SRC_PATH=$$clean_path($${PWD}/../../) +RS_BUILD_PATH=$$clean_path($${OUT_PWD}/../../) + +DEPENDPATH *= $$clean_path($${RS_SRC_PATH}/libretroshare/src/) +INCLUDEPATH *= $$clean_path($${RS_SRC_PATH}/libretroshare/src) +LIBS *= -L$$clean_path($${RS_BUILD_PATH}/libretroshare/src/lib/) -lretroshare equals(TARGET, retroshare):equals(TEMPLATE, lib){ } else { - PRE_TARGETDEPS *= $$clean_path($$OUT_PWD/../../libretroshare/src/lib/libretroshare.a) + PRE_TARGETDEPS *= $$clean_path($${RS_BUILD_PATH}/libretroshare/src/lib/libretroshare.a) } !include("../../openpgpsdk/src/use_openpgpsdk.pri"):error("Including") @@ -48,9 +51,6 @@ mLibs = $$RS_SQL_LIB ssl crypto $$RS_THREAD_LIB $$RS_UPNP_LIB dLibs = rs_jsonapi { - RS_SRC_PATH=$$clean_path($${PWD}/../../) - RS_BUILD_PATH=$$clean_path($${OUT_PWD}/../../) - no_rs_cross_compiling { RESTBED_SRC_PATH=$$clean_path($${RS_SRC_PATH}/supportlibs/restbed) RESTBED_BUILD_PATH=$$clean_path($${RS_BUILD_PATH}/supportlibs/restbed) @@ -73,6 +73,20 @@ rs_deep_search { win32-g++:mLibs += rpcrt4 } +rs_broadcast_discovery { + no_rs_cross_compiling { + UDP_DISCOVERY_SRC_PATH=$$clean_path($${RS_SRC_PATH}/supportlibs/udp-discovery-cpp/) + UDP_DISCOVERY_BUILD_PATH=$$clean_path($${RS_BUILD_PATH}/supportlibs/udp-discovery-cpp/) + INCLUDEPATH *= $$clean_path($${UDP_DISCOVERY_SRC_PATH}) + DEPENDPATH *= $$clean_path($${UDP_DISCOVERY_BUILD_PATH}) + QMAKE_LIBDIR *= $$clean_path($${UDP_DISCOVERY_BUILD_PATH}) + # Using sLibs would fail as libudp-discovery.a is generated at compile-time + LIBS *= -L$$clean_path($${UDP_DISCOVERY_BUILD_PATH}) -ludp-discovery + } else:sLibs *= udp-discovery + + win32-g++:dLibs *= wsock32 +} + static { sLibs *= $$mLibs } else { diff --git a/libretroshare/src/util/retrodb.cc b/libretroshare/src/util/retrodb.cc index 57d062812..a539c1676 100644 --- a/libretroshare/src/util/retrodb.cc +++ b/libretroshare/src/util/retrodb.cc @@ -3,7 +3,8 @@ * * * libretroshare: retroshare core library * * * - * Copyright 2012 Christopher Evi-Parker * + * Copyright (C) 2012 Christopher Evi-Parker * + * Copyright (C) 2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -22,106 +23,143 @@ #include #include -#include -#include "util/rstime.h" -#include +#include +#include +#include -#include "retrodb.h" -#include "rsdbbind.h" +#include "util/rstime.h" +#include "util/retrodb.h" +#include "util/rsdbbind.h" +#include "util/stacktrace.h" +#include "util/rsdir.h" //#define RETRODB_DEBUG -#ifndef NO_SQLCIPHER -#define ENABLE_ENCRYPTED_DB -#endif - const int RetroDb::OPEN_READONLY = SQLITE_OPEN_READONLY; const int RetroDb::OPEN_READWRITE = SQLITE_OPEN_READWRITE; const int RetroDb::OPEN_READWRITE_CREATE = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; -RetroDb::RetroDb(const std::string &dbPath, int flags, const std::string& key) : mDb(NULL), mKey(key) { +RetroDb::RetroDb(const std::string& dbPath, int flags, const std::string& key): + mDb(nullptr), mKey(key) +{ + bool alreadyExists = RsDirUtil::fileExists(dbPath); - int rc = sqlite3_open_v2(dbPath.c_str(), &mDb, flags, NULL); - - if(rc){ - std::cerr << "Can't open database, Error code: " << sqlite3_errmsg(mDb) - << std::endl; - sqlite3_close(mDb); - mDb = NULL; - return; - } - -#ifdef ENABLE_ENCRYPTED_DB - if(!mKey.empty()) - { - rc = sqlite3_key(mDb, mKey.c_str(), mKey.size()); - - if(rc){ - std::cerr << "Can't key database: " << sqlite3_errmsg(mDb) - << std::endl; - - sqlite3_close(mDb); - mDb = NULL; - return; - } - } - - char *err = NULL; - rc = sqlite3_exec(mDb, "PRAGMA cipher_migrate;", NULL, NULL, &err); - if (rc != SQLITE_OK) - { - std::cerr << "RetroDb::RetroDb(): Error upgrading database, error code: " << rc; - if (err) - { - std::cerr << ", " << err; - } - std::cerr << std::endl; - sqlite3_free(err); - } - - //Test DB for correct sqlcipher version - if (sqlite3_exec(mDb, "PRAGMA user_version;", NULL, NULL, NULL) != SQLITE_OK) + int rc = sqlite3_open_v2(dbPath.c_str(), &mDb, flags, nullptr); + if(rc) { - std::cerr << "RetroDb::RetroDb(): Failed to open database: " << dbPath << std::endl << "Trying with settings for sqlcipher version 3..."; - //Reopening the database with correct settings - rc = sqlite3_close(mDb); - mDb = NULL; - if(!rc) - rc = sqlite3_open_v2(dbPath.c_str(), &mDb, flags, NULL); - if(!rc && !mKey.empty()) - rc = sqlite3_key(mDb, mKey.c_str(), mKey.size()); - if(!rc) - rc = sqlite3_exec(mDb, "PRAGMA kdf_iter = 64000;", NULL, NULL, NULL); - if (!rc && (sqlite3_exec(mDb, "PRAGMA user_version;", NULL, NULL, NULL) == SQLITE_OK)) + RsErr() << __PRETTY_FUNCTION__ << " Can't open database, Error: " + << rc << " " << sqlite3_errmsg(mDb) << std::endl; + closeDb(); + print_stacktrace(); + return; + } + + if(alreadyExists) + { + /* If the database has been created by a RetroShare compiled without + * SQLCipher, open it as a plain SQLite database instead of failing + * miserably. If RetroShare has been compiled without SQLCipher but the + * database seems encrypted print a meaningful error message instead of + * crashing miserably. + * At some point we could implement a migration SQLite <-> SQLCipher + * mecanism and suggest it to the user, or give the option to the user + * to choice between plain SQLite or SQLCipher database, is some cases + * such as encrypted FS it might make sense to keep SQLite even if + * SQLCipher is availble for performance, as encryption is already + * provided at FS level. */ + + rc = sqlite3_exec( mDb, "PRAGMA schema_version;", + nullptr, nullptr, nullptr ); + if( rc == SQLITE_OK ) { - std::cerr << "\tSuccess" << std::endl; - } else { - std::cerr << "\tFailed, giving up" << std::endl; - sqlite3_close(mDb); - mDb = NULL; +#ifndef NO_SQLCIPHER + RsWarn() << __PRETTY_FUNCTION__ << " The database is not encrypted: " + << dbPath << std::endl; +#endif // ndef NO_SQLCIPHER + + return; + } + else + { +#ifdef NO_SQLCIPHER + RsErr() << __PRETTY_FUNCTION__ << " Error quering schema version." + << " Are you trying to open an encrypted database without " + << "compiling SQLCipher support?" << std::endl << std::endl; + print_stacktrace(); + closeDb(); +#else // def NO_SQLCIPHER + RsInfo() << __PRETTY_FUNCTION__ << " The database seems encrypted: " + << dbPath << std::endl; +#endif // def NO_SQLCIPHER + } + } + +#ifndef NO_SQLCIPHER + if(!mKey.empty()) + { + rc = sqlite3_key(mDb, mKey.c_str(), static_cast(mKey.size())); + + if(rc) + { + RsErr() << __PRETTY_FUNCTION__ << " Can't key database: " << rc + << " " << sqlite3_errmsg(mDb) << std::endl; + closeDb(); return; } } -#endif + + char* err = nullptr; + rc = sqlite3_exec(mDb, "PRAGMA cipher_migrate;", nullptr, nullptr, &err); + if (rc != SQLITE_OK) + { + RsErr() << __PRETTY_FUNCTION__ << " Error upgrading database, error " + << "code: " << rc << " " << err << std::endl; + sqlite3_free(err); + } + + // Test DB for correct sqlcipher version + if(sqlite3_exec( + mDb, "PRAGMA user_version;", + nullptr, nullptr, nullptr ) != SQLITE_OK) + { + RsWarn() << __PRETTY_FUNCTION__ << " Failed to open database: " + << dbPath << std::endl; + + //Reopening the database with correct settings + closeDb(); + if(!rc) rc = sqlite3_open_v2(dbPath.c_str(), &mDb, flags, nullptr); + if(!rc && !mKey.empty()) + rc = sqlite3_key(mDb, mKey.c_str(), static_cast(mKey.size())); + if(!rc) + rc = sqlite3_exec( mDb, "PRAGMA kdf_iter = 64000;", + nullptr, nullptr, nullptr ); + if (!rc && (sqlite3_exec( mDb, "PRAGMA user_version;", + nullptr, nullptr, nullptr ) == SQLITE_OK)) + { + RsInfo() << __PRETTY_FUNCTION__ << " Re-trying with settings for " + << "sqlcipher version 3 successed" << std::endl; + } + else + { + RsErr() << __PRETTY_FUNCTION__ << " Re-trying with settings for " + << "sqlcipher version 3 failed, giving up" << std::endl; + closeDb(); + return; + } + } +#endif // ndef NO_SQLCIPHER } -RetroDb::~RetroDb(){ +RetroDb::~RetroDb() { closeDb(); } - sqlite3_close(mDb); // no-op if mDb is NULL (https://www.sqlite.org/c3ref/close.html) - mDb = NULL ; -} - -void RetroDb::closeDb(){ - - int rc= sqlite3_close(mDb); - mDb = NULL ; - -#ifdef RETRODB_DEBUG - std::cerr << "RetroDb::closeDb(): Error code on close: " << rc << std::endl; -#else - (void)rc; -#endif +void RetroDb::closeDb() +{ + // no-op if mDb is nullptr (https://www.sqlite.org/c3ref/close.html) + int rc = sqlite3_close(mDb); + mDb = nullptr; + Dbg2() << __PRETTY_FUNCTION__ << " sqlite3_close return: " << rc + << std::endl; } #define TIME_LIMIT 3 diff --git a/libretroshare/src/util/retrodb.h b/libretroshare/src/util/retrodb.h index 8cf772c44..b48415152 100644 --- a/libretroshare/src/util/retrodb.h +++ b/libretroshare/src/util/retrodb.h @@ -19,8 +19,7 @@ * along with this program. If not, see . * * * *******************************************************************************/ -#ifndef RSSQLITE_H -#define RSSQLITE_H +#pragma once #ifdef NO_SQLCIPHER #include @@ -32,9 +31,10 @@ #include #include #include -#include "rsdbbind.h" -#include "contentvalue.h" +#include "util/rsdebug.h" +#include "util/rsdbbind.h" +#include "util/contentvalue.h" class RetroCursor; @@ -202,6 +202,8 @@ private: sqlite3* mDb; const std::string mKey; + + RS_SET_CONTEXT_DEBUG_LEVEL(3) }; /*! @@ -318,5 +320,3 @@ public: private: sqlite3_stmt* mStmt; }; - -#endif // RSSQLITE_H diff --git a/libretroshare/src/util/rsdebug.h b/libretroshare/src/util/rsdebug.h index dd054822c..227d5f8b7 100644 --- a/libretroshare/src/util/rsdebug.h +++ b/libretroshare/src/util/rsdebug.h @@ -1,9 +1,8 @@ /******************************************************************************* - * libretroshare/src/util: rsdebug.h * + * RetroShare debugging utilities * * * - * libretroshare: retroshare core library * - * * - * Copyright 2004-2008 by Robert Fernie * + * Copyright (C) 2004-2008 Robert Fernie * + * Copyright (C) 2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * @@ -19,16 +18,211 @@ * along with this program. If not, see . * * * *******************************************************************************/ -/* Moved from pqi/ to util/ so it can be used more generally. - */ +#pragma once -#ifndef RS_LOG_DEBUG_H -#define RS_LOG_DEBUG_H +#include + +#ifdef __ANDROID__ +# include +# include +# include + +enum class RsLoggerCategories +{ + DEBUG = ANDROID_LOG_DEBUG, + INFO = ANDROID_LOG_INFO, + WARNING = ANDROID_LOG_WARN, + ERROR = ANDROID_LOG_ERROR, + FATAL = ANDROID_LOG_FATAL +}; + +template +struct t_RsLogger +{ + inline t_RsLogger() = default; + + template + inline t_RsLogger& operator<<(const T& val) + { ostr << val; return *this; } + + /// needed for manipulators and things like std::endl + t_RsLogger& operator<<(std::ostream& (*pf)(std::ostream&)) + { + if(pf == static_cast( + &std::endl< char, std::char_traits > )) + { + __android_log_write( + static_cast(CATEGORY), + "RetroShare", ostr.str().c_str() ); + ostr.str() = ""; + } + else ostr << pf; + + return *this; + } + +private: + std::ostringstream ostr; +}; + +#else // def __ANDROID__ + +#include +#include + +enum class RsLoggerCategories +{ + DEBUG = 'D', + INFO = 'I', + WARNING = 'W', + ERROR = 'E', + FATAL = 'F' +}; + +template +struct t_RsLogger +{ + inline t_RsLogger() = default; + + template + inline std::ostream& operator<<(const T& val) + { + return std::cerr << static_cast(CATEGORY) << " " << time(nullptr) + << " " << val; + } +}; +#endif // def __ANDROID__ + + +/** + * Comfortable debug message loggin, supports chaining like std::cerr but can + * be easly and selectively disabled at compile time to reduce generated binary + * size and performance impact without too many #ifdef around. + * + * To selectively debug your context you can just add something like this in + * in that context, as an example for a class you can just add a line like this + * inside class declaration: +@code{.cpp} +RS_SET_CONTEXT_DEBUG_LEVEL(2) +@endcode + * And the you can write debug messages around the code of the class like this: +@code{.cpp} +Dbg1() << "Level 1 debug message example, this will be compiled and " + << "printed" << std::endl; +Dbg2() << "Level 2 debug message example, this will be compiled and " + << "printed" << std::endl; +Dbg3() << "Level 3 debug message example, this will not be compiled and " + << "printed, and without #ifdef around!!" << std::endl; +Dbg4() << "Level 4 debug message example, this will not be compiled and " + << "printed, and without #ifdef around!!" << std::endl; +@endcode + * To change the debugging level, for example to completely disable debug + * messages you can change it to 0 +@code{.cpp} +RS_SET_CONTEXT_DEBUG_LEVEL(0) +@endcode + * While to set it to maximim level you have to pass 4. + */ +using RsDbg = t_RsLogger; + + +/** + * Comfortable log information reporting helper, supports chaining like + * std::cerr. + * To report an information message you can just write: +@code{.cpp} +RsInfo() << __PRETTY_FUNCTION__ << "My information message" << std::cerr; +@endcode + */ +using RsInfo = t_RsLogger; + +/// Similar to @see RsInfo but for warning messages +using RsWarn = t_RsLogger; + +/// Similar to @see RsInfo but for error messages +using RsErr = t_RsLogger; + +/** Similar to @see RsInfo but for fatal errors (the ones which cause RetroShare + * to terminate) messages */ +using RsFatal = t_RsLogger; + +/** + * Keeps compatible syntax with RsDbg but explicitely do nothing in a way that + * any modern compiler should be smart enough to optimize out all the function + * calls. + */ +struct RsNoDbg +{ + inline RsNoDbg() = default; + + /** + * This match most of the types, but might be not enough for templated + * types + */ + template + inline RsNoDbg& operator<<(const T&) { return *this; } + + /// needed for manipulators and things like std::endl + inline RsNoDbg& operator<<(std::ostream& (*/*pf*/)(std::ostream&)) + { return *this; } +}; + +/** + * Concatenate preprocessor tokens A and B without expanding macro definitions + * (however, if invoked from a macro, macro arguments are expanded). + */ +#define RS_CONCAT_MACRO_NX(A, B) A ## B + +/// Concatenate preprocessor tokens A and B after macro-expanding them. +#define RS_CONCAT_MACRO(A, B) RS_CONCAT_MACRO_NX(A, B) + +/** + * Set local context debug level. + * Avoid copy pasting boilerplate code around @see RsDbg for usage details + */ +#define RS_SET_CONTEXT_DEBUG_LEVEL(level) \ + RS_CONCAT_MACRO(RS_SET_CONTEXT_DEBUG_LEVEL, level) + +// A bunch of boilerplate, but just in one place +#define RS_SET_CONTEXT_DEBUG_LEVEL0 \ + using Dbg1 = RsNoDbg; \ + using Dbg2 = RsNoDbg; \ + using Dbg3 = RsNoDbg; \ + using Dbg4 = RsNoDbg; +#define RS_SET_CONTEXT_DEBUG_LEVEL1 \ + using Dbg1 = RsDbg; \ + using Dbg2 = RsNoDbg; \ + using Dbg3 = RsNoDbg; \ + using Dbg4 = RsNoDbg; +#define RS_SET_CONTEXT_DEBUG_LEVEL2 \ + using Dbg1 = RsDbg; \ + using Dbg2 = RsDbg; \ + using Dbg3 = RsNoDbg; \ + using Dbg4 = RsNoDbg; +#define RS_SET_CONTEXT_DEBUG_LEVEL3 \ + using Dbg1 = RsDbg; \ + using Dbg2 = RsDbg; \ + using Dbg3 = RsDbg; \ + using Dbg4 = RsNoDbg; +#define RS_SET_CONTEXT_DEBUG_LEVEL4 \ + using Dbg1 = RsDbg; \ + using Dbg2 = RsDbg; \ + using Dbg3 = RsDbg; \ + using Dbg4 = RsDbg; + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +/// All the following lines are DEPRECATED!! #include +#include "util/rsdeprecate.h" + namespace RsLog { - enum logLvl { + enum RS_DEPRECATED_FOR("RsErr, RsDbg, RsNoDbg") logLvl { None = -1, Default = 0, Alert = 1, @@ -40,7 +234,7 @@ namespace RsLog { }; // this struct must be provided by the caller (to rslog()) - struct logInfo { + struct RS_DEPRECATED_FOR("RsErr, RsDbg, RsNoDbg") logInfo { // module specific log lvl logLvl lvl; // module name (displayed in log) @@ -48,9 +242,16 @@ namespace RsLog { }; } +RS_DEPRECATED_FOR("RsErr, RsDbg, RsNoDbg") int setDebugCrashMode(const char *cfile); + +RS_DEPRECATED_FOR("RsErr, RsDbg, RsNoDbg") int setDebugFile(const char *fname); + +RS_DEPRECATED_FOR("RsErr, RsDbg, RsNoDbg") int setOutputLevel(RsLog::logLvl lvl); + +RS_DEPRECATED_FOR("RsErr, RsDbg, RsNoDbg") void rslog(const RsLog::logLvl lvl, RsLog::logInfo *info, const std::string &msg); @@ -76,7 +277,3 @@ void rslog(const RsLog::logLvl lvl, RsLog::logInfo *info, const std::string &msg #define PQL_DEBUG_ALERT RSL_DEBUG_ALERT #define PQL_DEBUG_BASIC RSL_DEBUG_BASIC #define PQL_DEBUG_ALL RSL_DEBUG_ALL - - - -#endif diff --git a/libretroshare/src/util/rskbdinput.cc b/libretroshare/src/util/rskbdinput.cc new file mode 100644 index 000000000..38b0307a2 --- /dev/null +++ b/libretroshare/src/util/rskbdinput.cc @@ -0,0 +1,130 @@ +/******************************************************************************* + * libretroshare/src/retroshare/util/rskbdinput.cc * + * * + * Copyright (C) 2019 Cyril Soler * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +#ifndef __ANDROID__ + +#include +#include + +#ifdef WINDOWS_SYS +#include +#include + +#define PASS_MAX 512 + +namespace RsUtil { +std::string rs_getpass(const std::string& prompt,bool no_echo) +{ + static char getpassbuf [PASS_MAX + 1]; + size_t i = 0; + int c; + + if (!prompt.empty()) { + std::cerr << prompt ; + std::cerr.flush(); + } + + for (;;) { + c = _getch (); + if (c == '\r') { + getpassbuf [i] = '\0'; + break; + } + else if (i < PASS_MAX) { + getpassbuf[i++] = c; + } + + if (i >= PASS_MAX) { + getpassbuf [i] = '\0'; + break; + } + } + + if (!prompt.empty()) { + std::cerr << "\r\n" ; + std::cerr.flush(); + } + + return std::string(getpassbuf); +} +} +#else + +#include +#include +#include +#include +#include + +static int getch() +{ + int ch; + struct termios t_old, t_new; + + tcgetattr(STDIN_FILENO, &t_old); + t_new = t_old; + t_new.c_lflag &= ~(ICANON | ECHO); + tcsetattr(STDIN_FILENO, TCSANOW, &t_new); + + ch = getchar(); + + tcsetattr(STDIN_FILENO, TCSANOW, &t_old); + return ch; +} + +namespace RsUtil { + +std::string rs_getpass(const std::string& prompt, bool no_echo) +{ + const char BACKSPACE=127; + const char RETURN=10; + + std::string password; + unsigned char ch=0; + + std::cout < * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +#include + +namespace RsUtil { + + std::string rs_getpass(const std::string& prompt,bool no_echo=true) ; + +} diff --git a/libretroshare/src/util/rsmemory.h b/libretroshare/src/util/rsmemory.h index 7b475bcaf..8bbbc335a 100644 --- a/libretroshare/src/util/rsmemory.h +++ b/libretroshare/src/util/rsmemory.h @@ -60,7 +60,7 @@ bool myFunnyFunction( * passed, so any effect on performace would happen only in case where the * function is called without the parameter. */ -#define RS_DEFAULT_STORAGE_PARAM(Type) *std::unique_ptr(new Type) +#define RS_DEFAULT_STORAGE_PARAM(Type,...) *std::unique_ptr(new Type(__VA_ARGS__)) void *rs_malloc(size_t size) ; diff --git a/libretroshare/src/util/rsnet.cc b/libretroshare/src/util/rsnet.cc index 2703b1001..1e5f79181 100644 --- a/libretroshare/src/util/rsnet.cc +++ b/libretroshare/src/util/rsnet.cc @@ -162,6 +162,9 @@ std::ostream &operator<<(std::ostream &out, const struct sockaddr_in &addr) return out; } +std::ostream& operator<<(std::ostream& o, const sockaddr_storage& addr) +{ return o << sockaddr_storage_tostring(addr); } + /* thread-safe version of inet_ntoa */ std::string rs_inet_ntoa(struct in_addr in) diff --git a/libretroshare/src/util/rsnet.h b/libretroshare/src/util/rsnet.h index 74a1663fa..cad2c116a 100644 --- a/libretroshare/src/util/rsnet.h +++ b/libretroshare/src/util/rsnet.h @@ -84,7 +84,8 @@ bool isExternalNet(const struct in_addr *addr); // uses a re-entrant version of gethostbyname bool rsGetHostByName(const std::string& hostname, in_addr& returned_addr) ; -std::ostream& operator<<(std::ostream& o,const struct sockaddr_in&) ; +std::ostream& operator<<(std::ostream& o, const sockaddr_in&); +std::ostream& operator<<(std::ostream& o, const sockaddr_storage&); /* thread-safe version of inet_ntoa */ std::string rs_inet_ntoa(struct in_addr in); @@ -144,10 +145,6 @@ std::string sockaddr_storage_iptostring(const struct sockaddr_storage &addr); std::string sockaddr_storage_porttostring(const struct sockaddr_storage &addr); void sockaddr_storage_dump(const sockaddr_storage & addr, std::string * outputString = NULL); -// output -//void sockaddr_storage_output(const struct sockaddr_storage &addr, std::ostream &out); -//void sockaddr_storage_ipoutput(const struct sockaddr_storage &addr, std::ostream &out); - // net checks. bool sockaddr_storage_isnull(const struct sockaddr_storage &addr); bool sockaddr_storage_isValidNet(const struct sockaddr_storage &addr); diff --git a/libretroshare/src/util/rsrandom.cc b/libretroshare/src/util/rsrandom.cc index bc358064e..7ea8eb968 100644 --- a/libretroshare/src/util/rsrandom.cc +++ b/libretroshare/src/util/rsrandom.cc @@ -19,35 +19,39 @@ * along with this program. If not, see . * * * *******************************************************************************/ + +#include "rsrandom.h" + #include #include #include -#include "rsrandom.h" - #include -uint32_t RSRandom::index = RSRandom::N ; -std::vector RSRandom::MT(RSRandom::N,0u) ; -RsMutex RSRandom::rndMtx("RSRandom") ; +uint32_t RsRandom::index = RsRandom::N; +std::vector RsRandom::MT(RsRandom::N,0u); +RsMutex RsRandom::rndMtx("RsRandom"); -// According to our tests (cyril+thunder), on both Windows and Linux does -// RAND_bytes init itself automatically at first call, from system-based -// unpredictable values, so that seeding is not even needed. -// This call still adds some randomness (not much actually, but it's always good to -// have anyway) -// +/* According to our tests (cyril+thunder), on both Windows and Linux does + * RAND_bytes init itself automatically at first call, from system-based + * unpredictable values, so that seeding is not even needed. + * This call still adds some randomness (not much actually, but it's always good + * to have anyway) */ #ifdef WINDOWS_SYS -#include "util/rstime.h" -#ifdef WIN_PTHREADS_H -static bool auto_seed = RSRandom::seed( (time(NULL) + ((uint32_t) pthread_self())*0x1293fe)^0x18e34a12 ) ; -#else -static bool auto_seed = RSRandom::seed( (time(NULL) + ((uint32_t) pthread_self().p)*0x1293fe)^0x18e34a12 ) ; -#endif +# include "util/rstime.h" +# ifdef WIN_PTHREADS_H +static bool auto_seed = RsRandom::seed( + (time(nullptr) + + static_cast(pthread_self()) *0x1293fe)^0x18e34a12 ); +# else // def WIN_PTHREADS_H +static bool auto_seed = RsRandom::seed( + (time(nullptr) + + static_cast(pthread_self().p)*0x1293fe)^0x18e34a12 ); +# endif // def WIN_PTHREADS_H #endif -bool RSRandom::seed(uint32_t s) +bool RsRandom::seed(uint32_t s) { - RsStackMutex mtx(rndMtx) ; + RS_STACK_MUTEX(rndMtx); MT.resize(N,0) ; // because MT might not be already resized @@ -66,22 +70,22 @@ bool RSRandom::seed(uint32_t s) return true ; } -void RSRandom::random_bytes(unsigned char *data,uint32_t size) +void RsRandom::random_bytes(unsigned char *data,uint32_t size) { RAND_bytes(data,size) ; } -void RSRandom::locked_next_state() +void RsRandom::locked_next_state() { RAND_bytes((unsigned char *)&MT[0],N*sizeof(uint32_t)) ; index = 0 ; } -uint32_t RSRandom::random_u32() +uint32_t RsRandom::random_u32() { uint32_t y; { - RsStackMutex mtx(rndMtx) ; + RS_STACK_MUTEX(rndMtx); index++ ; @@ -102,22 +106,22 @@ uint32_t RSRandom::random_u32() return y; } -uint64_t RSRandom::random_u64() +uint64_t RsRandom::random_u64() { return ((uint64_t)random_u32() << 32ul) + random_u32() ; } -float RSRandom::random_f32() +float RsRandom::random_f32() { return random_u32() / (float)(~(uint32_t)0) ; } -double RSRandom::random_f64() +double RsRandom::random_f64() { return random_u64() / (double)(~(uint64_t)0) ; } -std::string RSRandom::random_alphaNumericString(uint32_t len) +std::string RsRandom::random_alphaNumericString(uint32_t len) { std::string s = "" ; diff --git a/libretroshare/src/util/rsrandom.h b/libretroshare/src/util/rsrandom.h index 59c488909..aeebfa56c 100644 --- a/libretroshare/src/util/rsrandom.h +++ b/libretroshare/src/util/rsrandom.h @@ -21,34 +21,43 @@ *******************************************************************************/ #pragma once -// RSRandom contains a random number generator that is -// - thread safe -// - system independant -// - fast -// - CRYPTOGRAPHICALLY SAFE, because it is based on openssl random number generator #include -#include +#include -class RSRandom +#include "util/rsthreads.h" +#include "util/rsdeprecate.h" + +/** + * RsRandom provide a random number generator that is + * - thread safe + * - platform independent + * - fast + * - CRYPTOGRAPHICALLY SAFE, because it is based on openssl random number + * generator + */ +class RsRandom { - public: - static uint32_t random_u32() ; - static uint64_t random_u64() ; - static float random_f32() ; - static double random_f64() ; +public: + static uint32_t random_u32(); + static uint64_t random_u64(); + static float random_f32(); + static double random_f64(); - static bool seed(uint32_t s) ; + static bool seed(uint32_t s); - static std::string random_alphaNumericString(uint32_t length) ; - static void random_bytes(unsigned char *data,uint32_t length) ; + static std::string random_alphaNumericString(uint32_t length); + static void random_bytes(uint8_t* data, uint32_t length); - private: - static RsMutex rndMtx ; +private: + static RsMutex rndMtx; - static const uint32_t N = 1024; + static const uint32_t N = 1024; - static void locked_next_state() ; - static uint32_t index ; - static std::vector MT ; + static void locked_next_state(); + static uint32_t index; + static std::vector MT; }; + +/// @deprecated this alias is provided only for code retro-compatibility +using RSRandom RS_DEPRECATED_FOR(RsRandom) = RsRandom; diff --git a/libretroshare/src/util/rsthreads.cc b/libretroshare/src/util/rsthreads.cc index 4d6189d12..f825eedeb 100644 --- a/libretroshare/src/util/rsthreads.cc +++ b/libretroshare/src/util/rsthreads.cc @@ -25,6 +25,7 @@ #include // for errno #include #include "util/rstime.h" +#include "util/rsdebug.h" #include "util/rstime.h" @@ -66,8 +67,8 @@ void RsThread::go() runloop(); - mHasStoppedSemaphore.set(1); mShouldStopSemaphore.set(0); + mHasStoppedSemaphore.set(1); // last value that we modify because this is interpreted as a signal that the object can be deleted. } void *RsThread::rsthread_init(void* p) { @@ -103,6 +104,21 @@ RsThread::RsThread() mShouldStopSemaphore.set(0) ; } +RsThread::~RsThread() +{ + if(isRunning()) + { + RsErr() << "Deleting a thread that is still running! Something is very wrong here and Retroshare is likely to crash because of this." << std::endl; + print_stacktrace(); + + while(isRunning()) + { + std::cerr << "." << std::endl; + rstime::rs_usleep(1000*1000); + } + } +} + bool RsThread::isRunning() { // do we need a mutex for this ? @@ -226,6 +242,10 @@ RsTickingThread::RsTickingThread() #endif } +RsTickingThread::~RsTickingThread() +{ + fullstop(); +} void RsSingleJobThread::runloop() { run() ; diff --git a/libretroshare/src/util/rsthreads.h b/libretroshare/src/util/rsthreads.h index 6a61a9b4e..920450615 100644 --- a/libretroshare/src/util/rsthreads.h +++ b/libretroshare/src/util/rsthreads.h @@ -243,11 +243,11 @@ class RsThread { public: RsThread(); - virtual ~RsThread() {} + virtual ~RsThread() ; void start(const std::string &threadName = ""); - // Returns true of the thread is still running. + // Returns true if the thread is still running. bool isRunning(); @@ -287,6 +287,7 @@ class RsTickingThread: public RsThread { public: RsTickingThread(); + virtual ~RsTickingThread(); void shutdown(); void fullstop(); diff --git a/libretroshare/src/util/rstime.h b/libretroshare/src/util/rstime.h index 397edfee1..6cc01e486 100644 --- a/libretroshare/src/util/rstime.h +++ b/libretroshare/src/util/rstime.h @@ -45,11 +45,14 @@ typedef int64_t rstime_t; // Do we really need this? Our names have rs prefix to avoid pollution already! namespace rstime { - /*! - * \brief This is a cross-system definition of usleep, which accepts any 32 bits number of micro-seconds. - */ - RS_DEPRECATED_FOR("std::this_thread::sleep_for") - int rs_usleep(uint32_t micro_seconds); +/** + * @deprecated { std::this_thread::sleep_for or + * std::this_thread::sleep_until instead } + * @brief This is a cross-system definition of usleep, which accepts any + * 32 bits number of micro-seconds. + */ +RS_DEPRECATED_FOR("std::this_thread::sleep_for") +int rs_usleep(uint32_t micro_seconds); /* Use this class to measure and display time duration of a given environment: diff --git a/libretroshare/src/util/rsurl.cc b/libretroshare/src/util/rsurl.cc index 563f151cc..e625815e4 100644 --- a/libretroshare/src/util/rsurl.cc +++ b/libretroshare/src/util/rsurl.cc @@ -201,6 +201,13 @@ RsUrl& RsUrl::delQueryK(const std::string& key) mQuery.erase(key); return *this; } +bool RsUrl::hasQueryK(const std::string& key) +{ return (mQuery.find(key) != mQuery.end()); } +const std::string* RsUrl::getQueryV(const std::string& key) +{ + if(hasQueryK(key)) return &(mQuery.find(key)->second); + return nullptr; +} const std::string& RsUrl::fragment() const { return mFragment; } RsUrl& RsUrl::setFragment(const std::string& fragment) diff --git a/libretroshare/src/util/rsurl.h b/libretroshare/src/util/rsurl.h index b1975d574..f02c7f636 100644 --- a/libretroshare/src/util/rsurl.h +++ b/libretroshare/src/util/rsurl.h @@ -59,6 +59,8 @@ struct RsUrl : RsSerializable RsUrl& setQuery(const std::map& query); RsUrl& setQueryKV(const std::string& key, const std::string& value); RsUrl& delQueryK(const std::string& key); + bool hasQueryK(const std::string& key); + const std::string* getQueryV(const std::string& key); const std::string& fragment() const; RsUrl& setFragment(const std::string& fragment); diff --git a/libretroshare/src/util/smallobject.h b/libretroshare/src/util/smallobject.h index 2f3ac592c..452037ac6 100644 --- a/libretroshare/src/util/smallobject.h +++ b/libretroshare/src/util/smallobject.h @@ -61,7 +61,7 @@ namespace RsMemoryManagement inline bool chunkOwnsPointer(const Chunk& c,void *p) const { - return p >= c._data && (static_cast(p)-c._data)/_blockSize < _numBlocks ; + return intptr_t(p) >= intptr_t(c._data) && (intptr_t(static_cast(p))-intptr_t(c._data))/intptr_t(_blockSize)< intptr_t( _numBlocks ); } void printStatistics() const ; diff --git a/libretroshare/src/util/stacktrace.h b/libretroshare/src/util/stacktrace.h index cf3a74e1f..cb7dc4e71 100644 --- a/libretroshare/src/util/stacktrace.h +++ b/libretroshare/src/util/stacktrace.h @@ -23,12 +23,10 @@ #include #include #include -#include -#if defined(__linux__) && defined(__GLIBC__) - -#include -#include +#ifdef __ANDROID__ +# include "util/rsdebug.h" +#endif /** * @brief Print a backtrace to FILE* out. @@ -40,7 +38,16 @@ * @param[in] maxFrames maximum number of stack frames you want to bu printed */ static inline void print_stacktrace( - bool demangle = true, FILE *out = stderr, unsigned int maxFrames = 63 ) + bool demangle = true, FILE *out = stderr, unsigned int maxFrames = 63 ); + + +#if defined(__linux__) && defined(__GLIBC__) + +#include +#include + +static inline void print_stacktrace( + bool demangle, FILE* out, unsigned int maxFrames ) { if(!out) { @@ -140,15 +147,111 @@ static inline void print_stacktrace( free(funcname); free(symbollist); } +#elif defined(__ANDROID__) // defined(__linux__) && defined(__GLIBC__) + +/* Inspired by the solution proposed by Louis Semprini on this thread + * https://stackoverflow.com/questions/8115192/android-ndk-getting-the-backtrace/35586148 + */ + +#include +#include +#include + +struct RsAndroidBacktraceState +{ + void** current; + void** end; +}; + +static inline _Unwind_Reason_Code android_unwind_callback( + struct _Unwind_Context* context, void* arg ) +{ + RsAndroidBacktraceState* state = static_cast(arg); + uintptr_t pc = _Unwind_GetIP(context); + if(pc) + { + if (state->current == state->end) return _URC_END_OF_STACK; + + *state->current++ = reinterpret_cast(pc); + } + return _URC_NO_REASON; +} + +static inline void print_stacktrace( + bool demangle, FILE* /*out*/, unsigned int /*maxFrames*/) +{ + constexpr int max = 5000; + void* buffer[max]; + + RsAndroidBacktraceState state; + state.current = buffer; + state.end = buffer + max; + + _Unwind_Backtrace(android_unwind_callback, &state); + + RsDbg() << std::endl << std::endl + << 0 << " " << buffer[0] << " " << __PRETTY_FUNCTION__ << std::endl; + + // Skip first frame which is print_stacktrace + int count = static_cast(state.current - buffer); + for(int idx = 1; idx < count; ++idx) + { + const void* addr = buffer[idx]; + + /* Ignore null addresses. + * They sometimes happen when using _Unwind_Backtrace() + * with compiler optimizations, when the Link Register is overwritten by + * the inner stack frames. */ + if(!addr) continue; + + /* Ignore duplicate addresses. + * They sometimes happen when using _Unwind_Backtrace() with compiler + * optimizations. */ + if(addr == buffer[idx-1]) continue; + + Dl_info info; + if( !(dladdr(addr, &info) && info.dli_sname) ) + { + RsDbg() << idx << " " << addr << " " << info.dli_fname + << " symbol not found" << std::endl; + continue; + } + + if(demangle) + { + int status = 0; + char* demangled = __cxxabiv1::__cxa_demangle( + info.dli_sname, nullptr, nullptr, &status ); + + if(demangled && (status == 0)) + RsDbg() << idx << " " << addr << " " << demangled << std::endl; + else + RsDbg() << idx << " " << addr << " " + << (info.dli_sname ? info.dli_sname : info.dli_fname) + << " __cxa_demangle failed with: " << status + << std::endl; + + free(demangled); + } + else RsDbg() << idx << " " << addr << " " + << (info.dli_sname ? info.dli_sname : info.dli_fname) + << std::endl; + } + + RsDbg() << std::endl << std::endl; +} #else // defined(__linux__) && defined(__GLIBC__) -static inline void print_stacktrace( - bool demangle = true, FILE *out = stderr, unsigned int max_frames = 63 ) -{ - (void) demangle; - (void) max_frames; - fprintf(out, "TODO: 2016/01/01 print_stacktrace not implemented yet for WINDOWS_SYS and ANDROID\n"); +static inline void print_stacktrace( + bool /*demangle*/, FILE* out, unsigned int /*max_frames*/ ) +{ + /** Notify the user which signal was caught. We use printf, because this + * is the most basic output function. Once you get a crash, it is + * possible that more complex output systems like streams and the like + * may be corrupted. So we make the most basic call possible to the + * lowest level, most standard print function. */ + fprintf(out, "print_stacktrace Not implemented yet for this platform\n"); } #endif // defined(__linux__) && defined(__GLIBC__) @@ -169,6 +272,7 @@ struct CrashStackTrace #endif } + [[ noreturn ]] static void abortHandler(int signum) { // associate each signal with a signal name string. @@ -184,6 +288,7 @@ struct CrashStackTrace #endif } +#ifndef __ANDROID__ /** Notify the user which signal was caught. We use printf, because this * is the most basic output function. Once you get a crash, it is * possible that more complex output systems like streams and the like @@ -193,6 +298,11 @@ struct CrashStackTrace fprintf(stderr, "Caught signal %d (%s)\n", signum, name); else fprintf(stderr, "Caught signal %d\n", signum); +#else // ndef __ANDROID__ + /** On Android the best we can to is to rely on RS debug utils */ + RsFatal() << __PRETTY_FUNCTION__ << " Caught signal " << signum << " " + << (name ? name : "") << std::endl; +#endif print_stacktrace(false); diff --git a/libretroshare/src/zeroconf/NOTES.txt b/libretroshare/src/zeroconf/NOTES.txt deleted file mode 100644 index e8803ff60..000000000 --- a/libretroshare/src/zeroconf/NOTES.txt +++ /dev/null @@ -1,33 +0,0 @@ - -The Code in this directory refers to APPLEs ZeroConf Library. - -We have two classes: p3ZeroConf & p3ZeroConfNat -The first provides ZeroConf(Bonjour) discovery services. -The second provides UPnP & NAT-PMP Nat Port Forwarding. - -OSX ----------------- -Both should compile with no problems under OSX. -Both will be compiled by default. - -p3ZeroConf is enabled by default. -p3ZeroConfNAT will become the default PortForwarding Service (once tested). - -Windows ----------------- -Under Windows, you require Apple's header files & library to compile. -If you are missing the libraries, you can disable their compilation in libretroshare. - -Furthermore - it'll only work if the Apple DNS Service is running on the Windows PC. -p3ZeroConf will be enabled by default (if included in the compilation). -p3ZeroConfNAT will not be enabled by default. - -Linux ----------------- -Neither of these classes will compile or be enabled under Linux. -There is another library: Avahi - which provides ZeroConf services. -It is likely to have a totally different interface - -so it will have to be coded up separately. - - - diff --git a/libretroshare/src/zeroconf/p3zcnatassist.cc b/libretroshare/src/zeroconf/p3zcnatassist.cc deleted file mode 100644 index 9e3ed5e58..000000000 --- a/libretroshare/src/zeroconf/p3zcnatassist.cc +++ /dev/null @@ -1,445 +0,0 @@ -/******************************************************************************* - * libretroshare/src/zeroconf: p3zcnatassist.cc * - * * - * libretroshare: retroshare core library * - * * - * Copyright 2011-2012 by Robert Fernie * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License as * - * published by the Free Software Foundation, either version 3 of the * - * License, or (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public License * - * along with this program. If not, see . * - * * - *******************************************************************************/ -#include "zeroconf/p3zeroconf.h" -#include "zeroconf/p3zcnatassist.h" - -#include -#include - -//#define DEBUG_ZCNATASSIST 1 - - -p3zcNatAssist::p3zcNatAssist() - :mZcMtx("p3zcNatAssist") -{ - -#ifdef DEBUG_ZCNATASSIST - std::cerr << "p3zcNatAssist::p3zcNatAssist()" << std::endl; - std::cerr << std::endl; -#endif - - mMappingStatus = ZC_SERVICE_STOPPED; - mMappingStatusTS = time(NULL); - - mLocalPort = 0; - mLocalPortSet = false; - - mExternalPort = 0; - mExternalPortSet = false; - - mMapped = false; - -} - -p3zcNatAssist::~p3zcNatAssist() -{ - shutdown(); -} - - /* pqiNetAssist - external interface functions */ -void p3zcNatAssist::enable(bool on) -{ -#ifdef DEBUG_ZCNATASSIST - std::cerr << "p3zcNatAssist::enable(" << on << ")"; - std::cerr << std::endl; -#endif - - RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/ - - mEnabled = on; - - if ((!mEnabled) && (mMappingStatus == ZC_SERVICE_ACTIVE)) - { - locked_stopMapping(); - } - -} - -void p3zcNatAssist::shutdown() /* blocking call */ -{ - -#ifdef DEBUG_ZCNATASSIST - std::cerr << "p3zcNatAssist::shutdown()"; - std::cerr << std::endl; -#endif - - enable(false); -} - -void p3zcNatAssist::restart() -{ -#ifdef DEBUG_ZCNATASSIST - std::cerr << "p3zcNatAssist::restart()"; - std::cerr << std::endl; -#endif - - RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/ - - if (mMappingStatus == ZC_SERVICE_ACTIVE) - { - locked_stopMapping(); - } -} - -bool p3zcNatAssist::getEnabled() -{ - RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/ - -#ifdef DEBUG_ZCNATASSIST - std::cerr << "p3zcNatAssist::getEnabled() : " << mEnabled; - std::cerr << std::endl; -#endif - - return mEnabled; -} - -bool p3zcNatAssist::getActive() -{ - RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/ - -#ifdef DEBUG_ZCNATASSIST - std::cerr << "p3zcNatAssist::getActive() : " << (mEnabled && mMapped); - std::cerr << std::endl; -#endif - - return (mEnabled && mMapped); -} - -void p3zcNatAssist::setInternalPort(unsigned short iport_in) -{ - -#ifdef DEBUG_ZCNATASSIST - std::cerr << "p3zcNatAssist::setInternalPort() : " << iport_in; - std::cerr << std::endl; -#endif - - bool changed = false; - { - RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/ - - changed = (mEnabled) && (mLocalPort != iport_in); - mLocalPort = iport_in; - mLocalPortSet = true; - - } - - if (changed) - { - restart(); - } -} - -void p3zcNatAssist::setExternalPort(unsigned short eport_in) -{ - -#ifdef DEBUG_ZCNATASSIST - std::cerr << "p3zcNatAssist::setExternalPort() : " << eport_in; - std::cerr << std::endl; -#endif - - bool changed = false; - { - RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/ - - changed = (mEnabled) && (mExternalPort != eport_in); - mExternalPort = eport_in; - mExternalPortSet = true; - - } - - if (changed) - { - restart(); - } -} - -bool p3zcNatAssist::getInternalAddress(struct sockaddr_storage &addr) -{ - -#ifdef DEBUG_ZCNATASSIST - std::cerr << "p3zcNatAssist::getInternalAddress() always returns false"; - std::cerr << std::endl; -#endif - - return false; -} - - -bool p3zcNatAssist::getExternalAddress(struct sockaddr_storage &addr) -{ - RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/ - - if (mMapped) - { -#ifdef DEBUG_ZCNATASSIST - std::cerr << "p3zcNatAssist::getExternalAddress() mMapped => true"; - std::cerr << std::endl; -#endif - addr = mExternalAddress; - return true; - } - - -#ifdef DEBUG_ZCNATASSIST - std::cerr << "p3zcNatAssist::getExternalAddress() !mMapped => false"; - std::cerr << std::endl; -#endif - - return false; -} - - -/***********************************************************************************/ - -int p3zcNatAssist::tick() -{ - { - RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/ - - locked_startMapping(); - } - - - checkServiceFDs(); // will cause callbacks - if data is ready. - - return 0; -} - -void p3zcNatAssist::checkServiceFDs() -{ - RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/ - - if (mMappingStatus == ZC_SERVICE_ACTIVE) - { - locked_checkFD(mMappingRef); - } -} - - -void p3zcNatAssist::locked_checkFD(DNSServiceRef ref) -{ - //std::cerr << "p3zcNatAssist::locked_checkFD() Start"; - //std::cerr << std::endl; - - int sockfd = DNSServiceRefSockFD(ref); - - fd_set ReadFDs, WriteFDs, ExceptFDs; - FD_ZERO(&ReadFDs); - FD_ZERO(&WriteFDs); - FD_ZERO(&ExceptFDs); - - FD_SET(sockfd, &ReadFDs); - - struct timeval timeout; - timeout.tv_sec = 0; - timeout.tv_usec = 0; - - if (select(sockfd + 1, &ReadFDs, &WriteFDs, &ExceptFDs, &timeout) < 0) - { - std::cerr << "p3zeroconf::checkFD() Select ERROR"; - std::cerr << std::endl; - return; - } - - if (FD_ISSET(sockfd, &ReadFDs)) - { - DNSServiceErrorType err = DNSServiceProcessResult(ref); - switch(err) - { - case 0: - /* ok */ - break; - default: - std::cerr << "DNSServiceProcessResult() ERROR: "; - std::cerr << displayDNSServiceError(err); - std::cerr << std::endl; - break; - } - } - - //std::cerr << "p3zcNatAssist::locked_checkFD() End"; - //std::cerr << std::endl; - return; - -} - - -void p3zcNatAssist_CallbackMapping( DNSServiceRef sdRef, DNSServiceFlags flags, - uint32_t interfaceIndex, DNSServiceErrorType errorCode, - uint32_t externalAddress, DNSServiceProtocol protocol, - uint16_t internalPort, uint16_t externalPort, - uint32_t ttl, void *context ) -{ - p3zcNatAssist *zc = (p3zcNatAssist *) context; - zc->callbackMapping(sdRef, flags, interfaceIndex, errorCode, externalAddress, protocol, internalPort, externalPort, ttl); -} - - -int p3zcNatAssist::locked_startMapping() -{ - if (!mEnabled) - { - std::cerr << "p3zcNatAssist::locked_startMapping()"; - std::cerr << "NatAssist not Enabled"; - std::cerr << std::endl; - return 0; - } - - if (!mLocalPortSet) - { - std::cerr << "p3zcNatAssist::locked_startMapping()"; - std::cerr << "Port Not Set"; - std::cerr << std::endl; - return 0; - } - - if (mMappingStatus == ZC_SERVICE_ACTIVE) - { - return 0; - } - - - std::cerr << "p3zcNatAssist::locked_startMapping() Mapping!"; - std::cerr << std::endl; - std::cerr << "p3zcNatAssist::locked_startMapping() Local Port: " << mLocalPort; - std::cerr << std::endl; - - DNSServiceRef *sdRef = &mMappingRef; - DNSServiceFlags flags = 0; /* no flags, currently reserved */ - uint32_t interfaceIndex = 0; /* primary interface */ - - DNSServiceProtocol protocol = (kDNSServiceProtocol_UDP | kDNSServiceProtocol_TCP); - uint16_t internalPort = htons(mLocalPort); - uint16_t externalPort = htons(mLocalPort); - if (mExternalPortSet) - { - externalPort = htons(mExternalPort); - } - - std::cerr << "p3zcNatAssist::locked_startMapping() External Port: " << ntohs(externalPort); - std::cerr << std::endl; - - uint32_t ttl = 0; /* default ttl */ - - DNSServiceNATPortMappingReply callBack = p3zcNatAssist_CallbackMapping; - void *context = this; - - DNSServiceErrorType errcode = DNSServiceNATPortMappingCreate(sdRef, flags, interfaceIndex, protocol, - internalPort, externalPort, ttl, callBack, context); - - if (errcode != kDNSServiceErr_NoError) - { - std::cerr << "p3zcNatAssist::locked_startMapping() ERROR: "; - std::cerr << displayDNSServiceError(errcode); - std::cerr << std::endl; - } - else - { - mMappingStatus = ZC_SERVICE_ACTIVE; - mMappingStatusTS = time(NULL); - } - - return 1; -} - - - -void p3zcNatAssist::callbackMapping(DNSServiceRef sdRef, DNSServiceFlags flags, - uint32_t interfaceIndex, DNSServiceErrorType errorCode, - uint32_t externalAddress, DNSServiceProtocol protocol, - uint16_t internalPort, uint16_t externalPort, uint32_t ttl) -{ - std::cerr << "p3zcNatAssist::callbackMapping()"; - std::cerr << std::endl; - - /* handle queryIp */ - if (errorCode != kDNSServiceErr_NoError) - { - std::cerr << "p3zcNatAssist::callbackMapping() FAILED ERROR: "; - std::cerr << displayDNSServiceError(errorCode); - std::cerr << std::endl; - return; - } - - if ((externalAddress == 0) && (externalPort == 0)) - { - /* failed :( */ - mMapped = false; - - std::cerr << "p3zcNatAssist::callbackMapping() ZeroAddress ... Mapping not possible"; - std::cerr << std::endl; - return; - } - - - mMapped = true; - - // THIS APPEARS TO BE IPv4 ONLY!. - - sockaddr_storage_clear(mExternalAddress); - struct sockaddr_in *addr = (struct sockaddr_in *) &mExternalAddress; - - addr->sin_family = AF_INET; - addr->sin_addr.s_addr = externalAddress; - addr->sin_port = externalPort; - - mTTL = ttl; - - std::cerr << "p3zcNatAssist::callbackMapping() Success"; - std::cerr << std::endl; - - std::cerr << "interfaceIndex: " << interfaceIndex; - std::cerr << std::endl; - - std::cerr << "internalPort: " << ntohs(internalPort); - std::cerr << std::endl; - - std::cerr << "externalAddress: " << sockaddr_storage_tostring(mExternalAddress); - std::cerr << std::endl; - - std::cerr << "protocol: " << protocol; - std::cerr << std::endl; - - std::cerr << "ttl: " << ttl; - std::cerr << std::endl; - -} - - -void p3zcNatAssist::locked_stopMapping() -{ - std::cerr << "p3zcNatAssist::locked_stopMapping()"; - std::cerr << std::endl; - - if (mMappingStatus != ZC_SERVICE_ACTIVE) - { - return; - } - - DNSServiceRefDeallocate(mMappingRef); - - mMappingStatus = ZC_SERVICE_STOPPED; - mMappingStatusTS = time(NULL); - mMapped = false; -} - - diff --git a/libretroshare/src/zeroconf/p3zcnatassist.h b/libretroshare/src/zeroconf/p3zcnatassist.h deleted file mode 100644 index d103c91d5..000000000 --- a/libretroshare/src/zeroconf/p3zcnatassist.h +++ /dev/null @@ -1,108 +0,0 @@ -/******************************************************************************* - * libretroshare/src/zeroconf: p3zcnatassist.h * - * * - * libretroshare: retroshare core library * - * * - * Copyright 2011-2012 by Robert Fernie * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License as * - * published by the Free Software Foundation, either version 3 of the * - * License, or (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public License * - * along with this program. If not, see . * - * * - *******************************************************************************/ -#ifndef MRK_P3_ZC_NAT_ASSIST_H -#define MRK_P3_ZC_NAT_ASSIST_H - -#include "util/rswin.h" - -#include "pqi/pqiassist.h" -#include "retroshare/rsdht.h" - -#include -#include -#include "pqi/pqinetwork.h" -#include "pqi/pqimonitor.h" -#include "pqi/p3peermgr.h" -#include "util/rsthreads.h" - -#include - - -class p3NetMgr; - -class p3zcNatAssist: public pqiNetAssistFirewall -{ - public: - p3zcNatAssist(); -virtual ~p3zcNatAssist(); - - /* pqiNetAssist - external interface functions */ -virtual int tick(); -virtual void enable(bool on); -virtual void shutdown(); /* blocking call */ -virtual void restart(); - -virtual bool getEnabled(); -virtual bool getActive(); - -virtual void setInternalPort(unsigned short iport_in); -virtual void setExternalPort(unsigned short eport_in); -virtual bool getInternalAddress(struct sockaddr_storage &addr); -virtual bool getExternalAddress(struct sockaddr_storage &addr); - - /* TO IMPLEMENT: New Port Forward interface to support as many ports as necessary */ -virtual bool requestPortForward(const PortForwardParams ¶ms) { return false; } -virtual bool statusPortForward(const uint32_t fwdId, PortForwardParams ¶ms) { return false; } - - /* pqiNetAssistConnect - external interface functions */ - - - public: - - // Callbacks must be public -> so they can be accessed. - void callbackMapping(DNSServiceRef sdRef, DNSServiceFlags flags, - uint32_t interfaceIndex, DNSServiceErrorType errorCode, - uint32_t externalAddress, DNSServiceProtocol protocol, - uint16_t internalPort, uint16_t externalPort, uint32_t ttl); - - private: - - /* monitoring fns */ - void checkServiceFDs(); - void locked_checkFD(DNSServiceRef ref); - - int locked_startMapping(); - void locked_stopMapping(); - - /**************** DATA ****************/ - - RsMutex mZcMtx; - - bool mEnabled; - bool mMapped; - - uint16_t mLocalPort; - bool mLocalPortSet; - - uint16_t mExternalPort; - bool mExternalPortSet; - - struct sockaddr_storage mExternalAddress; - int mTTL; - - DNSServiceRef mMappingRef; - uint32_t mMappingStatus; - rstime_t mMappingStatusTS; -}; - -#endif /* MRK_P3_ZC_NAT_ASSIST_H */ - diff --git a/libretroshare/src/zeroconf/p3zeroconf.cc b/libretroshare/src/zeroconf/p3zeroconf.cc deleted file mode 100644 index 6a29a8934..000000000 --- a/libretroshare/src/zeroconf/p3zeroconf.cc +++ /dev/null @@ -1,1426 +0,0 @@ -/******************************************************************************* - * libretroshare/src/zeroconf: p3zeroconf.cc * - * * - * libretroshare: retroshare core library * - * * - * Copyright 2011-2012 by Robert Fernie * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License as * - * published by the Free Software Foundation, either version 3 of the * - * License, or (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public License * - * along with this program. If not, see . * - * * - *******************************************************************************/ -#include "zeroconf/p3zeroconf.h" -#include -#include - -#include "pqi/authgpg.h" - -/* TODO - * - * - Get Local Port when it changes.... (need second interface?) - * - Get GpgId, SslId for all peers. - * - Able to install new sslIds for friends. - * - Hold data for all peers. - * - parse TxtRecord. - * - */ - -//#define DEBUG_ZEROCONF 1 - -#define ZC_MAX_QUERY_TIME 30 -#define ZC_MAX_RESOLVE_TIME 30 - -p3ZeroConf::p3ZeroConf(std::string gpgid, std::string sslid, pqiConnectCb *cb, p3NetMgr *nm, p3PeerMgr *pm) - :pqiNetAssistConnect(sslid, cb), mNetMgr(nm), mPeerMgr(pm), mZcMtx("p3ZeroConf") -{ - mRegistered = false; - mTextOkay = false; - mPortOkay = false; - - mOwnGpgId = gpgid; - mOwnSslId = sslid; - -#ifdef DEBUG_ZEROCONF - std::cerr << "p3ZeroConf::p3ZeroConf()" << std::endl; - std::cerr << "Using Id: " << sslid; - std::cerr << std::endl; -#endif - - mRegisterStatus = ZC_SERVICE_STOPPED; - mRegisterStatusTS = time(NULL); - mBrowseStatus = ZC_SERVICE_STOPPED; - mBrowseStatusTS = time(NULL); - mResolveStatus = ZC_SERVICE_STOPPED; - mResolveStatusTS = time(NULL); - mQueryStatus = ZC_SERVICE_STOPPED; - mQueryStatusTS = time(NULL); - - createTxtRecord(); -} - -p3ZeroConf::~p3ZeroConf() -{ - -} - - -void p3ZeroConf::start() -{ -#ifdef DEBUG_ZEROCONF - std::cerr << "p3ZeroConf::start()"; - std::cerr << std::endl; -#endif - -} - - /* pqiNetAssist - external interface functions */ -void p3ZeroConf::enable(bool on) -{ -#ifdef DEBUG_ZEROCONF - std::cerr << "p3ZeroConf::enable(" << on << ")"; - std::cerr << std::endl; -#endif - -} - -void p3ZeroConf::shutdown() /* blocking call */ -{ -} - - -void p3ZeroConf::restart() -{ -} - -bool p3ZeroConf::getEnabled() -{ - return true; -} - -bool p3ZeroConf::getActive() -{ - return true; -} - -bool p3ZeroConf::getNetworkStats(uint32_t &netsize, uint32_t &localnetsize) -{ - return false; // Cannot provide Network Stats. -} - -void p3ZeroConf::createTxtRecord() -{ - RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/ - - std::string gpgid = "gpgid=" + mOwnGpgId; - std::string sslid = "sslid=" + mOwnSslId; - - mTextRecord += (char) gpgid.length(); - mTextRecord += gpgid; - mTextRecord += (char) sslid.length(); - mTextRecord += sslid; - - std::cerr << "p3ZeroConf::createTxtRecord() Record: " << std::endl; - std::cerr << "------------------------------------" << std::endl; - std::cerr << mTextRecord; - std::cerr << std::endl; - std::cerr << "------------------------------------" << std::endl; - - mTextOkay = true; -} - -int procPeerTxtRecord(int txtLen, const unsigned char *txtRecord, std::string &peerGpgId, std::string &peerSslId) -{ - int txtRemaining = txtLen; - int idx = 0; - bool setGpg = false; - bool setSsl = false; - - std::cerr << "procPeerTxtRecord() processing"; - std::cerr << std::endl; - - while(txtRemaining > 0) - { - uint8_t len = txtRecord[idx]; - idx++; - txtRemaining -= 1; - - std::string record((const char *) txtRecord, idx, len); - - std::cerr << "procPeerTxtRecord() record: " << record; - std::cerr << std::endl; - - if (0 == strncmp(record.c_str(), "gpgid=", 6)) - { - peerGpgId = record.substr(6, -1); - setGpg = true; - - std::cerr << "procPeerTxtRecord() found peerGpgId: " << peerGpgId; - std::cerr << std::endl; - } - else if (0 == strncmp(record.c_str(), "sslid=", 6)) - { - peerSslId = record.substr(6, -1); - setSsl = true; - - std::cerr << "procPeerTxtRecord() found peerSslId: " << peerSslId; - std::cerr << std::endl; - } - else - { - std::cerr << "Unknown Record"; - } - idx += len; - txtRemaining -= len; - } - return (setGpg && setSsl); -} - - - /*** OVERLOADED from pqiNetListener ***/ -bool p3ZeroConf::resetListener(struct sockaddr_in &local) -{ - RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/ - - mLocalPort = ntohs(local.sin_port); - mPortOkay = true; - - if (mRegisterStatus == ZC_SERVICE_ACTIVE) - { - locked_stopRegister(); - } - return true; -} - - -/***************************************************************************** - ********* pqiNetAssistConnect - external interface functions *************** - *****************************************************************************/ - -/**** DUMMY FOR THE MOMENT *****/ - -bool p3ZeroConf::findPeer(std::string pid) -{ -#ifdef DEBUG_ZEROCONF - std::cerr << "p3ZeroConf::findPeer(" << pid << ")"; - std::cerr << std::endl; -#endif - - return true; -} - -bool p3ZeroConf::dropPeer(std::string pid) -{ -#ifdef DEBUG_ZEROCONF - std::cerr << "p3ZeroConf::dropPeer(" << pid << ")"; - std::cerr << std::endl; -#endif - - return true; -} - - - /* extract current peer status */ -bool p3ZeroConf::getPeerStatus(std::string id, - struct sockaddr_storage &/*laddr*/, struct sockaddr_storage &/*raddr*/, - uint32_t &/*type*/, uint32_t &/*mode*/) -{ - /* remove unused parameter warnings */ - (void) id; - -#ifdef DEBUG_ZEROCONF - std::cerr << "p3ZeroConf::getPeerStatus(" << id << ")"; - std::cerr << std::endl; -#endif - - return false; -} - -#if 0 -bool p3ZeroConf::getExternalInterface(struct sockaddr_storage &/*raddr*/, - uint32_t &/*mode*/) -{ - -#ifdef DEBUG_ZEROCONF - std::cerr << "p3ZeroConf::getExternalInterface()"; - std::cerr << std::endl; -#endif - - - return false; -} - -#endif - -bool p3ZeroConf::setAttachMode(bool on) -{ - -#ifdef DEBUG_ZEROCONF - std::cerr << "p3ZeroConf::setAttachMode(" << on << ")"; - std::cerr << std::endl; -#endif - - return true; -} - -int p3ZeroConf::addBadPeer(const struct sockaddr_storage &addr, uint32_t reason, uint32_t flags, uint32_t age) -{ - return 1; -} - -int p3ZeroConf::addKnownPeer(const std::string &pid, const struct sockaddr_storage &addr, uint32_t flags) -{ - return 1; -} - -void p3ZeroConf::ConnectionFeedback(std::string pid, int state) -{ - return; -} - - - -/***********************************************************************************/ -/* - * - * - * ZeroConf Interface for Retroshare. - * This will use the pqiNetAssistConnect Interface (like the DHT). - * - * we will advertise ourselves using GPGID & SSLID on the zeroconf interface. - * - * Will search local network for any peers. - * If they are our friends... callback to p3NetMgr to initiate connection. - * - * - * This should be very easy to implement under OSX.... so we start with that. - * For Windows, we will use Apple's libraries... so that should be similar too. - * Linux - won't bother with zeroconf for the moment - If someone feels like implementing that.. ok. - * - * Most important is that Windows and OSX can interact. - * - * We keep a simple system here.... - * 1) Register. - * 2) Enable Browsing. - * 3) Resolve Browse results one at a time. - * 4) Callback Resolve results. - * - * - */ - - -int p3ZeroConf::tick() -{ - { - RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/ - - locked_startRegister(); - locked_startBrowse(); - } - - - checkServiceFDs(); // will cause callbacks - if data is ready. - - checkResolveAction(); - checkLocationResults(); - checkQueryAction(); - checkQueryResults(); - - return 0; -} - -void p3ZeroConf::checkServiceFDs() -{ - RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/ - - //std::cerr << "p3ZeroConf::checkServiceFDs()"; - //std::cerr << std::endl; - - if (mRegisterStatus == ZC_SERVICE_ACTIVE) - { - locked_checkFD(mRegisterRef); - } - - if (mBrowseStatus == ZC_SERVICE_ACTIVE) - { - locked_checkFD(mBrowseRef); - } - - if (mResolveStatus == ZC_SERVICE_ACTIVE) - { - locked_checkFD(mResolveRef); - - rstime_t age = time(NULL) - mResolveStatusTS; - if (age > ZC_MAX_RESOLVE_TIME) - { - std::cerr << "p3ZeroConf::checkServiceFDs() Killing very old Resolve request"; - std::cerr << std::endl; - locked_stopResolve(); - - } - } - - - if (mQueryStatus == ZC_SERVICE_ACTIVE) - { - locked_checkFD(mQueryRef); - - rstime_t age = time(NULL) - mQueryStatusTS; - if (age > ZC_MAX_QUERY_TIME) - { - std::cerr << "p3ZeroConf::checkServiceFDs() Killing very old Query request"; - std::cerr << std::endl; - locked_stopQueryIp(); - } - } -} - - -void p3ZeroConf::locked_checkFD(DNSServiceRef ref) -{ - //std::cerr << "p3ZeroConf::locked_checkFD() Start"; - //std::cerr << std::endl; - - int sockfd = DNSServiceRefSockFD(ref); - - fd_set ReadFDs, WriteFDs, ExceptFDs; - FD_ZERO(&ReadFDs); - FD_ZERO(&WriteFDs); - FD_ZERO(&ExceptFDs); - - FD_SET(sockfd, &ReadFDs); - - struct timeval timeout; - timeout.tv_sec = 0; - timeout.tv_usec = 0; - - if (select(sockfd + 1, &ReadFDs, &WriteFDs, &ExceptFDs, &timeout) < 0) - { - std::cerr << "p3zeroconf::checkFD() Select ERROR"; - std::cerr << std::endl; - return; - } - - if (FD_ISSET(sockfd, &ReadFDs)) - { - DNSServiceErrorType err = DNSServiceProcessResult(ref); - switch(err) - { - case 0: - /* ok */ - break; - default: - std::cerr << "DNSServiceProcessResult() ERROR: "; - std::cerr << displayDNSServiceError(err); - std::cerr << std::endl; - break; - } - } - - //std::cerr << "p3ZeroConf::locked_checkFD() End"; - //std::cerr << std::endl; - return; - -} - - - -int p3ZeroConf::checkResolveAction() -{ - RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/ - - if (mResolveStatus == ZC_SERVICE_ACTIVE) - { - /* Do nothing - if we are already resolving */ - - return 0; - } - - /* iterate through the Browse Results... look for unresolved one - and do it! */ - - /* check the new results Queue first */ - if (mBrowseResults.size() > 0) - { - std::cerr << "p3ZeroConf::checkResolveAction() Getting Item from BrowseResults"; - std::cerr << std::endl; - - zcBrowseResult br = mBrowseResults.front(); - mBrowseResults.pop_front(); - - locked_startResolve(br.interfaceIndex, br.serviceName, br.regtype, br.replyDomain); - } - return 1; -} - - -int p3ZeroConf::checkLocationResults() -{ - zcLocationResult lr; - - { - RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/ - - /* check the results Queue */ - if (mLocationResults.empty()) - { - return 0; - } - - std::cerr << "p3ZeroConf::checkLocationResults() Getting Item from LocationResults"; - std::cerr << std::endl; - - lr = mLocationResults.front(); - mLocationResults.pop_front(); - - } - - /* now callback to mPeerMgr to add new location... This will eventually get back here - * via some magic! - */ - - std::cerr << "p3ZeroConf::checkLocationResults() adding new location."; - std::cerr << std::endl; - std::cerr << "gpgid = " << lr.gpgId; - std::cerr << std::endl; - std::cerr << "sslid = " << lr.sslId; - std::cerr << std::endl; - - rstime_t now = time(NULL); - mPeerMgr->addFriend(lr.sslId, lr.gpgId, RS_NET_MODE_UDP, RS_VS_DISC_FULL, RS_VS_DHT_FULL, now); - return 1; -} - - -int p3ZeroConf::checkQueryAction() -{ - RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/ - - if (mQueryStatus == ZC_SERVICE_ACTIVE) - { - /* Do nothing - if we are already resolving */ - - return 0; - } - - /* check the new results Queue first */ - if (mResolveResults.size() > 0) - { - std::cerr << "p3ZeroConf::checkQueryAction() Getting Item from ResolveResults"; - std::cerr << std::endl; - - zcResolveResult rr = mResolveResults.front(); - mResolveResults.pop_front(); - - locked_startQueryIp(rr.interfaceIndex, rr.hosttarget, rr.gpgId, rr.sslId); - } - return 1; -} - - -int p3ZeroConf::checkQueryResults() -{ - zcQueryResult qr; - { - RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/ - - /* check the results Queue */ - if (mQueryResults.empty()) - { - return 0; - } - - std::cerr << "p3ZeroConf::checkQueryResults() Getting Item from QueryResults"; - std::cerr << std::endl; - - qr = mQueryResults.front(); - mQueryResults.pop_front(); - - } - - /* now callback to mLinkMgr to say we can connect */ - - std::cerr << "p3ZeroConf::checkQueryResults() linkMgr->peerConnectRequest() to start link"; - std::cerr << std::endl; - std::cerr << "to gpgid = " << qr.gpgId; - std::cerr << std::endl; - std::cerr << "sslid = " << qr.sslId; - std::cerr << std::endl; - - rstime_t now = time(NULL); - uint32_t flags = RS_CB_FLAG_MODE_TCP; - uint32_t source = RS_CB_DHT; // SHOULD ADD NEW SOURCE ZC??? - struct sockaddr_storage dummyProxyAddr, dummySrcAddr; - sockaddr_storage_clear(dummyProxyAddr); - sockaddr_storage_clear(dummySrcAddr); - mConnCb->peerConnectRequest(qr.sslId, qr.addr, dummyProxyAddr, dummySrcAddr, - source, flags, 0, 0); - - return 1; -} - - - - - - -/* First Step is to register the DNSService */ - -void p3ZeroConf_CallbackRegister( DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, - const char *name, const char *regtype, const char *domain, void *context ) -{ - p3ZeroConf *zc = (p3ZeroConf *) context; - zc->callbackRegister(sdRef, flags, errorCode, name, regtype, domain); -} - - -int p3ZeroConf::locked_startRegister() -{ - if (mRegistered) - { - return 0; - } - - /* need, port & txtRecord setup already */ - if (!mTextOkay) - { - std::cerr << "p3ZeroConf::locked_startRegister()"; - std::cerr << "Text Not Setup"; - std::cerr << std::endl; - return 0; - } - - if (!mPortOkay) - { - std::cerr << "p3ZeroConf::locked_startRegister()"; - std::cerr << "Port Not Set"; - std::cerr << std::endl; - return 0; - } - - if (mRegisterStatus == ZC_SERVICE_ACTIVE) - { - return 0; - } - - - std::cerr << "p3ZeroConf::locked_startRegister() Registering!"; - std::cerr << std::endl; - std::cerr << "p3ZeroConf::locked_startRegister() Text: " << mTextRecord; - std::cerr << std::endl; - std::cerr << "p3ZeroConf::locked_startRegister() Port: " << mLocalPort; - std::cerr << std::endl; - - DNSServiceRef *sdRef = &mRegisterRef; - DNSServiceFlags flags = 0; /* no flags */ - uint32_t interfaceIndex = 0; /* all interfaces */ - char *name = NULL; /* may be NULL */ - - std::string regtype = "_librs._tcp"; - char *domain = NULL; /* may be NULL for all domains. */ - char *host = NULL; /* may be NULL for default hostname */ - - uint16_t port = htons(mLocalPort); - uint16_t txtLen = mTextRecord.length(); - const void *txtRecord = (void *) mTextRecord.c_str(); - DNSServiceRegisterReply callBack = p3ZeroConf_CallbackRegister; - void *context = this; - - DNSServiceErrorType errcode = DNSServiceRegister (sdRef, flags, interfaceIndex, - name, regtype.c_str(), domain, host, port, - txtLen, txtRecord, callBack, context); - - if (errcode != kDNSServiceErr_NoError) - { - std::cerr << "p3ZeroConf::locked_startRegister() ERROR: "; - std::cerr << displayDNSServiceError(errcode); - std::cerr << std::endl; - } - else - { - mRegisterStatus = ZC_SERVICE_ACTIVE; - mRegisterStatusTS = time(NULL); - mRegistered = true; - } - - return 1; -} - - - -void p3ZeroConf::callbackRegister( DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, - const char *name, const char *regtype, const char *domain) -{ - std::cerr << "p3ZeroConf::callbackRegister()"; - std::cerr << std::endl; - - /* handle queryIp */ - if (errorCode != kDNSServiceErr_NoError) - { - std::cerr << "p3ZeroConf::callbackRegister() FAILED ERROR: "; - std::cerr << displayDNSServiceError(errorCode); - std::cerr << std::endl; - return; - } - - std::cerr << "p3ZeroConf::callbackRegister() Success"; - std::cerr << std::endl; - -} - - -void p3ZeroConf::locked_stopRegister() -{ - std::cerr << "p3ZeroConf::locked_stopRegister()"; - std::cerr << std::endl; - - if (mRegisterStatus != ZC_SERVICE_ACTIVE) - { - return; - } - - DNSServiceRefDeallocate(mRegisterRef); - - mRegisterStatus = ZC_SERVICE_STOPPED; - mRegisterStatusTS = time(NULL); - mRegistered = false; -} - - -void p3ZeroConf_CallbackBrowse( DNSServiceRef sdRef, DNSServiceFlags flags, - uint32_t interfaceIndex, DNSServiceErrorType errorCode, - const char *serviceName, const char *regtype, const char *replyDomain, void *context ) -{ - p3ZeroConf *zc = (p3ZeroConf *) context; - zc->callbackBrowse(sdRef, flags, interfaceIndex, errorCode, serviceName, regtype, replyDomain); -} - - -int p3ZeroConf::locked_startBrowse() -{ - if (mBrowseStatus == ZC_SERVICE_ACTIVE) - { - return 0; - } - - std::cerr << "p3ZeroConf::locked_startBrowse()"; - std::cerr << std::endl; - - DNSServiceRef *sdRef = &mBrowseRef; - DNSServiceFlags flags = 0; - uint32_t interfaceIndex = 0; - const char *regtype = "_librs._tcp"; - const char *domain = NULL; - DNSServiceBrowseReply callBack = p3ZeroConf_CallbackBrowse; - void *context = this; - - DNSServiceErrorType errcode = DNSServiceBrowse(sdRef, flags, interfaceIndex, - regtype, domain, callBack, context); - - if (errcode != kDNSServiceErr_NoError) - { - std::cerr << "p3ZeroConf::locked_startBrowse() ERROR: "; - std::cerr << displayDNSServiceError(errcode); - std::cerr << std::endl; - } - else - { - mBrowseStatus = ZC_SERVICE_ACTIVE; - mBrowseStatusTS = time(NULL); - } - - return 1; -} - - -void p3ZeroConf::callbackBrowse(DNSServiceRef /* sdRef */, DNSServiceFlags flags, - uint32_t interfaceIndex, DNSServiceErrorType errorCode, - const char *serviceName, const char *regtype, const char *replyDomain) -{ - std::cerr << "p3ZeroConf::callbackBrowse()"; - std::cerr << std::endl; - - /* handle queryIp */ - if (errorCode != kDNSServiceErr_NoError) - { - std::cerr << "p3ZeroConf::callbackBrowse() FAILED ERROR: "; - std::cerr << displayDNSServiceError(errorCode); - std::cerr << std::endl; - return; - } - - zcBrowseResult br; - - br.flags = flags; - br.interfaceIndex = interfaceIndex; - br.serviceName = serviceName; - br.regtype = regtype; - br.replyDomain = replyDomain; - - std::cerr << "p3ZeroConf::callbackBrowse() "; - std::cerr << " flags: " << flags; - std::cerr << " interfaceIndex: " << interfaceIndex; - std::cerr << " serviceName: " << serviceName; - std::cerr << " regtype: " << regtype; - std::cerr << " replyDomain: " << replyDomain; - std::cerr << std::endl; - - if (flags & kDNSServiceFlagsAdd) - { - std::cerr << "p3ZeroConf::callbackBrowse() Add Flags => so newly found Service => BrowseResults"; - std::cerr << std::endl; - mBrowseResults.push_back(br); - } - else - { - std::cerr << "p3ZeroConf::callbackBrowse() Missing Add Flag => so Service now dropped, Ignoring"; - std::cerr << std::endl; - } - -} - - -int p3ZeroConf::locked_stopBrowse() -{ - std::cerr << "p3ZeroConf::locked_stopBrowse()"; - std::cerr << std::endl; - - if (mBrowseStatus != ZC_SERVICE_ACTIVE) - { - return 0; - } - - DNSServiceRefDeallocate(mBrowseRef); - mBrowseStatus = ZC_SERVICE_STOPPED; - mBrowseStatusTS = time(NULL); - return 1; -} - - - -void p3ZeroConf_CallbackResolve( DNSServiceRef sdRef, DNSServiceFlags flags, - uint32_t interfaceIndex, DNSServiceErrorType errorCode, - const char *fullname, const char *hosttarget, uint16_t port, - uint16_t txtLen, const unsigned char *txtRecord, void *context ) -{ - p3ZeroConf *zc = (p3ZeroConf *) context; - zc->callbackResolve(sdRef, flags, interfaceIndex, errorCode, fullname, hosttarget, port, txtLen, txtRecord); - -} - -void p3ZeroConf::locked_startResolve(uint32_t idx, std::string name, - std::string regtype, std::string domain) -{ - if (mResolveStatus == ZC_SERVICE_ACTIVE) - { - return; - } - - std::cerr << "p3ZeroConf::locked_startResolve()"; - std::cerr << std::endl; - - DNSServiceRef *sdRef = &mResolveRef; - DNSServiceFlags flags = 0; - DNSServiceResolveReply callBack = p3ZeroConf_CallbackResolve; - void *context = (void *) this; - - DNSServiceErrorType errcode = DNSServiceResolve(sdRef, flags, idx, - name.c_str(), regtype.c_str(), domain.c_str(), callBack, context); - - if (errcode != kDNSServiceErr_NoError) - { - std::cerr << "p3ZeroConf::locked_startResolve() ERROR: "; - std::cerr << displayDNSServiceError(errcode); - std::cerr << std::endl; - } - else - { - mResolveStatus = ZC_SERVICE_ACTIVE; - mResolveStatusTS = time(NULL); - } -} - - - -void p3ZeroConf::callbackResolve( DNSServiceRef /* sdRef */, DNSServiceFlags flags, - uint32_t interfaceIndex, DNSServiceErrorType errorCode, - const char *fullname, const char *hosttarget, uint16_t port, - uint16_t txtLen, const unsigned char *txtRecord) -{ - std::cerr << "p3ZeroConf::callbackResolve()"; - std::cerr << std::endl; - - if (errorCode != kDNSServiceErr_NoError) - { - std::cerr << "p3ZeroConf::callbackResolve() FAILED ERROR: "; - std::cerr << displayDNSServiceError(errorCode); - std::cerr << std::endl; - return; - } - - /* handle resolve */ - zcResolveResult rr; - - rr.flags = flags; - rr.interfaceIndex = interfaceIndex; - rr.fullname = fullname; - rr.hosttarget = hosttarget; - rr.port = ntohs(port); - rr.txtLen = txtLen; - //rr.txtRecord = NULL; //malloc(rr.txtLen); - //memcpy(rr.txtRecord, txtRecord, txtLen); - // We must consume the txtRecord and translate into strings... - - std::cerr << "p3ZeroConf::callbackResolve() "; - std::cerr << " flags: " << flags; - std::cerr << " interfaceIndex: " << interfaceIndex; - std::cerr << " fullname: " << fullname; - std::cerr << " hosttarget: " << hosttarget; - std::cerr << " port: " << ntohs(port); - std::cerr << " txtLen: " << txtLen; - std::cerr << std::endl; - - std::string peerGpgId; - std::string peerSslId; - if (procPeerTxtRecord(txtLen, txtRecord, peerGpgId, peerSslId)) - { - rr.gpgId = peerGpgId; - rr.sslId = peerSslId; - - /* check if we care - install ssl record */ - int resolve = locked_checkResolvedPeer(rr); - if (resolve) - { - mResolveResults.push_back(rr); - } - } - - if (flags & kDNSServiceFlagsMoreComing) - { - std::cerr << "p3ZeroConf::callbackResolve() Expecting More Results.. keeping Ref"; - std::cerr << std::endl; - } - else - { - std::cerr << "p3ZeroConf::callbackResolve() Result done.. closing Ref"; - std::cerr << std::endl; - - locked_stopResolve(); - } -} - - -/* returns if we are interested in the peer */ -int p3ZeroConf::locked_checkResolvedPeer(const zcResolveResult &rr) -{ - /* if self - drop it */ - if ((rr.gpgId == mOwnGpgId) && (rr.sslId == mOwnSslId)) - { - std::cerr << "p3ZeroConf::locked_checkpeer() Found Self on LAN:"; - std::cerr << std::endl; - std::cerr << "gpgid = " << rr.gpgId; - std::cerr << std::endl; - std::cerr << "sslid = " << rr.sslId; - std::cerr << std::endl; - - return 0; - } - - /* check if peerGpgId is in structure already */ - std::map::iterator it; - it = mPeerDetails.find(rr.gpgId); - if (it == mPeerDetails.end()) - { - /* possibility we don't have any SSL ID's for this person - * check against AuthGPG() - */ - if ((AuthGPG::getAuthGPG()->isGPGAccepted(rr.gpgId)) || (rr.gpgId == mOwnGpgId)) - { - zcPeerDetails newFriend; - newFriend.gpgId = rr.gpgId; - mPeerDetails[rr.gpgId] = newFriend; - - it = mPeerDetails.find(rr.gpgId); - } - else - { - std::cerr << "p3ZeroConf::locked_checkpeer() Found Unknown peer on LAN:"; - std::cerr << std::endl; - std::cerr << "gpgid = " << rr.gpgId; - std::cerr << std::endl; - std::cerr << "sslid = " << rr.sslId; - std::cerr << std::endl; - - return 0; - } - } - - /* now see if we have an sslId */ - std::map::iterator lit; - lit = it->second.mLocations.find(rr.sslId); - if (lit == it->second.mLocations.end()) - { - /* install a new location -> flag it as this */ - zcLocationDetails loc; - loc.mSslId = rr.sslId; - loc.mStatus = ZC_STATUS_FOUND | ZC_STATUS_NEW_LOCATION; - loc.mPort = rr.port; - loc.mFullName = rr.fullname; - loc.mHostTarget = rr.hosttarget; - loc.mFoundTs = time(NULL); - - it->second.mLocations[rr.sslId] = loc; - - - std::cerr << "p3ZeroConf::locked_checkpeer() Adding New Location for:"; - std::cerr << std::endl; - std::cerr << "gpgid = " << rr.gpgId; - std::cerr << std::endl; - std::cerr << "sslid = " << rr.sslId; - std::cerr << std::endl; - std::cerr << "port = " << rr.port; - std::cerr << std::endl; - - - /* install item in ADD Queue */ - zcLocationResult locResult(rr.gpgId, rr.sslId); - mLocationResults.push_back(locResult); - - /* return 1, to resolve fully */ - return 1; - } - - - std::cerr << "p3ZeroConf::locked_checkpeer() Updating Location for:"; - std::cerr << std::endl; - std::cerr << "gpgid = " << rr.gpgId; - std::cerr << std::endl; - std::cerr << "sslid = " << rr.sslId; - std::cerr << std::endl; - std::cerr << "port = " << rr.port; - std::cerr << std::endl; - - lit->second.mStatus |= ZC_STATUS_FOUND; - lit->second.mPort = rr.port; - lit->second.mFullName = rr.fullname; - lit->second.mHostTarget = rr.hosttarget; - lit->second.mFoundTs = time(NULL); - - /* otherwise we get here - and we see if we are already connected */ - if (lit->second.mStatus & ZC_STATUS_CONNECTED) - { - return 0; - } - return 1; -} - -int p3ZeroConf::locked_stopResolve() -{ - std::cerr << "p3ZeroConf::locked_stopResolve()"; - std::cerr << std::endl; - - if (mResolveStatus != ZC_SERVICE_ACTIVE) - { - return 0; - } - - DNSServiceRefDeallocate(mResolveRef); - mResolveStatus = ZC_SERVICE_STOPPED; - mResolveStatusTS = time(NULL); - return 1; -} - - - - -void p3ZeroConf_CallbackQueryIp( DNSServiceRef sdRef, DNSServiceFlags flags, - uint32_t interfaceIndex, DNSServiceErrorType errorCode, - const char *fullname, uint16_t rrtype, uint16_t rrclass, - uint16_t rdlen, const void *rdata, uint32_t ttl, void *context ) -{ - p3ZeroConf *zc = (p3ZeroConf *) context; - zc->callbackQueryIp(sdRef, flags, interfaceIndex, errorCode, fullname, rrtype, rrclass, rdlen, rdata, ttl); - -} - -void p3ZeroConf::locked_startQueryIp(uint32_t idx, std::string hosttarget, std::string gpgId, std::string sslId) -{ - if (mQueryStatus == ZC_SERVICE_ACTIVE) - { - return; - } - - std::cerr << "p3ZeroConf::locked_startQueryIp()"; - std::cerr << std::endl; - std::cerr << "\thosttarget: " << hosttarget; - std::cerr << std::endl; - std::cerr << "\tgpgId: " << gpgId; - std::cerr << std::endl; - std::cerr << "\tsslId: " << sslId; - std::cerr << std::endl; - - - DNSServiceRef *sdRef = &mQueryRef; - DNSServiceFlags flags = 0; - uint16_t rrtype = kDNSServiceType_A; - uint16_t rrclass = kDNSServiceClass_IN; - DNSServiceQueryRecordReply callBack = p3ZeroConf_CallbackQueryIp; - void *context = (void *) this; - - DNSServiceErrorType errcode = DNSServiceQueryRecord(sdRef, flags, idx, - hosttarget.c_str(), rrtype, rrclass, callBack, context); - - if (errcode != kDNSServiceErr_NoError) - { - std::cerr << "p3ZeroConf::locked_startQueryIp() ERROR: "; - std::cerr << displayDNSServiceError(errcode); - std::cerr << std::endl; - } - else - { - std::cerr << "p3ZeroConf::locked_startQueryIp() Query Active"; - std::cerr << std::endl; - - mQueryStatus = ZC_SERVICE_ACTIVE; - mQueryStatusTS = time(NULL); - mQueryGpgId = gpgId; - mQuerySslId = sslId; - } -} - -void p3ZeroConf::callbackQueryIp( DNSServiceRef /* sdRef */, DNSServiceFlags flags, - uint32_t interfaceIndex, DNSServiceErrorType errorCode, - const char *fullname, uint16_t rrtype, uint16_t rrclass, - uint16_t rdlen, const void *rdata, uint32_t ttl) -{ - std::cerr << "p3ZeroConf::callbackQueryIp()"; - std::cerr << std::endl; - - /* handle queryIp */ - if (errorCode != kDNSServiceErr_NoError) - { - std::cerr << "p3ZeroConf::callbackQueryIp() FAILED ERROR: "; - std::cerr << displayDNSServiceError(errorCode); - std::cerr << std::endl; - return; - } - - /* handle resolve */ - zcQueryResult qr; - - qr.flags = flags; - qr.interfaceIndex = interfaceIndex; - qr.fullname = fullname; - qr.rrtype = rrtype; - qr.rrclass = rrclass; - qr.rdlen = rdlen; - //qr.rdata = NULL; //malloc(rr.rdlen); - //memcpy(rr.rdata, rdata, rdlen); - qr.ttl = ttl; - - std::cerr << "p3ZeroConf::callbackQuery() "; - std::cerr << " flags: " << flags; - std::cerr << " interfaceIndex: " << interfaceIndex; - std::cerr << " fullname: " << fullname; - std::cerr << " rrtype: " << rrtype; - std::cerr << " rrclass: " << rrclass; - std::cerr << " rdlen: " << rdlen; - std::cerr << " ttl: " << ttl; - std::cerr << std::endl; - - /* add in the query Ids, that we saved... */ - qr.sslId = mQuerySslId; - qr.gpgId = mQueryGpgId; - - if ((rrtype == kDNSServiceType_A) && (rdlen == 4)) - { - // IPV4 type. - sockaddr_storage_clear(qr.addr); - struct sockaddr_in *addr = (struct sockaddr_in *) &(qr.addr); - addr->sin_family = AF_INET; - addr->sin_addr.s_addr = *((uint32_t *) rdata); - addr->sin_port = htons(0); - - if (locked_completeQueryResult(qr)) // Saves Query Results, and fills in Port details. - { - mQueryResults.push_back(qr); - } - } - else - { - std::cerr << "p3ZeroConf::callbackQuery() Unknown rrtype"; - std::cerr << std::endl; - } - - if (flags & kDNSServiceFlagsMoreComing) - { - std::cerr << "p3ZeroConf::callbackQuery() Expecting More Results.. keeping Ref"; - std::cerr << std::endl; - } - else - { - std::cerr << "p3ZeroConf::callbackQuery() Result done.. closing Ref"; - std::cerr << std::endl; - - locked_stopQueryIp(); - } -} - - -/* returns 1 if all is good */ -int p3ZeroConf::locked_completeQueryResult(zcQueryResult &qr) -{ - /* check if peerGpgId is in structure already */ - std::map::iterator it; - it = mPeerDetails.find(qr.gpgId); - if (it == mPeerDetails.end()) - { - /* Should not be possible to get here! */ - std::cerr << "p3ZeroConf::locked_completeQueryResults() Missing GPGID"; - std::cerr << std::endl; - - return 0; - } - - /* now see if we have an sslId */ - std::map::iterator lit; - lit = it->second.mLocations.find(qr.sslId); - if (lit == it->second.mLocations.end()) - { - /* Should not be possible to get here! */ - std::cerr << "p3ZeroConf::locked_completeQueryResults() Missing SSLID"; - std::cerr << std::endl; - - return 0; - } - - - /*** NOW HAVE FOUND ENTRY, exchange info ****/ - - std::cerr << "p3ZeroConf::locked_completeQueryResults() Filling in Peer IpAddress"; - std::cerr << std::endl; - - sockaddr_storage_setport(qr.addr, lit->second.mPort); - lit->second.mAddress = qr.addr; - lit->second.mStatus |= ZC_STATUS_IPADDRESS; - lit->second.mAddrTs = time(NULL); - - /* if we have connected? */ - if (lit->second.mStatus & ZC_STATUS_CONNECTED) - { - std::cerr << "p3ZeroConf::locked_completeQueryResults() Warning Already Connected"; - std::cerr << std::endl; - } - return 1; -} - - -int p3ZeroConf::locked_stopQueryIp() -{ - std::cerr << "p3ZeroConf::locked_stopQueryIp()"; - std::cerr << std::endl; - - if (mQueryStatus != ZC_SERVICE_ACTIVE) - { - return 0; - } - - DNSServiceRefDeallocate(mQueryRef); - mQueryStatus = ZC_SERVICE_STOPPED; - mQueryStatusTS = time(NULL); - return 1; -} - - - - -std::string displayDNSServiceError(DNSServiceErrorType errcode) -{ - std::string str; - switch(errcode) - { - default: - str = "kDNSServiceErr_??? UNKNOWN-CODE"; - break; - case kDNSServiceErr_NoError: - str = "kDNSServiceErr_NoError"; - break; - case kDNSServiceErr_Unknown: - str = "kDNSServiceErr_Unknown"; - break; - case kDNSServiceErr_NoSuchName: - str = "kDNSServiceErr_NoSuchName"; - break; - case kDNSServiceErr_NoMemory: - str = "kDNSServiceErr_NoMemory"; - break; - case kDNSServiceErr_BadParam: - str = "kDNSServiceErr_BadParam"; - break; - case kDNSServiceErr_BadReference: - str = "kDNSServiceErr_BadReference"; - break; - case kDNSServiceErr_BadState: - str = "kDNSServiceErr_BadState"; - break; - case kDNSServiceErr_BadFlags: - str = "kDNSServiceErr_BadFlags"; - break; - case kDNSServiceErr_Unsupported: - str = "kDNSServiceErr_Unsupported"; - break; - case kDNSServiceErr_NotInitialized: - str = "kDNSServiceErr_NotInitialized"; - break; - case kDNSServiceErr_AlreadyRegistered: - str = "kDNSServiceErr_AlreadyRegistered"; - break; - case kDNSServiceErr_NameConflict: - str = "kDNSServiceErr_NameConflict"; - break; - case kDNSServiceErr_Invalid: - str = "kDNSServiceErr_Invalid"; - break; - case kDNSServiceErr_Firewall: - str = "kDNSServiceErr_Firewall"; - break; - case kDNSServiceErr_Incompatible: - str = "kDNSServiceErr_Incompatible"; - break; - case kDNSServiceErr_BadInterfaceIndex: - str = "kDNSServiceErr_BadInterfaceIndex"; - break; - case kDNSServiceErr_Refused: - str = "kDNSServiceErr_Refused"; - break; - case kDNSServiceErr_NoSuchRecord: - str = "kDNSServiceErr_NoSuchRecord"; - break; - case kDNSServiceErr_NoAuth: - str = "kDNSServiceErr_NoAuth"; - break; - case kDNSServiceErr_NoSuchKey: - str = "kDNSServiceErr_NoSuchKey"; - break; - case kDNSServiceErr_NATTraversal: - str = "kDNSServiceErr_NATTraversal"; - break; - case kDNSServiceErr_DoubleNAT: - str = "kDNSServiceErr_DoubleNAT"; - break; - case kDNSServiceErr_BadTime: - str = "kDNSServiceErr_BadTime"; - break; - case kDNSServiceErr_BadSig: - str = "kDNSServiceErr_BadSig"; - break; - case kDNSServiceErr_BadKey: - str = "kDNSServiceErr_BadKey"; - break; - case kDNSServiceErr_Transient: - str = "kDNSServiceErr_Transient"; - break; - case kDNSServiceErr_ServiceNotRunning: - str = "kDNSServiceErr_ServiceNotRunning"; - break; - case kDNSServiceErr_NATPortMappingUnsupported: - str = "kDNSServiceErr_NATPortMappingUnsupported"; - break; - case kDNSServiceErr_NATPortMappingDisabled: - str = "kDNSServiceErr_NATPortMappingDisabled"; - break; -#if 0 - case kDNSServiceErr_NoRouter: - str = "kDNSServiceErr_NoRouter"; - break; - case kDNSServiceErr_PollingMode: - str = "kDNSServiceErr_PollingMode"; - break; -#endif - } - - return str; -} - - - -/*********************************************************************************** - * Handle Peer Data, list of friends etc. - * - * We need data structures to handle the Info from libretroshare, - * and the info from ZeroConf too. - * - ****/ - -/* This needs to be a separate class - as we don't know which peer it is - * associated with until we have Resolved the details. - */ - -class RsZCBrowseDetails -{ - public: - RsZCBrowseDetails(); - - uint32_t mBrowseState; - rstime_t mBrowseUpdate; - - uint32_t mBrowseInterfaceIndex; - std::string mBrowserServiceName; - std::string mBrowserRegType; - std::string mBrowserReplyDomain; - - uint32_t mResolveInterfaceIndex; - std::string mResolveFullname; - std::string mResolveHostTarget; - uint32_t mResolvePort; - std::string mResolveTxtRecord; -}; - - - -class RsZCPeerDetails -{ - /* passed from libretroshare */ - - std::string mGpgId; - std::string mSslId; - - uint32_t mPeerStatus; /* FRIEND, FOF, ONLINE, OFFLINE */ - - /* Browse Info */ - - uint32_t mBrowseState; - rstime_t mBrowseUpdate; - - uint32_t mBrowseInterfaceIndex; - std::string mBrowserServiceName; - std::string mBrowserRegType; - std::string mBrowserReplyDomain; - - /* Resolve Info */ - - uint32_t mResolveInterfaceIndex; - std::string mResolveFullname; - std::string mResolveHostTarget; - uint32_t mResolvePort; - std::string mResolveTxtRecord; -}; - - - - - - - - - - - diff --git a/libretroshare/src/zeroconf/p3zeroconf.h b/libretroshare/src/zeroconf/p3zeroconf.h deleted file mode 100644 index 317659c4a..000000000 --- a/libretroshare/src/zeroconf/p3zeroconf.h +++ /dev/null @@ -1,286 +0,0 @@ -/******************************************************************************* - * libretroshare/src/zeroconf: p3zeroconf.h * - * * - * libretroshare: retroshare core library * - * * - * Copyright 2011-2012 by Robert Fernie * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License as * - * published by the Free Software Foundation, either version 3 of the * - * License, or (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public License * - * along with this program. If not, see . * - * * - *******************************************************************************/ -#ifndef MRK_P3_ZEROCONF_H -#define MRK_P3_ZEROCONF_H - -#include "util/rswin.h" - -#include "pqi/pqiassist.h" -#include "retroshare/rsdht.h" - -#include -#include -#include "pqi/pqinetwork.h" -#include "pqi/pqimonitor.h" -#include "pqi/p3peermgr.h" -#include "util/rsthreads.h" - -#include - - -class zcBrowseResult -{ - public: - DNSServiceFlags flags; - uint32_t interfaceIndex; - std::string serviceName; - std::string regtype; - std::string replyDomain; -}; - - -class zcResolveResult -{ - public: - zcResolveResult() { return; } // :txtRecord(NULL) { return; } - ~zcResolveResult() { return; } //{ if (txtRecord) { free(txtRecord); txtRecord = NULL; } } - - DNSServiceFlags flags; - uint32_t interfaceIndex; - std::string fullname; - std::string hosttarget; - uint16_t port; - uint16_t txtLen; - //unsigned char *txtRecord; - - // extra results. - std::string gpgId; - std::string sslId; -}; - - -class zcQueryResult -{ - public: - zcQueryResult() { return; } //:rdata(NULL) { return; } - ~zcQueryResult() {return; } //{ if (rdata) { free(rdata); rdata = NULL; } } - - DNSServiceFlags flags; - uint32_t interfaceIndex; - std::string fullname; - uint16_t rrtype; - uint16_t rrclass; - uint16_t rdlen; - //void *rdata; - uint32_t ttl; - - // Extra ones. - std::string sslId; - std::string gpgId; - struct sockaddr_storage addr; -}; - - -class zcLocationResult -{ - public: - zcLocationResult() { return; } - zcLocationResult(std::string _gpgId, std::string _sslId) - :gpgId(_gpgId), sslId(_sslId) { return; } - - std::string gpgId; - std::string sslId; -}; - -#define ZC_STATUS_NEW_LOCATION 1 -#define ZC_STATUS_FOUND 2 -#define ZC_STATUS_CONNECTED 4 -#define ZC_STATUS_IPADDRESS 8 - -class zcLocationDetails -{ - public: - std::string mSslId; - rstime_t mFoundTs; - uint32_t mStatus; - std::string mHostTarget; - std::string mFullName; - uint16_t mPort; - - struct sockaddr_storage mAddress; - rstime_t mAddrTs; -}; - - -class zcPeerDetails -{ - public: - - std::string gpgId; - std::map mLocations; - -}; - -#define ZC_SERVICE_STOPPED 0 -#define ZC_SERVICE_ACTIVE 1 - -// This is used by p3zcNatAssist too. -std::string displayDNSServiceError(DNSServiceErrorType errcode); - -class p3NetMgr; - -class p3ZeroConf: public pqiNetAssistConnect, public pqiNetListener -{ - public: - p3ZeroConf(std::string gpgid, std::string sslid, pqiConnectCb *cb, p3NetMgr *nm, p3PeerMgr *pm); -virtual ~p3ZeroConf(); - - /*** OVERLOADED from pqiNetListener ***/ - -virtual bool resetListener(struct sockaddr_in &local); - -void start(); /* starts up the thread */ - - /* pqiNetAssist - external interface functions */ -virtual int tick(); -virtual void enable(bool on); -virtual void shutdown(); /* blocking call */ -virtual void restart(); - -virtual bool getEnabled(); -virtual bool getActive(); -virtual bool getNetworkStats(uint32_t &netsize, uint32_t &localnetsize); - - /* pqiNetAssistConnect - external interface functions */ - - /* add / remove peers */ -virtual bool findPeer(std::string id); -virtual bool dropPeer(std::string id); - -virtual int addBadPeer(const struct sockaddr_storage &addr, uint32_t reason, uint32_t flags, uint32_t age); -virtual int addKnownPeer(const std::string &pid, const struct sockaddr_storage &addr, uint32_t flags); - - /* feedback on success failure of Connections */ -virtual void ConnectionFeedback(std::string pid, int state); - - /* extract current peer status */ -virtual bool getPeerStatus(std::string id, - struct sockaddr_storage &laddr, struct sockaddr_storage &raddr, - uint32_t &type, uint32_t &mode); - -virtual bool setAttachMode(bool on); - - /* pqiNetAssistConnect - external interface functions */ - - - public: - - // Callbacks must be public -> so they can be accessed. - void callbackRegister(DNSServiceRef sdRef, DNSServiceFlags flags, - DNSServiceErrorType errorCode, - const char *name, const char *regtype, const char *domain); - - void callbackBrowse(DNSServiceRef sdRef, DNSServiceFlags flags, - uint32_t interfaceIndex, DNSServiceErrorType errorCode, - const char *serviceName, const char *regtype, const char *replyDomain); - - void callbackResolve( DNSServiceRef sdRef, DNSServiceFlags flags, - uint32_t interfaceIndex, DNSServiceErrorType errorCode, - const char *fullname, const char *hosttarget, uint16_t port, - uint16_t txtLen, const unsigned char *txtRecord); - - void callbackQueryIp( DNSServiceRef sdRef, DNSServiceFlags flags, - uint32_t interfaceIndex, DNSServiceErrorType errorCode, - const char *fullname, uint16_t rrtype, uint16_t rrclass, - uint16_t rdlen, const void *rdata, uint32_t ttl); - - private: - - void createTxtRecord(); - - /* monitoring fns */ - void checkServiceFDs(); - void locked_checkFD(DNSServiceRef ref); - int checkResolveAction(); - int checkLocationResults(); - int checkQueryAction(); - int checkQueryResults(); - - /**** THESE ARE MAINLY SEMI LOCKED.... not quite sure when the callback will happen! ***/ - - int locked_startRegister(); - void locked_stopRegister(); - - int locked_startBrowse(); - int locked_stopBrowse(); - - - void locked_startResolve(uint32_t idx, std::string name, - std::string regtype, std::string domain); - int locked_checkResolvedPeer(const zcResolveResult &rr); - int locked_stopResolve(); - - void locked_startQueryIp(uint32_t idx, std::string fullname, - std::string gpgId, std::string sslId); - int locked_completeQueryResult(zcQueryResult &qr); - int locked_stopQueryIp(); - - - /**************** DATA ****************/ - - p3NetMgr *mNetMgr; - p3PeerMgr *mPeerMgr; - - RsMutex mZcMtx; - - std::string mOwnGpgId; - std::string mOwnSslId; - - bool mRegistered; - bool mTextOkay; - bool mPortOkay; - - uint16_t mLocalPort; - std::string mTextRecord; - - DNSServiceRef mRegisterRef; - DNSServiceRef mBrowseRef; - DNSServiceRef mResolveRef; - DNSServiceRef mQueryRef; - - uint32_t mRegisterStatus; - uint32_t mBrowseStatus; - uint32_t mResolveStatus; - uint32_t mQueryStatus; - - rstime_t mRegisterStatusTS; - rstime_t mBrowseStatusTS; - rstime_t mResolveStatusTS; - rstime_t mQueryStatusTS; - - std::string mQuerySslId; - std::string mQueryGpgId; - -std::list mBrowseResults; -std::list mResolveResults; -std::list mLocationResults; -std::list mQueryResults; - - - - rstime_t mMinuteTS; - - std::map mPeerDetails; -}; - -#endif /* MRK_P3_ZEROCONF_H */ - diff --git a/retroshare-gui/src/gui/ChatLobbyWidget.cpp b/retroshare-gui/src/gui/ChatLobbyWidget.cpp index f93d9a501..a5e5579a0 100644 --- a/retroshare-gui/src/gui/ChatLobbyWidget.cpp +++ b/retroshare-gui/src/gui/ChatLobbyWidget.cpp @@ -322,8 +322,8 @@ void ChatLobbyWidget::lobbyTreeWidgetCustomPopupMenu(QPoint) QPixmap pixmap ; - if(idd.mAvatar.mSize == 0 || !pixmap.loadFromData(idd.mAvatar.mData, idd.mAvatar.mSize, "PNG")) - pixmap = QPixmap::fromImage(GxsIdDetails::makeDefaultIcon(*it)) ; + if(idd.mAvatar.mSize == 0 || !GxsIdDetails::loadPixmapFromData(idd.mAvatar.mData, idd.mAvatar.mSize, pixmap, GxsIdDetails::SMALL)) + pixmap = GxsIdDetails::makeDefaultIcon(*it,GxsIdDetails::SMALL) ; QAction *action = mnu->addAction(QIcon(pixmap), QString("%1 (%2)").arg(QString::fromUtf8(idd.mNickname.c_str()), QString::fromStdString((*it).toStdString())), this, SLOT(subscribeChatLobbyAs())); action->setData(QString::fromStdString((*it).toStdString())) ; @@ -331,10 +331,14 @@ void ChatLobbyWidget::lobbyTreeWidgetCustomPopupMenu(QPoint) } } +#ifdef TO_BE_REMOVED + // This code is not needed anymore because AutoSubscribe is now automatically handled with chat room subscription. + if (item->data(COLUMN_DATA, ROLE_AUTOSUBSCRIBE).toBool()) contextMnu.addAction(QIcon(IMAGE_AUTOSUBSCRIBE), tr("Remove Auto Subscribe"), this, SLOT(autoSubscribeItem())); else if(!own_identities.empty()) contextMnu.addAction(QIcon(IMAGE_SUBSCRIBE), tr("Add Auto Subscribe"), this, SLOT(autoSubscribeItem())); +#endif contextMnu.addAction(QIcon(IMAGE_COPYRSLINK), tr("Copy RetroShare Link"), this, SLOT(copyItemLink())); } @@ -603,19 +607,16 @@ void ChatLobbyWidget::updateDisplay() item->setIcon(COLUMN_NAME, subscribed ? icon : icon.pixmap(ui.lobbyTreeWidget->iconSize(), QIcon::Disabled)); } + // In the new model (after lobby save to disk) the auto-subscribe flag is used to automatically join lobbies that where + // previously being used when the t software quits. + bool autoSubscribe = rsMsgs->getLobbyAutoSubscribe(lobby.lobby_id); - if (autoSubscribe && subscribed) + if (autoSubscribe && subscribed && _lobby_infos.find(lobby.lobby_id) == _lobby_infos.end()) { - if(_lobby_infos.find(lobby.lobby_id) == _lobby_infos.end()) - { - if (item == ui.lobbyTreeWidget->currentItem()) - { - ChatDialog::chatFriend(ChatId(lobby.lobby_id)) ; - }else{ - ChatDialog::chatFriend(ChatId(lobby.lobby_id),false) ; - } - } + ChatDialog *cd = ChatDialog::getChat(ChatId(lobby.lobby_id), RS_CHAT_OPEN); + + addChatPage(dynamic_cast(cd)); } updateItem(ui.lobbyTreeWidget, item, lobby.lobby_id, lobby.lobby_name,lobby.lobby_topic, lobby.total_number_of_peers, subscribed, autoSubscribe,lobby_flags); @@ -674,6 +675,16 @@ void ChatLobbyWidget::updateDisplay() bool autoSubscribe = rsMsgs->getLobbyAutoSubscribe(lobby.lobby_id); updateItem(ui.lobbyTreeWidget, item, lobby.lobby_id, lobby.lobby_name,lobby.lobby_topic, lobby.gxs_ids.size(), true, autoSubscribe,lobby_flags); + + std::map::iterator it = _lobby_infos.find(lobby.lobby_id) ; + + // look for chat rooms that are subscribed but not displayed as such + + if(it == _lobby_infos.end() && rsMsgs->joinVisibleChatLobby(lobby.lobby_id,lobby.gxs_id)) + { + std::cerr << "Adding back ChatLobbyDialog for subscribed lobby " << std::hex << lobby.lobby_id << std::dec << std::endl; + ChatDialog::chatFriend(ChatId(lobby.lobby_id),true) ; + } } publicSubLobbyItem->setHidden(publicSubLobbyItem->childCount()==0); publicSubLobbyItem->setText(COLUMN_NAME, tr("Public Subscribed chat rooms")+ QString(" (") + QString::number(publicSubLobbyItem->childCount())+QString(")")); diff --git a/retroshare-gui/src/gui/Circles/CreateCircleDialog.cpp b/retroshare-gui/src/gui/Circles/CreateCircleDialog.cpp index 985eeca72..8808f17a3 100644 --- a/retroshare-gui/src/gui/Circles/CreateCircleDialog.cpp +++ b/retroshare-gui/src/gui/Circles/CreateCircleDialog.cpp @@ -270,8 +270,8 @@ void CreateCircleDialog::addMember(const RsGxsIdGroup &idGroup) QPixmap pixmap ; - if(idGroup.mImage.mSize == 0 || !pixmap.loadFromData(idGroup.mImage.mData, idGroup.mImage.mSize, "PNG")) - pixmap = QPixmap::fromImage(GxsIdDetails::makeDefaultIcon(RsGxsId(idGroup.mMeta.mGroupId))); + if(idGroup.mImage.mSize == 0 || !GxsIdDetails::loadPixmapFromData(idGroup.mImage.mData, idGroup.mImage.mSize, pixmap, GxsIdDetails::SMALL)) + pixmap = GxsIdDetails::makeDefaultIcon(RsGxsId(idGroup.mMeta.mGroupId),GxsIdDetails::SMALL); if (idGroup.mPgpKnown){ RsPeerDetails details; @@ -331,8 +331,8 @@ void CreateCircleDialog::addCircle(const RsGxsCircleDetails &cirDetails) QPixmap pixmap ; - if(gxs_details.mAvatar.mSize == 0 || !pixmap.loadFromData(gxs_details.mAvatar.mData, gxs_details.mAvatar.mSize, "PNG")) - pixmap = QPixmap::fromImage(GxsIdDetails::makeDefaultIcon(gxs_details.mId)); + if(gxs_details.mAvatar.mSize == 0 || !GxsIdDetails::loadPixmapFromData(gxs_details.mAvatar.mData, gxs_details.mAvatar.mSize, pixmap, GxsIdDetails::SMALL)) + pixmap = GxsIdDetails::makeDefaultIcon(gxs_details.mId,GxsIdDetails::SMALL); addMember(keyId, idtype, nickname, QIcon(pixmap)); @@ -814,8 +814,8 @@ void CreateCircleDialog::loadIdentities(uint32_t token) QPixmap pixmap ; - if(idGroup.mImage.mSize == 0 || !pixmap.loadFromData(idGroup.mImage.mData, idGroup.mImage.mSize, "PNG")) - pixmap = QPixmap::fromImage(GxsIdDetails::makeDefaultIcon(RsGxsId(idGroup.mMeta.mGroupId))) ; + if(idGroup.mImage.mSize == 0 || !GxsIdDetails::loadPixmapFromData(idGroup.mImage.mData, idGroup.mImage.mSize, pixmap, GxsIdDetails::SMALL)) + pixmap = GxsIdDetails::makeDefaultIcon(RsGxsId(idGroup.mMeta.mGroupId),GxsIdDetails::SMALL) ; if (idGroup.mMeta.mGroupFlags & RSGXSID_GROUPFLAG_REALID_kept_for_compatibility) { diff --git a/retroshare-gui/src/gui/FileTransfer/TransfersDialog.cpp b/retroshare-gui/src/gui/FileTransfer/TransfersDialog.cpp index c9f912420..15b57e6d8 100644 --- a/retroshare-gui/src/gui/FileTransfer/TransfersDialog.cpp +++ b/retroshare-gui/src/gui/FileTransfer/TransfersDialog.cpp @@ -717,6 +717,7 @@ private: // we pack the couple (id of DL, id of source) into a single 32-bits pointer that is required by the AbstractItemModel class. +#pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstrict-aliasing" uint32_t src = uint32_t( *reinterpret_cast(&ref) & TRANSFERS_NB_SOURCES_BIT_MASK_32BITS ) ; uint32_t ntr = ( *reinterpret_cast(&ref)) >> TRANSFERS_NB_SOURCES_BITS_32BITS ; @@ -1108,6 +1109,8 @@ void TransfersDialog::activatePage(TransfersDialog::Page page) break ; case TransfersDialog::RemoteSharedFilesTab: ui.tabWidget->setCurrentWidget(remoteSharedFiles) ; break ; + case TransfersDialog::DownloadTab: ui.tabWidget->setCurrentWidget(ui.tab) ; + break ; } } diff --git a/retroshare-gui/src/gui/FriendsDialog.cpp b/retroshare-gui/src/gui/FriendsDialog.cpp index 545c75915..2d196978d 100644 --- a/retroshare-gui/src/gui/FriendsDialog.cpp +++ b/retroshare-gui/src/gui/FriendsDialog.cpp @@ -43,17 +43,14 @@ #include "FriendsDialog.h" #include "NetworkView.h" #include "NetworkDialog.h" +#include "gui/common/NewFriendList.h" #include "gui/Identity/IdDialog.h" -#ifdef RS_USE_CIRCLES -#include "gui/Circles/CirclesDialog.h" -#endif /* Images for Newsfeed icons */ //#define IMAGE_NEWSFEED "" //#define IMAGE_NEWSFEED_NEW ":/images/message-state-new.png" #define IMAGE_NETWORK2 ":/icons/png/netgraph.png" #define IMAGE_PEERS ":/icons/png/keyring.png" #define IMAGE_IDENTITY ":/images/identity/identities_32.png" -//#define IMAGE_CIRCLES ":/icons/png/circles.png" /****** * #define FRIENDS_DEBUG 1 @@ -62,8 +59,7 @@ static FriendsDialog *instance = NULL; /** Constructor */ -FriendsDialog::FriendsDialog(QWidget *parent) - : RsAutoUpdatePage(1500,parent) +FriendsDialog::FriendsDialog(QWidget *parent) : MainPage(parent) { /* Invoke the Qt Designer generated object setup routine */ ui.setupUi(this); @@ -77,10 +73,8 @@ FriendsDialog::FriendsDialog(QWidget *parent) ui.chatWidget->setWelcomeMessage(msg); ui.chatWidget->init(ChatId::makeBroadcastId(), tr("Broadcast")); - connect(NotifyQt::getInstance(), SIGNAL(chatMessageReceived(ChatMessage)), - this, SLOT(chatMessageReceived(ChatMessage))); - connect(NotifyQt::getInstance(), SIGNAL(chatStatusChanged(ChatId,QString)), - this, SLOT(chatStatusReceived(ChatId,QString))); + connect(NotifyQt::getInstance(), SIGNAL(chatMessageReceived(ChatMessage)), this, SLOT(chatMessageReceived(ChatMessage))); + connect(NotifyQt::getInstance(), SIGNAL(chatStatusChanged(ChatId,QString)), this, SLOT(chatStatusReceived(ChatId,QString))); #else // def RS_DIRECT_CHAT ui.tabWidget->removeTab(ui.tabWidget->indexOf(ui.groupChatTab)); #endif // def RS_DIRECT_CHAT @@ -97,47 +91,15 @@ FriendsDialog::FriendsDialog(QWidget *parent) ui.tabWidget->addTab(networkView = new NetworkView(),QIcon(IMAGE_NETWORK2), tr("Network graph")); ui.tabWidget->addTab(networkDialog = new NetworkDialog(),QIcon(IMAGE_PEERS), tr("Keyring")); - //ui.tabWidget->addTab(new ProfileWidget(), tr("Profile")); - //newsFeed = new NewsFeed(); - //int newsFeedTabIndex = ui.tabWidget->insertTab(0, newsFeed, tr("News Feed")); - //ui.tabWidget->setCurrentIndex(newsFeedTabIndex); - ui.tabWidget->hideCloseButton(0); ui.tabWidget->hideCloseButton(1); ui.tabWidget->hideCloseButton(2); ui.tabWidget->hideCloseButton(3); ui.tabWidget->hideCloseButton(4); - /* get the current text and text color of the tab bar */ - //newsFeedTabColor = ui.tabWidget->tabBar()->tabTextColor(newsFeedTabIndex); - //newsFeedText = ui.tabWidget->tabBar()->tabText(newsFeedTabIndex); - - //connect(newsFeed, SIGNAL(newsFeedChanged(int)), this, SLOT(newsFeedChanged(int))); - -// menu = new QMenu(); -// menu->addAction(ui.actionAdd_Friend); -// menu->addAction(ui.actionAdd_Group); -// menu->addAction(ui.actionCreate_new_Chat_lobby); -// -// menu->addSeparator(); -// menu->addAction(ui.actionSet_your_Avatar); -// menu->addAction(ui.actionSet_your_Personal_Message); -// -// ui.menutoolButton->setMenu(menu); - - /*QToolButton *addFriendButton = new QToolButton(this); - addFriendButton->setIcon(QIcon(":/images/user/add_user24.png")); - addFriendButton->setToolTip(tr("Add friend node")); - connect(addFriendButton, SIGNAL(clicked()), this, SLOT(addFriend())); - ui.friendList->addToolButton(addFriendButton);*/ - /* Set initial size the splitter */ ui.splitter->setStretchFactor(0, 0); ui.splitter->setStretchFactor(1, 1); - /*remove -QList sizes; - sizes << height() << 100; // Qt calculates the right sizes - ui.splitter_2->setSizes(sizes);*/ loadmypersonalstatus(); @@ -145,9 +107,9 @@ QList sizes; // load settings RsAutoUpdatePage::lockAllEvents(); - ui.friendList->setColumnVisible(FriendList::COLUMN_LAST_CONTACT, false); - ui.friendList->setColumnVisible(FriendList::COLUMN_IP, false); - ui.friendList->setColumnVisible(FriendList::COLUMN_ID, false); + ui.friendList->setColumnVisible(RsFriendListModel::COLUMN_THREAD_LAST_CONTACT, false); + ui.friendList->setColumnVisible(RsFriendListModel::COLUMN_THREAD_IP, false); + ui.friendList->setColumnVisible(RsFriendListModel::COLUMN_THREAD_ID, false); ui.friendList->setShowGroups(true); processSettings(true); RsAutoUpdatePage::unlockAllEvents(); @@ -192,10 +154,6 @@ void FriendsDialog::activatePage(FriendsDialog::Page page) { case FriendsDialog::IdTab: ui.tabWidget->setCurrentWidget(idDialog) ; break ; -#ifdef RS_USE_CIRCLES - case FriendsDialog::CirclesTab: ui.tabWidget->setCurrentWidget(circlesDialog) ; - break ; -#endif case FriendsDialog::NetworkTab: ui.tabWidget->setCurrentWidget(networkDialog) ; break ; case FriendsDialog::BroadcastTab: ui.tabWidget->setCurrentWidget(networkDialog) ; @@ -233,11 +191,6 @@ void FriendsDialog::processSettings(bool bLoad) Settings->endGroup(); } -void FriendsDialog::showEvent(QShowEvent *event) -{ - RsAutoUpdatePage::showEvent(event); -} - void FriendsDialog::chatMessageReceived(const ChatMessage &msg) { if(msg.chat_id.isBroadcast()) @@ -267,10 +220,6 @@ void FriendsDialog::chatStatusReceived(const ChatId &chat_id, const QString &sta } } -void FriendsDialog::updateDisplay() -{ -} - void FriendsDialog::addFriend() { std::string groupId = ui.friendList->getSelectedGroupId(); diff --git a/retroshare-gui/src/gui/FriendsDialog.h b/retroshare-gui/src/gui/FriendsDialog.h index 8383b18e4..6eb9cdf7a 100644 --- a/retroshare-gui/src/gui/FriendsDialog.h +++ b/retroshare-gui/src/gui/FriendsDialog.h @@ -21,8 +21,6 @@ #ifndef _FRIENDSDIALOG_H #define _FRIENDSDIALOG_H -#include "retroshare-gui/RsAutoUpdatePage.h" - #include "ui_FriendsDialog.h" #define IMAGE_NETWORK ":/icons/png/network.png" @@ -33,7 +31,7 @@ class NetworkView; class IdDialog; class CirclesDialog; -class FriendsDialog : public RsAutoUpdatePage +class FriendsDialog : public MainPage { Q_OBJECT @@ -41,9 +39,7 @@ public: enum Page { /* Fixed numbers for load and save the last page */ IdTab = 0, /** Identities page. */ -#ifdef RS_USE_CIRCLES - CirclesTab = 1, /** Circles page. */ -#endif + // CirclesTab = 1, /** Circles page - DEPRECATED - please keep the numbering. */ NetworkTab = 2, /** Network page. */ NetworkViewTab = 3, /** Network new graph. */ BroadcastTab = 4 /** Old group chat page. */ @@ -61,8 +57,6 @@ public: virtual UserNotify *getUserNotify(QObject *parent); - virtual void updateDisplay() ; // overloaded from RsAutoUpdatePage - static bool isGroupChatActive(); static void groupChatActivate(); @@ -71,14 +65,8 @@ public: NetworkDialog *networkDialog ; NetworkView *networkView ; -#ifdef RS_USE_CIRCLES - CirclesDialog *circlesDialog; -#endif IdDialog *idDialog; -protected: - void showEvent (QShowEvent *event); - private slots: void chatMessageReceived(const ChatMessage& msg); void chatStatusReceived(const ChatId& chat_id, const QString& status_string); diff --git a/retroshare-gui/src/gui/FriendsDialog.ui b/retroshare-gui/src/gui/FriendsDialog.ui index f935355d8..beb9a68e5 100644 --- a/retroshare-gui/src/gui/FriendsDialog.ui +++ b/retroshare-gui/src/gui/FriendsDialog.ui @@ -145,17 +145,14 @@ - - - 61 - 61 - + + + 0 + 0 + - - - 61 - 61 - + + false @@ -199,7 +196,7 @@ - + 0 @@ -353,11 +350,6 @@ - - StyledLabel - QLabel -
gui/common/StyledLabel.h
-
AvatarWidget QLabel @@ -365,9 +357,14 @@ 1 - FriendList + StyledLabel + QLabel +
gui/common/StyledLabel.h
+
+ + ChatWidget QWidget -
gui/common/FriendList.h
+
gui/chat/ChatWidget.h
1
@@ -382,9 +379,9 @@
gui/common/StyledElidedLabel.h
- ChatWidget + NewFriendList QWidget -
gui/chat/ChatWidget.h
+
gui/common/NewFriendList.h
1
diff --git a/retroshare-gui/src/gui/HomePage.cpp b/retroshare-gui/src/gui/HomePage.cpp index 5637a4b18..385e6c075 100644 --- a/retroshare-gui/src/gui/HomePage.cpp +++ b/retroshare-gui/src/gui/HomePage.cpp @@ -48,14 +48,15 @@ HomePage::HomePage(QWidget *parent) : MainPage(parent), ui(new Ui::HomePage), - mIncludeAllIPs(false) + mIncludeAllIPs(false), + mUseShortFormat(true) { ui->setupUi(this); updateOwnCert(); connect(ui->addButton, SIGNAL(clicked()), this, SLOT(addFriend())); - connect(ui->LoadCertFileButton, SIGNAL(clicked()), this, SLOT(loadCert())); + //connect(ui->LoadCertFileButton, SIGNAL(clicked()), this, SLOT(loadCert())); QAction *WebMailAction = new QAction(QIcon(),tr("Invite via WebMail"), this); connect(WebMailAction, SIGNAL(triggered()), this, SLOT(webMail())); @@ -75,11 +76,9 @@ HomePage::HomePage(QWidget *parent) : QObject::connect(ui->userCertEdit,SIGNAL(customContextMenuRequested(QPoint)),this,SLOT(certContextMenu(QPoint))); - connect(ui->runStartWizard_PB,SIGNAL(clicked()), this,SLOT(runStartWizard())) ; connect(ui->openwebhelp,SIGNAL(clicked()), this,SLOT(openWebHelp())) ; - ui->runStartWizard_PB->hide(); // until future rework - ui->LoadCertFileButton->hide(); // duplicates functionality => not good. + //ui->LoadCertFileButton->hide(); // duplicates functionality => not good. int S = QFontMetricsF(font()).height(); QString help_str = tr( @@ -109,11 +108,19 @@ void HomePage::certContextMenu(QPoint point) menu.addAction(CopyAction); menu.addAction(SaveAction); + QAction *shortFormatAct = new QAction(QIcon(), tr("Use new (short) certificate format"),this); + connect(shortFormatAct, SIGNAL(triggered()), this, SLOT(toggleUseShortFormat())); + shortFormatAct->setCheckable(true); + shortFormatAct->setChecked(mUseShortFormat); + + menu.addAction(shortFormatAct); + if(!RsAccounts::isHiddenNode()) { - QAction *includeIPsAct = new QAction(QIcon(), mIncludeAllIPs? tr("Include only current IP"):tr("Include all your known IPs"),this); + QAction *includeIPsAct = new QAction(QIcon(), tr("Include all your known IPs"),this); connect(includeIPsAct, SIGNAL(triggered()), this, SLOT(toggleIncludeAllIPs())); includeIPsAct->setCheckable(true); + includeIPsAct->setChecked(mIncludeAllIPs); menu.addAction(includeIPsAct); } @@ -121,6 +128,11 @@ void HomePage::certContextMenu(QPoint point) menu.exec(QCursor::pos()); } +void HomePage::toggleUseShortFormat() +{ + mUseShortFormat = !mUseShortFormat; + updateOwnCert(); +} void HomePage::toggleIncludeAllIPs() { mIncludeAllIPs = !mIncludeAllIPs; @@ -144,11 +156,16 @@ void HomePage::updateOwnCert() return ; } - std::string invite = rsPeers->GetRetroshareInvite(detail.id,false,include_extra_locators); + std::string invite ; + + if(mUseShortFormat) + rsPeers->getShortInvite(invite,rsPeers->getOwnId(),true,!mIncludeAllIPs); + else + invite = rsPeers->GetRetroshareInvite(detail.id,false,include_extra_locators); ui->userCertEdit->setPlainText(QString::fromUtf8(invite.c_str())); - QString description = ConfCertDialog::getCertificateDescription(detail,false,include_extra_locators); + QString description = ConfCertDialog::getCertificateDescription(detail,false,mUseShortFormat,include_extra_locators); ui->userCertEdit->setToolTip(description); } @@ -232,18 +249,13 @@ void HomePage::webMail() connwiz.exec (); } -void HomePage::loadCert() -{ - ConnectFriendWizard connwiz (this); - - connwiz.setStartId(ConnectFriendWizard::Page_Cert); - connwiz.exec (); -} - -void HomePage::runStartWizard() -{ - QuickStartWizard(this).exec(); -} +// void HomePage::loadCert() +// { +// ConnectFriendWizard connwiz (this); +// +// connwiz.setStartId(ConnectFriendWizard::Page_Cert); +// connwiz.exec (); +// } void HomePage::openWebHelp() { diff --git a/retroshare-gui/src/gui/HomePage.h b/retroshare-gui/src/gui/HomePage.h index b90c1081e..58a7c65b9 100644 --- a/retroshare-gui/src/gui/HomePage.h +++ b/retroshare-gui/src/gui/HomePage.h @@ -41,10 +41,10 @@ class HomePage : public MainPage public: explicit HomePage(QWidget *parent); ~HomePage(); - - virtual QIcon iconPixmap() const { return QIcon(":/icons/png/home.png") ; } //MainPage - virtual QString pageName() const { return tr("Home") ; } //MainPage - virtual QString helpText() const { return ""; } //MainPage + + virtual QIcon iconPixmap() const { return QIcon(":/icons/png/home.png") ; } //MainPage + virtual QString pageName() const { return tr("Home") ; } //MainPage + virtual QString helpText() const { return ""; } //MainPage private slots: void certContextMenu(QPoint); @@ -52,18 +52,19 @@ private slots: void runEmailClient(); void copyCert(); void saveCert(); - void addFriend(); - void webMail(); - void loadCert(); - void runStartWizard() ; + void addFriend(); + void webMail(); + //void loadCert(); void openWebHelp() ; void recommendFriends(); - void toggleIncludeAllIPs(); + void toggleIncludeAllIPs(); + void toggleUseShortFormat(); private: Ui::HomePage *ui; - - bool mIncludeAllIPs; + + bool mIncludeAllIPs; + bool mUseShortFormat; }; diff --git a/retroshare-gui/src/gui/HomePage.ui b/retroshare-gui/src/gui/HomePage.ui index da8d7b25d..fea881a6f 100644 --- a/retroshare-gui/src/gui/HomePage.ui +++ b/retroshare-gui/src/gui/HomePage.ui @@ -14,6 +14,25 @@ Form + + + + + 0 + 0 + + + + + + + :/images/logo/logo_web_nobackground.png + + + Qt::AlignCenter + + + @@ -52,7 +71,7 @@ ... - + :/icons/help_64.png:/icons/help_64.png @@ -141,134 +160,6 @@ private and secure decentralized communication platform.
- - - - - 0 - 0 - - - - - - - :/images/logo/logo_web_nobackground.png - - - Qt::AlignCenter - - - - - - - Launch startup wizard - - - - :/images/tools_wizard.png:/images/tools_wizard.png - - - - - - - - - - - - - - 11 - - - - - - - Did you receive a certificate from a friend? - - - - - - - Add friends certificate - - - - :/icons/png/invite.png:/icons/png/invite.png - - - - 24 - 24 - - - - Qt::ToolButtonTextBesideIcon - - - false - - - - - - - Add certificate file - - - - :/icons/svg/folders1.svg:/icons/svg/folders1.svg - - - - 24 - 24 - - - - Qt::ToolButtonTextBesideIcon - - - false - - - - - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - @@ -316,18 +207,105 @@ private and secure decentralized communication platform. + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + + + + + + 11 + + + + + + + Did you receive a certificate from a friend? + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Add friends certificate + + + + :/icons/png/invite.png:/icons/png/invite.png + + + + 24 + 24 + + + + Qt::ToolButtonTextBesideIcon + + + false + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + label addFrame label_2 addframe - runStartWizard_PB frame helpframe - + diff --git a/retroshare-gui/src/gui/Identity/IdDetailsDialog.cpp b/retroshare-gui/src/gui/Identity/IdDetailsDialog.cpp index 58378a656..e5aae3b49 100644 --- a/retroshare-gui/src/gui/Identity/IdDetailsDialog.cpp +++ b/retroshare-gui/src/gui/Identity/IdDetailsDialog.cpp @@ -183,11 +183,11 @@ void IdDetailsDialog::insertIdDetails(uint32_t token) QPixmap pixmap; - if(data.mImage.mSize > 0 && pixmap.loadFromData(data.mImage.mData, data.mImage.mSize, "PNG")) - ui->avatarLabel->setPixmap(pixmap) ; + if(data.mImage.mSize > 0 && GxsIdDetails::loadPixmapFromData(data.mImage.mData, data.mImage.mSize, pixmap, GxsIdDetails::LARGE)) + ui->avatarLabel->setPixmap(pixmap); else { - pixmap = QPixmap::fromImage(GxsIdDetails::makeDefaultIcon(RsGxsId(data.mMeta.mGroupId)) ) ; + pixmap = GxsIdDetails::makeDefaultIcon(RsGxsId(data.mMeta.mGroupId),GxsIdDetails::LARGE) ; ui->avatarLabel->setPixmap(pixmap) ; // we need to use the default pixmap here, generated from the ID } diff --git a/retroshare-gui/src/gui/Identity/IdDialog.cpp b/retroshare-gui/src/gui/Identity/IdDialog.cpp index d9e06df09..d5b6b799b 100644 --- a/retroshare-gui/src/gui/Identity/IdDialog.cpp +++ b/retroshare-gui/src/gui/Identity/IdDialog.cpp @@ -752,8 +752,8 @@ void IdDialog::loadCircleGroupMeta(const uint32_t &token) QPixmap pixmap ; - if(idd.mAvatar.mSize == 0 || !pixmap.loadFromData(idd.mAvatar.mData, idd.mAvatar.mSize, "PNG")) - pixmap = QPixmap::fromImage(GxsIdDetails::makeDefaultIcon(it->first)) ; + if(idd.mAvatar.mSize == 0 || !GxsIdDetails::loadPixmapFromData(idd.mAvatar.mData, idd.mAvatar.mSize, pixmap,GxsIdDetails::SMALL)) + pixmap = GxsIdDetails::makeDefaultIcon(it->first,GxsIdDetails::SMALL) ; if(has_id) subitem->setText(CIRCLEGROUP_CIRCLE_COL_GROUPNAME, QString::fromUtf8(idd.mNickname.c_str())) ; @@ -1551,8 +1551,8 @@ bool IdDialog::fillIdListItem(const RsGxsIdGroup& data, QTreeWidgetItem *&item, QPixmap pixmap ; - if(data.mImage.mSize == 0 || !pixmap.loadFromData(data.mImage.mData, data.mImage.mSize, "PNG")) - pixmap = QPixmap::fromImage(GxsIdDetails::makeDefaultIcon(RsGxsId(data.mMeta.mGroupId))) ; + if(data.mImage.mSize == 0 || !GxsIdDetails::loadPixmapFromData(data.mImage.mData, data.mImage.mSize, pixmap,GxsIdDetails::SMALL)) + pixmap = GxsIdDetails::makeDefaultIcon(RsGxsId(data.mMeta.mGroupId),GxsIdDetails::SMALL) ; item->setIcon(RSID_COL_NICKNAME, QIcon(pixmap)); @@ -1797,8 +1797,8 @@ void IdDialog::insertIdDetails(uint32_t token) QPixmap pixmap ; - if(data.mImage.mSize == 0 || !pixmap.loadFromData(data.mImage.mData, data.mImage.mSize, "PNG")) - pixmap = QPixmap::fromImage(GxsIdDetails::makeDefaultIcon(RsGxsId(data.mMeta.mGroupId))) ; + if(data.mImage.mSize == 0 || !GxsIdDetails::loadPixmapFromData(data.mImage.mData, data.mImage.mSize, pixmap,GxsIdDetails::LARGE)) + pixmap = GxsIdDetails::makeDefaultIcon(RsGxsId(data.mMeta.mGroupId),GxsIdDetails::LARGE) ; #ifdef ID_DEBUG std::cerr << "Setting header frame image : " << pixmap.width() << " x " << pixmap.height() << std::endl; @@ -1987,11 +1987,11 @@ QString IdDialog::createUsageString(const RsIdentityUsage& u) const RetroShareLink::enumType service_type = RetroShareLink::TYPE_UNKNOWN; switch(u.mServiceId) - { - case RS_SERVICE_GXS_TYPE_CHANNELS: service_name = tr("Channels") ;service_type = RetroShareLink::TYPE_CHANNEL ; break ; - case RS_SERVICE_GXS_TYPE_FORUMS: service_name = tr("Forums") ; service_type = RetroShareLink::TYPE_FORUM ; break ; - case RS_SERVICE_GXS_TYPE_POSTED: service_name = tr("Posted") ; service_type = RetroShareLink::TYPE_POSTED ; break ; - case RS_SERVICE_TYPE_CHAT: service_name = tr("Chat") ; service_type = RetroShareLink::TYPE_CHAT_ROOM ; break ; + { + case RsServiceType::CHANNELS: service_name = tr("Channels") ;service_type = RetroShareLink::TYPE_CHANNEL ; break ; + case RsServiceType::FORUMS: service_name = tr("Forums") ; service_type = RetroShareLink::TYPE_FORUM ; break ; + case RsServiceType::POSTED: service_name = tr("Posted") ; service_type = RetroShareLink::TYPE_POSTED ; break ; + case RsServiceType::CHAT: service_name = tr("Chat") ; service_type = RetroShareLink::TYPE_CHAT_ROOM ; break ; default: service_name = tr("Unknown"); service_type = RetroShareLink::TYPE_UNKNOWN ; } @@ -2470,8 +2470,8 @@ void IdDialog::IdListCustomPopupMenu( QPoint ) QPixmap pixmap ; - if(idd.mAvatar.mSize == 0 || !pixmap.loadFromData(idd.mAvatar.mData, idd.mAvatar.mSize, "PNG")) - pixmap = QPixmap::fromImage(GxsIdDetails::makeDefaultIcon(*it)) ; + if(idd.mAvatar.mSize == 0 || !GxsIdDetails::loadPixmapFromData(idd.mAvatar.mData, idd.mAvatar.mSize, pixmap,GxsIdDetails::SMALL)) + pixmap = GxsIdDetails::makeDefaultIcon(*it,GxsIdDetails::SMALL) ; QAction *action = mnu->addAction(QIcon(pixmap), QString("%1 (%2)").arg(QString::fromUtf8(idd.mNickname.c_str()), QString::fromStdString((*it).toStdString())), this, SLOT(chatIdentity())); action->setData(QString::fromStdString((*it).toStdString())) ; diff --git a/retroshare-gui/src/gui/Identity/IdEditDialog.cpp b/retroshare-gui/src/gui/Identity/IdEditDialog.cpp index d0b0d72ee..bde6b8f0d 100644 --- a/retroshare-gui/src/gui/Identity/IdEditDialog.cpp +++ b/retroshare-gui/src/gui/Identity/IdEditDialog.cpp @@ -195,7 +195,7 @@ void IdEditDialog::setAvatar(const QPixmap &avatar) ui->avatarLabel->setPixmap(mAvatar); } else { // we need to use the default pixmap here, generated from the ID - ui->avatarLabel->setPixmap(QPixmap::fromImage(GxsIdDetails::makeDefaultIcon(RsGxsId(mEditGroup.mMeta.mGroupId)))); + ui->avatarLabel->setPixmap(GxsIdDetails::makeDefaultIcon(RsGxsId(mEditGroup.mMeta.mGroupId))); } } @@ -257,9 +257,8 @@ void IdEditDialog::loadExistingId(uint32_t token) mGroupId = mEditGroup.mMeta.mGroupId; QPixmap avatar; - if (mEditGroup.mImage.mSize > 0) { - avatar.loadFromData(mEditGroup.mImage.mData, mEditGroup.mImage.mSize, "PNG"); - } + if (mEditGroup.mImage.mSize > 0) + GxsIdDetails::loadPixmapFromData(mEditGroup.mImage.mData, mEditGroup.mImage.mSize, avatar,GxsIdDetails::LARGE); setAvatar(avatar); diff --git a/retroshare-gui/src/gui/MainWindow.cpp b/retroshare-gui/src/gui/MainWindow.cpp index 3a81877ce..b0a438930 100644 --- a/retroshare-gui/src/gui/MainWindow.cpp +++ b/retroshare-gui/src/gui/MainWindow.cpp @@ -31,10 +31,13 @@ #include #include +#ifdef MESSENGER_WINDOW +#include "MessengerWindow.h" +#endif + #include "rshare.h" #include "MainWindow.h" #include "ui_MainWindow.h" -#include "MessengerWindow.h" #include "HomePage.h" #include "NetworkDialog.h" #include "gui/FileTransfer/SearchDialog.h" @@ -172,6 +175,16 @@ MainWindow::MainWindow(QWidget* parent, Qt::WindowFlags flags) ui = new Ui::MainWindow; trayIcon = NULL; + friendsDialog=NULL; + idDialog=NULL; + chatLobbyDialog=NULL; + settingsDialog=NULL; + transfersDialog=NULL; + messagesDialog=NULL; + gxschannelDialog=NULL; + gxsforumDialog=NULL; + postedDialog=NULL; + /* Invoke the Qt Designer generated QObject setup routine */ ui->setupUi(this); @@ -359,7 +372,9 @@ MainWindow::~MainWindow() delete soundStatus; delete toasterDisable; delete sysTrayStatus; +#ifdef MESSENGER_WINDOW MessengerWindow::releaseInstance(); +#endif #ifdef UNFINISHED delete applicationWindow; #endif @@ -586,7 +601,9 @@ void MainWindow::createTrayIcon() notifyMenu->menuAction()->setVisible(false); trayMenu->addSeparator(); +#ifdef MESSENGER_WINDOW trayMenu->addAction(QIcon(IMAGE_MESSENGER), tr("Open Messenger"), this, SLOT(showMessengerWindow())); +#endif trayMenu->addAction(QIcon(IMAGE_MESSAGES), tr("Open Messages"), this, SLOT(showMess())); #ifdef ENABLE_WEBUI trayMenu->addAction(QIcon(":/images/emblem-web.png"), tr("Show web interface"), this, SLOT(showWebinterface())); @@ -1085,11 +1102,13 @@ void MainWindow::showSettings() showWindow(MainWindow::Options); } +#ifdef MESSENGER_WINDOW /** Shows Messenger window */ void MainWindow::showMessengerWindow() { MessengerWindow::showYourself(); } +#endif /** Shows Statistics window */ void MainWindow::showStatisticsWindow() diff --git a/retroshare-gui/src/gui/MainWindow.h b/retroshare-gui/src/gui/MainWindow.h index d90b9e8bc..00c2b2664 100644 --- a/retroshare-gui/src/gui/MainWindow.h +++ b/retroshare-gui/src/gui/MainWindow.h @@ -59,7 +59,6 @@ class NetworkDialog; class SearchDialog; class TransfersDialog; class MessagesDialog; -class MessengerWindow; class PluginsPage; class HomePage; //class ChannelFeed; @@ -68,6 +67,9 @@ class MainPage; class NewsFeed; class UserNotify; +#ifdef MESSENGER_WINDOW +class MessengerWindow; +#endif #ifdef UNFINISHED class ApplicationWindow; #endif @@ -224,7 +226,9 @@ private slots: /** Toolbar fns. */ void addFriend(); //void newRsCollection(); +#ifdef MESSENGER_WINDOW void showMessengerWindow(); +#endif void showStatisticsWindow(); #ifdef ENABLE_WEBUI void showWebinterface(); diff --git a/retroshare-gui/src/gui/People/IdentityWidget.cpp b/retroshare-gui/src/gui/People/IdentityWidget.cpp index 64f1873d9..53c9ba8f9 100644 --- a/retroshare-gui/src/gui/People/IdentityWidget.cpp +++ b/retroshare-gui/src/gui/People/IdentityWidget.cpp @@ -100,7 +100,8 @@ void IdentityWidget::updateData(const RsGxsIdGroup &gxs_group_info) ui->labelPositive->setText(QString::number(info.mFriendsPositiveVotes)); ui->labelNegative->setText(QString::number(info.mFriendsNegativeVotes)); - if (!_havePGPDetail) { + if (!_havePGPDetail) + { QFont font = ui->labelName->font(); font.setItalic(false); ui->labelName->setFont(font); @@ -110,23 +111,17 @@ void IdentityWidget::updateData(const RsGxsIdGroup &gxs_group_info) ui->labelKeyId->setText(_keyId); ui->labelKeyId->setVisible(false); - /// (TODO) Get real ident icon - QImage image; - - if(_group_info.mImage.mSize > 0 && image.loadFromData(_group_info.mImage.mData, _group_info.mImage.mSize, "PNG")) - image = image; - else - image = GxsIdDetails::makeDefaultIcon(RsGxsId(_group_info.mMeta.mGroupId)); - - if (_avatar != image) { - _avatar = image; - _scene->clear(); - _scene->addPixmap(QPixmap::fromImage(image.scaled(ui->graphicsView->width(),ui->graphicsView->height()))); - emit imageUpdated(); - }//if (_avatar != image) - }//if (!_havePGPDetail) + /// (TODO) Get real ident icon + QPixmap pixmap; - //}//if (_group_info != gxs_group_info) + if(!( (_group_info.mImage.mSize > 0) && GxsIdDetails::loadPixmapFromData(_group_info.mImage.mData, _group_info.mImage.mSize, pixmap) )) + pixmap = GxsIdDetails::makeDefaultIcon(RsGxsId(_group_info.mMeta.mGroupId)); + + _avatar = pixmap.toImage(); + _scene->clear(); + _scene->addPixmap(pixmap.scaled(ui->graphicsView->width(),ui->graphicsView->height())); + emit imageUpdated(); + } } void IdentityWidget::updateData(const RsPeerDetails &pgp_details) @@ -138,12 +133,10 @@ void IdentityWidget::updateData(const RsPeerDetails &pgp_details) _nickname = QString::fromUtf8(_details.name.c_str()); if (!_haveGXSId) m_myName = _nickname; ui->labelName->setText(m_myName); - if (_haveGXSId) { - ui->labelName->setToolTip(tr("GXS name:") + (" "+m_myName) + ("\n") - +(tr("PGP name:")+(" "+_nickname))); - } else {//if (m_myName != _nickname) + if (_haveGXSId) + ui->labelName->setToolTip(tr("GXS name:") + (" "+m_myName) + ("\n") +(tr("PGP name:")+(" "+_nickname))); + else ui->labelName->setToolTip(tr("PGP name:")+(" "+_nickname)); - }//else (m_myName != _nickname) QFont font = ui->labelName->font(); font.setItalic(true); @@ -212,11 +205,6 @@ void IdentityWidget::setIsSelected(bool value) font.setBold(value); ui->labelName->setFont(font); } -/* -bool IdentityWidget::isSelected() -{ - return m_isSelected; -}*/ void IdentityWidget::setIsCurrent(bool value) { @@ -229,11 +217,6 @@ void IdentityWidget::setIsCurrent(bool value) ui->label_NegIcon_2->setVisible(value); ui->pbAdd->setVisible(value); } -/* -bool IdentityWidget::isCurrent() -{ - return m_isCurrent; -}*/ void IdentityWidget::pbAdd_clicked() { diff --git a/retroshare-gui/src/gui/People/PeopleDialog.cpp b/retroshare-gui/src/gui/People/PeopleDialog.cpp index e97ad3c98..626df8206 100644 --- a/retroshare-gui/src/gui/People/PeopleDialog.cpp +++ b/retroshare-gui/src/gui/People/PeopleDialog.cpp @@ -426,15 +426,15 @@ void PeopleDialog::iw_AddButtonClickedExt() { IdentityWidget *dest= qobject_cast(QObject::sender()); - if (dest) { + if (dest) + { QMenu contextMnu( this ); QMenu *mnu = contextMnu.addMenu(QIcon(":/icons/png/circles.png"),tr("Invite to Circle")) ; std::map::iterator itCurs; - for( itCurs =_ext_circles_widgets.begin(); - itCurs != _ext_circles_widgets.end(); - ++itCurs) { + for( itCurs =_ext_circles_widgets.begin(); itCurs != _ext_circles_widgets.end(); ++itCurs) + { CircleWidget *curs = itCurs->second; QIcon icon = QIcon(curs->getImage()); QString name = curs->getName(); @@ -442,7 +442,7 @@ void PeopleDialog::iw_AddButtonClickedExt() QAction *action = mnu->addAction(icon, name, this, SLOT(addToCircleExt())); action->setData(QString::fromStdString(curs->groupInfo().mGroupId.toStdString()) + ";" + QString::fromStdString(dest->groupInfo().mMeta.mGroupId.toStdString())); - }//for( itCurs =_ext_circles_widgets.begin(); + } std::list own_identities ; rsIdentity->getOwnIds(own_identities) ; @@ -467,8 +467,8 @@ void PeopleDialog::iw_AddButtonClickedExt() QPixmap pixmap ; - if(idd.mAvatar.mSize == 0 || !pixmap.loadFromData(idd.mAvatar.mData, idd.mAvatar.mSize, "PNG")) - pixmap = QPixmap::fromImage(GxsIdDetails::makeDefaultIcon(*it)) ; + if(idd.mAvatar.mSize == 0 || !GxsIdDetails::loadPixmapFromData(idd.mAvatar.mData, idd.mAvatar.mSize, pixmap,GxsIdDetails::SMALL)) + pixmap = GxsIdDetails::makeDefaultIcon(*it,GxsIdDetails::SMALL) ; QAction *action = mnu->addAction(QIcon(pixmap), QString("%1 (%2)").arg(QString::fromUtf8(idd.mNickname.c_str()), QString::fromStdString((*it).toStdString())), this, SLOT(chatIdentity())); action->setData(QString::fromStdString((*it).toStdString()) + ";" + QString::fromStdString(dest->groupInfo().mMeta.mGroupId.toStdString())) ; @@ -492,7 +492,7 @@ void PeopleDialog::iw_AddButtonClickedExt() actionDetails->setData( QString::fromStdString(dest->groupInfo().mMeta.mGroupId.toStdString())); contextMnu.exec(QCursor::pos()); - }//if (dest) + } } void PeopleDialog::iw_AddButtonClickedInt() @@ -513,10 +513,10 @@ void PeopleDialog::iw_AddButtonClickedInt() QAction *action = contextMnu.addAction(icon, name, this, SLOT(addToCircleInt())); action->setData(QString::fromStdString(curs->groupInfo().mGroupId.toStdString()) + ";" + QString::fromStdString(dest->details().gpg_id.toStdString())); - }//for( itCurs =_int_circles_widgets.begin(); + } contextMnu.exec(QCursor::pos()); - }//if (dest) + } } void PeopleDialog::addToCircleExt() diff --git a/retroshare-gui/src/gui/PhotoShare/AlbumDialog.cpp b/retroshare-gui/src/gui/PhotoShare/AlbumDialog.cpp index 1a5e00ae9..e943d21d7 100644 --- a/retroshare-gui/src/gui/PhotoShare/AlbumDialog.cpp +++ b/retroshare-gui/src/gui/PhotoShare/AlbumDialog.cpp @@ -21,6 +21,7 @@ #include #include "AlbumDialog.h" +#include "gui/gxs/GxsIdDetails.h" #include "ui_AlbumDialog.h" #include "retroshare/rsgxsflags.h" @@ -60,7 +61,7 @@ void AlbumDialog::setUp() QPixmap qtn; - qtn.loadFromData(mAlbum.mThumbnail.data, mAlbum.mThumbnail.size, mAlbum.mThumbnail.type.c_str()); + GxsIdDetails::loadPixmapFromData(mAlbum.mThumbnail.data, mAlbum.mThumbnail.size, mAlbum.mThumbnail.type.c_str(),qtn); if(mAlbum.mThumbnail.size != 0) { diff --git a/retroshare-gui/src/gui/Posted/PostedDialog.cpp b/retroshare-gui/src/gui/Posted/PostedDialog.cpp index d4c288732..c312bd8e8 100644 --- a/retroshare-gui/src/gui/Posted/PostedDialog.cpp +++ b/retroshare-gui/src/gui/Posted/PostedDialog.cpp @@ -109,7 +109,9 @@ QString PostedDialog::icon(IconType type) case ICON_POPULAR_GROUP: return ""; case ICON_OTHER_GROUP: - return ""; + return ":/icons/png/feed-other.png"; + case ICON_SEARCH: + return ":/images/find.png"; case ICON_DEFAULT: return ":/icons/png/posted.png"; } @@ -163,7 +165,7 @@ void PostedDialog::loadGroupSummaryToken(const uint32_t &token, std::listmIcon[group.mMeta.mGroupId] = image; } diff --git a/retroshare-gui/src/gui/Posted/PostedGroupDialog.cpp b/retroshare-gui/src/gui/Posted/PostedGroupDialog.cpp index 6fcb14024..678c41a98 100644 --- a/retroshare-gui/src/gui/Posted/PostedGroupDialog.cpp +++ b/retroshare-gui/src/gui/Posted/PostedGroupDialog.cpp @@ -20,6 +20,7 @@ #include #include "PostedGroupDialog.h" +#include "gui/gxs/GxsIdDetails.h" #include #include @@ -163,9 +164,9 @@ bool PostedGroupDialog::service_loadGroup(uint32_t token, Mode /*mode*/, RsGroup if (group.mGroupImage.mData) { QPixmap pixmap; - if (pixmap.loadFromData(group.mGroupImage.mData, group.mGroupImage.mSize, "PNG")) { + if (GxsIdDetails::loadPixmapFromData(group.mGroupImage.mData, group.mGroupImage.mSize, pixmap,GxsIdDetails::ORIGINAL)) setLogo(pixmap); - } + } else { setLogo(QPixmap(":/icons/png/posted.png")); } diff --git a/retroshare-gui/src/gui/Posted/PostedItem.cpp b/retroshare-gui/src/gui/Posted/PostedItem.cpp index 9ad0aa839..5e42a1ef6 100644 --- a/retroshare-gui/src/gui/Posted/PostedItem.cpp +++ b/retroshare-gui/src/gui/Posted/PostedItem.cpp @@ -25,6 +25,7 @@ #include "rshare.h" #include "PostedItem.h" #include "gui/feeds/FeedHolder.h" +#include "gui/gxs/GxsIdDetails.h" #include "util/misc.h" #include "ui_PostedItem.h" @@ -255,7 +256,7 @@ void PostedItem::fill() if(mPost.mImage.mData != NULL) { QPixmap pixmap; - pixmap.loadFromData(mPost.mImage.mData, mPost.mImage.mSize, "PNG"); + GxsIdDetails::loadPixmapFromData(mPost.mImage.mData, mPost.mImage.mSize, pixmap,GxsIdDetails::ORIGINAL); // Wiping data - as its been passed to thumbnail. QPixmap sqpixmap = pixmap.scaled(desired_width,desired_height, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); diff --git a/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp b/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp index ec2994ced..da04f457a 100644 --- a/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp +++ b/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp @@ -424,9 +424,8 @@ ChatLobbyDialog::~ChatLobbyDialog() // announce leaving of lobby // check that the lobby still exists. - if (mChatId.isLobbyId()) { - rsMsgs->unsubscribeChatLobby(mChatId.toLobbyId()); - } + if (mChatId.isLobbyId()) + rsMsgs->sendLobbyStatusPeerLeaving(mChatId.toLobbyId()); // save settings processSettings(false); @@ -912,7 +911,10 @@ void ChatLobbyDialog::showDialog(uint chatflags) if (chatflags & RS_CHAT_FOCUS) { MainWindow::showWindow(MainWindow::ChatLobby); - dynamic_cast(MainWindow::getPage(MainWindow::ChatLobby))->setCurrentChatPage(this) ; + MainPage *p = MainWindow::getPage(MainWindow::ChatLobby); + + if(p != NULL) + dynamic_cast(p)->setCurrentChatPage(this) ; } } diff --git a/retroshare-gui/src/gui/chat/ChatWidget.cpp b/retroshare-gui/src/gui/chat/ChatWidget.cpp index 5f29b2a20..bb7352ffd 100644 --- a/retroshare-gui/src/gui/chat/ChatWidget.cpp +++ b/retroshare-gui/src/gui/chat/ChatWidget.cpp @@ -94,6 +94,8 @@ ChatWidget::ChatWidget(QWidget *parent) //Resize Tool buttons ui->emoteiconButton->setFixedSize(buttonSize); ui->emoteiconButton->setIconSize(iconSize); + ui->stickerButton->setFixedSize(buttonSize); + ui->stickerButton->setIconSize(iconSize); ui->attachPictureButton->setFixedSize(buttonSize); ui->attachPictureButton->setIconSize(iconSize); ui->addFileButton->setFixedSize(buttonSize); @@ -145,6 +147,7 @@ ChatWidget::ChatWidget(QWidget *parent) ui->markButton->setToolTip(tr("Mark this selected text
Ctrl+M")); connect(ui->emoteiconButton, SIGNAL(clicked()), this, SLOT(smileyWidget())); + connect(ui->stickerButton, SIGNAL(clicked()), this, SLOT(stickerWidget())); connect(ui->attachPictureButton, SIGNAL(clicked()), this, SLOT(addExtraPicture())); connect(ui->addFileButton, SIGNAL(clicked()), this , SLOT(addExtraFile())); connect(ui->sendButton, SIGNAL(clicked()), this, SLOT(sendChat())); @@ -1545,6 +1548,22 @@ void ChatWidget::addSmiley() ui->chatTextEdit->textCursor().insertText(smiley); } +void ChatWidget::stickerWidget() +{ + Emoticons::showStickerWidget(this, ui->stickerButton, SLOT(sendSticker()), true); +} + +void ChatWidget::sendSticker() +{ + QString sticker = qobject_cast(sender())->statusTip(); + QString encodedImage; + if (RsHtml::makeEmbeddedImage(sticker, encodedImage, 640*480, maxMessageSize() - 200)) { //-200 for the html stuff + RsHtml::optimizeHtml(encodedImage, 0); + std::string msg = encodedImage.toUtf8().constData(); + rsMsgs->sendChat(chatId, msg); + } +} + void ChatWidget::clearChatHistory() { ui->textBrowser->clear(); diff --git a/retroshare-gui/src/gui/chat/ChatWidget.h b/retroshare-gui/src/gui/chat/ChatWidget.h index d8f949503..b1b0a23db 100644 --- a/retroshare-gui/src/gui/chat/ChatWidget.h +++ b/retroshare-gui/src/gui/chat/ChatWidget.h @@ -159,6 +159,8 @@ private slots: void smileyWidget(); void addSmiley(); + void stickerWidget(); + void sendSticker(); void addExtraFile(); void addExtraPicture(); diff --git a/retroshare-gui/src/gui/chat/ChatWidget.ui b/retroshare-gui/src/gui/chat/ChatWidget.ui index 16a411eb5..a937bf247 100644 --- a/retroshare-gui/src/gui/chat/ChatWidget.ui +++ b/retroshare-gui/src/gui/chat/ChatWidget.ui @@ -343,6 +343,32 @@ border-image: url(:/images/closepressed.png) + + + + Qt::NoFocus + + + Insert sticker + + + + + + + :/icons/png/new.png:/icons/png/new.png + + + + 28 + 28 + + + + true + + + diff --git a/retroshare-gui/src/gui/chat/PopupChatWindow.cpp b/retroshare-gui/src/gui/chat/PopupChatWindow.cpp index 8cf4b1601..17c2c38c3 100644 --- a/retroshare-gui/src/gui/chat/PopupChatWindow.cpp +++ b/retroshare-gui/src/gui/chat/PopupChatWindow.cpp @@ -22,6 +22,7 @@ #include #include +#include #include "PopupChatWindow.h" #include "ChatDialog.h" @@ -75,21 +76,30 @@ PopupChatWindow::PopupChatWindow(bool tabbed, QWidget *parent, Qt::WindowFlags f ui.tabWidget->setVisible(tabbedWindow); - if (Settings->getChatFlags() & RS_CHAT_TABBED_WINDOW) { - ui.actionDockTab->setVisible(tabbedWindow == false); - ui.actionUndockTab->setVisible(tabbedWindow); - } else { - ui.actionDockTab->setVisible(false); - ui.actionUndockTab->setVisible(false); - } +// if (Settings->getChatFlags() & RS_CHAT_TABBED_WINDOW) { +// ui.actionDockTab->setVisible(tabbedWindow == false); +// ui.actionUndockTab->setVisible(tabbedWindow); +// } else { +// ui.actionDockTab->setVisible(false); +// ui.actionUndockTab->setVisible(false); +// +// } + +// ui.actionAvatar->setVisible(false); // removed because it is already handled by clicking on your own avatar. +// ui.actionSetOnTop->setVisible(false);// removed, because the window manager should handle this already. +// ui.actionColor->setVisible(false);// moved to the context menu + + ui.chattoolBar->hide(); // no widgets left! setAttribute(Qt::WA_DeleteOnClose, true); - connect(ui.actionAvatar, SIGNAL(triggered()),this, SLOT(getAvatar())); - connect(ui.actionColor, SIGNAL(triggered()), this, SLOT(setStyle())); - connect(ui.actionDockTab, SIGNAL(triggered()), this, SLOT(dockTab())); - connect(ui.actionUndockTab, SIGNAL(triggered()), this, SLOT(undockTab())); - connect(ui.actionSetOnTop, SIGNAL(toggled(bool)), this, SLOT(setOnTop())); + // connect(ui.actionAvatar, SIGNAL(triggered()),this, SLOT(getAvatar())); + // connect(ui.actionColor, SIGNAL(triggered()), this, SLOT(setStyle())); + // connect(ui.actionDockTab, SIGNAL(triggered()), this, SLOT(dockTab())); + // connect(ui.actionUndockTab, SIGNAL(triggered()), this, SLOT(undockTab())); + // connect(ui.actionSetOnTop, SIGNAL(toggled(bool)), this, SLOT(setOnTop())); + + connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); connect(ui.tabWidget, SIGNAL(tabChanged(ChatDialog*)), this, SLOT(tabChanged(ChatDialog*))); connect(ui.tabWidget, SIGNAL(tabClosed(ChatDialog*)), this, SLOT(tabClosed(ChatDialog*))); @@ -102,6 +112,21 @@ PopupChatWindow::PopupChatWindow(bool tabbed, QWidget *parent, Qt::WindowFlags f } } +void PopupChatWindow::showContextMenu(QPoint) +{ + QMenu contextMnu(this); + contextMnu.addAction(QIcon(":/images/highlight.png"),tr("Choose window color..."),this,SLOT(setStyle())); + + if (Settings->getChatFlags() & RS_CHAT_TABBED_WINDOW) + { + if(tabbedWindow) + contextMnu.addAction(QIcon(":/images/tab-dock.png"),tr("Dock window"),this,SLOT(docTab())); + + contextMnu.addAction(QIcon(":/images/tab-undock.png"),tr("Dock window"),this,SLOT(undockTab())); + } + contextMnu.exec(QCursor::pos()); +} + /** Destructor. */ PopupChatWindow::~PopupChatWindow() { diff --git a/retroshare-gui/src/gui/chat/PopupChatWindow.h b/retroshare-gui/src/gui/chat/PopupChatWindow.h index d3c76c45c..86f8ebc80 100644 --- a/retroshare-gui/src/gui/chat/PopupChatWindow.h +++ b/retroshare-gui/src/gui/chat/PopupChatWindow.h @@ -55,6 +55,7 @@ protected: void closeEvent(QCloseEvent *event); private slots: + void setStyle(); void getAvatar(); void tabChanged(ChatDialog *dialog); void tabInfoChanged(ChatDialog *dialog); @@ -63,9 +64,9 @@ private slots: void dialogClose(ChatDialog *dialog); void dockTab(); void undockTab(); - void setStyle(); void setOnTop(); void blink(bool on); + void showContextMenu(QPoint p); private: bool tabbedWindow; diff --git a/retroshare-gui/src/gui/chat/PopupChatWindow.ui b/retroshare-gui/src/gui/chat/PopupChatWindow.ui index 244d6eb8f..f85a570b6 100644 --- a/retroshare-gui/src/gui/chat/PopupChatWindow.ui +++ b/retroshare-gui/src/gui/chat/PopupChatWindow.ui @@ -10,6 +10,9 @@ 451 + + Qt::CustomContextMenu + MainWindow diff --git a/retroshare-gui/src/gui/common/AvatarDefs.cpp b/retroshare-gui/src/gui/common/AvatarDefs.cpp index 926bc4dea..0332f50d0 100644 --- a/retroshare-gui/src/gui/common/AvatarDefs.cpp +++ b/retroshare-gui/src/gui/common/AvatarDefs.cpp @@ -41,11 +41,11 @@ void AvatarDefs::getOwnAvatar(QPixmap &avatar, const QString& defaultImage) } /* load image */ - avatar.loadFromData(data, size, "PNG") ; + GxsIdDetails::loadPixmapFromData(data, size, avatar,GxsIdDetails::ORIGINAL) ; free(data); } -void AvatarDefs::getAvatarFromSslId(const RsPeerId& sslId, QPixmap &avatar, const QString& defaultImage) +bool AvatarDefs::getAvatarFromSslId(const RsPeerId& sslId, QPixmap &avatar, const QString& defaultImage) { unsigned char *data = NULL; int size = 0; @@ -54,15 +54,16 @@ void AvatarDefs::getAvatarFromSslId(const RsPeerId& sslId, QPixmap &avatar, cons rsMsgs->getAvatarData(RsPeerId(sslId), data, size); if (size == 0) { avatar = QPixmap(defaultImage); - return; + return false; } /* load image */ - avatar.loadFromData(data, size, "PNG") ; + GxsIdDetails::loadPixmapFromData(data, size, avatar, GxsIdDetails::LARGE) ; free(data); + return true; } -void AvatarDefs::getAvatarFromGxsId(const RsGxsId& gxsId, QPixmap &avatar, const QString& defaultImage) +bool AvatarDefs::getAvatarFromGxsId(const RsGxsId& gxsId, QPixmap &avatar, const QString& defaultImage) { //int size = 0; @@ -72,16 +73,18 @@ void AvatarDefs::getAvatarFromGxsId(const RsGxsId& gxsId, QPixmap &avatar, const if(!rsIdentity->getIdDetails(gxsId, details)) { avatar = QPixmap(defaultImage); - return ; + return false; } /* load image */ - if(details.mAvatar.mSize == 0 || !avatar.loadFromData(details.mAvatar.mData, details.mAvatar.mSize, "PNG")) - avatar = QPixmap::fromImage(GxsIdDetails::makeDefaultIcon(gxsId)); + if(details.mAvatar.mSize == 0 || !GxsIdDetails::loadPixmapFromData(details.mAvatar.mData, details.mAvatar.mSize, avatar,GxsIdDetails::LARGE)) + avatar = GxsIdDetails::makeDefaultIcon(gxsId,GxsIdDetails::LARGE); + + return true; } -void AvatarDefs::getAvatarFromGpgId(const RsPgpId& gpgId, QPixmap &avatar, const QString& defaultImage) +bool AvatarDefs::getAvatarFromGpgId(const RsPgpId& gpgId, QPixmap &avatar, const QString& defaultImage) { unsigned char *data = NULL; int size = 0; @@ -105,11 +108,13 @@ void AvatarDefs::getAvatarFromGpgId(const RsPgpId& gpgId, QPixmap &avatar, const if (size == 0) { avatar = QPixmap(defaultImage); - return; + return false; } /* load image */ - avatar.loadFromData(data, size, "PNG") ; + GxsIdDetails::loadPixmapFromData(data, size, avatar); free(data); + + return true; } diff --git a/retroshare-gui/src/gui/common/AvatarDefs.h b/retroshare-gui/src/gui/common/AvatarDefs.h index b084b8be3..b32d58c36 100644 --- a/retroshare-gui/src/gui/common/AvatarDefs.h +++ b/retroshare-gui/src/gui/common/AvatarDefs.h @@ -35,9 +35,9 @@ class AvatarDefs public: static void getOwnAvatar(QPixmap &avatar, const QString& defaultImage = AVATAR_DEFAULT_IMAGE); - static void getAvatarFromSslId(const RsPeerId& sslId, QPixmap &avatar, const QString& defaultImage = AVATAR_DEFAULT_IMAGE); - static void getAvatarFromGpgId(const RsPgpId & gpgId, QPixmap &avatar, const QString& defaultImage = AVATAR_DEFAULT_IMAGE); - static void getAvatarFromGxsId(const RsGxsId & gxsId, QPixmap &avatar, const QString& defaultImage = AVATAR_DEFAULT_IMAGE); + static bool getAvatarFromSslId(const RsPeerId& sslId, QPixmap &avatar, const QString& defaultImage = AVATAR_DEFAULT_IMAGE); + static bool getAvatarFromGpgId(const RsPgpId & gpgId, QPixmap &avatar, const QString& defaultImage = AVATAR_DEFAULT_IMAGE); + static bool getAvatarFromGxsId(const RsGxsId & gxsId, QPixmap &avatar, const QString& defaultImage = AVATAR_DEFAULT_IMAGE); }; #endif diff --git a/retroshare-gui/src/gui/common/AvatarDialog.cpp b/retroshare-gui/src/gui/common/AvatarDialog.cpp index 921f2df54..c6a9f9c0b 100644 --- a/retroshare-gui/src/gui/common/AvatarDialog.cpp +++ b/retroshare-gui/src/gui/common/AvatarDialog.cpp @@ -45,6 +45,9 @@ AvatarDialog::AvatarDialog(QWidget *parent) : updateInterface(); } +const int AvatarDialog::RS_AVATAR_DEFAULT_IMAGE_W = 64; +const int AvatarDialog::RS_AVATAR_DEFAULT_IMAGE_H = 64; + AvatarDialog::~AvatarDialog() { delete(ui); @@ -52,7 +55,7 @@ AvatarDialog::~AvatarDialog() void AvatarDialog::changeAvatar() { - QPixmap img = misc::getOpenThumbnailedPicture(this, tr("Load Avatar"), 128, 128); + QPixmap img = misc::getOpenThumbnailedPicture(this, tr("Load Avatar"), RS_AVATAR_DEFAULT_IMAGE_W,RS_AVATAR_DEFAULT_IMAGE_H); if (img.isNull()) return; diff --git a/retroshare-gui/src/gui/common/AvatarDialog.h b/retroshare-gui/src/gui/common/AvatarDialog.h index 488f09462..407e95604 100644 --- a/retroshare-gui/src/gui/common/AvatarDialog.h +++ b/retroshare-gui/src/gui/common/AvatarDialog.h @@ -35,6 +35,9 @@ class AvatarDialog : public QDialog Q_OBJECT public: + static const int RS_AVATAR_DEFAULT_IMAGE_W ; + static const int RS_AVATAR_DEFAULT_IMAGE_H ; + AvatarDialog(QWidget *parent = 0); ~AvatarDialog(); diff --git a/retroshare-gui/src/gui/common/AvatarWidget.cpp b/retroshare-gui/src/gui/common/AvatarWidget.cpp index 3422015bc..5cd9f5d79 100644 --- a/retroshare-gui/src/gui/common/AvatarWidget.cpp +++ b/retroshare-gui/src/gui/common/AvatarWidget.cpp @@ -18,12 +18,15 @@ * * *******************************************************************************/ +#include + #include #include #include #include #include "gui/notifyqt.h" +#include "util/misc.h" #include "gui/common/AvatarDefs.h" #include "gui/common/AvatarDialog.h" @@ -85,19 +88,33 @@ void AvatarWidget::mouseReleaseEvent(QMouseEvent */*event*/) if (!mFlag.isOwnId) { return; } + QPixmap img = misc::getOpenThumbnailedPicture(this, tr("Choose avatar"), AvatarDialog::RS_AVATAR_DEFAULT_IMAGE_W,AvatarDialog::RS_AVATAR_DEFAULT_IMAGE_H); - AvatarDialog dialog(this); + if (img.isNull()) + return; - QPixmap avatar; - AvatarDefs::getOwnAvatar(avatar, ""); + setPixmap(img); - dialog.setAvatar(avatar); - if (dialog.exec() == QDialog::Accepted) { - QByteArray newAvatar; - dialog.getAvatar(newAvatar); + QByteArray data; + QBuffer buffer(&data); - rsMsgs->setOwnAvatarData((unsigned char *)(newAvatar.data()), newAvatar.size()) ; // last char 0 included. - } + buffer.open(QIODevice::WriteOnly); + img.save(&buffer, "PNG"); // writes image into a in PNG format + + rsMsgs->setOwnAvatarData((unsigned char *)(data.data()), data.size()) ; // last char 0 included. + +// AvatarDialog dialog(this); +// +// QPixmap avatar; +// AvatarDefs::getOwnAvatar(avatar, ""); +// +// dialog.setAvatar(avatar); +// if (dialog.exec() == QDialog::Accepted) { +// QByteArray newAvatar; +// dialog.getAvatar(newAvatar); +// +// rsMsgs->setOwnAvatarData((unsigned char *)(newAvatar.data()), newAvatar.size()) ; // last char 0 included. +// } } void AvatarWidget::setFrameType(FrameType type) diff --git a/retroshare-gui/src/gui/common/Emoticons.cpp b/retroshare-gui/src/gui/common/Emoticons.cpp index 4c7250746..37e40e72f 100644 --- a/retroshare-gui/src/gui/common/Emoticons.cpp +++ b/retroshare-gui/src/gui/common/Emoticons.cpp @@ -21,23 +21,40 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include #include "Emoticons.h" #include "util/HandleRichText.h" +#include "retroshare/rsinit.h" + +#define ICONNAME "groupicon.png" static QHash, QHash > > Smileys; static QVector grpOrdered; +static QVector StickerGroups; +static QStringList filters; +static QHash tooltipcache; void Emoticons::load() +{ + loadSmiley(); + filters << "*.png" << "*.jpg" << "*.gif"; + loadSticker(QString::fromStdString(RsAccounts::ConfigDirectory()) + "/stickers"); //under .retroshare, shared between users + loadSticker(QString::fromStdString(RsAccounts::AccountDirectory()) + "/stickers"); //under account, unique for user + loadSticker(QString::fromStdString(RsAccounts::systemDataDirectory()) + "/stickers"); //exe's folder, shipped with RS +} + +void Emoticons::loadSmiley() { QString sm_AllLines; bool internalFiles = true; @@ -267,3 +284,184 @@ void Emoticons::showSmileyWidget(QWidget *parent, QWidget *button, const char *s smWidget->move(x, y) ; smWidget->show() ; } + +void Emoticons::loadSticker(QString foldername) +{ + QDir dir(foldername); + if(!dir.exists()) return; + + //If it contains at a least one png then add it as a group + QStringList files = dir.entryList(filters, QDir::Files); + if(files.count() > 0) + StickerGroups.append(foldername); + + //Check subfolders + QFileInfoList subfolders = dir.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot); + for(int i = 0; isetAttribute(Qt::WA_DeleteOnClose) ; + smWidget->setWindowTitle("Stickers") ; + + if(StickerGroups.count() == 0) { + QMessageBox::warning(parent, "Stickers", "No stickers installed"); + return; + } + bool bOnlyOneGroup = (StickerGroups.count() == 1); + + QTabWidget *smTab = nullptr; + if (! bOnlyOneGroup) + { + smTab = new QTabWidget(smWidget); + QGridLayout *smGLayout = new QGridLayout(smWidget); + smGLayout->setContentsMargins(0,0,0,0); + smGLayout->addWidget(smTab); + } + + const int buttonWidth = QFontMetricsF(smWidget->font()).height()*5; + const int buttonHeight = QFontMetricsF(smWidget->font()).height()*5; + int maxRowCount = 0; + int maxCountPerLine = 0; + + QVectorIterator grp(StickerGroups); + while(grp.hasNext()) + { + QDir groupDir = QDir(grp.next()); + QString groupName = groupDir.dirName(); + groupDir.setNameFilters(filters); + + QWidget *tabGrpWidget = nullptr; + if (! bOnlyOneGroup) + { + //Lazy load tooltips for the current tab + QObject::connect(smTab, &QTabWidget::currentChanged, [=](int index){ + QWidget* current = smTab->widget(index); + loadToolTips(current); + }); + + tabGrpWidget = new QWidget(smTab); + + // (Cyril) Never use an absolute size. It needs to be scaled to the actual font size on the screen. + // + QFontMetricsF fm(parent->font()) ; + smTab->setIconSize(QSize(28*fm.height()/14.0,28*fm.height()/14.0)); + smTab->setMinimumWidth(400); + smTab->setTabPosition(QTabWidget::South); + smTab->setStyleSheet("QTabBar::tab { height: 44px; width: 44px; }"); + + int index; + if (groupDir.exists(ICONNAME)) //use groupicon.png if exists, else the first png as a group icon + index = smTab->addTab( tabGrpWidget, QIcon(groupDir.absoluteFilePath(ICONNAME)), ""); + else + index = smTab->addTab( tabGrpWidget, QIcon(groupDir.entryInfoList(QDir::Files)[0].canonicalFilePath()), ""); + smTab->setTabToolTip(index, groupName); + } else { + tabGrpWidget = smWidget; + } + + QGridLayout *tabGLayout = new QGridLayout(tabGrpWidget); + tabGLayout->setContentsMargins(0,0,0,0); + tabGLayout->setSpacing(0); + + QFileInfoList group = groupDir.entryInfoList(QDir::Files, QDir::Name); + int rowCount = (int)sqrt((double)group.size()); + int countPerLine = (group.size()/rowCount) + ((group.size() % rowCount) ? 1 : 0); + maxRowCount = qMax(maxRowCount, rowCount); + maxCountPerLine = qMax(maxCountPerLine, countPerLine); + + int lin = 0; + int col = 0; + for(int i = 0; i < group.length(); ++i) + { + QFileInfo fi = group[i]; + if(fi.fileName().compare(ICONNAME, Qt::CaseInsensitive) == 0) + continue; + QPushButton *button = new QPushButton("", tabGrpWidget); + button->setIconSize(QSize(buttonWidth, buttonHeight)); + button->setFixedSize(QSize(buttonWidth, buttonHeight)); + button->setIcon(QPixmap(fi.absoluteFilePath())); + button->setToolTip(fi.fileName()); + button->setStatusTip(fi.absoluteFilePath()); + button->setStyleSheet("QPushButton:hover {border: 3px solid #0099cc; border-radius: 3px;}"); + button->setFlat(true); + tabGLayout->addWidget(button,col,lin); + ++lin; + if(lin >= countPerLine) + { + lin = 0; + ++col; + } + QObject::connect(button, SIGNAL(clicked()), parent, slotAddMethod); + QObject::connect(button, SIGNAL(clicked()), smWidget, SLOT(close())); + } + + } + + //Load tooltips for the first page + QWidget * firstpage; + if(bOnlyOneGroup) { + firstpage = smWidget; + } else { + firstpage = smTab->currentWidget(); + } + loadToolTips(firstpage); + + //Get left up pos of button + QPoint butTopLeft = button->mapToGlobal(QPoint(0,0)); + //Get widget's size + QSize sizeWidget = smWidget->sizeHint(); + //Get screen's size + QSize sizeScreen = QApplication::desktop()->size(); + + //Calculate left distance to screen start + int distToScreenLeft = butTopLeft.x(); + //Calculate right distance to screen end + int distToRightScreen = sizeScreen.width() - (butTopLeft.x() + button->width()); + + //Calculate left position + int x; + if (distToScreenLeft >= distToRightScreen) //More distance in left than right in screen + x = butTopLeft.x() - sizeWidget.width(); //Place widget on left of button + else + x = butTopLeft.x() + button->width(); //Place widget on right of button + + //Calculate top position + int y; + if (above) //Widget must be above the button + y = butTopLeft.y() + button->height() - sizeWidget.height(); + else + y = butTopLeft.y() + button->height()/2 - sizeWidget.height()/2; //Centered on button height + + if (y + sizeWidget.height() > sizeScreen.height()) //Widget will be too low + y = sizeScreen.height() - sizeWidget.height(); //Place widget bottom at screen bottom + + if (y < 0) //Widget will be too high + y = 0; //Place widget top at screen top + + smWidget->move(x, y); + smWidget->show(); +} + +void Emoticons::loadToolTips(QWidget *container) +{ + QList children = container->findChildren(); + for(int i = 0; i < children.length(); ++i) { + if(!children[i]->toolTip().contains('<')) { + if(tooltipcache.contains(children[i]->statusTip())) { + children[i]->setToolTip(tooltipcache[children[i]->statusTip()]); + } else { + QString tooltip; + if(RsHtml::makeEmbeddedImage(children[i]->statusTip(), tooltip, 300*300)) { + tooltipcache.insert(children[i]->statusTip(), tooltip); + children[i]->setToolTip(tooltip); + } + + } + + } + } +} diff --git a/retroshare-gui/src/gui/common/Emoticons.h b/retroshare-gui/src/gui/common/Emoticons.h index 2b04fdd6d..f4b42c0ff 100644 --- a/retroshare-gui/src/gui/common/Emoticons.h +++ b/retroshare-gui/src/gui/common/Emoticons.h @@ -28,10 +28,14 @@ class Emoticons { public: static void load(); + static void loadSmiley(); + static void loadSticker(QString foldername); static void showSmileyWidget(QWidget *parent, QWidget *button, const char *slotAddMethod, bool above); + static void showStickerWidget(QWidget *parent, QWidget *button, const char *slotAddMethod, bool above); -// static void formatText(QString &text); +private: + static void loadToolTips(QWidget *container); }; #endif diff --git a/retroshare-gui/src/gui/common/FriendList.cpp b/retroshare-gui/src/gui/common/FriendList.cpp index c496bb79e..49bd7ab56 100644 --- a/retroshare-gui/src/gui/common/FriendList.cpp +++ b/retroshare-gui/src/gui/common/FriendList.cpp @@ -126,8 +126,7 @@ FriendList::FriendList(QWidget *parent) : #ifdef RS_DIRECT_CHAT connect(ui->peerTreeWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, SLOT(chatfriend(QTreeWidgetItem *))); #else - connect( ui->peerTreeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), - this, SLOT(expandItem(QTreeWidgetItem *)) ); + connect( ui->peerTreeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(expandItem(QTreeWidgetItem *)) ); #endif connect(NotifyQt::getInstance(), SIGNAL(groupsChanged(int)), this, SLOT(groupsChanged())); @@ -1014,6 +1013,7 @@ void FriendList::insertPeers() if (rsState == 0) { sslFont.setBold(true); sslColor = mTextColorStatus[RS_STATUS_ONLINE]; + } else { sslFont = StatusDefs::font(rsState); sslColor = mTextColorStatus[rsState]; @@ -1965,7 +1965,7 @@ bool FriendList::exportFriendlist(QString &fileName) /** * @brief helper function to show a message box */ -void showXMLParsingError() +static void showXMLParsingError() { // show error to user QMessageBox mbox; diff --git a/retroshare-gui/src/gui/common/FriendList.h b/retroshare-gui/src/gui/common/FriendList.h index 4aed1c43b..3a5c15bbe 100644 --- a/retroshare-gui/src/gui/common/FriendList.h +++ b/retroshare-gui/src/gui/common/FriendList.h @@ -35,6 +35,7 @@ namespace Ui { class RSTreeWidgetItemCompareRole; class QTreeWidgetItem; class QToolButton; +struct PgpItemInfo; class FriendList : public RsAutoUpdatePage { @@ -137,6 +138,7 @@ private: bool importExportFriendlistFileDialog(QString &fileName, bool import); bool exportFriendlist(QString &fileName); bool importFriendlist(QString &fileName, bool &errorPeers, bool &errorGroups); + void manageProfileLocations(QTreeWidgetItem *gpgItem,const RsPgpId& gpg_id,PgpItemInfo& info); private slots: void groupsChanged(); diff --git a/retroshare-gui/src/gui/common/FriendListModel.cpp b/retroshare-gui/src/gui/common/FriendListModel.cpp new file mode 100644 index 000000000..d7d625121 --- /dev/null +++ b/retroshare-gui/src/gui/common/FriendListModel.cpp @@ -0,0 +1,1274 @@ +/******************************************************************************* + * retroshare-gui/src/gui/msgs/RsFriendListModel.cpp * + * * + * Copyright 2019 by Cyril Soler * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include "gui/common/StatusDefs.h" +#include "gui/common/AvatarDefs.h" +#include "util/HandleRichText.h" +#include "util/DateTime.h" +#include "gui/common/FriendListModel.h" +#include "gui/gxs/GxsIdDetails.h" +#include "gui/gxs/GxsIdTreeWidgetItem.h" +#include "retroshare/rsexpr.h" +#include "retroshare/rsmsgs.h" + +//#define DEBUG_MODEL +//#define DEBUG_MODEL_INDEX + +#define IS_MESSAGE_UNREAD(flags) (flags & (RS_MSG_NEW | RS_MSG_UNREAD_BY_USER)) + +#define IMAGE_GROUP24 ":/images/user/group24.png" +#define IMAGE_STAR_ON ":/images/star-on-16.png" +#define IMAGE_STAR_OFF ":/images/star-off-16.png" + +std::ostream& operator<<(std::ostream& o, const QModelIndex& i);// defined elsewhere + +static const uint16_t UNDEFINED_GROUP_INDEX_VALUE = (sizeof(uintptr_t)==4)?0x1ff:0xffff; // max value for 9 bits +static const uint16_t UNDEFINED_NODE_INDEX_VALUE = (sizeof(uintptr_t)==4)?0x1ff:0xffff; // max value for 9 bits +static const uint16_t UNDEFINED_PROFILE_INDEX_VALUE = (sizeof(uintptr_t)==4)?0xfff:0xffff; // max value for 12 bits + +const QString RsFriendListModel::FilterString("filtered"); +const uint32_t MAX_INTERNAL_DATA_UPDATE_DELAY = 300 ; // re-update the internal data every 5 mins. Should properly cover sleep/wake-up changes. +const uint32_t MAX_NODE_UPDATE_DELAY = 1 ; // re-update the internal data every 5 mins. Should properly cover sleep/wake-up changes. + +static const uint32_t NODE_DETAILS_UPDATE_DELAY = 5; // update each node every 5 secs. + +RsFriendListModel::RsFriendListModel(QObject *parent) + : QAbstractItemModel(parent) +{ + mDisplayGroups = true; + mFilterStrings.clear(); + mLastNodeUpdate=0; + mLastInternalDataUpdate=0; +} + +RsFriendListModel::EntryIndex::EntryIndex() + : type(ENTRY_TYPE_UNKNOWN),group_index(UNDEFINED_GROUP_INDEX_VALUE),profile_index(UNDEFINED_PROFILE_INDEX_VALUE),node_index(UNDEFINED_NODE_INDEX_VALUE) +{ +} + +// The index encodes the whole hierarchy of parents. This allows to very efficiently compute indices of the parent of an index. +// +// On 32 bits architectures the format is the following: +// +// 0x [2 bits] [9 bits] [12 bits] [9 bits] +// | | | | +// | | | +---- location/node index +// | | +-------------- profile index +// | +----------------------- group index +// +-------------------------------- type +// +// On 64 bits architectures the format is the following: +// +// 0x [16 bits] [16 bits] [16 bits] [16 bits] +// | | | | +// | | | +---- location/node index +// | | +-------------- profile index +// | +----------------------- group index +// +-------------------------------- type +// +// Only valid indexes a 0x00->UNDEFINED_INDEX_VALUE-1. + +template<> bool RsFriendListModel::convertIndexToInternalId<4>(const EntryIndex& e,quintptr& id) +{ + // the internal id is set to the place in the table of items. We simply shift to allow 0 to mean something special. + + id = (((uint32_t)e.type) << 30) + ((uint32_t)e.group_index << 21) + ((uint32_t)e.profile_index << 9) + (uint32_t)e.node_index; + return true; +} +template<> bool RsFriendListModel::convertIndexToInternalId<8>(const EntryIndex& e,quintptr& id) +{ + // the internal id is set to the place in the table of items. We simply shift to allow 0 to mean something special. + + id = (((uint64_t)e.type) << 48) + ((uint64_t)e.group_index << 32) + ((uint64_t)e.profile_index << 16) + (uint64_t)e.node_index; + return true; +} + +template<> bool RsFriendListModel::convertInternalIdToIndex<4>(quintptr ref,EntryIndex& e) +{ + if(ref == 0) + return false ; + + e.group_index = (ref >> 21) & 0x1ff;// 9 bits + e.profile_index = (ref >> 9) & 0xfff;// 12 bits + e.node_index = (ref >> 0) & 0x1ff;// 9 bits + + e.type = static_cast((ref >> 30) & 0x03); + + return true; +} + +template<> bool RsFriendListModel::convertInternalIdToIndex<8>(quintptr ref,EntryIndex& e) +{ + if(ref == 0) + return false ; + + e.group_index = (ref >> 32) & 0xffff; + e.profile_index = (ref >> 16) & 0xffff; + e.node_index = (ref >> 0) & 0xffff; + + e.type = static_cast((ref >> 48) & 0xffff); + + return true; +} + + +void RsFriendListModel::setDisplayStatusString(bool b) +{ + mDisplayStatusString = b; + postMods(); +} + +void RsFriendListModel::setDisplayGroups(bool b) +{ + mDisplayGroups = b; + + updateInternalData(); +} +void RsFriendListModel::preMods() +{ + emit layoutAboutToBeChanged(); + + beginResetModel(); +} +void RsFriendListModel::postMods() +{ + endResetModel(); + emit layoutChanged(); + emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(mTopLevel.size()-1,COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL)); +} + +int RsFriendListModel::rowCount(const QModelIndex& parent) const +{ + if(parent.column() >= COLUMN_THREAD_NB_COLUMNS) + return 0; + + if(parent.internalId() == 0) + return mTopLevel.size(); + + EntryIndex index; + if(!convertInternalIdToIndex(parent.internalId(),index)) + return 0; + + if(index.type == ENTRY_TYPE_GROUP) + return mGroups[index.group_index].child_profile_indices.size(); + + if(index.type == ENTRY_TYPE_PROFILE) + if(index.group_index < UNDEFINED_GROUP_INDEX_VALUE) + return mProfiles[mGroups[index.group_index].child_profile_indices[index.profile_index]].child_node_indices.size(); + else + return mProfiles[index.profile_index].child_node_indices.size(); + + if(index.type == ENTRY_TYPE_NODE) + return 0; +} + +int RsFriendListModel::columnCount(const QModelIndex &parent) const +{ + return COLUMN_THREAD_NB_COLUMNS ; +} + +bool RsFriendListModel::hasChildren(const QModelIndex &parent) const +{ + if(!parent.isValid()) + return true; + + EntryIndex parent_index ; + convertInternalIdToIndex(parent.internalId(),parent_index); + + if(parent_index.type == ENTRY_TYPE_NODE) + return false; + + if(parent_index.type == ENTRY_TYPE_PROFILE) + if(parent_index.group_index < UNDEFINED_GROUP_INDEX_VALUE) + return !mProfiles[mGroups[parent_index.group_index].child_profile_indices[parent_index.profile_index]].child_node_indices.empty(); + else + return !mProfiles[parent_index.profile_index].child_node_indices.empty(); + + if(parent_index.type == ENTRY_TYPE_GROUP) + return !mGroups[parent_index.group_index].child_profile_indices.empty(); + + return false; +} + +RsFriendListModel::EntryIndex RsFriendListModel::EntryIndex::parent() const +{ + EntryIndex i(*this); + + switch(type) + { + case ENTRY_TYPE_GROUP: return EntryIndex(); + + case ENTRY_TYPE_PROFILE: + if(i.group_index==UNDEFINED_GROUP_INDEX_VALUE) + return EntryIndex(); + else + { + i.type = ENTRY_TYPE_GROUP; + i.profile_index = UNDEFINED_PROFILE_INDEX_VALUE; + } + break; + + case ENTRY_TYPE_NODE: i.type = ENTRY_TYPE_PROFILE; + i.node_index = UNDEFINED_NODE_INDEX_VALUE; + break; + } + + return i; +} + +RsFriendListModel::EntryIndex RsFriendListModel::EntryIndex::child(int row,const std::vector& top_level) const +{ + EntryIndex i(*this); + + switch(type) + { + case ENTRY_TYPE_UNKNOWN: + i = top_level[row]; + break; + + case ENTRY_TYPE_GROUP: i.type = ENTRY_TYPE_PROFILE; + i.profile_index = row; + break; + + case ENTRY_TYPE_PROFILE: i.type = ENTRY_TYPE_NODE; + i.node_index = row; + break; + + case ENTRY_TYPE_NODE: i = EntryIndex(); + break; + } + + return i; + +} +uint32_t RsFriendListModel::EntryIndex::parentRow(uint32_t nb_groups) const +{ + switch(type) + { + default: + case ENTRY_TYPE_UNKNOWN : return 0; + case ENTRY_TYPE_GROUP : return group_index; + case ENTRY_TYPE_PROFILE : return (group_index==UNDEFINED_GROUP_INDEX_VALUE)?(profile_index+nb_groups):profile_index; + case ENTRY_TYPE_NODE : return node_index; + } +} + +QModelIndex RsFriendListModel::index(int row, int column, const QModelIndex& parent) const +{ + if(row < 0 || column < 0 || column >= COLUMN_THREAD_NB_COLUMNS) + return QModelIndex(); + + if(parent.internalId() == 0) + { + quintptr ref ; + + convertIndexToInternalId(mTopLevel[row],ref); + return createIndex(row,column,ref) ; + } + + EntryIndex parent_index ; + convertInternalIdToIndex(parent.internalId(),parent_index); +#ifdef DEBUG_MODEL_INDEX + RsDbg() << "Index row=" << row << " col=" << column << " parent=" << parent << std::endl; +#endif + + quintptr ref; + EntryIndex new_index = parent_index.child(row,mTopLevel); + convertIndexToInternalId(new_index,ref); + +#ifdef DEBUG_MODEL_INDEX + RsDbg() << " returning " << createIndex(row,column,ref) << std::endl; +#endif + + return createIndex(row,column,ref); +} + +QModelIndex RsFriendListModel::parent(const QModelIndex& index) const +{ + if(!index.isValid()) + return QModelIndex(); + + EntryIndex I ; + convertInternalIdToIndex(index.internalId(),I); + + EntryIndex p = I.parent(); + + if(p.type == ENTRY_TYPE_UNKNOWN) + return QModelIndex(); + + quintptr i; + convertIndexToInternalId(p,i); + + return createIndex(I.parentRow(mGroups.size()),0,i); +} + +Qt::ItemFlags RsFriendListModel::flags(const QModelIndex& index) const +{ + if (!index.isValid()) + return 0; + + return QAbstractItemModel::flags(index); +} + +QVariant RsFriendListModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if(role == Qt::DisplayRole) + switch(section) + { + case COLUMN_THREAD_NAME: return tr("Name"); + case COLUMN_THREAD_ID: return tr("Id"); + case COLUMN_THREAD_LAST_CONTACT: return tr("Last contact"); + case COLUMN_THREAD_IP: return tr("IP"); + default: + return QVariant(); + } + + return QVariant(); +} + +QVariant RsFriendListModel::data(const QModelIndex &index, int role) const +{ +#ifdef DEBUG_MESSAGE_MODEL + std::cerr << "calling data(" << index << ") role=" << role << std::endl; +#endif + + if(!index.isValid()) + return QVariant(); + + quintptr ref = (index.isValid())?index.internalId():0 ; + +#ifdef DEBUG_MESSAGE_MODEL + std::cerr << "data(" << index << ")" ; +#endif + + if(!ref) + { +#ifdef DEBUG_MESSAGE_MODEL + std::cerr << " [empty]" << std::endl; +#endif + return QVariant() ; + } + + EntryIndex entry; + + if(!convertInternalIdToIndex(ref,entry)) + { +#ifdef DEBUG_MESSAGE_MODEL + std::cerr << "Bad pointer: " << (void*)ref << std::endl; +#endif + return QVariant() ; + } + + switch(role) + { + case Qt::SizeHintRole: return sizeHintRole(entry,index.column()) ; + case Qt::DisplayRole: return displayRole(entry,index.column()) ; + case Qt::FontRole: return fontRole(entry,index.column()) ; + case Qt::TextColorRole: return textColorRole(entry,index.column()) ; + case Qt::DecorationRole: return decorationRole(entry,index.column()) ; + + case FilterRole: return filterRole(entry,index.column()) ; + case SortRole: return sortRole(entry,index.column()) ; + case OnlineRole: return onlineRole(entry,index.column()) ; + case TypeRole: return QVariant((int)entry.type); + + default: + return QVariant(); + } +} + +QVariant RsFriendListModel::textColorRole(const EntryIndex& fmpe,int column) const +{ + switch(fmpe.type) + { + case ENTRY_TYPE_GROUP: return QVariant(QBrush(mTextColorGroup)); + case ENTRY_TYPE_PROFILE: + case ENTRY_TYPE_NODE: return QVariant(QBrush(mTextColorStatus[ onlineRole(fmpe,column).toBool() ?RS_STATUS_ONLINE:RS_STATUS_OFFLINE])); + default: + return QVariant(); + } +} + +QVariant RsFriendListModel::statusRole(const EntryIndex& fmpe,int column) const +{ + return QVariant();//fmpe.mMsgStatus); +} + +bool RsFriendListModel::passesFilter(const EntryIndex& e,int column) const +{ + QString s ; + bool passes_strings = true ; + + if(e.type == ENTRY_TYPE_PROFILE && !mFilterStrings.empty()) + { + switch(mFilterType) + { + case FILTER_TYPE_ID: s = displayRole(e,COLUMN_THREAD_ID).toString(); + break; + + case FILTER_TYPE_NAME: s = displayRole(e,COLUMN_THREAD_NAME).toString(); + if(s.isNull()) + passes_strings = false; + break; + }; + } + + if(!s.isNull()) + for(auto iter(mFilterStrings.begin()); iter != mFilterStrings.end(); ++iter) + passes_strings = passes_strings && s.contains(*iter,Qt::CaseInsensitive); + + return passes_strings; +} + +QVariant RsFriendListModel::filterRole(const EntryIndex& e,int column) const +{ + if(passesFilter(e,column)) + return QVariant(FilterString); + + return QVariant(QString()); +} + +uint32_t RsFriendListModel::updateFilterStatus(ForumModelIndex i,int column,const QStringList& strings) +{ + QString s ; + uint32_t count = 0; + + return count; +} + + +void RsFriendListModel::setFilter(FilterType filter_type, const QStringList& strings) +{ +#ifdef DEBUG_MODEL + std::cerr << "Setting filter to filter_type=" << int(filter_type) << " and strings to " ; + foreach(const QString& str,strings) + std::cerr << "\"" << str.toStdString() << "\" " ; + std::cerr << std::endl; +#endif + + preMods(); + + mFilterType = filter_type; + mFilterStrings = strings; + + postMods(); +} + +QVariant RsFriendListModel::toolTipRole(const EntryIndex& fmpe,int column) const +{ + return QVariant(); +} + +QVariant RsFriendListModel::sizeHintRole(const EntryIndex& e,int col) const +{ + float x_factor = QFontMetricsF(QApplication::font()).height()/14.0f ; + float y_factor = QFontMetricsF(QApplication::font()).height()/14.0f ; + + if(e.type == ENTRY_TYPE_NODE) + y_factor *= 3.0; + + if((e.type == ENTRY_TYPE_PROFILE) && !isProfileExpanded(e)) + y_factor *= 3.0; + + if(e.type == ENTRY_TYPE_GROUP) + y_factor = std::max(y_factor, 24.0f / 14.0f ); // allows to fit the 24 pixels icon for groups in the line + + switch(col) + { + default: + case COLUMN_THREAD_NAME: return QVariant( QSize(x_factor * 170, y_factor*14*1.1f )); + case COLUMN_THREAD_IP: return QVariant( QSize(x_factor * 75 , y_factor*14*1.1f )); + case COLUMN_THREAD_ID: return QVariant( QSize(x_factor * 75 , y_factor*14*1.1f )); + case COLUMN_THREAD_LAST_CONTACT: return QVariant( QSize(x_factor * 75 , y_factor*14*1.1f )); + } +} + +QVariant RsFriendListModel::sortRole(const EntryIndex& entry,int column) const +{ + switch(column) + { + case COLUMN_THREAD_LAST_CONTACT: + { + switch(entry.type) + { + case ENTRY_TYPE_PROFILE: + { + const HierarchicalProfileInformation *prof = getProfileInfo(entry); + + if(!prof) + return QVariant(); + + uint32_t last_contact = 0; + + for(uint32_t i=0;ichild_node_indices.size();++i) + last_contact = std::max(last_contact, mLocations[prof->child_node_indices[i]].node_info.lastConnect); + + return QVariant(last_contact); + } + break; + default: + return QVariant(); + } + } + break; + + default: + return displayRole(entry,column); + } +} + +QVariant RsFriendListModel::onlineRole(const EntryIndex& e, int col) const +{ + switch(e.type) + { + default: + case ENTRY_TYPE_GROUP: + { + const HierarchicalGroupInformation& g(mGroups[e.group_index]); + + for(uint32_t j=0;jchild_node_indices.size();++i) + if(mLocations[prof->child_node_indices[i]].node_info.state & RS_PEER_STATE_CONNECTED) + return QVariant(true); + + return QVariant(); + } + break; + + case ENTRY_TYPE_NODE: + const HierarchicalNodeInformation *node = getNodeInfo(e); + + if(!node) + return QVariant(); + + return QVariant(bool(node->node_info.state & RS_PEER_STATE_CONNECTED)); + } +} + +QVariant RsFriendListModel::fontRole(const EntryIndex& e, int col) const +{ +#ifdef DEBUG_MODEL_INDEX + std::cerr << " font role " << e.type << ", (" << (int)e.group_index << ","<< (int)e.profile_index << ","<< (int)e.node_index << ") col="<< col<<": " << std::endl; +#endif + + bool b = onlineRole(e,col).toBool(); + + if(b) + { + QFont font ; + font.setBold(b); + + return QVariant(font); + } + else + return QVariant(); +} + +class AutoEndel +{ +public: + ~AutoEndel() { std::cerr << std::endl;} +}; + +QVariant RsFriendListModel::displayRole(const EntryIndex& e, int col) const +{ +#ifdef DEBUG_MODEL_INDEX + std::cerr << " Display role " << e.type << ", (" << (int)e.group_index << ","<< (int)e.profile_index << ","<< (int)e.node_index << ") col="<< col<<": "; + AutoEndel x; +#endif + + switch(e.type) + { + case ENTRY_TYPE_GROUP: + { + const HierarchicalGroupInformation *group = getGroupInfo(e); + + if(!group) + return QVariant(); + + uint32_t nb_online = 0; + + for(uint32_t i=0;ichild_profile_indices.size();++i) + for(uint32_t j=0;jchild_profile_indices[i]].child_node_indices.size();++j) + if(mLocations[mProfiles[group->child_profile_indices[i]].child_node_indices[j]].node_info.state & RS_PEER_STATE_CONNECTED) + { + nb_online++; + break;// only breaks the inner loop, on purpose. + } + + switch(col) + { + case COLUMN_THREAD_NAME: +#ifdef DEBUG_MODEL_INDEX + std::cerr << group->group_info.name.c_str() ; +#endif + + if(!group->child_profile_indices.empty()) + return QVariant(QString::fromUtf8(group->group_info.name.c_str())+" (" + QString::number(nb_online) + "/" + QString::number(group->child_profile_indices.size()) + ")"); + else + return QVariant(QString::fromUtf8(group->group_info.name.c_str())); + + case COLUMN_THREAD_ID: return QVariant(QString::fromStdString(group->group_info.id.toStdString())); + default: + return QVariant(); + } + } + break; + + case ENTRY_TYPE_PROFILE: + { + const HierarchicalProfileInformation *profile = getProfileInfo(e); + + if(!profile) + return QVariant(); + +#ifdef DEBUG_MODEL_INDEX + std::cerr << profile->profile_info.name.c_str() ; +#endif + switch(col) + { + case COLUMN_THREAD_NAME: return QVariant(QString::fromUtf8(profile->profile_info.name.c_str())); + case COLUMN_THREAD_ID: return QVariant(QString::fromStdString(profile->profile_info.gpg_id.toStdString()) ); + + default: + return QVariant(); + } + } + break; + + case ENTRY_TYPE_NODE: + const HierarchicalNodeInformation *node = getNodeInfo(e); + + if(!node) + return QVariant(); + +#ifdef DEBUG_MODEL_INDEX + std::cerr << node->node_info.location.c_str() ; +#endif + switch(col) + { + case COLUMN_THREAD_NAME: if(node->node_info.location.empty()) + return QVariant(QString::fromStdString(node->node_info.id.toStdString())); + + { + std::string css = rsMsgs->getCustomStateString(node->node_info.id); + + if(!css.empty() && mDisplayStatusString) + return QVariant(QString::fromUtf8(node->node_info.location.c_str())+"\n"+QString::fromUtf8(css.c_str())); + else + return QVariant(QString::fromUtf8(node->node_info.location.c_str())); + } + + case COLUMN_THREAD_LAST_CONTACT: return QVariant(QDateTime::fromTime_t(node->node_info.lastConnect).toString()); + case COLUMN_THREAD_IP: return QVariant( (node->node_info.state & RS_PEER_STATE_CONNECTED) ? StatusDefs::connectStateIpString(node->node_info) : QString("---")); + case COLUMN_THREAD_ID: return QVariant( QString::fromStdString(node->node_info.id.toStdString()) ); + + default: + return QVariant(); + } break; + + return QVariant(); + } +} + +// This function makes sure that the internal data gets updated. They are situations where the otification system cannot +// send the information about changes, such as when the computer is put on sleep. + +void RsFriendListModel::checkInternalData(bool force) +{ + rstime_t now = time(NULL); + + if(mLastInternalDataUpdate + MAX_INTERNAL_DATA_UPDATE_DELAY < now || force) + updateInternalData(); + + if(mLastNodeUpdate + MAX_NODE_UPDATE_DELAY < now) + { + for(uint32_t i=0;igetPeerDetails(id,mLocations[i].node_info); + mLocations[i].last_update_ts = now; + } + + mLastNodeUpdate = now; + } +} + +const RsFriendListModel::HierarchicalGroupInformation *RsFriendListModel::getGroupInfo(const EntryIndex& e) const +{ + if(e.group_index >= mGroups.size()) + return NULL ; + else + return &mGroups[e.group_index]; +} + +const RsFriendListModel::HierarchicalProfileInformation *RsFriendListModel::getProfileInfo(const EntryIndex& e) const +{ + // First look into the relevant group, then for the correct profile in this group. + + if(e.type != ENTRY_TYPE_PROFILE) + return NULL ; + + if(e.group_index < UNDEFINED_GROUP_INDEX_VALUE) + { + const HierarchicalGroupInformation& group(mGroups[e.group_index]); + + if(e.profile_index >= group.child_profile_indices.size()) + return NULL ; + + return &mProfiles[group.child_profile_indices[e.profile_index]]; + } + else + return &mProfiles[e.profile_index]; +} + +const RsFriendListModel::HierarchicalNodeInformation *RsFriendListModel::getNodeInfo(const EntryIndex& e) const +{ + if(e.type != ENTRY_TYPE_NODE) + return NULL ; + + uint32_t pindex = 0; + + if(e.group_index < UNDEFINED_GROUP_INDEX_VALUE) + { + const HierarchicalGroupInformation& group(mGroups[e.group_index]); + + if(e.profile_index >= group.child_profile_indices.size()) + return NULL ; + + pindex = group.child_profile_indices[e.profile_index]; + } + else + { + if(e.profile_index >= mProfiles.size()) + return NULL ; + + pindex = e.profile_index; + } + + if(e.node_index >= mProfiles[pindex].child_node_indices.size()) + return NULL ; + + time_t now = time(NULL); + HierarchicalNodeInformation& node(mLocations[mProfiles[pindex].child_node_indices[e.node_index]]); + + return &node; +} + +bool RsFriendListModel::getPeerOnlineStatus(const EntryIndex& e) const +{ + const HierarchicalNodeInformation *noded = getNodeInfo(e) ; + return (noded && (noded->node_info.state & RS_PEER_STATE_CONNECTED)); +} + +QVariant RsFriendListModel::decorationRole(const EntryIndex& entry,int col) const +{ + if(col > 0) + return QVariant(); + + switch(entry.type) + { + case ENTRY_TYPE_GROUP: return QVariant(QIcon(IMAGE_GROUP24)); + + case ENTRY_TYPE_PROFILE: + { + if(!isProfileExpanded(entry)) + { + QPixmap sslAvatar(AVATAR_DEFAULT_IMAGE); + + const HierarchicalProfileInformation *hn = getProfileInfo(entry); + + for(uint32_t i=0;ichild_node_indices.size();++i) + if(AvatarDefs::getAvatarFromSslId(RsPeerId(mLocations[hn->child_node_indices[i]].node_info.id.toStdString()), sslAvatar)) + return QVariant(QIcon(sslAvatar)); + + return QVariant(QIcon(sslAvatar)); + } + + return QVariant(); + } + + case ENTRY_TYPE_NODE: + { + const HierarchicalNodeInformation *hn = getNodeInfo(entry); + + if(!hn) + return QVariant(); + + QPixmap sslAvatar; + AvatarDefs::getAvatarFromSslId(RsPeerId(hn->node_info.id.toStdString()), sslAvatar); + + return QVariant(QIcon(sslAvatar)); + } + default: return QVariant(); + } +} + +void RsFriendListModel::clear() +{ + preMods(); + + mGroups.clear(); + mProfiles.clear(); + mLocations.clear(); + mTopLevel.clear(); + + postMods(); + + emit friendListChanged(); +} + +static bool decreasing_time_comp(const std::pair& e1,const std::pair& e2) { return e2.first < e1.first ; } + +void RsFriendListModel::debug_dump() const +{ + std::cerr << "==== FriendListModel Debug dump ====" << std::endl; + + for(uint32_t j=0;j(i.internalId(),e) || e.type != ENTRY_TYPE_GROUP) + return false; + + const HierarchicalGroupInformation *ginfo = getGroupInfo(e); + + if(ginfo) + { + data = ginfo->group_info; + return true; + } + else + return false; +} +bool RsFriendListModel::getProfileData(const QModelIndex& i,RsProfileDetails& data) const +{ + if(!i.isValid()) + return false; + + EntryIndex e; + if(!convertInternalIdToIndex(i.internalId(),e) || e.type != ENTRY_TYPE_PROFILE) + return false; + + const HierarchicalProfileInformation *gprof = getProfileInfo(e); + + if(gprof) + { + data = gprof->profile_info; + return true; + } + else + return false; +} +bool RsFriendListModel::getNodeData (const QModelIndex& i,RsNodeDetails & data) const +{ + if(!i.isValid()) + return false; + + EntryIndex e; + if(!convertInternalIdToIndex(i.internalId(),e) || e.type != ENTRY_TYPE_NODE) + return false; + + const HierarchicalNodeInformation *gnode = getNodeInfo(e); + + if(gnode) + { + data = gnode->node_info; + return true; + } + else + return false; +} + +RsFriendListModel::EntryType RsFriendListModel::getType(const QModelIndex& i) const +{ + if(!i.isValid()) + return ENTRY_TYPE_UNKNOWN; + + EntryIndex e; + if(!convertInternalIdToIndex(i.internalId(),e)) + return ENTRY_TYPE_UNKNOWN; + + return e.type; +} + +std::map::const_iterator RsFriendListModel::createInvalidatedProfile(const RsPgpId& _pgp_id,const RsPgpFingerprint& fpr,std::map& pgp_indices,std::vector& mProfiles) +{ + // This is necessary by the time the full fingerprint is used in PeerNetItem. + + RsPgpId pgp_id; + + if(!fpr.isNull()) + pgp_id = rsPeers->pgpIdFromFingerprint(fpr); + else + pgp_id = _pgp_id; + + auto it2 = pgp_indices.find(pgp_id); + + if(it2 != pgp_indices.end()) + { + std::cerr << "(EE) asked to create an invalidated profile that already exists!" << std::endl; + return it2; + } + + HierarchicalProfileInformation hprof ; + + if(rsPeers->getGPGDetails(pgp_id,hprof.profile_info)) + { + std::cerr << "(EE) asked to create an invalidated profile that already exists!" << std::endl; + return it2; + } + + hprof.profile_info.isOnlyGPGdetail = true; + hprof.profile_info.gpg_id = pgp_id; + + hprof.profile_info.name = tr("Profile ID ").toStdString() + pgp_id.toStdString() + tr(" (Not yet validated)").toStdString(); + hprof.profile_info.issuer = pgp_id; + + hprof.profile_info.fpr = fpr; /* pgp fingerprint */ + + hprof.profile_info.trustLvl = 0; + hprof.profile_info.validLvl = 0; + + pgp_indices[pgp_id] = mProfiles.size(); + mProfiles.push_back(hprof); + + it2 = pgp_indices.find(pgp_id); + +#ifdef DEBUG_MODEL + RsDbg() << " Creating invalidated profile pgp id = " << pgp_id << " (" << hprof.profile_info.name << ") and fingerprint " << fpr << std::endl; +#endif + return it2; +} + +std::map::const_iterator RsFriendListModel::checkProfileIndex(const RsPgpId& pgp_id,std::map& pgp_indices,std::vector& mProfiles,bool create) +{ + auto it2 = pgp_indices.find(pgp_id); + + if(it2 == pgp_indices.end()) + { + if(!create) + { + std::cerr << "(EE) trying to display profile " << pgp_id <<" that is actually not a friend." << std::endl; + return it2; + } + HierarchicalProfileInformation hprof ; + rsPeers->getGPGDetails(pgp_id,hprof.profile_info); + + pgp_indices[pgp_id] = mProfiles.size(); + mProfiles.push_back(hprof); + + it2 = pgp_indices.find(pgp_id); + +#ifdef DEBUG_MODEL + RsDbg() << " Creating profile pgp id = " << pgp_id << " (" << hprof.profile_info.name << ")" << std::endl; +#endif + } + return it2; +} + +void RsFriendListModel::updateInternalData() +{ + preMods(); + + beginRemoveRows(QModelIndex(),0,mTopLevel.size()-1); + endRemoveRows(); + + mGroups.clear(); + mProfiles.clear(); + mLocations.clear(); + + mTopLevel.clear(); + + // create a map of profiles and groups + std::map pgp_indices; + + // parse PGP friends that may or may not have a known location. Create the associated data. + + std::list pgp_friends; + rsPeers->getGPGAcceptedList(pgp_friends); + + for(auto it(pgp_friends.begin());it!=pgp_friends.end();++it) + checkProfileIndex(*it,pgp_indices,mProfiles,true); + + // Now parse peer ids and look for the associated PGP id. If not found, raise an error. +#ifdef DEBUG_MODEL + RsDbg() << "Updating Nodes information: " << std::endl; +#endif + std::list peer_ids ; + rsPeers->getFriendList(peer_ids); + + for(auto it(peer_ids.begin());it!=peer_ids.end();++it) + { + // profiles + + HierarchicalNodeInformation hnode ; + rsPeers->getPeerDetails(*it,hnode.node_info); + + // If the Peer ID belong to our own profile, we add our own profile to the list. Otherwise we do not display it in the friend list. + + auto it2 = checkProfileIndex(hnode.node_info.gpg_id,pgp_indices,mProfiles,hnode.node_info.gpg_id == rsPeers->getGPGOwnId()); + + if(it2 == pgp_indices.end()) + { + // This peer's pgp key hasn't been validated yet. We list such peers at the end. + + it2 = createInvalidatedProfile(hnode.node_info.gpg_id,hnode.node_info.fpr,pgp_indices,mProfiles); + } + + mProfiles[it2->second].child_node_indices.push_back(mLocations.size()); + mLocations.push_back(hnode); + } + + + // finally, parse groups + + if(mDisplayGroups) + { + // groups + + std::list groupInfoList; + rsPeers->getGroupInfoList(groupInfoList) ; + +#ifdef DEBUG_MODEL + RsDbg() << "Updating Groups information: " << std::endl; +#endif + + for(auto it(groupInfoList.begin());it!=groupInfoList.end();++it) + { + // first, fill the group hierarchical info + + HierarchicalGroupInformation hgroup; + hgroup.group_info = *it; + +#ifdef DEBUG_MODEL + RsDbg() << " Group \"" << hgroup.group_info.name << "\"" << std::endl; +#endif + + for(auto it2((*it).peerIds.begin());it2!=(*it).peerIds.end();++it2) + { + // Then for each peer in this group, make sure that the peer is already known, and if not create it + + auto it3 = checkProfileIndex(*it2,pgp_indices,mProfiles,false); + + if(it3 == pgp_indices.end())// not found + continue; + + hgroup.child_profile_indices.push_back(it3->second); + } + + mGroups.push_back(hgroup); + } + } + + // now the top level list + +#ifdef DEBUG_MODEL + RsDbg() << "Creating top level list" << std::endl; +#endif + + mTopLevel.clear(); + std::set already_in_a_group; + + if(mDisplayGroups) // in this case, we list all groups at the top level followed by the profiles without parent group + { + for(uint32_t i=0;i(index.internalId(),entry)) + return; + + const HierarchicalProfileInformation *hp = getProfileInfo(entry); + const HierarchicalGroupInformation *hg = getGroupInfo(entry); + + std::string s ; + + if(hg) s += hg->group_info.id.toStdString() ; + if(hp) s += hp->profile_info.gpg_id.toStdString(); + + if(!s.empty()) + mExpandedProfiles.erase(s); + + // apparently we cannot be subtle here. + emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(mTopLevel.size()-1,COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL)); +} + +void RsFriendListModel::expandItem(const QModelIndex& index) +{ + if(getType(index) != ENTRY_TYPE_PROFILE) + return; + + EntryIndex entry; + + if(!convertInternalIdToIndex(index.internalId(),entry)) + return; + + const HierarchicalProfileInformation *hp = getProfileInfo(entry); + const HierarchicalGroupInformation *hg = getGroupInfo(entry); + + std::string s ; + + if(hg) s += hg->group_info.id.toStdString() ; + if(hp) s += hp->profile_info.gpg_id.toStdString(); + + if(!s.empty()) + mExpandedProfiles.insert(s); + + // apparently we cannot be subtle here. + emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(mTopLevel.size()-1,COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL)); +} + +bool RsFriendListModel::isProfileExpanded(const EntryIndex& e) const +{ + if(e.type != ENTRY_TYPE_PROFILE) + return false; + + const HierarchicalProfileInformation *hp = getProfileInfo(e); + const HierarchicalGroupInformation *hg = getGroupInfo(e); + + std::string s ; + + if(hg) s += hg->group_info.id.toStdString() ; + if(hp) s += hp->profile_info.gpg_id.toStdString(); + + return mExpandedProfiles.find(s) != mExpandedProfiles.end(); +} + diff --git a/retroshare-gui/src/gui/common/FriendListModel.h b/retroshare-gui/src/gui/common/FriendListModel.h new file mode 100644 index 000000000..5e8d84930 --- /dev/null +++ b/retroshare-gui/src/gui/common/FriendListModel.h @@ -0,0 +1,240 @@ +/******************************************************************************* + * retroshare-gui/src/gui/msgs/RsFriendListModel.h * + * * + * Copyright 2019 by Cyril Soler * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +#pragma once + +#include +#include + +#include "retroshare/rsstatus.h" +#include "retroshare/rsmsgs.h" +#include "retroshare/rspeers.h" + +typedef uint32_t ForumModelIndex; + +// This class is the item model used by Qt to display the information + +class RsFriendListModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + explicit RsFriendListModel(QObject *parent = NULL); + ~RsFriendListModel(){} + + class RsNodeDetails: public RsPeerDetails {};// in the near future, there will be a specific class for Profile/Node details in replacement of RsPeerDetails + class RsProfileDetails: public RsPeerDetails {}; + + struct HierarchicalGroupInformation + { + RsGroupInfo group_info; + std::vector child_profile_indices; // index in the array of hierarchical profiles + }; + struct HierarchicalProfileInformation + { + RsProfileDetails profile_info; + std::vector child_node_indices; // indices of nodes in the array of nodes. + }; + struct HierarchicalNodeInformation + { + HierarchicalNodeInformation() : last_update_ts(0) {} + + rstime_t last_update_ts; + RsNodeDetails node_info; + }; + + enum Columns { + COLUMN_THREAD_NAME = 0x00, + COLUMN_THREAD_LAST_CONTACT = 0x01, + COLUMN_THREAD_IP = 0x02, + COLUMN_THREAD_ID = 0x03, + COLUMN_THREAD_NB_COLUMNS = 0x04 + }; + + enum Roles{ SortRole = Qt::UserRole+1, + StatusRole = Qt::UserRole+2, + UnreadRole = Qt::UserRole+3, + FilterRole = Qt::UserRole+4, + OnlineRole = Qt::UserRole+5, + TypeRole = Qt::UserRole+6 + }; + + enum FilterType{ FILTER_TYPE_NONE = 0x00, + FILTER_TYPE_ID = 0x01, + FILTER_TYPE_NAME = 0x02 + }; + + enum EntryType{ ENTRY_TYPE_UNKNOWN = 0x00, + ENTRY_TYPE_GROUP = 0x01, + ENTRY_TYPE_PROFILE = 0x02, + ENTRY_TYPE_NODE = 0x03 + }; + + // This structure encodes the position of a node in the hierarchy. The type tells which of the index fields are valid. + + struct EntryIndex + { + public: + EntryIndex(); + + EntryType type; // type of the entry (group,profile,location) + + // Indices w.r.t. parent. The set of indices entirely determines the position of the entry in the hierarchy. + // An index of 0xff means "undefined" + + uint16_t group_index; // index of the group in mGroups tab + uint16_t profile_index; // index of the child profile in its own group if group_index < 0xff, or in the mProfiles tab otherwise. + uint16_t node_index; // index of the child node in its own profile + + EntryIndex parent() const; + EntryIndex child(int row,const std::vector& top_level) const; + uint32_t parentRow(uint32_t nb_groups) const; + }; + + QModelIndex root() const{ return createIndex(0,0,(void*)NULL) ;} + QModelIndex getIndexOfGroup(const RsNodeGroupId& mid) const; + + static const QString FilterString ; + + // This method will asynchroneously update the data + + void setDisplayGroups(bool b); + bool getDisplayGroups() const { return mDisplayGroups; } + + void setDisplayStatusString(bool b); + bool getDisplayStatusString() const { return mDisplayStatusString; } + + EntryType getType(const QModelIndex&) const; + + bool getGroupData (const QModelIndex&,RsGroupInfo &) const; + bool getProfileData(const QModelIndex&,RsProfileDetails&) const; + bool getNodeData (const QModelIndex&,RsNodeDetails &) const; + + void setFilter(FilterType filter_type, const QStringList& strings) ; + + void expandItem(const QModelIndex&) ; + void collapseItem(const QModelIndex&) ; + + // Overloaded methods from QAbstractItemModel + + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + bool hasChildren(const QModelIndex &parent = QModelIndex()) const override; + + QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex& child) const override; + Qt::ItemFlags flags(const QModelIndex& index) const override; + + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + + void clear() ; + + /* Color definitions (for standard see qss.default) */ + QColor mTextColorGroup; + QColor mTextColorStatus[RS_STATUS_COUNT]; + +private: + const HierarchicalGroupInformation *getGroupInfo (const EntryIndex&) const; + const HierarchicalProfileInformation *getProfileInfo(const EntryIndex&)const; + const HierarchicalNodeInformation *getNodeInfo(const EntryIndex&) const; + + bool isProfileExpanded(const EntryIndex& e) const; + void checkNode(HierarchicalNodeInformation& node); + bool getPeerOnlineStatus(const EntryIndex& e) const; + std::map::const_iterator checkProfileIndex(const RsPgpId& pgp_id, + std::map& pgp_indices, + std::vector& mProfiles, + bool create); + + std::map::const_iterator createInvalidatedProfile(const RsPgpId& pgp_id, + const RsPgpFingerprint& fpr, + std::map& pgp_indices, + std::vector& mProfiles); + + QVariant sizeHintRole (const EntryIndex& e, int col) const; + QVariant displayRole (const EntryIndex& e, int col) const; + QVariant decorationRole(const EntryIndex& e, int col) const; + QVariant toolTipRole (const EntryIndex& e, int col) const; + QVariant statusRole (const EntryIndex& e, int col) const; + QVariant sortRole (const EntryIndex& e, int col) const; + QVariant fontRole (const EntryIndex& e, int col) const; + QVariant textColorRole (const EntryIndex& e, int col) const; + QVariant onlineRole (const EntryIndex& e, int col) const; + QVariant filterRole (const EntryIndex& e, int col) const; + + /*! + * \brief debug_dump + * Dumps the hierarchy of posts in the terminal, to allow checking whether the internal representation is correct. + */ + +public slots: + void checkInternalData(bool force); + void debug_dump() const; + +signals: + void dataLoaded(); // emitted after the messages have been set. Can be used to updated the UI. + void friendListChanged(); // emitted after the messages have been set. Can be used to updated the UI. + void dataAboutToLoad(); + +private: + void updateInternalData(); + bool passesFilter(const EntryIndex &e, int column) const; + + void preMods() ; + void postMods() ; + + void *getParentRef(void *ref,int& row) const; + void *getChildRef(void *ref,int row) const; + int getChildrenCount(void *ref) const; + + template static bool convertIndexToInternalId(const EntryIndex& e,quintptr& ref); + template static bool convertInternalIdToIndex(quintptr ref, EntryIndex& e); + + uint32_t updateFilterStatus(ForumModelIndex i,int column,const QStringList& strings); + + QStringList mFilterStrings; + FilterType mFilterType; + + bool mDisplayGroups ; + bool mDisplayStatusString ; + rstime_t mLastInternalDataUpdate; + rstime_t mLastNodeUpdate;; + + // The 3 vectors below store thehierarchical information for groups, profiles and locations, + // meaning which is the child/parent of which. The actual group/profile/node data are also stored in the + // structure. + + mutable std::vector mGroups; + mutable std::vector mProfiles; + mutable std::vector mLocations; + + // The top level list contains all nodes to display, which type depends on the option to display groups or not. + // Idices in the list may be profile indices or group indices. In the former case the profile child index refers to + // the inde in the mProfiles tab, whereas in the the later case, the child index refers to the index of the profile in the + // group it belows to. + + std::vector mTopLevel; + + // keeps track of expanded/collapsed items, so as to only show icon for collapsed profiles + + std::set mExpandedProfiles; +}; + diff --git a/retroshare-gui/src/gui/common/NewFriendList.cpp b/retroshare-gui/src/gui/common/NewFriendList.cpp new file mode 100644 index 000000000..38e6ba3fd --- /dev/null +++ b/retroshare-gui/src/gui/common/NewFriendList.cpp @@ -0,0 +1,1506 @@ +/******************************************************************************* + * gui/common/NewFriendList.cpp * + * * + * Copyright (C) 2011, Retroshare Team * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include "rsserver/rsaccounts.h" +#include "retroshare/rspeers.h" + +#include "GroupDefs.h" +#include "gui/chat/ChatDialog.h" +#include "gui/common/AvatarDefs.h" + +#include "gui/connect/ConfCertDialog.h" +#include "gui/connect/PGPKeyDialog.h" +#include "gui/connect/ConnectFriendWizard.h" +#include "gui/groups/CreateGroup.h" +#include "gui/msgs/MessageComposer.h" +#include "gui/notifyqt.h" +#include "gui/RetroShareLink.h" +#include "retroshare-gui/RsAutoUpdatePage.h" +#ifdef UNFINISHED_FD +#include "gui/unfinished/profile/ProfileView.h" +#endif +#include "RSTreeWidgetItem.h" +#include "StatusDefs.h" +#include "util/misc.h" +#include "vmessagebox.h" +#include "util/QtVersion.h" +#include "gui/chat/ChatUserNotify.h" +#include "gui/connect/ConnectProgressDialog.h" +#include "gui/common/ElidedLabel.h" + +#include "NewFriendList.h" +#include "ui_NewFriendList.h" + +/* Images for context menu icons */ +#define IMAGE_DENYFRIEND ":/images/denied16.png" +#define IMAGE_REMOVEFRIEND ":/images/remove_user24.png" +#define IMAGE_EXPORTFRIEND ":/images/user/friend_suggestion16.png" +#define IMAGE_ADDFRIEND ":/images/user/add_user16.png" +#define IMAGE_FRIENDINFO ":/images/info16.png" +#define IMAGE_CHAT ":/images/chat_24.png" +#define IMAGE_MSG ":/images/mail_new.png" +#define IMAGE_CONNECT ":/images/connect_friend.png" +#define IMAGE_COPYLINK ":/images/copyrslink.png" +#define IMAGE_GROUP16 ":/images/user/group16.png" +#define IMAGE_EDIT ":/images/edit_16.png" +#define IMAGE_REMOVE ":/images/delete.png" +#define IMAGE_EXPAND ":/images/edit_add24.png" +#define IMAGE_COLLAPSE ":/images/edit_remove24.png" +/* Images for Status icons */ +#define IMAGE_AVAILABLE ":/images/user/identityavaiblecyan24.png" +#define IMAGE_PASTELINK ":/images/pasterslink.png" +#define IMAGE_GROUP24 ":/images/user/group24.png" + +#define COLUMN_DATA 0 // column for storing the userdata id + +// #define ROLE_ID Qt::UserRole +// #define ROLE_STANDARD Qt::UserRole + 1 +// #define ROLE_SORT_GROUP Qt::UserRole + 2 +// #define ROLE_SORT_STANDARD_GROUP Qt::UserRole + 3 +// #define ROLE_SORT_NAME Qt::UserRole + 4 +// #define ROLE_SORT_STATE Qt::UserRole + 5 +// #define ROLE_FILTER Qt::UserRole + 6 + +// states for sorting (equal values are possible) +// used in BuildSortString - state + name +#define PEER_STATE_ONLINE 1 +#define PEER_STATE_BUSY 2 +#define PEER_STATE_AWAY 3 +#define PEER_STATE_AVAILABLE 4 +#define PEER_STATE_INACTIVE 5 +#define PEER_STATE_OFFLINE 6 + +/****** + * #define FRIENDS_DEBUG 1 + *****/ + +Q_DECLARE_METATYPE(ElidedLabel*) + +class FriendListSortFilterProxyModel: public QSortFilterProxyModel +{ +public: + FriendListSortFilterProxyModel(const QHeaderView *header,QObject *parent = NULL): QSortFilterProxyModel(parent), + m_header(header), + m_sortingEnabled(false), + m_showOfflineNodes(true) {} + + bool lessThan(const QModelIndex& left, const QModelIndex& right) const override + { + bool is_group_1 = left.data(RsFriendListModel::TypeRole).toUInt() == (uint)RsFriendListModel::ENTRY_TYPE_GROUP; + bool is_group_2 = right.data(RsFriendListModel::TypeRole).toUInt() == (uint)RsFriendListModel::ENTRY_TYPE_GROUP; + + if(is_group_1 ^ is_group_2) // if the two are different, put the group first. + return is_group_1 ; + + bool online1 = left .data(RsFriendListModel::OnlineRole).toBool(); + bool online2 = right.data(RsFriendListModel::OnlineRole).toBool(); + + if(online1 != online2 && m_sortByState) + return (m_header->sortIndicatorOrder()==Qt::AscendingOrder)?online1:online2 ; // always put online nodes first + + return left.data(RsFriendListModel::SortRole) < right.data(RsFriendListModel::SortRole) ; + } + + bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override + { + // do not show empty groups + + QModelIndex index = sourceModel()->index(source_row,0,source_parent); + + if(index.data(RsFriendListModel::TypeRole) == RsFriendListModel::ENTRY_TYPE_GROUP) + { + RsGroupInfo group_info ; + static_cast(sourceModel())->getGroupData(index,group_info); + + if(group_info.peerIds.empty()) + return false; + } + + // Filter offline friends + + if(!m_showOfflineNodes && !index.data(RsFriendListModel::OnlineRole).toBool()) + return false; + + return index.data(RsFriendListModel::FilterRole).toString() == RsFriendListModel::FilterString ; + } + + void sort( int column, Qt::SortOrder order = Qt::AscendingOrder ) override + { + if(m_sortingEnabled) + return QSortFilterProxyModel::sort(column,order) ; + } + + void setSortingEnabled(bool b) { m_sortingEnabled = b ; } + void setSortByState(bool b) { m_sortByState = b ; } + void setShowOfflineNodes(bool b) { m_showOfflineNodes = b ; } + + bool showOfflineNodes() const { return m_showOfflineNodes ; } + bool sortByState() const { return m_sortByState ; } + +private: + const QHeaderView *m_header ; + bool m_sortingEnabled; + bool m_sortByState; + bool m_showOfflineNodes; +}; + +NewFriendList::NewFriendList(QWidget *parent) : /* RsAutoUpdatePage(5000,parent),*/ ui(new Ui::NewFriendList()) +{ + ui->setupUi(this); + + ui->filterLineEdit->setPlaceholderText(tr("Search")) ; + ui->filterLineEdit->showFilterIcon(); + + mModel = new RsFriendListModel(); + mProxyModel = new FriendListSortFilterProxyModel(ui->peerTreeWidget->header(),this); + + mProxyModel->setSourceModel(mModel); + mProxyModel->setSortRole(RsFriendListModel::SortRole); + mProxyModel->setDynamicSortFilter(false); + mProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); + mProxyModel->setFilterRole(RsFriendListModel::FilterRole); + mProxyModel->setFilterRegExp(QRegExp(RsFriendListModel::FilterString)); + + ui->peerTreeWidget->setModel(mProxyModel); + + /* Add filter actions */ + QString headerText = mModel->headerData(RsFriendListModel::COLUMN_THREAD_NAME,Qt::Horizontal,Qt::DisplayRole).toString(); + ui->filterLineEdit->addFilter(QIcon(), headerText, RsFriendListModel::COLUMN_THREAD_NAME, QString("%1 %2").arg(tr("Search"), headerText)); + ui->filterLineEdit->addFilter(QIcon(), tr("ID"), RsFriendListModel::COLUMN_THREAD_ID, tr("Search ID")); + + mActionSortByState = new QAction(tr("Online friends on top"), this); + mActionSortByState->setCheckable(true); + + //setting default filter by column as subject + ui->filterLineEdit->setCurrentFilter(RsFriendListModel::COLUMN_THREAD_NAME); + ui->peerTreeWidget->setSortingEnabled(true); + + /* Set sort */ + sortColumn(RsFriendListModel::COLUMN_THREAD_NAME, Qt::AscendingOrder); + toggleSortByState(false); + // workaround for Qt bug, should be solved in next Qt release 4.7.0 + // http://bugreports.qt.nokia.com/browse/QTBUG-8270 + QShortcut *Shortcut = new QShortcut(QKeySequence(Qt::Key_Delete), ui->peerTreeWidget, 0, 0, Qt::WidgetShortcut); + connect(Shortcut, SIGNAL(activated()), this, SLOT(removefriend()),Qt::QueuedConnection); + + QFontMetricsF fontMetrics(ui->peerTreeWidget->font()); + + /* Set initial column width */ + int fontWidth = fontMetrics.width("W"); + ui->peerTreeWidget->setColumnWidth(RsFriendListModel::COLUMN_THREAD_NAME , 22 * fontWidth); + ui->peerTreeWidget->setColumnWidth(RsFriendListModel::COLUMN_THREAD_IP , 15 * fontWidth); + ui->peerTreeWidget->setColumnWidth(RsFriendListModel::COLUMN_THREAD_ID , 32 * fontWidth); + ui->peerTreeWidget->setColumnWidth(RsFriendListModel::COLUMN_THREAD_LAST_CONTACT, 12 * fontWidth); + + int avatarHeight = fontMetrics.height() * 3; + ui->peerTreeWidget->setIconSize(QSize(avatarHeight, avatarHeight)); + + mModel->checkInternalData(true); + + QHeaderView *h = ui->peerTreeWidget->header(); + h->setContextMenuPolicy(Qt::CustomContextMenu); + + connect(ui->peerTreeWidget->header(),SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(sortColumn(int,Qt::SortOrder))); + + connect(ui->peerTreeWidget, SIGNAL(expanded(const QModelIndex&)), this, SLOT(itemExpanded(const QModelIndex&))); + connect(ui->peerTreeWidget, SIGNAL(collapsed(const QModelIndex&)), this, SLOT(itemCollapsed(const QModelIndex&))); + connect(mActionSortByState, SIGNAL(toggled(bool)), this, SLOT(toggleSortByState(bool))); + connect(ui->peerTreeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(peerTreeWidgetCustomPopupMenu())); + + // Using Queued connections here is pretty important since the notifications may come from a different thread. + + connect(NotifyQt::getInstance(), SIGNAL(friendsChanged()) , this, SLOT(forceUpdateDisplay()),Qt::QueuedConnection); + connect(NotifyQt::getInstance(), SIGNAL(groupsChanged(int)) , this, SLOT(forceUpdateDisplay()),Qt::QueuedConnection); + connect(NotifyQt::getInstance(), SIGNAL(peerConnected(const QString&)) , this, SLOT(forceUpdateDisplay()),Qt::QueuedConnection); + connect(NotifyQt::getInstance(), SIGNAL(peerDisconnected(const QString&)), this, SLOT(forceUpdateDisplay()),Qt::QueuedConnection); + + connect(ui->actionShowOfflineFriends, SIGNAL(triggered(bool)), this, SLOT(setShowUnconnected(bool))); + connect(ui->actionShowState, SIGNAL(triggered(bool)), this, SLOT(setShowState(bool)) ); + connect(ui->actionShowGroups, SIGNAL(triggered(bool)), this, SLOT(setShowGroups(bool)) ); + connect(ui->actionExportFriendlist, SIGNAL(triggered()) , this, SLOT(exportFriendlistClicked())); + connect(ui->actionImportFriendlist, SIGNAL(triggered()) , this, SLOT(importFriendlistClicked())); + + connect(ui->filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterItems(QString)),Qt::QueuedConnection); + connect(h, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(headerContextMenuRequested(QPoint))); + +// #ifdef RS_DIRECT_CHAT +// connect(ui->peerTreeWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, SLOT(chatNode())); +// #endif + +} + +NewFriendList::~NewFriendList() +{ + delete ui; +} + +void NewFriendList::itemExpanded(const QModelIndex& index) +{ + mModel->expandItem(mProxyModel->mapToSource(index)); +} +void NewFriendList::itemCollapsed(const QModelIndex& index) +{ + mModel->collapseItem(mProxyModel->mapToSource(index)); +} + +void NewFriendList::sortColumn(int col,Qt::SortOrder so) +{ + std::set expanded_indexes; + std::set selected_indexes; + + saveExpandedPathsAndSelection(expanded_indexes, selected_indexes); + mProxyModel->setSortingEnabled(true); + mProxyModel->sort(col,so); + mProxyModel->setSortingEnabled(false); + restoreExpandedPathsAndSelection(expanded_indexes, selected_indexes); +} + +void NewFriendList::headerContextMenuRequested(QPoint p) +{ + QMenu displayMenu(tr("Show Items"), this); + + QWidget *widget = new QWidget(&displayMenu); + widget->setStyleSheet( ".QWidget{background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1,stop:0 #FEFEFE, stop:1 #E8E8E8); border: 1px solid #CCCCCC;}"); + + // create menu header + QHBoxLayout *hbox = new QHBoxLayout(widget); + hbox->setMargin(0); + hbox->setSpacing(6); + + QLabel *iconLabel = new QLabel(widget); + QPixmap pix = QPixmap(":/images/user/friends24.png").scaledToHeight(QFontMetricsF(iconLabel->font()).height()*1.5); + iconLabel->setPixmap(pix); + iconLabel->setMaximumSize(iconLabel->frameSize().height() + pix.height(), pix.width()); + hbox->addWidget(iconLabel); + + QLabel *textLabel = new QLabel("Show/hide...", widget); + hbox->addWidget(textLabel); + + QSpacerItem *spacerItem = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + hbox->addItem(spacerItem); + + widget->setLayout(hbox); + + QWidgetAction *widgetAction = new QWidgetAction(this); + widgetAction->setDefaultWidget(widget); + displayMenu.addAction(widgetAction); + + displayMenu.addAction(mActionSortByState); + + mActionSortByState->setChecked(mProxyModel->sortByState()); + + displayMenu.addAction(ui->actionShowOfflineFriends); + displayMenu.addAction(ui->actionShowState); + displayMenu.addAction(ui->actionShowGroups); + + ui->actionShowOfflineFriends->setChecked(mProxyModel->showOfflineNodes()); + ui->actionShowState->setChecked(mModel->getDisplayStatusString()); + ui->actionShowGroups->setChecked(mModel->getDisplayGroups()); + + QHeaderView *header = ui->peerTreeWidget->header(); + + { + QAction *action = displayMenu.addAction(QIcon(), tr("Last contact"), this, SLOT(toggleColumnVisible())); + action->setCheckable(true); + action->setData(RsFriendListModel::COLUMN_THREAD_LAST_CONTACT); + action->setChecked(!header->isSectionHidden(RsFriendListModel::COLUMN_THREAD_LAST_CONTACT)); + } + + { + QAction *action = displayMenu.addAction(QIcon(), tr("IP"), this, SLOT(toggleColumnVisible())); + action->setCheckable(true); + action->setData(RsFriendListModel::COLUMN_THREAD_IP); + action->setChecked(!header->isSectionHidden(RsFriendListModel::COLUMN_THREAD_IP)); + } + + { + QAction *action = displayMenu.addAction(QIcon(), tr("ID"), this, SLOT(toggleColumnVisible())); + action->setCheckable(true); + action->setData(RsFriendListModel::COLUMN_THREAD_ID); + action->setChecked(!header->isSectionHidden(RsFriendListModel::COLUMN_THREAD_ID)); + } + + displayMenu.exec(QCursor::pos()); +} + +void NewFriendList::addToolButton(QToolButton *toolButton) +{ + if (!toolButton) + return; + + /* Initialize button */ + toolButton->setAutoRaise(true); + float S = QFontMetricsF(ui->filterLineEdit->font()).height() ; + toolButton->setIconSize(QSize(S*1.5,S*1.5)); + toolButton->setFocusPolicy(Qt::NoFocus); + + ui->titleBarFrame->layout()->addWidget(toolButton); +} + +void NewFriendList::saveExpandedPathsAndSelection(std::set& expanded_indexes, std::set& selected_indexes) +{ +#ifdef DEBUG_NEW_FRIEND_LIST + std::cerr << "Saving expended paths and selection..." << std::endl; +#endif + + for(int row = 0; row < mProxyModel->rowCount(); ++row) + recursSaveExpandedItems(mProxyModel->index(row,0),QString(),expanded_indexes,selected_indexes); +} + +void NewFriendList::restoreExpandedPathsAndSelection(const std::set& expanded_indexes, const std::set& selected_indexes) +{ +#ifdef DEBUG_NEW_FRIEND_LIST + std::cerr << "Restoring expended paths and selection..." << std::endl; +#endif + + ui->peerTreeWidget->blockSignals(true) ; + + for(int row = 0; row < mProxyModel->rowCount(); ++row) + recursRestoreExpandedItems(mProxyModel->index(row,0),QString(),expanded_indexes,selected_indexes); + + ui->peerTreeWidget->blockSignals(false) ; +} + +void NewFriendList::recursSaveExpandedItems(const QModelIndex& index,const QString& parent_path,std::set& exp, std::set& sel) +{ + QString local_path = parent_path + index.sibling(index.row(),RsFriendListModel::COLUMN_THREAD_ID).data(Qt::DisplayRole).toString() + " "; + + if(ui->peerTreeWidget->selectionModel()->selection().contains(index)) + sel.insert(local_path) ; + + if(ui->peerTreeWidget->isExpanded(index)) + { +#ifdef DEBUG_NEW_FRIEND_LIST + std::cerr << "Index " << local_path.toStdString() << " is expanded." << std::endl; +#endif + if(index.isValid()) + exp.insert(local_path) ; + + for(int row=0;rowrowCount(index);++row) + recursSaveExpandedItems(index.child(row,0),local_path,exp,sel) ; + } +#ifdef DEBUG_NEW_FRIEND_LIST + else + std::cerr << "Index " << local_path.toStdString() << " is not expanded." << std::endl; +#endif +} + +void NewFriendList::recursRestoreExpandedItems(const QModelIndex& index, const QString& parent_path, const std::set& exp, const std::set &sel) +{ + QString local_path = parent_path + index.sibling(index.row(),RsFriendListModel::COLUMN_THREAD_ID).data(Qt::DisplayRole).toString() + " "; +#ifdef DEBUG_NEW_FRIEND_LIST + std::cerr << "at index " << index.row() << ". data[1]=" << local_path.toStdString() << std::endl; +#endif + + if(sel.find(local_path) != sel.end()) + ui->peerTreeWidget->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Rows); + + if(exp.find(local_path) != exp.end()) + { +#ifdef DEBUG_NEW_FRIEND_LIST + std::cerr << "re expanding index " << local_path.toStdString() << std::endl; +#endif + + ui->peerTreeWidget->setExpanded(index,true) ; + + for(int row=0;rowrowCount(index);++row) + recursRestoreExpandedItems(index.child(row,0),local_path,exp,sel) ; + } +} + + +void NewFriendList::processSettings(bool load) +{ + // state of peer tree + + if (load) // load settings + { + // states + setShowUnconnected(!Settings->value("hideUnconnected", !mProxyModel->showOfflineNodes()).toBool()); + setShowState(Settings->value("showState", mModel->getDisplayStatusString()).toBool()); + setShowGroups(Settings->value("showGroups", mModel->getDisplayGroups()).toBool()); + + setColumnVisible(RsFriendListModel::COLUMN_THREAD_IP,Settings->value("showIP", isColumnVisible(RsFriendListModel::COLUMN_THREAD_IP)).toBool()); + setColumnVisible(RsFriendListModel::COLUMN_THREAD_ID,Settings->value("showID", isColumnVisible(RsFriendListModel::COLUMN_THREAD_ID)).toBool()); + setColumnVisible(RsFriendListModel::COLUMN_THREAD_LAST_CONTACT,Settings->value("showLastContact", isColumnVisible(RsFriendListModel::COLUMN_THREAD_LAST_CONTACT)).toBool()); + + // sort + toggleSortByState(Settings->value("sortByState", mProxyModel->sortByState()).toBool()); + + // open groups + int arrayIndex = Settings->beginReadArray("Groups"); + for (int index = 0; index < arrayIndex; ++index) { + Settings->setArrayIndex(index); + + std::string gids = Settings->value("open").toString().toStdString(); + } + Settings->endArray(); + } + else + { + // save settings + + // states + Settings->setValue("hideUnconnected", !mProxyModel->showOfflineNodes()); + Settings->setValue("showState", mModel->getDisplayStatusString()); + Settings->setValue("showGroups", mModel->getDisplayGroups()); + + Settings->setValue("showIP",isColumnVisible(RsFriendListModel::COLUMN_THREAD_IP)); + Settings->setValue("showID",isColumnVisible(RsFriendListModel::COLUMN_THREAD_ID)); + Settings->setValue("showLastContact",isColumnVisible(RsFriendListModel::COLUMN_THREAD_LAST_CONTACT)); + + // sort + Settings->setValue("sortByState", mProxyModel->sortByState()); + + Settings->endArray(); + } +} + +void NewFriendList::toggleSortByState(bool sort) +{ + mProxyModel->setSortByState(sort); + mProxyModel->setFilterRegExp(QRegExp(QString(RsFriendListModel::FilterString))) ;// triggers a re-display. +} + +void NewFriendList::changeEvent(QEvent *e) +{ + QWidget::changeEvent(e); + switch (e->type()) { + case QEvent::StyleChange: + break; + default: + // remove compiler warnings + break; + } +} + +/** + * Creates the context popup menu and its submenus, + * then shows it at the current cursor position. + */ +void NewFriendList::peerTreeWidgetCustomPopupMenu() +{ + QModelIndex index = getCurrentSourceIndex(); + RsFriendListModel::EntryType type = mModel->getType(index); + + QMenu contextMenu(this); + + QWidget *widget = new QWidget(&contextMenu); + widget->setStyleSheet( ".QWidget{background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1,stop:0 #FEFEFE, stop:1 #E8E8E8); border: 1px solid #CCCCCC;}"); + + // create menu header + QHBoxLayout *hbox = new QHBoxLayout(widget); + hbox->setMargin(0); + hbox->setSpacing(6); + + QLabel *iconLabel = new QLabel(widget); + QPixmap pix = QPixmap(":/images/user/friends24.png").scaledToHeight(QFontMetricsF(iconLabel->font()).height()*1.5); + iconLabel->setPixmap(pix); + iconLabel->setMaximumSize(iconLabel->frameSize().height() + pix.height(), pix.width()); + hbox->addWidget(iconLabel); + + QLabel *textLabel = new QLabel("Friend list", widget); + hbox->addWidget(textLabel); + + QSpacerItem *spacerItem = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + hbox->addItem(spacerItem); + + widget->setLayout(hbox); + + QWidgetAction *widgetAction = new QWidgetAction(this); + widgetAction->setDefaultWidget(widget); + contextMenu.addAction(widgetAction); + + // create menu entries + if(index.isValid()) + { + // define header + switch (type) { + case RsFriendListModel::ENTRY_TYPE_GROUP: + //this is a GPG key + textLabel->setText("" + tr("Group") + ""); + break; + case RsFriendListModel::ENTRY_TYPE_PROFILE: + //this is a GPG key + textLabel->setText("" + tr("Friend") + ""); + break; + case RsFriendListModel::ENTRY_TYPE_NODE: + //this is a SSL key + textLabel->setText("" + tr("Node") + ""); + break; + } + + switch (type) + { + case RsFriendListModel::ENTRY_TYPE_GROUP: + { + RsGroupInfo group_info ; + mModel->getGroupData(index,group_info); + + bool standard = group_info.flag & RS_GROUP_FLAG_STANDARD; +#ifdef RS_DIRECT_CHAT + contextMenu.addAction(QIcon(IMAGE_MSG), tr("Send message to whole group"), this, SLOT(msgGroup())); + contextMenu.addSeparator(); +#endif // RS_DIRECT_CHAT + contextMenu.addAction(QIcon(IMAGE_EDIT), tr("Edit Group"), this, SLOT(editGroup())); + + QAction *action = contextMenu.addAction(QIcon(IMAGE_REMOVE), tr("Remove Group"), this, SLOT(removeGroup())); + action->setDisabled(standard); + } + break; + + case RsFriendListModel::ENTRY_TYPE_PROFILE: + { + contextMenu.addAction(QIcon(IMAGE_FRIENDINFO), tr("Profile details"), this, SLOT(configureProfile())); + contextMenu.addAction(QIcon(IMAGE_DENYFRIEND), tr("Deny connections"), this, SLOT(removeProfile())); + + RsFriendListModel::RsProfileDetails details; + mModel->getProfileData(index,details); + + if(mModel->getDisplayGroups()) + { + QMenu* addToGroupMenu = NULL; + QMenu* moveToGroupMenu = NULL; + + std::list groupInfoList; + rsPeers->getGroupInfoList(groupInfoList); + + GroupDefs::sortByName(groupInfoList); + + RsPgpId gpgId ( details.gpg_id ); + + QModelIndex parent = mModel->parent(index); + + bool foundGroup = false; + // add action for all groups, except the own group + for (std::list::iterator groupIt = groupInfoList.begin(); groupIt != groupInfoList.end(); ++groupIt) { + if (std::find(groupIt->peerIds.begin(), groupIt->peerIds.end(), gpgId) == groupIt->peerIds.end()) { + if (parent.isValid()) + { + if (addToGroupMenu == NULL) + addToGroupMenu = new QMenu(tr("Add to group"), &contextMenu); + + QAction* addToGroupAction = new QAction(GroupDefs::name(*groupIt), addToGroupMenu); + addToGroupAction->setData(QString::fromStdString(groupIt->id.toStdString())); + connect(addToGroupAction, SIGNAL(triggered()), this, SLOT(addToGroup())); + addToGroupMenu->addAction(addToGroupAction); + } + + if (moveToGroupMenu == NULL) { + moveToGroupMenu = new QMenu(tr("Move to group"), &contextMenu); + } + QAction* moveToGroupAction = new QAction(GroupDefs::name(*groupIt), moveToGroupMenu); + moveToGroupAction->setData(QString::fromStdString(groupIt->id.toStdString())); + connect(moveToGroupAction, SIGNAL(triggered()), this, SLOT(moveToGroup())); + moveToGroupMenu->addAction(moveToGroupAction); + } else { + foundGroup = true; + } + } + + QMenu *groupsMenu = contextMenu.addMenu(QIcon(IMAGE_GROUP16), tr("Groups")); + groupsMenu->addAction(QIcon(IMAGE_EXPAND), tr("Create new group"), this, SLOT(createNewGroup())); + + if (addToGroupMenu || moveToGroupMenu || foundGroup) { + if (addToGroupMenu) { + groupsMenu->addMenu(addToGroupMenu); + } + + if (moveToGroupMenu) { + groupsMenu->addMenu(moveToGroupMenu); + } + + if (foundGroup) + { + // add remove from group + if (parent.isValid() && mModel->getType(parent) == RsFriendListModel::ENTRY_TYPE_GROUP) + { + RsGroupInfo info ; + mModel->getGroupData(parent,info); + + QAction *removeFromGroup = groupsMenu->addAction(tr("Remove from group ")+QString::fromUtf8(info.name.c_str())); + removeFromGroup->setData(parent.sibling(parent.row(),RsFriendListModel::COLUMN_THREAD_ID).data(Qt::DisplayRole)); + connect(removeFromGroup, SIGNAL(triggered()), this, SLOT(removeFromGroup())); + } + + QAction *removeFromAllGroups = groupsMenu->addAction(tr("Remove from all groups")); + removeFromAllGroups->setData(""); + connect(removeFromAllGroups, SIGNAL(triggered()), this, SLOT(removeFromGroup())); + } + } + } + + } + break ; + + case RsFriendListModel::ENTRY_TYPE_NODE: + { +#ifdef RS_DIRECT_CHAT + contextMenu.addAction(QIcon(IMAGE_CHAT), tr("Chat"), this, SLOT(chatNode())); + contextMenu.addAction(QIcon(IMAGE_MSG), tr("Send message to this node"), this, SLOT(msgNode())); + contextMenu.addSeparator(); +#endif // RS_DIRECT_CHAT + + contextMenu.addAction(QIcon(IMAGE_FRIENDINFO), tr("Node details"), this, SLOT(configureNode())); + + if (type == RsFriendListModel::ENTRY_TYPE_PROFILE || type == RsFriendListModel::ENTRY_TYPE_NODE) + contextMenu.addAction(QIcon(IMAGE_EXPORTFRIEND), tr("Recommend this node to..."), this, SLOT(recommendNode())); + + RsFriendListModel::RsNodeDetails details; + mModel->getNodeData(index,details); + + if(!rsPeers->isHiddenNode(rsPeers->getOwnId()) || rsPeers->isHiddenNode( details.id )) + contextMenu.addAction(QIcon(IMAGE_CONNECT), tr("Attempt to connect"), this, SLOT(connectNode())); + + contextMenu.addAction(QIcon(IMAGE_COPYLINK), tr("Copy certificate link"), this, SLOT(copyFullCertificate())); + + //this is a SSL key + contextMenu.addAction(QIcon(IMAGE_REMOVEFRIEND), tr("Remove Friend Node"), this, SLOT(removeNode())); + + } + } + + } + + contextMenu.addSeparator(); + + QAction *action = contextMenu.addAction(QIcon(IMAGE_PASTELINK), tr("Paste certificate link"), this, SLOT(pastePerson())); + if (RSLinkClipboard::empty(RetroShareLink::TYPE_CERTIFICATE)) + action->setDisabled(true); + + contextMenu.addAction(QIcon(IMAGE_EXPAND), tr("Expand all"), ui->peerTreeWidget, SLOT(expandAll())); + contextMenu.addAction(QIcon(IMAGE_COLLAPSE), tr("Collapse all"), ui->peerTreeWidget, SLOT(collapseAll())); + + contextMenu.addSeparator(); + + contextMenu.addAction(ui->actionExportFriendlist); + contextMenu.addAction(ui->actionImportFriendlist); + + contextMenu.exec(QCursor::pos()); +} + +void NewFriendList::createNewGroup() +{ + CreateGroup createGrpDialog (RsNodeGroupId(), this); + createGrpDialog.exec(); +} + +static QIcon createAvatar(const QPixmap &avatar, const QPixmap &overlay) +{ + int avatarWidth = avatar.width(); + int avatarHeight = avatar.height(); + + QPixmap pixmap(avatar); + + int overlaySize = (avatarWidth > avatarHeight) ? (avatarWidth/2.5) : (avatarHeight/2.5); + int overlayX = avatarWidth - overlaySize; + int overlayY = avatarHeight - overlaySize; + + QPainter painter(&pixmap); + painter.drawPixmap(overlayX, overlayY, overlaySize, overlaySize, overlay); + + QIcon icon; + icon.addPixmap(pixmap); + return icon; +} + +void NewFriendList::addFriend() +{ + std::string groupId = getSelectedGroupId(); + + ConnectFriendWizard connwiz (this); + + if (groupId.empty() == false) { + connwiz.setGroup(groupId); + } + + connwiz.exec (); +} +void NewFriendList::msgProfile() +{ + RsFriendListModel::RsNodeDetails det; + + if(!getCurrentNode(det)) + return; + + MessageComposer::msgFriend(det.id); +} +void NewFriendList::msgGroup() +{ + RsFriendListModel::RsNodeDetails det; + + if(!getCurrentNode(det)) + return; + + MessageComposer::msgFriend(det.id); +} +void NewFriendList::msgNode() +{ + RsFriendListModel::RsNodeDetails det; + + if(!getCurrentNode(det)) + return; + + MessageComposer::msgFriend(det.id); +} +void NewFriendList::chatNode() +{ + RsFriendListModel::RsNodeDetails det; + + if(!getCurrentNode(det)) + return; + + ChatDialog::chatFriend(ChatId(det.id)); +} + +void NewFriendList::recommendNode() +{ + RsFriendListModel::RsNodeDetails det; + + if(!getCurrentNode(det)) + return; + + MessageComposer::recommendFriend(std::set({ det.id })); +} + +void NewFriendList::pastePerson() +{ + //RSLinkClipboard::process(RetroShareLink::TYPE_PERSON); + RSLinkClipboard::process(RetroShareLink::TYPE_CERTIFICATE); +} + +void NewFriendList::copyFullCertificate() +{ + RsFriendListModel::RsNodeDetails det; + + if(!getCurrentNode(det)) + return; + + QList urls; + RetroShareLink link = RetroShareLink::createCertificate(det.id); + urls.push_back(link); + + std::cerr << "link: " << std::endl; + std::cerr<< link.toString().toStdString() << std::endl; + + RSLinkClipboard::copyLinks(urls); +} + +/** + * Find out which group is selected + * + * @return If a group item is selected, its groupId otherwise an empty string + */ +std::string NewFriendList::getSelectedGroupId() const +{ + RsGroupInfo ginfo; + + if(!getCurrentGroup(ginfo)) + return std::string(); + + return ginfo.id.toStdString(); +} + +QModelIndex NewFriendList::getCurrentSourceIndex() const +{ + QModelIndexList selectedIndexes = ui->peerTreeWidget->selectionModel()->selectedIndexes(); + + if(selectedIndexes.size() != RsFriendListModel::COLUMN_THREAD_NB_COLUMNS) // check that a single row is selected + return QModelIndex(); + + return mProxyModel->mapToSource(*selectedIndexes.begin()); +} +bool NewFriendList::getCurrentGroup(RsGroupInfo& info) const +{ + /* get the current, and extract the Id */ + + QModelIndex index = getCurrentSourceIndex(); + + if(!index.isValid()) + return false; + + return mModel->getGroupData(index,info); +} +bool NewFriendList::getCurrentNode(RsFriendListModel::RsNodeDetails& prof) const +{ + /* get the current, and extract the Id */ + + QModelIndex index = getCurrentSourceIndex(); + + if(!index.isValid()) + return false; + + return mModel->getNodeData(index,prof); +} +bool NewFriendList::getCurrentProfile(RsFriendListModel::RsProfileDetails& prof) const +{ + /* get the current, and extract the Id */ + + QModelIndex index = getCurrentSourceIndex(); + + if(!index.isValid()) + return false; + + return mModel->getProfileData(index,prof); +} + +#ifdef UNFINISHED_FD +/* GUI stuff -> don't do anything directly with Control */ +void FriendsDialog::viewprofile() +{ + /* display Dialog */ + + QTreeWidgetItem *c = getCurrentPeer(); + + + // static ProfileView *profileview = new ProfileView(); + + + if (!c) + return; + + /* set the Id */ + std::string id = getRsId(c); + + profileview -> setPeerId(id); + profileview -> show(); +} +#endif + +/* So from the Peers Dialog we can call the following control Functions: + * (1) Remove Current. FriendRemove(id) + * (2) Allow/DisAllow. FriendStatus(id, accept) + * (2) Connect. FriendConnectAttempt(id, accept) + * (3) Set Address. FriendSetAddress(id, str, port) + * (4) Set Trust. FriendTrustSignature(id, bool) + * (5) Configure (GUI Only) -> 3/4 + * + * All of these rely on the finding of the current Id. + */ +void NewFriendList::removeNode() +{ + RsFriendListModel::RsNodeDetails det; + if(!getCurrentNode(det) || !rsPeers) + return; + + if ((QMessageBox::question(this, "RetroShare", tr("Do you want to remove this node?"), QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes)) == QMessageBox::Yes) + rsPeers->removeFriendLocation(det.id); + + checkInternalData(true); +} + +void NewFriendList::removeProfile() +{ + RsFriendListModel::RsProfileDetails det; + if(!getCurrentProfile(det) || !rsPeers) + return; + + if ((QMessageBox::question(this, "RetroShare", tr("Do you want to remove this Friend?"), QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes)) == QMessageBox::Yes) + rsPeers->removeFriend(det.gpg_id); + + checkInternalData(true); +} + +void NewFriendList::connectNode() +{ + RsFriendListModel::RsNodeDetails det; + if(!getCurrentNode(det) || !rsPeers) + return; + + rsPeers->connectAttempt(det.id); + ConnectProgressDialog::showProgress(det.id); +} + +/* GUI stuff -> don't do anything directly with Control */ +void NewFriendList::configureNode() +{ + RsFriendListModel::RsNodeDetails det; + + if(!getCurrentNode(det)) + return; + + ConfCertDialog::showIt(det.id, ConfCertDialog::PageDetails); +} +void NewFriendList::configureProfile() +{ + RsFriendListModel::RsProfileDetails det; + + if(!getCurrentProfile(det)) + return; + + PGPKeyDialog::showIt(det.gpg_id, PGPKeyDialog::PageDetails); +} + +void NewFriendList::addToGroup() +{ + RsFriendListModel::RsProfileDetails det; + if(!getCurrentProfile(det) || !rsPeers) + return; + + RsNodeGroupId groupId ( qobject_cast(sender())->data().toString().toStdString()); + RsPgpId gpgId (det.gpg_id); + + if (gpgId.isNull() || groupId.isNull()) + return; + + // automatically expand the group, the peer is added to + expandGroup(groupId); + + // add to group + rsPeers->assignPeerToGroup(groupId, gpgId, true); + checkInternalData(true); +} +void NewFriendList::forceUpdateDisplay() +{ + checkInternalData(true); +} + +// void NewFriendList::updateDisplay() +// { +// checkInternalData(false); +// } + +void NewFriendList::moveToGroup() +{ + RsFriendListModel::RsProfileDetails pinfo; + + if(!getCurrentProfile(pinfo)) + return; + + RsNodeGroupId groupId ( qobject_cast(sender())->data().toString().toStdString()); + RsPgpId gpgId ( pinfo.gpg_id ); + + if (gpgId.isNull() || groupId.isNull()) + return; + + // remove from all groups + rsPeers->assignPeerToGroup(RsNodeGroupId(), gpgId, false); + + // automatically expand the group, the peer is added to + expandGroup(groupId); + + // add to group + rsPeers->assignPeerToGroup(groupId, gpgId, true); + checkInternalData(true); +} + +void NewFriendList::removeFromGroup() +{ + RsFriendListModel::RsProfileDetails pinfo; + + if(!getCurrentProfile(pinfo)) + return; + + RsNodeGroupId groupId ( qobject_cast(sender())->data().toString().toStdString()); + RsPgpId gpgId ( pinfo.gpg_id ); + + if (gpgId.isNull()) + return; + + // remove from (all) group(s) + rsPeers->assignPeerToGroup(groupId, gpgId, false); + checkInternalData(true); +} + +void NewFriendList::editGroup() +{ + RsGroupInfo pinfo; + + if(!getCurrentGroup(pinfo)) + return; + + RsNodeGroupId groupId ( pinfo.id ); + + if (!groupId.isNull()) + { + CreateGroup editGrpDialog(groupId, this); + editGrpDialog.exec(); + } + checkInternalData(true); +} + +void NewFriendList::removeGroup() +{ + RsGroupInfo pinfo; + + if(!getCurrentGroup(pinfo)) + return; + + rsPeers->removeGroup(pinfo.id); + checkInternalData(true); +} + +void NewFriendList::checkInternalData(bool force) +{ + std::set expanded_indexes; + std::set selected_indexes; + + saveExpandedPathsAndSelection(expanded_indexes, selected_indexes); + + mModel->checkInternalData(force); + + restoreExpandedPathsAndSelection(expanded_indexes, selected_indexes); +} + +void NewFriendList::exportFriendlistClicked() +{ + QString fileName; + if(!importExportFriendlistFileDialog(fileName, false)) + // error was already shown - just return + return; + + if(!exportFriendlist(fileName)) + // error was already shown - just return + return; + + QMessageBox mbox; + mbox.setIcon(QMessageBox::Information); + mbox.setText(tr("Done!")); + mbox.setInformativeText(tr("Your friendlist is stored at:\n") + fileName + + tr("\n(keep in mind that the file is unencrypted!)")); + mbox.setStandardButtons(QMessageBox::Ok); + mbox.exec(); +} + +void NewFriendList::importFriendlistClicked() +{ + QString fileName; + if(!importExportFriendlistFileDialog(fileName, true)) + // error was already shown - just return + return; + + bool errorPeers, errorGroups; + if(importFriendlist(fileName, errorPeers, errorGroups)) { + QMessageBox mbox; + mbox.setIcon(QMessageBox::Information); + mbox.setText(tr("Done!")); + mbox.setInformativeText(tr("Your friendlist was imported from:\n") + fileName); + mbox.setStandardButtons(QMessageBox::Ok); + mbox.exec(); + } else { + QMessageBox mbox; + mbox.setIcon(QMessageBox::Warning); + mbox.setText(tr("Done - but errors happened!")); + mbox.setInformativeText(tr("Your friendlist was imported from:\n") + fileName + + (errorPeers ? tr("\nat least one peer was not added") : "") + + (errorGroups ? tr("\nat least one peer was not added to a group") : "") + ); + mbox.setStandardButtons(QMessageBox::Ok); + mbox.exec(); + } +} + +/** + * @brief opens a file dialog to select a file containing a friendlist + * @param fileName file containing a friendlist + * @param import show dialog for importing (true) or exporting (false) friendlist + * @return success or failure + * + * This function also shows an error message when no valid file was selected + */ +bool NewFriendList::importExportFriendlistFileDialog(QString &fileName, bool import) +{ + bool res = true; + if (import) { + res = misc::getOpenFileName(this, RshareSettings::LASTDIR_CERT + , tr("Select file for importing your friendlist from") + , tr("XML File (*.xml);;All Files (*)") + , fileName + , QFileDialog::DontConfirmOverwrite + ); + } else { + res = misc::getSaveFileName(this, RshareSettings::LASTDIR_CERT + , tr("Select a file for exporting your friendlist to") + , tr("XML File (*.xml);;All Files (*)") + , fileName, NULL + , (QFileDialog::Options)0 + ); + } + if ( res && !fileName.endsWith(".xml",Qt::CaseInsensitive) ) + fileName = fileName.append(".xml"); + + return res; +} + +/** + * @brief exports friendlist to a given file + * @param fileName file for storing friendlist + * @return success or failure + * + * This function also shows an error message when the selected file is invalid/not writable + */ +bool NewFriendList::exportFriendlist(QString &fileName) +{ + QDomDocument doc("FriendListWithGroups"); + QDomElement root = doc.createElement("root"); + doc.appendChild(root); + + QFile file(fileName); + if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) { + // show error to user + QMessageBox mbox; + mbox.setIcon(QMessageBox::Warning); + mbox.setText(tr("Error")); + mbox.setInformativeText(tr("File is not writeable!\n") + fileName); + mbox.setStandardButtons(QMessageBox::Ok); + mbox.exec(); + return false; + } + + std::list gpg_ids; + rsPeers->getGPGAcceptedList(gpg_ids); + + std::list group_info_list; + rsPeers->getGroupInfoList(group_info_list); + + QDomElement pgpIDs = doc.createElement("pgpIDs"); + RsPeerDetails detailPGP; + for(std::list::iterator list_iter = gpg_ids.begin(); list_iter != gpg_ids.end(); list_iter++) { + rsPeers->getGPGDetails(*list_iter, detailPGP); + QDomElement pgpID = doc.createElement("pgpID"); + // these values aren't used and just stored for better human readability + pgpID.setAttribute("id", QString::fromStdString(detailPGP.gpg_id.toStdString())); + pgpID.setAttribute("name", QString::fromUtf8(detailPGP.name.c_str())); + + std::list ssl_ids; + rsPeers->getAssociatedSSLIds(*list_iter, ssl_ids); + for(std::list::iterator list_iter = ssl_ids.begin(); list_iter != ssl_ids.end(); list_iter++) { + RsPeerDetails detailSSL; + if (!rsPeers->getPeerDetails(*list_iter, detailSSL)) + continue; + + std::string certificate = rsPeers->GetRetroshareInvite(detailSSL.id, true,true); + // remove \n from certificate + certificate.erase(std::remove(certificate.begin(), certificate.end(), '\n'), certificate.end()); + + QDomElement sslID = doc.createElement("sslID"); + // these values aren't used and just stored for better human readability + sslID.setAttribute("sslID", QString::fromStdString(detailSSL.id.toStdString())); + if(!detailSSL.location.empty()) + sslID.setAttribute("location", QString::fromUtf8(detailSSL.location.c_str())); + + // required values + sslID.setAttribute("certificate", QString::fromStdString(certificate)); + sslID.setAttribute("service_perm_flags", detailSSL.service_perm_flags.toUInt32()); + + pgpID.appendChild(sslID); + } + pgpIDs.appendChild(pgpID); + } + root.appendChild(pgpIDs); + + QDomElement groups = doc.createElement("groups"); + for(std::list::iterator list_iter = group_info_list.begin(); list_iter != group_info_list.end(); list_iter++) { + RsGroupInfo group_info = *list_iter; + + //skip groups without peers + if(group_info.peerIds.empty()) + continue; + + QDomElement group = doc.createElement("group"); + // id is not needed since it may differ between locatiosn / pgp ids (groups are identified by name) + group.setAttribute("name", QString::fromUtf8(group_info.name.c_str())); + group.setAttribute("flag", group_info.flag); + + for(std::set::iterator i = group_info.peerIds.begin(); i != group_info.peerIds.end(); i++) { + QDomElement pgpID = doc.createElement("pgpID"); + std::string pid = i->toStdString(); + pgpID.setAttribute("id", QString::fromStdString(pid)); + group.appendChild(pgpID); + } + groups.appendChild(group); + } + root.appendChild(groups); + + QTextStream ts(&file); + ts.setCodec("UTF-8"); + ts << doc.toString(); + file.close(); + + return true; +} + +/** + * @brief helper function to show a message box + */ +static void showXMLParsingError() +{ + // show error to user + QMessageBox mbox; + mbox.setIcon(QMessageBox::Warning); + mbox.setText(QObject::tr("Error")); + mbox.setInformativeText(QObject::tr("unable to parse XML file!")); + mbox.setStandardButtons(QMessageBox::Ok); + mbox.exec(); +} + +/** + * @brief Imports friends from a given file + * @param fileName file to load friends from + * @param errorPeers an error occured while adding a peer + * @param errorGroups an error occured while adding a peer to a group + * @return success or failure (an error can also happen when adding a peer and/or adding a peer to a group fails at least once) + */ +bool NewFriendList::importFriendlist(QString &fileName, bool &errorPeers, bool &errorGroups) +{ + QDomDocument doc; + // load from file + { + QFile file(fileName); + + if (!file.open(QIODevice::ReadOnly)) { + // show error to user + QMessageBox mbox; + mbox.setIcon(QMessageBox::Warning); + mbox.setText(tr("Error")); + mbox.setInformativeText(tr("File is not readable!\n") + fileName); + mbox.setStandardButtons(QMessageBox::Ok); + mbox.exec(); + return false; + } + + bool ok = doc.setContent(&file); + file.close(); + + if(!ok) { + showXMLParsingError(); + return false; + } + } + + QDomElement root = doc.documentElement(); + if(root.tagName() != "root") { + showXMLParsingError(); + return false; + } + + errorPeers = false; + errorGroups = false; + + std::string error_string; + RsPeerDetails rsPeerDetails; + RsPeerId rsPeerID; + RsPgpId rsPgpID; + + // lock all events for faster processing + RsAutoUpdatePage::lockAllEvents(); + + // pgp and ssl IDs + QDomElement pgpIDs; + { + QDomNodeList nodes = root.elementsByTagName("pgpIDs"); + if(nodes.isEmpty() || nodes.size() != 1){ + showXMLParsingError(); + return false; + } + + pgpIDs = nodes.item(0).toElement(); + if(pgpIDs.isNull()){ + showXMLParsingError(); + return false; + } + } + QDomNode pgpIDElem = pgpIDs.firstChildElement("pgpID"); + while (!pgpIDElem.isNull()) { + QDomElement sslIDElem = pgpIDElem.firstChildElement("sslID"); + while (!sslIDElem.isNull()) { + rsPeerID.clear(); + rsPgpID.clear(); + + // load everything needed from the pubkey string + std::string pubkey = sslIDElem.attribute("certificate").toStdString(); + ServicePermissionFlags service_perm_flags(sslIDElem.attribute("service_perm_flags").toInt()); + if (!rsPeers->acceptInvite(pubkey, service_perm_flags)) { + errorPeers = true; + std::cerr << "FriendList::importFriendlist(): failed to get peer detaisl from public key (SSL id: " << sslIDElem.attribute("sslID", "invalid").toStdString() << ")" << std::endl; + } + sslIDElem = sslIDElem.nextSiblingElement("sslID"); + } + pgpIDElem = pgpIDElem.nextSiblingElement("pgpID"); + } + + // groups + QDomElement groups; + { + QDomNodeList nodes = root.elementsByTagName("groups"); + if(nodes.isEmpty() || nodes.size() != 1){ + showXMLParsingError(); + return false; + } + + groups = nodes.item(0).toElement(); + if(groups.isNull()){ + showXMLParsingError(); + return false; + } + } + QDomElement group = groups.firstChildElement("group"); + while (!group.isNull()) { + // get name and flags and try to get the group ID + std::string groupName = group.attribute("name").toStdString(); + uint32_t flag = group.attribute("flag").toInt(); + RsNodeGroupId groupId; + if(getOrCreateGroup(groupName, flag, groupId)) { + // group id found! + QDomElement pgpID = group.firstChildElement("pgpID"); + while (!pgpID.isNull()) { + // add pgp id to group + RsPgpId rsPgpId(pgpID.attribute("id").toStdString()); + if(rsPgpID.isNull() || !rsPeers->assignPeerToGroup(groupId, rsPgpId, true)) { + errorGroups = true; + std::cerr << "FriendList::importFriendlist(): failed to add '" << rsPeers->getGPGName(rsPgpId) << "'' to group '" << groupName << "'" << std::endl; + } + + pgpID = pgpID.nextSiblingElement("pgpID"); + } + pgpID = pgpID.nextSiblingElement("pgpID"); + } else { + errorGroups = true; + std::cerr << "FriendList::importFriendlist(): failed to find/create group '" << groupName << "'" << std::endl; + } + group = group.nextSiblingElement("group"); + } + + // unlock events + RsAutoUpdatePage::unlockAllEvents(); + + return !(errorPeers || errorGroups); +} + +/** + * @brief Gets the groups ID for a given group name + * @param name group name to search for + * @param id groupd id for the given name + * @return success or fail + */ +bool NewFriendList::getGroupIdByName(const std::string &name, RsNodeGroupId &id) +{ + std::list grpList; + if(!rsPeers->getGroupInfoList(grpList)) + return false; + + foreach (const RsGroupInfo &grp, grpList) { + if(grp.name == name) { + id = grp.id; + return true; + } + } + + return false; +} + +/** + * @brief Gets the groups ID for a given group name. If no groupd was it will create one + * @param name group name to search for + * @param flag flag to use when creating the group + * @param id groupd id + * @return success or failure + */ +bool NewFriendList::getOrCreateGroup(const std::string& name, uint flag, RsNodeGroupId &id) +{ + if(getGroupIdByName(name, id)) + return true; + + // -> create one + RsGroupInfo grp; + grp.id.clear(); // RS will generate an ID + grp.name = name; + grp.flag = flag; + + if(!rsPeers->addGroup(grp)) + return false; + + // try again + return getGroupIdByName(name, id); +} + + +void NewFriendList::setShowUnconnected(bool show) +{ + mProxyModel->setShowOfflineNodes(show); + mProxyModel->setFilterRegExp(QRegExp(QString(RsFriendListModel::FilterString))) ;// triggers a re-display. +} + +bool NewFriendList::isColumnVisible(int col) const +{ + return !ui->peerTreeWidget->isColumnHidden(col); +} +void NewFriendList::setColumnVisible(int col,bool visible) +{ + ui->peerTreeWidget->setColumnHidden(col, !visible); +} +void NewFriendList::toggleColumnVisible() +{ + QAction *action = dynamic_cast(sender()); + + if (!action) + return; + + int column = action->data().toInt(); + bool visible = action->isChecked(); + + ui->peerTreeWidget->setColumnHidden(column, !visible); +} + +void NewFriendList::setShowState(bool show) +{ + mModel->setDisplayStatusString(show); +} + +void NewFriendList::setShowGroups(bool show) +{ + mModel->setDisplayGroups(show); +} + +/** + * Hides all items that don't contain text in the name column. + */ +void NewFriendList::filterItems(const QString &text) +{ + QStringList lst = text.split(' ',QString::SkipEmptyParts); + int filterColumn = ui->filterLineEdit->currentFilter(); + + if(filterColumn == 0) + mModel->setFilter(RsFriendListModel::FILTER_TYPE_NAME,lst); + else + mModel->setFilter(RsFriendListModel::FILTER_TYPE_ID,lst); + + // We do this in order to trigger a new filtering action in the proxy model. + mProxyModel->setFilterRegExp(QRegExp(QString(RsFriendListModel::FilterString))) ; + + if(!lst.empty()) + ui->peerTreeWidget->expandAll(); + else + ui->peerTreeWidget->collapseAll(); +} + +void NewFriendList::expandGroup(const RsNodeGroupId& gid) +{ + QModelIndex index = mProxyModel->mapFromSource(mModel->getIndexOfGroup(gid)); + ui->peerTreeWidget->setExpanded(index,true) ; +} diff --git a/retroshare-gui/src/gui/common/NewFriendList.h b/retroshare-gui/src/gui/common/NewFriendList.h new file mode 100644 index 000000000..17214093d --- /dev/null +++ b/retroshare-gui/src/gui/common/NewFriendList.h @@ -0,0 +1,158 @@ +/******************************************************************************* + * gui/common/NewFriendList.h * + * * + * Copyright (C) 2011, Retroshare Team * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +#pragma once + +#include + +#include +#include + +#include "FriendListModel.h" +#include "RsAutoUpdatePage.h" +#include "retroshare/rsstatus.h" + +namespace Ui { + class NewFriendList; +} + +class RSTreeWidgetItemCompareRole; +class QTreeWidgetItem; +class QToolButton; +class FriendListSortFilterProxyModel; + +class NewFriendList: public QWidget +{ + Q_OBJECT + + Q_PROPERTY(QColor textColorGroup READ textColorGroup WRITE setTextColorGroup) + Q_PROPERTY(QColor textColorStatusOffline READ textColorStatusOffline WRITE setTextColorStatusOffline) + Q_PROPERTY(QColor textColorStatusAway READ textColorStatusAway WRITE setTextColorStatusAway) + Q_PROPERTY(QColor textColorStatusBusy READ textColorStatusBusy WRITE setTextColorStatusBusy) + Q_PROPERTY(QColor textColorStatusOnline READ textColorStatusOnline WRITE setTextColorStatusOnline) + Q_PROPERTY(QColor textColorStatusInactive READ textColorStatusInactive WRITE setTextColorStatusInactive) + +public: + explicit NewFriendList(QWidget *parent = 0); + ~NewFriendList(); + + // Add a tool button to the tool area + void addToolButton(QToolButton *toolButton); + void processSettings(bool load); + void setColumnVisible(int col,bool visible); + bool isColumnVisible(int col) const; + + std::string getSelectedGroupId() const; + + //void updateDisplay() override; + + QColor textColorGroup() const { return mModel->mTextColorGroup; } + QColor textColorStatusOffline() const { return mModel->mTextColorStatus[RS_STATUS_OFFLINE ]; } + QColor textColorStatusAway() const { return mModel->mTextColorStatus[RS_STATUS_AWAY ]; } + QColor textColorStatusBusy() const { return mModel->mTextColorStatus[RS_STATUS_BUSY ]; } + QColor textColorStatusOnline() const { return mModel->mTextColorStatus[RS_STATUS_ONLINE ]; } + QColor textColorStatusInactive() const { return mModel->mTextColorStatus[RS_STATUS_INACTIVE]; } + + void setTextColorGroup(QColor color) { mModel->mTextColorGroup = color; } + void setTextColorStatusOffline(QColor color) { mModel->mTextColorStatus[RS_STATUS_OFFLINE ] = color; } + void setTextColorStatusAway(QColor color) { mModel->mTextColorStatus[RS_STATUS_AWAY ] = color; } + void setTextColorStatusBusy(QColor color) { mModel->mTextColorStatus[RS_STATUS_BUSY ] = color; } + void setTextColorStatusOnline(QColor color) { mModel->mTextColorStatus[RS_STATUS_ONLINE ] = color; } + void setTextColorStatusInactive(QColor color) { mModel->mTextColorStatus[RS_STATUS_INACTIVE] = color; } + +public slots: + void filterItems(const QString &text); + void toggleSortByState(bool sort); + void forceUpdateDisplay(); + + void toggleColumnVisible(); + void setShowGroups(bool show); + void setShowUnconnected(bool hidden); + void setShowState(bool show); + void headerContextMenuRequested(QPoint); + +private slots: + void sortColumn(int col,Qt::SortOrder so); + void itemExpanded(const QModelIndex&); + void itemCollapsed(const QModelIndex&); + +protected: + void changeEvent(QEvent *e); + +private: + Ui::NewFriendList *ui; + RsFriendListModel *mModel; + QAction *mActionSortByState; + + void expandGroup(const RsNodeGroupId& gid); + void recursRestoreExpandedItems(const QModelIndex& index, const QString& parent_path, const std::set& exp, const std::set &sel); + void recursSaveExpandedItems(const QModelIndex& index,const QString& parent_path,std::set& exp, std::set& sel); + void saveExpandedPathsAndSelection(std::set& expanded_indexes, std::set& selected_indexes); + void restoreExpandedPathsAndSelection(const std::set& expanded_indexes, const std::set& selected_indexes); + + void checkInternalData(bool force); + + QModelIndex getCurrentSourceIndex() const; + + bool getCurrentNode(RsFriendListModel::RsNodeDetails& prof) const; + bool getCurrentGroup(RsGroupInfo& prof) const; + bool getCurrentProfile(RsFriendListModel::RsProfileDetails& prof) const; + + // Settings for peer list display + bool mShowState; + + std::set openGroups; + std::set openPeers; + + bool getOrCreateGroup(const std::string& name, uint flag, RsNodeGroupId& id); + bool getGroupIdByName(const std::string& name, RsNodeGroupId& id); + + bool importExportFriendlistFileDialog(QString &fileName, bool import); + bool exportFriendlist(QString &fileName); + bool importFriendlist(QString &fileName, bool &errorPeers, bool &errorGroups); + + FriendListSortFilterProxyModel *mProxyModel ; +private slots: + void peerTreeWidgetCustomPopupMenu(); + void pastePerson(); + void connectNode(); + void configureNode(); + void configureProfile(); + void chatNode(); + void copyFullCertificate(); + void addFriend(); + void msgNode(); + void msgGroup(); + void msgProfile(); + void recommendNode(); + void removeNode(); + void removeProfile(); + void createNewGroup() ; + + void addToGroup(); + void moveToGroup(); + void removeFromGroup(); + + void editGroup(); + void removeGroup(); + + void exportFriendlistClicked(); + void importFriendlistClicked(); +}; diff --git a/retroshare-gui/src/gui/common/NewFriendList.ui b/retroshare-gui/src/gui/common/NewFriendList.ui new file mode 100644 index 000000000..3ec1c6c03 --- /dev/null +++ b/retroshare-gui/src/gui/common/NewFriendList.ui @@ -0,0 +1,132 @@ + + + NewFriendList + + + + 0 + 0 + 475 + 292 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::Box + + + QFrame::Sunken + + + + 3 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + + + + + + + Qt::CustomContextMenu + + + true + + + false + + + + + + + true + + + Offline Friends + + + Show Offline Friends + + + + + true + + + Status + + + Show status + + + + + true + + + Groups + + + Show groups + + + + + export friendlist + + + export your friendlist including groups + + + + + import friendlist + + + import your friendlist including groups + + + + + + LineEditClear + QLineEdit +
gui/common/LineEditClear.h
+
+
+ + +
diff --git a/retroshare-gui/src/gui/common/StatusDefs.cpp b/retroshare-gui/src/gui/common/StatusDefs.cpp index f40949d17..5d0db8395 100644 --- a/retroshare-gui/src/gui/common/StatusDefs.cpp +++ b/retroshare-gui/src/gui/common/StatusDefs.cpp @@ -243,7 +243,7 @@ QString StatusDefs::connectStateWithoutTransportTypeString(RsPeerDetails &detail return stateString; } -QString StatusDefs::connectStateIpString(RsPeerDetails &details) +QString StatusDefs::connectStateIpString(const RsPeerDetails &details) { QString stateString = QString(""); diff --git a/retroshare-gui/src/gui/common/StatusDefs.h b/retroshare-gui/src/gui/common/StatusDefs.h index d06cbb1d9..b922e28e4 100644 --- a/retroshare-gui/src/gui/common/StatusDefs.h +++ b/retroshare-gui/src/gui/common/StatusDefs.h @@ -40,7 +40,7 @@ public: static QString peerStateString(int peerState); static QString connectStateString(RsPeerDetails &details); static QString connectStateWithoutTransportTypeString(RsPeerDetails &details); - static QString connectStateIpString(RsPeerDetails &details); + static QString connectStateIpString(const RsPeerDetails &details); }; #endif diff --git a/retroshare-gui/src/gui/connect/ConfCertDialog.cpp b/retroshare-gui/src/gui/connect/ConfCertDialog.cpp index 907e765cf..072c966d5 100644 --- a/retroshare-gui/src/gui/connect/ConfCertDialog.cpp +++ b/retroshare-gui/src/gui/connect/ConfCertDialog.cpp @@ -89,11 +89,13 @@ ConfCertDialog::ConfCertDialog(const RsPeerId& id, const RsPgpId &pgp_id, QWidge //ui._chat_CB->hide() ; setAttribute(Qt::WA_DeleteOnClose, true); + ui._shortFormat_CB->setChecked(true); connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(applyDialog())); connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(close())); connect(ui._shouldAddSignatures_CB, SIGNAL(toggled(bool)), this, SLOT(loadInvitePage())); connect(ui._includeIPHistory_CB, SIGNAL(toggled(bool)), this, SLOT(loadInvitePage())); + connect(ui._shortFormat_CB, SIGNAL(toggled(bool)), this, SLOT(loadInvitePage())); ui.avatar->setFrameType(AvatarWidget::NORMAL_FRAME); @@ -270,14 +272,14 @@ void ConfCertDialog::loadInvitePage() // ui.userCertificateText_2->setFont(font); // ui.userCertificateText_2->setText(QString::fromUtf8(pgp_key.c_str())); - std::string invite = rsPeers->GetRetroshareInvite(detail.id, - ui._shouldAddSignatures_CB->isChecked(), - ui._includeIPHistory_CB->isChecked() - ) ; + std::string invite ; - QString infotext = getCertificateDescription(detail,ui._shouldAddSignatures_CB->isChecked(), - ui._includeIPHistory_CB->isChecked() - ); + if(ui._shortFormat_CB->isChecked()) + rsPeers->getShortInvite(invite,detail.id,true,!ui._includeIPHistory_CB->isChecked() ); + else + invite = rsPeers->GetRetroshareInvite(detail.id, ui._shouldAddSignatures_CB->isChecked(), ui._includeIPHistory_CB->isChecked() ) ; + + QString infotext = getCertificateDescription(detail,ui._shouldAddSignatures_CB->isChecked(),ui._shortFormat_CB->isChecked(), ui._includeIPHistory_CB->isChecked() ); ui.userCertificateText->setToolTip(infotext) ; @@ -291,15 +293,20 @@ void ConfCertDialog::loadInvitePage() ui.userCertificateText->setText(QString::fromUtf8(invite.c_str())); } -QString ConfCertDialog::getCertificateDescription(const RsPeerDetails& detail,bool signatures_included,bool include_additional_locators) +QString ConfCertDialog::getCertificateDescription(const RsPeerDetails& detail,bool signatures_included,bool use_short_format,bool include_additional_locators) { //infotext += tr("

Use this certificate to make new friends. Send it by email, or give it hand to hand.

") ; QString infotext = QObject::tr("

This certificate contains:") ; infotext += "

    " ; - infotext += "
  • a Profile key"; + + if(use_short_format) + infotext += "
  • a Profile fingerprint"; + else + infotext += "
  • a Profile key"; + infotext += " (" + QString::fromUtf8(detail.name.c_str()) + "@" + detail.gpg_id.toStdString().c_str()+") " ; - if(signatures_included) + if(signatures_included && !use_short_format) infotext += tr("with")+" "+QString::number(detail.gpgSigners.size()-1)+" "+tr("external signatures
  • ") ; else infotext += "" ; diff --git a/retroshare-gui/src/gui/connect/ConfCertDialog.h b/retroshare-gui/src/gui/connect/ConfCertDialog.h index a52ac3cdb..019e46598 100644 --- a/retroshare-gui/src/gui/connect/ConfCertDialog.h +++ b/retroshare-gui/src/gui/connect/ConfCertDialog.h @@ -58,7 +58,7 @@ public: /* window will destroy itself! */ } static void loadAll(); - static QString getCertificateDescription(const RsPeerDetails& det,bool signatures_included,bool extra_locators_included); + static QString getCertificateDescription(const RsPeerDetails& det, bool signatures_included, bool use_short_format, bool extra_locators_included); signals: void configChanged(); diff --git a/retroshare-gui/src/gui/connect/ConfCertDialog.ui b/retroshare-gui/src/gui/connect/ConfCertDialog.ui index 324f0fcb8..5c11ff46c 100644 --- a/retroshare-gui/src/gui/connect/ConfCertDialog.ui +++ b/retroshare-gui/src/gui/connect/ConfCertDialog.ui @@ -6,8 +6,8 @@ 0 0 - 600 - 584 + 658 + 1120 @@ -389,6 +389,13 @@ + + + + short format + + + diff --git a/retroshare-gui/src/gui/connect/ConnectFriendWizard.cpp b/retroshare-gui/src/gui/connect/ConnectFriendWizard.cpp index b58e8f94d..f4d1ba6ed 100755 --- a/retroshare-gui/src/gui/connect/ConnectFriendWizard.cpp +++ b/retroshare-gui/src/gui/connect/ConnectFriendWizard.cpp @@ -84,14 +84,14 @@ ConnectFriendWizard::ConnectFriendWizard(QWidget *parent) : // (csoler) I'm hiding this, since it is not needed anymore with the new Home page. ui->userFrame->hide(); - ui->userFileFrame->hide(); // in homepage dropmenu now +// ui->userFileFrame->hide(); // in homepage dropmenu now // this define comes from Qt example. I don't have mac, so it wasn't tested #ifndef Q_OS_MAC setWizardStyle(ModernStyle); #endif - setStartId(Page_Intro); + setStartId(Page_Text); // at this moment I don't know, what information should be in help // setOption(HaveHelpButton, true); @@ -106,8 +106,8 @@ ConnectFriendWizard::ConnectFriendWizard(QWidget *parent) : ui->ErrorMessagePage->registerField("errorMessage", ui->messageLabel, "text"); /* disable not used pages */ - ui->foffRadioButton->hide(); - ui->rsidRadioButton->hide(); + //ui->foffRadioButton->hide(); + //ui->rsidRadioButton->hide(); ui->cp_Label->hide(); ui->requestinfolabel->hide(); @@ -129,6 +129,8 @@ ConnectFriendWizard::ConnectFriendWizard(QWidget *parent) : body += "\n" + GetStartedDialog::GetCutBelowText(); body += "\n\n" + QString::fromUtf8(rsPeers->GetRetroshareInvite().c_str()); + mIsShortInvite = false; + std::string advsetting; if(rsConfig->getConfigurationOption(RS_CONFIG_ADVANCED, advsetting) && (advsetting == "YES")) { @@ -147,14 +149,10 @@ ConnectFriendWizard::ConnectFriendWizard(QWidget *parent) : switch (rsFiles->filePermDirectDL()) { case RS_FILE_PERM_DIRECT_DL_YES: - ui->_direct_transfer_CB->setIcon(QIcon(":/icons/warning_yellow_128.png")); - ui->_direct_transfer_CB->setToolTip(ui->_direct_transfer_CB->toolTip().append(tr("\nWarning: In your File-Transfer option, you select allow direct download to Yes."))); ui->_direct_transfer_CB_2->setIcon(QIcon(":/icons/warning_yellow_128.png")); ui->_direct_transfer_CB_2->setToolTip(ui->_direct_transfer_CB_2->toolTip().append(tr("\nWarning: In your File-Transfer option, you select allow direct download to Yes."))); break ; case RS_FILE_PERM_DIRECT_DL_NO: - ui->_direct_transfer_CB->setIcon(QIcon(":/icons/warning_yellow_128.png")); - ui->_direct_transfer_CB->setToolTip(ui->_direct_transfer_CB->toolTip().append(tr("\nWarning: In your File-Transfer option, you select allow direct download to No."))); ui->_direct_transfer_CB_2->setIcon(QIcon(":/icons/warning_yellow_128.png")); ui->_direct_transfer_CB_2->setToolTip(ui->_direct_transfer_CB_2->toolTip().append(tr("\nWarning: In your File-Transfer option, you select allow direct download to No."))); break ; @@ -277,7 +275,6 @@ QString ConnectFriendWizard::getErrorString(uint32_t error_code) void ConnectFriendWizard::setCertificate(const QString &certificate, bool friendRequest) { if (certificate.isEmpty()) { - setStartId(Page_Intro); return; } @@ -299,8 +296,6 @@ void ConnectFriendWizard::setCertificate(const QString &certificate, bool friend { mCertificate = certificate.toUtf8().constData(); - // Cyril: I disabled this because it seems to be not used anymore. - //setStartId(friendRequest ? Page_FriendRequest : Page_Conclusion); setStartId(Page_Conclusion); if (friendRequest){ ui->cp_Label->show(); @@ -309,7 +304,33 @@ void ConnectFriendWizard::setCertificate(const QString &certificate, bool friend ui->ConclusionPage->setSubTitle(tr("Details about the request")); } } - } else { + } + else if(rsPeers->parseShortInvite(certificate.toUtf8().constData(),peerDetails,cert_load_error_code)) + { + mIsShortInvite = true; + + if(peerDetails.id == rsPeers->getOwnId()) + { + setField("errorMessage", tr("This is your own certificate! You would not want to make friend with yourself. Wouldn't you?") ) ; + error = false; + setStartId(Page_ErrorMessage); + } + else + { + mCertificate = certificate.toUtf8().constData(); + + setStartId(Page_Conclusion); + + if (friendRequest){ + ui->cp_Label->show(); + ui->requestinfolabel->show(); + setTitleText(ui->ConclusionPage, tr("Friend request")); + ui->ConclusionPage->setSubTitle(tr("Details about the request")); + } + } + } + else + { // error message setField("errorMessage", tr("Certificate Load Failed") + ": \n\n" + getErrorString(cert_load_error_code)) ; setStartId(Page_ErrorMessage); @@ -361,9 +382,6 @@ static void fillGroups(ConnectFriendWizard *wizard, QComboBox *comboBox, const Q void ConnectFriendWizard::initializePage(int id) { switch ((Page) id) { - case Page_Intro: - ui->textRadioButton->setChecked(true); - break; case Page_Text: connect(ui->userCertHelpButton, SIGNAL( clicked()), this, SLOT(showHelpUserCert())); connect(ui->userCertIncludeSignaturesButton, SIGNAL(clicked()), this, SLOT(toggleSignatureState())); @@ -389,53 +407,9 @@ void ConnectFriendWizard::initializePage(int id) cleanFriendCert(); - break; - case Page_Cert: - connect(ui->userFileCreateButton, SIGNAL(clicked()), this, SLOT(generateCertificateCalled())); - connect(ui->friendFileNameOpenButton, SIGNAL(clicked()), this, SLOT(loadFriendCert())); - - ui->friendFileNameEdit->setAcceptFile(true); - - ui->CertificatePage->registerField("friendCertificateFile*", ui->friendFileNameEdit); - break; - case Page_Foff: - ui->userSelectionCB->addItem(tr("Any peer I've not signed")); - ui->userSelectionCB->addItem(tr("Friends of my friends who already trust me")); - ui->userSelectionCB->addItem(tr("Signed peers showing as denied")); - - ui->selectedPeersTW->setHorizontalHeaderItem(0, new QTableWidgetItem(tr(""))); - ui->selectedPeersTW->setHorizontalHeaderItem(1, new QTableWidgetItem(tr("Peer name"))); - ui->selectedPeersTW->setHorizontalHeaderItem(2, new QTableWidgetItem(tr("Also signed by"))); - ui->selectedPeersTW->setHorizontalHeaderItem(3, new QTableWidgetItem(tr("Peer id"))); - - connect(ui->makeFriendButton, SIGNAL(clicked()), this, SLOT(signAllSelectedUsers())); - connect(ui->userSelectionCB, SIGNAL(activated(int)), this, SLOT(updatePeersList(int))); - - updatePeersList(ui->userSelectionCB->currentIndex()); - - ui->FofPage->setComplete(false); - break; - case Page_Rsid: - ui->RsidPage->registerField("friendRSID*", ui->friendRsidEdit); break; case Page_WebMail: - case Page_Email: - { - ui->EmailPage->registerField("addressEdit*", ui->addressEdit); - ui->EmailPage->registerField("subjectEdit*", ui->subjectEdit); - - ui->subjectEdit->setText(tr("RetroShare Invitation")); - ui->inviteTextEdit->setPlainText(GetStartedDialog::GetInviteText()); - - QString body = ui->inviteTextEdit->toPlainText(); - - body += "\n" + GetStartedDialog::GetCutBelowText(); - body += "\n\n" + QString::fromUtf8(rsPeers->GetRetroshareInvite().c_str()); - - ui->inviteTextEdit->setPlainText(body); - } - break; case Page_ErrorMessage: break; case Page_Conclusion: @@ -589,75 +563,6 @@ void ConnectFriendWizard::initializePage(int id) } break; - case Page_FriendRequest: - { - std::cerr << "Friend request page id : " << peerDetails.id << "; gpg_id : " << peerDetails.gpg_id << std::endl; - - ui->fr_avatar->setFrameType(AvatarWidget::NORMAL_FRAME); - setPixmap(QWizard::LogoPixmap, QPixmap(":/images/user/user_request48.png")); - - ui->fr_signGPGCheckBox->setChecked(false); - - //set the radio button to sign the GPG key - if (peerDetails.accept_connection && !peerDetails.ownsign) { - //gpg key connection is already accepted, don't propose to accept it again - ui->fr_acceptNoSignGPGCheckBox->hide(); - ui->fr_signGPGCheckBox->show(); - ui->fr_acceptNoSignGPGCheckBox->setChecked(false); - } - if (!peerDetails.accept_connection && peerDetails.ownsign) { - //gpg key is already signed, don't propose to sign it again - ui->fr_acceptNoSignGPGCheckBox->setChecked(true); - ui->fr_signGPGCheckBox->hide(); - } - if (!peerDetails.accept_connection && !peerDetails.ownsign) { - ui->fr_acceptNoSignGPGCheckBox->setChecked(true); - ui->fr_signGPGCheckBox->show(); - ui->fr_acceptNoSignGPGCheckBox->show(); - } - if (peerDetails.accept_connection && peerDetails.ownsign) { - ui->fr_acceptNoSignGPGCheckBox->setChecked(false); - ui->fr_acceptNoSignGPGCheckBox->hide(); - ui->fr_signGPGCheckBox->hide(); - } - - ui->fr_nameEdit->setText(QString::fromUtf8(peerDetails.name.c_str())); - ui->fr_emailEdit->setText(QString::fromUtf8(peerDetails.email.c_str())); - - QString loc = QString::fromUtf8(peerDetails.location.c_str()); - if (!loc.isEmpty()) - { - loc += " ("; - loc += QString::fromStdString(peerDetails.id.toStdString()); - loc += ")"; - } - else - { - if (!peerDetails.id.isNull()) - { - loc += QString::fromStdString(peerDetails.id.toStdString()); - } - } - - ui->fr_nodeEdit->setText(loc); - - ui->fr_InfoTopLabel->setText(tr("You have a friend request from") + " " + QString::fromUtf8(peerDetails.name.c_str())); - - fillGroups(this, ui->fr_groupComboBox, groupId); - } - break; - case Page_FriendRecommendations: - ui->frec_recommendList->setHeaderText(tr("Recommend friends")); - ui->frec_recommendList->setModus(FriendSelectionWidget::MODUS_CHECK); - ui->frec_recommendList->setShowType(FriendSelectionWidget::SHOW_GROUP | FriendSelectionWidget::SHOW_SSL); - ui->frec_recommendList->start(); - - ui->frec_toList->setHeaderText(tr("To")); - ui->frec_toList->setModus(FriendSelectionWidget::MODUS_CHECK); - ui->frec_toList->start(); - - ui->frec_messageEdit->setText(MessageComposer::recommendMessage()); - break; } } @@ -694,7 +599,6 @@ bool ConnectFriendWizard::validateCurrentPage() error = true; switch ((Page) currentId()) { - case Page_Intro: case Page_WebMail: break; case Page_Text: @@ -702,7 +606,8 @@ bool ConnectFriendWizard::validateCurrentPage() std::string certstr = ui->friendCertEdit->toPlainText().toUtf8().constData(); uint32_t cert_load_error_code; - if (rsPeers->loadDetailsFromStringCert(certstr, peerDetails, cert_load_error_code)) { + if (rsPeers->loadDetailsFromStringCert(certstr, peerDetails, cert_load_error_code) || rsPeers->parseShortInvite(certstr,peerDetails,cert_load_error_code)) + { mCertificate = certstr; #ifdef FRIEND_WIZARD_DEBUG std::cerr << "ConnectFriendWizard got id : " << peerDetails.id << "; gpg_id : " << peerDetails.gpg_id << std::endl; @@ -721,111 +626,10 @@ bool ConnectFriendWizard::validateCurrentPage() error = false; break; } - case Page_Cert: - { - QString fn = ui->friendFileNameEdit->text(); - if (QFile::exists(fn)) { - //Todo: move read from file to p3Peers::loadCertificateFromFile - - // read from file - std::string certstr; - QFile CertFile(fn); - if (CertFile.open(QIODevice::ReadOnly | QIODevice::Text)) { - certstr = QString(CertFile.readAll()).toStdString(); - CertFile.close(); - } - - if (certstr.empty()) { - setField("errorMessage", QString(tr("Certificate Load Failed:can't read from file %1")).arg(fn+" ") ); - error = false; - break; - } - - uint32_t cert_error_code; - if (rsPeers->loadDetailsFromStringCert(certstr, peerDetails, cert_error_code)) { - mCertificate = certstr; -#ifdef FRIEND_WIZARD_DEBUG - std::cerr << "ConnectFriendWizard got id : " << peerDetails.id << "; gpg_id : " << peerDetails.gpg_id << std::endl; -#endif - - if(peerDetails.id == rsPeers->getOwnId()) - { - setField("errorMessage", tr("This is your own certificate! You would not want to make friend with yourself. Wouldn't you?") ) ; - error = false; - } - } else { - setField("errorMessage", QString(tr("Certificate Load Failed:something is wrong with %1")).arg(fn) + " : " + getErrorString(cert_error_code)); - error = false; - } - } else { - setField("errorMessage", QString(tr("Certificate Load Failed:file %1 not found")).arg(fn)); - error = false; - } - break; - } - case Page_Foff: - break; - case Page_Rsid: - { - QString rsidstring = ui->friendRsidEdit->text(); - - if (rsidstring.isEmpty()) { - return false; - } - - // search for peer id in string - RsPeerId rsidstr = PeerDefs::idFromRsid(rsidstring, false); - - if (rsidstr.isNull() || !rsPeers->getPeerDetails(rsidstr, peerDetails)) { - setField("errorMessage", tr("This Peer %1 is not available in your Network").arg(rsidstring)); - error = false; - } - break; - } - case Page_Email: - { - QString mailaddresses = ui->addressEdit->text(); - if (mailaddresses.isEmpty()) { - return false; - } - - QString body = ui->inviteTextEdit->toPlainText(); - - body += "\n" + GetStartedDialog::GetCutBelowText(); - body += "\n\n" + QString::fromUtf8(rsPeers->GetRetroshareInvite().c_str()); - - sendMail (mailaddresses, ui->subjectEdit->text(), body); - } - break; case Page_ErrorMessage: break; case Page_Conclusion: break; - case Page_FriendRequest: - break; - case Page_FriendRecommendations: - { - std::set recommendIds; - ui->frec_recommendList->selectedIds(recommendIds, false); - - if (recommendIds.empty()) { - QMessageBox::warning(this, "RetroShare", tr("Please select at least one friend for recommendation."), QMessageBox::Ok, QMessageBox::Ok); - return false; - } - - std::set toIds; - ui->frec_toList->selectedIds(toIds, false); - - if (toIds.empty()) { - QMessageBox::warning(this, "RetroShare", tr("Please select at least one friend as recipient."), QMessageBox::Ok, QMessageBox::Ok); - return false; - } - - std::set::iterator toId; - for (toId = toIds.begin(); toId != toIds.end(); ++toId) { - MessageComposer::recommendFriend(recommendIds, *toId, ui->frec_messageEdit->toHtml(), true); - } - } } return true; @@ -834,26 +638,10 @@ bool ConnectFriendWizard::validateCurrentPage() int ConnectFriendWizard::nextId() const { switch ((Page) currentId()) { - case Page_Intro: - if (ui->textRadioButton->isChecked()) return Page_Text; - if (ui->certRadioButton->isChecked()) return Page_Cert; - if (ui->foffRadioButton->isChecked()) return Page_Foff; - if (ui->rsidRadioButton->isChecked()) return Page_Rsid; - if (ui->webmailRadioButton->isChecked()) return Page_WebMail; - if (ui->emailRadioButton->isChecked()) return Page_Email; - if (ui->friendRecommendationsRadioButton->isChecked()) return Page_FriendRecommendations; - return ConnectFriendWizard::Page_Foff; - case Page_Text: - case Page_Cert: - case Page_Rsid: - return error ? ConnectFriendWizard::Page_Conclusion : ConnectFriendWizard::Page_ErrorMessage; - case Page_Foff: + case Page_Text: return Page_Conclusion; case Page_WebMail: - case Page_Email: case Page_ErrorMessage: case Page_Conclusion: - case Page_FriendRequest: - case Page_FriendRecommendations: return -1; } @@ -864,12 +652,7 @@ ServicePermissionFlags ConnectFriendWizard::serviceFlags() const { ServicePermissionFlags flags(0) ; - if (hasVisitedPage(Page_FriendRequest)) - { - if( ui->_direct_transfer_CB->isChecked()) flags |= RS_NODE_PERM_DIRECT_DL ; - if( ui->_allow_push_CB->isChecked()) flags |= RS_NODE_PERM_ALLOW_PUSH ; - if( ui->_require_WL_CB->isChecked()) flags |= RS_NODE_PERM_REQUIRE_WL ; - } else if (hasVisitedPage(Page_Conclusion)) { +if (hasVisitedPage(Page_Conclusion)) { if( ui->_direct_transfer_CB_2->isChecked()) flags |= RS_NODE_PERM_DIRECT_DL ; if( ui->_allow_push_CB_2->isChecked()) flags |= RS_NODE_PERM_ALLOW_PUSH ; if( ui->_require_WL_CB_2->isChecked()) flags |= RS_NODE_PERM_REQUIRE_WL ; @@ -888,17 +671,14 @@ void ConnectFriendWizard::accept() sign = ui->signGPGCheckBox->isChecked(); accept_connection = ui->acceptNoSignGPGCheckBox->isChecked(); add_key_to_keyring = ui->addKeyToKeyring_CB->isChecked() ; - } else if (hasVisitedPage(Page_FriendRequest)) { - std::cerr << "ConnectFriendWizard::accept() called with page friend request visited" << std::endl; - - sign = ui->fr_signGPGCheckBox->isChecked(); - accept_connection = ui->fr_acceptNoSignGPGCheckBox->isChecked(); - } else { + } else { QDialog::accept(); return; } - if (!mCertificate.empty() && add_key_to_keyring) + // add the profile pgp key to keyring + + if(!mIsShortInvite && !mCertificate.empty() && add_key_to_keyring) { RsPgpId pgp_id ; RsPeerId ssl_id ; @@ -913,33 +693,45 @@ void ConnectFriendWizard::accept() bool runProgressDialog = false; + // add the peer as friend, either with or without pgp signature validation, depending on whether we have the key or not + // Note: that is different than having a short invite or not. + + // first, set data related to profile key. + if(accept_connection && !peerDetails.gpg_id.isNull()) { std::cerr << "ConclusionPage::validatePage() accepting GPG key for connection." << std::endl; - rsPeers->addFriend(peerDetails.id, peerDetails.gpg_id,serviceFlags()) ; - rsPeers->setServicePermissionFlags(peerDetails.gpg_id,serviceFlags()) ; - if(ui->_addIPToWhiteList_CB_2->isChecked()) - { - sockaddr_storage addr ; - if(sockaddr_storage_ipv4_aton(addr,peerDetails.extAddr.c_str()) && sockaddr_storage_isValidNet(addr)) - { - std::cerr << "ConclusionPage::adding IP " << sockaddr_storage_tostring(addr) << " to whitelist." << std::endl; - rsBanList->addIpRange(addr,ui->_addIPToWhiteList_ComboBox_2->currentIndex(),RSBANLIST_TYPE_WHITELIST,std::string(tr("Added with certificate from %1").arg(ui->nameEdit->text()).toUtf8().constData())); - } - } + if(peerDetails.skip_pgp_signature_validation) + rsPeers->addSslOnlyFriend(peerDetails.id, peerDetails.gpg_id,peerDetails); + else + rsPeers->addFriend(peerDetails.id, peerDetails.gpg_id,serviceFlags()) ; + + rsPeers->setServicePermissionFlags(peerDetails.gpg_id,serviceFlags()) ; + + if(ui->_addIPToWhiteList_CB_2->isChecked()) + { + sockaddr_storage addr ; + if(sockaddr_storage_ipv4_aton(addr,peerDetails.extAddr.c_str()) && sockaddr_storage_isValidNet(addr)) + { + std::cerr << "ConclusionPage::adding IP " << sockaddr_storage_tostring(addr) << " to whitelist." << std::endl; + rsBanList->addIpRange(addr,ui->_addIPToWhiteList_ComboBox_2->currentIndex(),RSBANLIST_TYPE_WHITELIST,std::string(tr("Added with certificate from %1").arg(ui->nameEdit->text()).toUtf8().constData())); + } + } if(sign) { std::cerr << "ConclusionPage::validatePage() signing GPG key." << std::endl; rsPeers->signGPGCertificate(peerDetails.gpg_id); //bye default sign set accept_connection to true; rsPeers->setServicePermissionFlags(peerDetails.gpg_id,serviceFlags()) ; - } + } - if (!groupId.isEmpty()) - rsPeers->assignPeerToGroup(RsNodeGroupId(groupId.toStdString()), peerDetails.gpg_id, true); + if (!groupId.isEmpty()) + rsPeers->assignPeerToGroup(RsNodeGroupId(groupId.toStdString()), peerDetails.gpg_id, true); } + // Then set data related to node location + if ((accept_connection) && (!peerDetails.id.isNull())) { runProgressDialog = true; @@ -970,9 +762,7 @@ void ConnectFriendWizard::accept() rsPeers->setDynDNS(peerDetails.id, peerDetails.dyndns); } for(auto&& ipr : peerDetails.ipAddressList) - rsPeers->addPeerLocator( - peerDetails.id, - RsUrl(ipr.substr(0, ipr.find(' '))) ); + rsPeers->addPeerLocator( peerDetails.id, RsUrl(ipr.substr(0, ipr.find(' '))) ); } } @@ -985,7 +775,6 @@ void ConnectFriendWizard::accept() } NotifyQt::getInstance()->notifyListChange(NOTIFY_LIST_NEIGHBOURS,1) ; - QDialog::accept(); } @@ -1057,19 +846,23 @@ void ConnectFriendWizard::cleanFriendCert() } else { std::string cleanCert; - int error_code; + uint32_t error_code; - if (rsPeers->cleanCertificate(cert, cleanCert, error_code)) { + if (rsPeers->cleanCertificate(cert, cleanCert, mIsShortInvite, error_code)) + { certValid = true; - if (cert != cleanCert) { - disconnect(ui->friendCertEdit, SIGNAL(textChanged()), this, SLOT(friendCertChanged())); + + if (cert != cleanCert) + { QTextCursor textCursor = ui->friendCertEdit->textCursor(); - ui->friendCertEdit->setPlainText(QString::fromUtf8(cleanCert.c_str())); - ui->friendCertEdit->setTextCursor(textCursor); + + whileBlocking(ui->friendCertEdit)->setPlainText(QString::fromUtf8(cleanCert.c_str())); + whileBlocking(ui->friendCertEdit)->setTextCursor(textCursor); + ui->friendCertCleanLabel->setStyleSheet(""); - connect(ui->friendCertEdit, SIGNAL(textChanged()), this, SLOT(friendCertChanged())); } - errorMsg = tr("Certificate appears to be valid"); + errorMsg = tr("Valid certificate") + (mIsShortInvite?" (Short format)":" (plain format with profile key)"); + ui->friendCertCleanLabel->setPixmap(QPixmap(":/images/accepted16.png")); } else { if (error_code > 0) { @@ -1151,6 +944,7 @@ void ConnectFriendWizard::saveCert() ts << ui->userCertEdit->document()->toPlainText(); } +#ifdef TO_BE_REMOVED //========================== CertificatePage ================================= void ConnectFriendWizard::loadFriendCert() @@ -1330,7 +1124,9 @@ void ConnectFriendWizard::signAllSelectedUsers() //============================= RsidPage ===================================== + //============================ Emailpage ===================================== +#endif //========================= ErrorMessagePage ================================= diff --git a/retroshare-gui/src/gui/connect/ConnectFriendWizard.h b/retroshare-gui/src/gui/connect/ConnectFriendWizard.h index 6d9a74e57..5951fd7c2 100755 --- a/retroshare-gui/src/gui/connect/ConnectFriendWizard.h +++ b/retroshare-gui/src/gui/connect/ConnectFriendWizard.h @@ -50,7 +50,7 @@ class ConnectFriendWizard : public QWizard Q_PROPERTY(QString titleColor READ titleColor WRITE setTitleColor) public: - enum Page { Page_Intro, Page_Text, Page_Cert, Page_ErrorMessage, Page_Conclusion, Page_Foff, Page_Rsid, Page_WebMail, Page_Email, Page_FriendRequest, Page_FriendRecommendations }; + enum Page { Page_Text, Page_ErrorMessage, Page_Conclusion, Page_WebMail }; ConnectFriendWizard(QWidget *parent = 0); ~ConnectFriendWizard(); @@ -94,22 +94,18 @@ private slots: ServicePermissionFlags serviceFlags() const ; /* CertificatePage */ - void loadFriendCert(); - void generateCertificateCalled(); - - /* FofPage */ - void updatePeersList(int index); - void signAllSelectedUsers(); + //void loadFriendCert(); + //void generateCertificateCalled(); /* ConclusionPage */ void groupCurrentIndexChanged(int index); - + /* WebMailPage */ - void inviteGmail(); - void inviteYahoo(); - void inviteOutlook(); - void inviteAol(); - void inviteYandex(); + void inviteGmail(); + void inviteYahoo(); + void inviteOutlook(); + void inviteAol(); + void inviteYandex(); void toggleAdvanced(); @@ -119,12 +115,14 @@ private: void updateStylesheet(); void setTitleText(QWizardPage *page, const QString &title); bool AdvancedVisible; - + private: bool error; RsPeerDetails peerDetails; std::string mCertificate; + bool mIsShortInvite; + /* Stylesheet */ QString mBannerPixmap; int mTitleFontSize; @@ -141,9 +139,9 @@ private: /* ConclusionPage */ QString groupId; - + /* WebMailPage */ - QString subject; + QString subject; QString body; Ui::ConnectFriendWizard *ui; diff --git a/retroshare-gui/src/gui/connect/ConnectFriendWizard.ui b/retroshare-gui/src/gui/connect/ConnectFriendWizard.ui index 051e7f979..8aadc22db 100644 --- a/retroshare-gui/src/gui/connect/ConnectFriendWizard.ui +++ b/retroshare-gui/src/gui/connect/ConnectFriendWizard.ui @@ -6,8 +6,8 @@ 0 0 - 600 - 400 + 1139 + 1171 @@ -17,69 +17,6 @@ :/images/logo/logo_16.png:/images/logo/logo_16.png - - - Add a new Friend - - - This wizard will help you to connect to your friend(s) to RetroShare network.<br>Select how you would like to add a friend: - - - ConnectFriendWizard::Page_Intro - - - - - - Enter the certificate manually - - - - - - - &You get a certificate file from your friend - - - - - - - &Make friend with selected friends of my friends - - - - - - - Enter RetroShare ID manually - - - - - - - &Send an Invitation by Web Mail Providers - - - - - - - &Send an Invitation by Email - (Your friend will receive an email with instructions how to download RetroShare) - - - - - - - Recommend many friends to each other - - - - - RetroShare certificate @@ -386,154 +323,6 @@ - - - Certificate files - - - Use PGP certificates saved in files. - - - ConnectFriendWizard::Page_Cert - - - - - - Import friend's certificate... - - - true - - - - - - You have to generate a file with your certificate and give it to your friend. Also, you can use a file generated before. - - - true - - - - - - - Export my certificate... - - - - - - - - - - Drag and Drop your friends's certificate in this Window or specify path in the box below - - - - - - - - - - - - Browse - - - - - - - - - - Friends of friends - - - Select now who you want to make friends with. - - - ConnectFriendWizard::Page_Foff - - - - - - Show me: - - - - - - - - - - true - - - 4 - - - false - - - - - - - - - - - Make friend with these peers - - - - - - - - RetroShare ID - - - Use RetroShare ID for adding a Friend which is available in your network. - - - ConnectFriendWizard::Page_Rsid - - - - - - Add Friends RetroShare ID... - - - true - - - - - - - - Paste Friends RetroShare ID in the box below - - - - - - - Enter the RetroShare ID of your Friend, e.g. Peer@BDE8D16A46D938CF - - - - - RetroShare is better with Friends @@ -725,281 +514,6 @@ - - - Invite Friends by Email - - - Enter your friends' email addresses (separate each one with a semicolon) - - - ConnectFriendWizard::Page_Email - - - - - - - - Your friends' email addresses: - - - - - - - Enter Friends Email addresses - - - - - - - - - - - Subject: - - - - - - - - - - - - true - - - - - - - - Friend request - - - Details about the request - - - ConnectFriendWizard::Page_FriendRequest - - - - 6 - - - 6 - - - - - - - - You have a friend request from - - - - - - - - - - 96 - 96 - - - - - 96 - 96 - - - - - - - - Peer details - - - - QFormLayout::AllNonFixedFieldsGrow - - - - - Name: - - - - - - - Name - - - - - - - Email: - - - - - - - Node: - - - - - - - Node - - - - - - - Email - - - - - - - - - - - - - - Options - - - - - - - - - 0 - 0 - - - - Add friend to group: - - - - - - - - 0 - 0 - - - - - - - - - - Authenticate friend (Sign PGP Key) - - - - - - - Add as friend to connect with - - - - - - - - - - Options - - - - - - Use as direct source, when available - - - - - - - Auto-download recommended files - - - - - - - Require whitelist clearance to connect - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - - - - To accept the Friend Request, click the Finish button. - - - - - - - Qt::Vertical - - - - 488 - 118 - - - - - - Sorry, some error appeared @@ -1303,7 +817,7 @@ - <html><head/><body><p align="justify">Retroshare periodically checks your friend lists for browsable files matching your transfers, to establish a direct transfer. In this case, your friend knows you're downloading the file.</p><p align="justify">To prevent this behavior for this friend only, uncheck this box. You can still perform a direct transfer if you explicitly ask for it, by e.g. downloading from your friend's file list. This setting is applied to all locations of the same node.</p></body></html> + <html><head/><body><p align="justify">Retroshare periodically checks your friend lists for browsable files matching your transfers, to establish a direct transfer. In this case, your friend knows you're downloading the file.</p><p align="justify">To prevent this behavior for this friend only, uncheck this box. You can still perform a direct transfer if you explicitly ask for it, by e.g. downloading from your friend's file list. This setting is applied to all nodes with the same profile key.</p></body></html> Can be used as direct source @@ -1446,60 +960,6 @@ - - - Friend Recommendations - - - Recommend many friends to each others - - - ConnectFriendWizard::Page_FriendRecommendations - - - - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - - - - - - - Message: - - - - - - - - 0 - 0 - - - - - - @@ -1507,23 +967,6 @@ QLabel
    gui/common/StyledLabel.h
    - - FriendSelectionWidget - QWidget -
    gui/common/FriendSelectionWidget.h
    - 1 -
    - - AvatarWidget - QLabel -
    gui/common/AvatarWidget.h
    - 1 -
    - - DropLineEdit - QLineEdit -
    gui/common/DropLineEdit.h
    -
    ConnectFriendPage QWizardPage @@ -1537,8 +980,8 @@
    - + diff --git a/retroshare-gui/src/gui/connect/ConnectProgressDialog.cpp b/retroshare-gui/src/gui/connect/ConnectProgressDialog.cpp index 580e1144e..8f039f911 100755 --- a/retroshare-gui/src/gui/connect/ConnectProgressDialog.cpp +++ b/retroshare-gui/src/gui/connect/ConnectProgressDialog.cpp @@ -183,6 +183,14 @@ void ConnectProgressDialog::initDialog() ui->UdpResult->hide(); ui->UdpProgressBar->hide(); ui->UdpLabel->hide(); + + ui->DhtLabel->hide(); + ui->DhtProgressBar->hide(); + ui->DhtResult->hide(); + + ui->LookupLabel->hide(); + ui->LookupProgressBar->hide(); + ui->LookupResult->hide(); } else { diff --git a/retroshare-gui/src/gui/emojione.qrc b/retroshare-gui/src/gui/emojione.qrc index 77ddbc113..fdbfc58aa 100644 --- a/retroshare-gui/src/gui/emojione.qrc +++ b/retroshare-gui/src/gui/emojione.qrc @@ -1,682 +1,941 @@ - - emojione/1F52E.png - emojione/26f4.png - emojione/1F6A0.png - emojione/1F6A1.png - emojione/1F6A2.png - emojione/1F6A5.png - emojione/1F6A6.png - emojione/1F6A7.png - emojione/1F6A8.png - emojione/1F6E3.png - emojione/1F6E4.png - emojione/1F6E5.png - emojione/1F6E6.png - emojione/1F6E7.png - emojione/1F6E8.png - emojione/1F6E9.png - emojione/1F6EA.png - emojione/1F6EB.png - emojione/1F6EC.png - emojione/1F6F0.png - emojione/1F6F1.png - emojione/1F6F2.png - emojione/1F6F3.png - emojione/1F30A.png - emojione/1F30B.png - emojione/1F30C.png - emojione/1F5FB.png - emojione/1F5FC.png - emojione/1F5FD.png - emojione/1F5FE.png - emojione/1F5FF.png - emojione/1F3D4.png - emojione/1F3D5.png - emojione/1F3D6.png - emojione/1F3D7.png - emojione/1F3D8.png - emojione/1F3D9.png - emojione/1F3DA.png - emojione/1F3DB.png - emojione/1F3DC.png - emojione/1F3DD.png - emojione/1F3DE.png - emojione/1F3DF.png - emojione/1F3E0.png - emojione/1F3E1.png - emojione/1F3E2.png - emojione/1F3E3.png - emojione/1F3E4.png - emojione/1F3E5.png - emojione/1F3E6.png - emojione/1F3E7.png - emojione/1F3E8.png - emojione/1F3E9.png - emojione/1F3EA.png - emojione/1F3EB.png - emojione/1F3EC.png - emojione/1F3ED.png - emojione/1F3EE.png - emojione/1F3EF.png - emojione/1F3F0.png - emojione/1f325.png - emojione/1F30D.png - emojione/1F30E.png - emojione/1F30F.png - emojione/1F31A.png - emojione/1F31B.png - emojione/1F31C.png - emojione/1F31D.png - emojione/1F31E.png - emojione/1F31F.png - emojione/1f324.png - emojione/1f326.png - emojione/1F35A.png - emojione/1F35B.png - emojione/1F35C.png - emojione/1F35D.png - emojione/1F35E.png - emojione/1F36B.png - emojione/1F36C.png - emojione/1F36D.png - emojione/1F36E.png - emojione/1F36F.png - emojione/1F5E1.png - emojione/1F6E1.png - emojione/1F38A.png - emojione/1F6BF.png - emojione/1F6C1.png - emojione/1F6CB.png - emojione/1F6CC.png - emojione/1F6CD.png - emojione/1F6CE.png - emojione/1F6CF.png - emojione/2602.png - emojione/2763.png - emojione/1F33A.png - emojione/1F33B.png - emojione/1F33C.png - emojione/1F40A.png - emojione/1F34A.png - emojione/1F34B.png - emojione/1F34C.png - emojione/1F34D.png - emojione/1F34E.png - emojione/1F34F.png - emojione/1f32d.png - emojione/1f32e.png - emojione/1f32f.png - emojione/1F35F.png - emojione/people.png - emojione/people2.png - emojione/nature.png - emojione/food.png - emojione/travel.png - emojione/objects.png - emojione/symbols.png - emojione/activity.png - emojione/00A9.png - emojione/00AE.png - emojione/1F525.png - emojione/1F004.png - emojione/1F4AA.png - emojione/1F4AB.png - emojione/1F4AC.png - emojione/1F4AD.png - emojione/1F4AE.png - emojione/1F4AF.png - emojione/1F4A1.png - emojione/1F4A2.png - emojione/1F4A3.png - emojione/1F4A4.png - emojione/1F4A5.png - emojione/1F4A6.png - emojione/1F4A7.png - emojione/1F4A8.png - emojione/1F4A9.png - emojione/1F4C0.png - emojione/1F4C1.png - emojione/1F4C2.png - emojione/1F4C3.png - emojione/1F4C4.png - emojione/1F4C5.png - emojione/1F4C6.png - emojione/1F4C7.png - emojione/1F4C8.png - emojione/1F4C9.png - emojione/1F4CA.png - emojione/1F4CB.png - emojione/1F4CC.png - emojione/1F4CD.png - emojione/1F4CE.png - emojione/1F4CF.png - emojione/1F4D0.png - emojione/1F4D1.png - emojione/1F4D2.png - emojione/1F4D3.png - emojione/1F4D4.png - emojione/1F4D5.png - emojione/1F4D6.png - emojione/1F4D7.png - emojione/1F4D8.png - emojione/1F4D9.png - emojione/1F4DA.png - emojione/1F4DB.png - emojione/1F4DC.png - emojione/1F4DD.png - emojione/1F4DE.png - emojione/1F4DF.png - emojione/1F4E0.png - emojione/1F4E1.png - emojione/1F4E2.png - emojione/1F4E3.png - emojione/1F4E4.png - emojione/1F4E5.png - emojione/1F4E6.png - emojione/1F4E7.png - emojione/1F4E8.png - emojione/1F4E9.png - emojione/1F4EA.png - emojione/1F4EB.png - emojione/1F4EC.png - emojione/1F4ED.png - emojione/1F4EE.png - emojione/1F4EF.png - emojione/1F4F0.png - emojione/1F4F1.png - emojione/1F4F2.png - emojione/1F4F3.png - emojione/1F4F4.png - emojione/1F4F5.png - emojione/1F4F6.png - emojione/1F4F7.png - emojione/1F4F8.png - emojione/1F4F9.png - emojione/1F4FA.png - emojione/1F4FB.png - emojione/1F4FC.png - emojione/1F4FD.png - emojione/1F4FE.png - emojione/1F5E2.png - emojione/1F17E.png - emojione/1F17F.png - emojione/1F18E.png - emojione/1F19A.png - emojione/1F21A.png - emojione/1F22F.png - emojione/1F23A.png - emojione/1F32A.png - emojione/1F32B.png - emojione/1F32C.png - emojione/1F36A.png - emojione/1F37A.png - emojione/1F37B.png - emojione/1F40C.png - emojione/1F42F.png - emojione/1F43A.png - emojione/1F43B.png - emojione/1F43C.png - emojione/1F43D.png - emojione/1F43E.png - emojione/1F43F.png - emojione/1F44A.png - emojione/1F44B.png - emojione/1F44C.png - emojione/1F44D.png - emojione/1F44E.png - emojione/1F44F.png - emojione/1F46A.png - emojione/1F46B.png - emojione/1F46C.png - emojione/1F46D.png - emojione/1F46E.png - emojione/1F46F.png - emojione/1F47A.png - emojione/1F47B.png - emojione/1F47C.png - emojione/1F47D.png - emojione/1F47E.png - emojione/1F47F.png - emojione/1F48A.png - emojione/1F48B.png - emojione/1F48C.png - emojione/1F48D.png - emojione/1F48E.png - emojione/1F48F.png - emojione/1F49A.png - emojione/1F49B.png - emojione/1F49C.png - emojione/1F49D.png - emojione/1F49E.png - emojione/1F49F.png - emojione/1F54A.png - emojione/1F60A.png - emojione/1F60B.png - emojione/1F60C.png - emojione/1F60D.png - emojione/1F60E.png - emojione/1F60F.png - emojione/1F61A.png - emojione/1F61B.png - emojione/1F61C.png - emojione/1F61D.png - emojione/1F61E.png - emojione/1F61F.png - emojione/1F62A.png - emojione/1F62B.png - emojione/1F62C.png - emojione/1F62D.png - emojione/1F62E.png - emojione/1F62F.png - emojione/1F63A.png - emojione/1F63B.png - emojione/1F63C.png - emojione/1F63D.png - emojione/1F63E.png - emojione/1F63F.png - emojione/1F64A.png - emojione/1F64B.png - emojione/1F64C.png - emojione/1F64D.png - emojione/1F64E.png - emojione/1F64F.png - emojione/1F68A.png - emojione/1F68B.png - emojione/1F68C.png - emojione/1F68D.png - emojione/1F68E.png - emojione/1F68F.png - emojione/1F69A.png - emojione/1F69B.png - emojione/1F69C.png - emojione/1F69D.png - emojione/1F69E.png - emojione/1F69F.png - emojione/1F170.png - emojione/1F171.png - emojione/1F191.png - emojione/1F192.png - emojione/1F193.png - emojione/1F194.png - emojione/1F195.png - emojione/1F196.png - emojione/1F197.png - emojione/1F198.png - emojione/1F199.png - emojione/1F201.png - emojione/1F202.png - emojione/1F300.png - emojione/1F301.png - emojione/1F302.png - emojione/1F303.png - emojione/1F304.png - emojione/1F305.png - emojione/1F306.png - emojione/1F307.png - emojione/1F308.png - emojione/1F309.png - emojione/1F310.png - emojione/1F311.png - emojione/1F312.png - emojione/1F313.png - emojione/1F314.png - emojione/1F315.png - emojione/1F316.png - emojione/1F317.png - emojione/1F318.png - emojione/1F319.png - emojione/1F320.png - emojione/1F321.png - emojione/1F327.png - emojione/1F328.png - emojione/1F329.png - emojione/1F330.png - emojione/1F331.png - emojione/1F332.png - emojione/1F333.png - emojione/1F334.png - emojione/1F335.png - emojione/1F336.png - emojione/1F337.png - emojione/1F338.png - emojione/1F339.png - emojione/1F33D.png - emojione/1F340.png - emojione/1F341.png - emojione/1F342.png - emojione/1F343.png - emojione/1F344.png - emojione/1F345.png - emojione/1F346.png - emojione/1F347.png - emojione/1F348.png - emojione/1F349.png - emojione/1F350.png - emojione/1F351.png - emojione/1F352.png - emojione/1F353.png - emojione/1F354.png - emojione/1F355.png - emojione/1F356.png - emojione/1F357.png - emojione/1F358.png - emojione/1F359.png - emojione/1F360.png - emojione/1F361.png - emojione/1F362.png - emojione/1F363.png - emojione/1F364.png - emojione/1F365.png - emojione/1F366.png - emojione/1F367.png - emojione/1F368.png - emojione/1F369.png - emojione/1F370.png - emojione/1F371.png - emojione/1F372.png - emojione/1F373.png - emojione/1F374.png - emojione/1F375.png - emojione/1F376.png - emojione/1F377.png - emojione/1F378.png - emojione/1F379.png - emojione/1F380.png - emojione/1F381.png - emojione/1F382.png - emojione/1F383.png - emojione/1F384.png - emojione/1F385.png - emojione/1F386.png - emojione/1F387.png - emojione/1F388.png - emojione/1F389.png - emojione/1F390.png - emojione/1F391.png - emojione/1F392.png - emojione/1F393.png - emojione/1F394.png - emojione/1F395.png - emojione/1F396.png - emojione/1F397.png - emojione/1F398.png - emojione/1F399.png - emojione/1F400.png - emojione/1F401.png - emojione/1F402.png - emojione/1F403.png - emojione/1F404.png - emojione/1F405.png - emojione/1F406.png - emojione/1F407.png - emojione/1F408.png - emojione/1F409.png - emojione/1F410.png - emojione/1F411.png - emojione/1F412.png - emojione/1F413.png - emojione/1F414.png - emojione/1F415.png - emojione/1F416.png - emojione/1F417.png - emojione/1F418.png - emojione/1F419.png - emojione/1F420.png - emojione/1F421.png - emojione/1F422.png - emojione/1F423.png - emojione/1F424.png - emojione/1F425.png - emojione/1F426.png - emojione/1F427.png - emojione/1F428.png - emojione/1F429.png - emojione/1F430.png - emojione/1F431.png - emojione/1F432.png - emojione/1F433.png - emojione/1F434.png - emojione/1F435.png - emojione/1F436.png - emojione/1F437.png - emojione/1F438.png - emojione/1F439.png - emojione/1F440.png - emojione/1F441.png - emojione/1F442.png - emojione/1F443.png - emojione/1F444.png - emojione/1F445.png - emojione/1F446.png - emojione/1F447.png - emojione/1F448.png - emojione/1F449.png - emojione/1F450.png - emojione/1F451.png - emojione/1F452.png - emojione/1F453.png - emojione/1F454.png - emojione/1F455.png - emojione/1F456.png - emojione/1F457.png - emojione/1F458.png - emojione/1F459.png - emojione/1F460.png - emojione/1F461.png - emojione/1F462.png - emojione/1F463.png - emojione/1F464.png - emojione/1F465.png - emojione/1F466.png - emojione/1F467.png - emojione/1F468.png - emojione/1F469.png - emojione/1F470.png - emojione/1F471.png - emojione/1F472.png - emojione/1F473.png - emojione/1F474.png - emojione/1F475.png - emojione/1F476.png - emojione/1F477.png - emojione/1F478.png - emojione/1F479.png - emojione/1F480.png - emojione/1F481.png - emojione/1F482.png - emojione/1F483.png - emojione/1F484.png - emojione/1F485.png - emojione/1F486.png - emojione/1F487.png - emojione/1F488.png - emojione/1F489.png - emojione/1F490.png - emojione/1F491.png - emojione/1F492.png - emojione/1F493.png - emojione/1F494.png - emojione/1F495.png - emojione/1F496.png - emojione/1F497.png - emojione/1F498.png - emojione/1F499.png - emojione/1F574.png - emojione/1F575.png - emojione/1F595.png - emojione/1F596.png - emojione/1F597.png - emojione/1F598.png - emojione/1F599.png - emojione/1F59E.png - emojione/1F573.png - emojione/1F577.png - emojione/1F578.png - emojione/1F579.png - emojione/1F581.png - emojione/1F600.png - emojione/1F601.png - emojione/1F602.png - emojione/1F603.png - emojione/1F604.png - emojione/1F605.png - emojione/1F606.png - emojione/1F607.png - emojione/1F608.png - emojione/1F609.png - emojione/1F610.png - emojione/1F611.png - emojione/1F612.png - emojione/1F613.png - emojione/1F614.png - emojione/1F615.png - emojione/1F616.png - emojione/1F617.png - emojione/1F618.png - emojione/1F619.png - emojione/1F620.png - emojione/1F621.png - emojione/1F622.png - emojione/1F623.png - emojione/1F624.png - emojione/1F625.png - emojione/1F626.png - emojione/1F627.png - emojione/1F628.png - emojione/1F629.png - emojione/1F630.png - emojione/1F631.png - emojione/1F632.png - emojione/1F633.png - emojione/1F634.png - emojione/1F635.png - emojione/1F636.png - emojione/1F637.png - emojione/1F638.png - emojione/1F639.png - emojione/1F640.png - emojione/1F641.png - emojione/1F642.png - emojione/1f644.png - emojione/1F645.png - emojione/1F646.png - emojione/1F647.png - emojione/1F648.png - emojione/1F649.png - emojione/1F680.png - emojione/1F681.png - emojione/1F682.png - emojione/1F683.png - emojione/1F684.png - emojione/1F685.png - emojione/1F686.png - emojione/1F687.png - emojione/1F688.png - emojione/1F689.png - emojione/1F690.png - emojione/1F691.png - emojione/1F692.png - emojione/1F693.png - emojione/1F694.png - emojione/1F695.png - emojione/1F696.png - emojione/1F697.png - emojione/1F698.png - emojione/1F699.png - emojione/2B1B.png - emojione/2B1C.png - emojione/2B05.png - emojione/2B06.png - emojione/2B07.png - emojione/2B50.png - emojione/2B55.png - emojione/21A9.png - emojione/21AA.png - emojione/23E9.png - emojione/23EA.png - emojione/23EB.png - emojione/23EC.png - emojione/23F0.png - emojione/23F3.png - emojione/24C2.png - emojione/25AA.png - emojione/25AB.png - emojione/25B6.png - emojione/25C0.png - emojione/25FB.png - emojione/25FC.png - emojione/25FD.png - emojione/25FE.png - emojione/26A0.png - emojione/26A1.png - emojione/26AA.png - emojione/26AB.png - emojione/26BD.png - emojione/26BE.png - emojione/26C4.png - emojione/26C5.png - emojione/26CE.png - emojione/26D4.png - emojione/26EA.png - emojione/26F2.png - emojione/26F3.png - emojione/26F5.png - emojione/26FA.png - emojione/26FD.png - emojione/27A1.png - emojione/27B0.png - emojione/27BF.png - emojione/203C.png - emojione/231A.png - emojione/231B.png - emojione/260E.png - emojione/261D.png - emojione/263A.png - emojione/264A.png - emojione/264B.png - emojione/264C.png - emojione/264D.png - emojione/264E.png - emojione/264F.png - emojione/267B.png - emojione/267F.png - emojione/270A.png - emojione/270B.png - emojione/270C.png - emojione/270F.png - emojione/274C.png - emojione/274E.png - emojione/303D.png - emojione/2049.png - emojione/2600.png - emojione/2601.png - emojione/2604.png - emojione/2611.png - emojione/2614.png - emojione/2615.png - emojione/2639.png - emojione/2620.png - emojione/2708.png - emojione/2744.png - emojione/2764.png - emojione/2934.png - emojione/2935.png - emojione/3030.png - emojione/1f910.png - emojione/1f911.png - emojione/1f912.png - emojione/1f913.png - emojione/1f914.png - emojione/1f915.png - emojione/1f916.png - emojione/1f917.png - emojione/1f922.png - emojione/1f923.png - emojione/1f924.png - emojione/1f925.png - emojione/1f927.png - emojione/1f643.png - emojione/emotes.acs - + + emojione/1F52E.png + emojione/26f4.png + emojione/1F6A0.png + emojione/1F6A1.png + emojione/1F6A2.png + emojione/1F6A5.png + emojione/1F6A6.png + emojione/1F6A7.png + emojione/1F6A8.png + emojione/1F6E3.png + emojione/1F6E4.png + emojione/1F6E5.png + emojione/1F6E6.png + emojione/1F6E7.png + emojione/1F6E8.png + emojione/1F6E9.png + emojione/1F6EA.png + emojione/1F6EB.png + emojione/1F6EC.png + emojione/1F6F0.png + emojione/1F6F1.png + emojione/1F6F2.png + emojione/1F6F3.png + emojione/1F30A.png + emojione/1F30B.png + emojione/1F30C.png + emojione/1F5FB.png + emojione/1F5FC.png + emojione/1F5FD.png + emojione/1F5FE.png + emojione/1F5FF.png + emojione/1F3D4.png + emojione/1F3D5.png + emojione/1F3D6.png + emojione/1F3D7.png + emojione/1F3D8.png + emojione/1F3D9.png + emojione/1F3DA.png + emojione/1F3DB.png + emojione/1F3DC.png + emojione/1F3DD.png + emojione/1F3DE.png + emojione/1F3DF.png + emojione/1F3E0.png + emojione/1F3E1.png + emojione/1F3E2.png + emojione/1F3E3.png + emojione/1F3E4.png + emojione/1F3E5.png + emojione/1F3E6.png + emojione/1F3E7.png + emojione/1F3E8.png + emojione/1F3E9.png + emojione/1F3EA.png + emojione/1F3EB.png + emojione/1F3EC.png + emojione/1F3ED.png + emojione/1F3EE.png + emojione/1F3EF.png + emojione/1F3F0.png + emojione/1f325.png + emojione/1F30D.png + emojione/1F30E.png + emojione/1F30F.png + emojione/1F31A.png + emojione/1F31B.png + emojione/1F31C.png + emojione/1F31D.png + emojione/1F31E.png + emojione/1F31F.png + emojione/1f324.png + emojione/1f326.png + emojione/1F35A.png + emojione/1F35B.png + emojione/1F35C.png + emojione/1F35D.png + emojione/1F35E.png + emojione/1F36B.png + emojione/1F36C.png + emojione/1F36D.png + emojione/1F36E.png + emojione/1F36F.png + emojione/1F5E1.png + emojione/1F6E1.png + emojione/1F38A.png + emojione/1F6BF.png + emojione/1F6C1.png + emojione/1F6CB.png + emojione/1F6CC.png + emojione/1F6CD.png + emojione/1F6CE.png + emojione/1F6CF.png + emojione/2602.png + emojione/2763.png + emojione/1F33A.png + emojione/1F33B.png + emojione/1F33C.png + emojione/1F40A.png + emojione/1F34A.png + emojione/1F34B.png + emojione/1F34C.png + emojione/1F34D.png + emojione/1F34E.png + emojione/1F34F.png + emojione/1f32d.png + emojione/1f32e.png + emojione/1f32f.png + emojione/1F35F.png + emojione/people.png + emojione/people2.png + emojione/nature.png + emojione/food.png + emojione/travel.png + emojione/objects.png + emojione/symbols.png + emojione/activity.png + emojione/00A9.png + emojione/00AE.png + emojione/1F525.png + emojione/1F004.png + emojione/1F4AA.png + emojione/1F4AB.png + emojione/1F4AC.png + emojione/1F4AD.png + emojione/1F4AE.png + emojione/1F4AF.png + emojione/1F4A1.png + emojione/1F4A2.png + emojione/1F4A3.png + emojione/1F4A4.png + emojione/1F4A5.png + emojione/1F4A6.png + emojione/1F4A7.png + emojione/1F4A8.png + emojione/1F4A9.png + emojione/1F4C0.png + emojione/1F4C1.png + emojione/1F4C2.png + emojione/1F4C3.png + emojione/1F4C4.png + emojione/1F4C5.png + emojione/1F4C6.png + emojione/1F4C7.png + emojione/1F4C8.png + emojione/1F4C9.png + emojione/1F4CA.png + emojione/1F4CB.png + emojione/1F4CC.png + emojione/1F4CD.png + emojione/1F4CE.png + emojione/1F4CF.png + emojione/1F4D0.png + emojione/1F4D1.png + emojione/1F4D2.png + emojione/1F4D3.png + emojione/1F4D4.png + emojione/1F4D5.png + emojione/1F4D6.png + emojione/1F4D7.png + emojione/1F4D8.png + emojione/1F4D9.png + emojione/1F4DA.png + emojione/1F4DB.png + emojione/1F4DC.png + emojione/1F4DD.png + emojione/1F4DE.png + emojione/1F4DF.png + emojione/1F4E0.png + emojione/1F4E1.png + emojione/1F4E2.png + emojione/1F4E3.png + emojione/1F4E4.png + emojione/1F4E5.png + emojione/1F4E6.png + emojione/1F4E7.png + emojione/1F4E8.png + emojione/1F4E9.png + emojione/1F4EA.png + emojione/1F4EB.png + emojione/1F4EC.png + emojione/1F4ED.png + emojione/1F4EE.png + emojione/1F4EF.png + emojione/1F4F0.png + emojione/1F4F1.png + emojione/1F4F2.png + emojione/1F4F3.png + emojione/1F4F4.png + emojione/1F4F5.png + emojione/1F4F6.png + emojione/1F4F7.png + emojione/1F4F8.png + emojione/1F4F9.png + emojione/1F4FA.png + emojione/1F4FB.png + emojione/1F4FC.png + emojione/1F4FD.png + emojione/1F4FE.png + emojione/1F5E2.png + emojione/1F17E.png + emojione/1F17F.png + emojione/1F18E.png + emojione/1F19A.png + emojione/1F21A.png + emojione/1F22F.png + emojione/1F23A.png + emojione/1F32A.png + emojione/1F32B.png + emojione/1F32C.png + emojione/1F36A.png + emojione/1F37A.png + emojione/1F37B.png + emojione/1F40C.png + emojione/1F42F.png + emojione/1F43A.png + emojione/1F43B.png + emojione/1F43C.png + emojione/1F43D.png + emojione/1F43E.png + emojione/1F43F.png + emojione/1F44A.png + emojione/1F44B.png + emojione/1F44C.png + emojione/1F44D.png + emojione/1F44E.png + emojione/1F44F.png + emojione/1F46A.png + emojione/1F46B.png + emojione/1F46C.png + emojione/1F46D.png + emojione/1F46E.png + emojione/1F46F.png + emojione/1F47A.png + emojione/1F47B.png + emojione/1F47C.png + emojione/1F47D.png + emojione/1F47E.png + emojione/1F47F.png + emojione/1F48A.png + emojione/1F48B.png + emojione/1F48C.png + emojione/1F48D.png + emojione/1F48E.png + emojione/1F48F.png + emojione/1F49A.png + emojione/1F49B.png + emojione/1F49C.png + emojione/1F49D.png + emojione/1F49E.png + emojione/1F49F.png + emojione/1F54A.png + emojione/1F60A.png + emojione/1F60B.png + emojione/1F60C.png + emojione/1F60D.png + emojione/1F60E.png + emojione/1F60F.png + emojione/1F61A.png + emojione/1F61B.png + emojione/1F61C.png + emojione/1F61D.png + emojione/1F61E.png + emojione/1F61F.png + emojione/1F62A.png + emojione/1F62B.png + emojione/1F62C.png + emojione/1F62D.png + emojione/1F62E.png + emojione/1F62F.png + emojione/1F63A.png + emojione/1F63B.png + emojione/1F63C.png + emojione/1F63D.png + emojione/1F63E.png + emojione/1F63F.png + emojione/1F64A.png + emojione/1F64B.png + emojione/1F64C.png + emojione/1F64D.png + emojione/1F64E.png + emojione/1F64F.png + emojione/1F68A.png + emojione/1F68B.png + emojione/1F68C.png + emojione/1F68D.png + emojione/1F68E.png + emojione/1F68F.png + emojione/1F69A.png + emojione/1F69B.png + emojione/1F69C.png + emojione/1F69D.png + emojione/1F69E.png + emojione/1F69F.png + emojione/1F170.png + emojione/1F171.png + emojione/1F191.png + emojione/1F192.png + emojione/1F193.png + emojione/1F194.png + emojione/1F195.png + emojione/1F196.png + emojione/1F197.png + emojione/1F198.png + emojione/1F199.png + emojione/1F201.png + emojione/1F202.png + emojione/1F300.png + emojione/1F301.png + emojione/1F302.png + emojione/1F303.png + emojione/1F304.png + emojione/1F305.png + emojione/1F306.png + emojione/1F307.png + emojione/1F308.png + emojione/1F309.png + emojione/1F310.png + emojione/1F311.png + emojione/1F312.png + emojione/1F313.png + emojione/1F314.png + emojione/1F315.png + emojione/1F316.png + emojione/1F317.png + emojione/1F318.png + emojione/1F319.png + emojione/1F320.png + emojione/1F321.png + emojione/1F327.png + emojione/1F328.png + emojione/1F329.png + emojione/1F330.png + emojione/1F331.png + emojione/1F332.png + emojione/1F333.png + emojione/1F334.png + emojione/1F335.png + emojione/1F336.png + emojione/1F337.png + emojione/1F338.png + emojione/1F339.png + emojione/1F33D.png + emojione/1F340.png + emojione/1F341.png + emojione/1F342.png + emojione/1F343.png + emojione/1F344.png + emojione/1F345.png + emojione/1F346.png + emojione/1F347.png + emojione/1F348.png + emojione/1F349.png + emojione/1F350.png + emojione/1F351.png + emojione/1F352.png + emojione/1F353.png + emojione/1F354.png + emojione/1F355.png + emojione/1F356.png + emojione/1F357.png + emojione/1F358.png + emojione/1F359.png + emojione/1F360.png + emojione/1F361.png + emojione/1F362.png + emojione/1F363.png + emojione/1F364.png + emojione/1F365.png + emojione/1F366.png + emojione/1F367.png + emojione/1F368.png + emojione/1F369.png + emojione/1F370.png + emojione/1F371.png + emojione/1F372.png + emojione/1F373.png + emojione/1F374.png + emojione/1F375.png + emojione/1F376.png + emojione/1F377.png + emojione/1F378.png + emojione/1F379.png + emojione/1F380.png + emojione/1F381.png + emojione/1F382.png + emojione/1F383.png + emojione/1F384.png + emojione/1F385.png + emojione/1F386.png + emojione/1F387.png + emojione/1F388.png + emojione/1F389.png + emojione/1F390.png + emojione/1F391.png + emojione/1F392.png + emojione/1F393.png + emojione/1F394.png + emojione/1F395.png + emojione/1F396.png + emojione/1F397.png + emojione/1F398.png + emojione/1F399.png + emojione/1F400.png + emojione/1F401.png + emojione/1F402.png + emojione/1F403.png + emojione/1F404.png + emojione/1F405.png + emojione/1F406.png + emojione/1F407.png + emojione/1F408.png + emojione/1F409.png + emojione/1F410.png + emojione/1F411.png + emojione/1F412.png + emojione/1F413.png + emojione/1F414.png + emojione/1F415.png + emojione/1F416.png + emojione/1F417.png + emojione/1F418.png + emojione/1F419.png + emojione/1F420.png + emojione/1F421.png + emojione/1F422.png + emojione/1F423.png + emojione/1F424.png + emojione/1F425.png + emojione/1F426.png + emojione/1F427.png + emojione/1F428.png + emojione/1F429.png + emojione/1F430.png + emojione/1F431.png + emojione/1F432.png + emojione/1F433.png + emojione/1F434.png + emojione/1F435.png + emojione/1F436.png + emojione/1F437.png + emojione/1F438.png + emojione/1F439.png + emojione/1F440.png + emojione/1F441.png + emojione/1F442.png + emojione/1F443.png + emojione/1F444.png + emojione/1F445.png + emojione/1F446.png + emojione/1F447.png + emojione/1F448.png + emojione/1F449.png + emojione/1F450.png + emojione/1F451.png + emojione/1F452.png + emojione/1F453.png + emojione/1F454.png + emojione/1F455.png + emojione/1F456.png + emojione/1F457.png + emojione/1F458.png + emojione/1F459.png + emojione/1F460.png + emojione/1F461.png + emojione/1F462.png + emojione/1F463.png + emojione/1F464.png + emojione/1F465.png + emojione/1F466.png + emojione/1F467.png + emojione/1F468.png + emojione/1F469.png + emojione/1F470.png + emojione/1F471.png + emojione/1F472.png + emojione/1F473.png + emojione/1F474.png + emojione/1F475.png + emojione/1F476.png + emojione/1F477.png + emojione/1F478.png + emojione/1F479.png + emojione/1F480.png + emojione/1F481.png + emojione/1F482.png + emojione/1F483.png + emojione/1F484.png + emojione/1F485.png + emojione/1F486.png + emojione/1F487.png + emojione/1F488.png + emojione/1F489.png + emojione/1F490.png + emojione/1F491.png + emojione/1F492.png + emojione/1F493.png + emojione/1F494.png + emojione/1F495.png + emojione/1F496.png + emojione/1F497.png + emojione/1F498.png + emojione/1F499.png + emojione/1F574.png + emojione/1F575.png + emojione/1F595.png + emojione/1F596.png + emojione/1F597.png + emojione/1F598.png + emojione/1F599.png + emojione/1F59E.png + emojione/1F573.png + emojione/1F577.png + emojione/1F578.png + emojione/1F579.png + emojione/1F581.png + emojione/1F600.png + emojione/1F601.png + emojione/1F602.png + emojione/1F603.png + emojione/1F604.png + emojione/1F605.png + emojione/1F606.png + emojione/1F607.png + emojione/1F608.png + emojione/1F609.png + emojione/1F610.png + emojione/1F611.png + emojione/1F612.png + emojione/1F613.png + emojione/1F614.png + emojione/1F615.png + emojione/1F616.png + emojione/1F617.png + emojione/1F618.png + emojione/1F619.png + emojione/1F620.png + emojione/1F621.png + emojione/1F622.png + emojione/1F623.png + emojione/1F624.png + emojione/1F625.png + emojione/1F626.png + emojione/1F627.png + emojione/1F628.png + emojione/1F629.png + emojione/1F630.png + emojione/1F631.png + emojione/1F632.png + emojione/1F633.png + emojione/1F634.png + emojione/1F635.png + emojione/1F636.png + emojione/1F637.png + emojione/1F638.png + emojione/1F639.png + emojione/1F640.png + emojione/1F641.png + emojione/1F642.png + emojione/1f644.png + emojione/1F645.png + emojione/1F646.png + emojione/1F647.png + emojione/1F648.png + emojione/1F649.png + emojione/1F680.png + emojione/1F681.png + emojione/1F682.png + emojione/1F683.png + emojione/1F684.png + emojione/1F685.png + emojione/1F686.png + emojione/1F687.png + emojione/1F688.png + emojione/1F689.png + emojione/1F690.png + emojione/1F691.png + emojione/1F692.png + emojione/1F693.png + emojione/1F694.png + emojione/1F695.png + emojione/1F696.png + emojione/1F697.png + emojione/1F698.png + emojione/1F699.png + emojione/2B1B.png + emojione/2B1C.png + emojione/2B05.png + emojione/2B06.png + emojione/2B07.png + emojione/2B50.png + emojione/2B55.png + emojione/21A9.png + emojione/21AA.png + emojione/23E9.png + emojione/23EA.png + emojione/23EB.png + emojione/23EC.png + emojione/23F0.png + emojione/23F3.png + emojione/24C2.png + emojione/25AA.png + emojione/25AB.png + emojione/25B6.png + emojione/25C0.png + emojione/25FB.png + emojione/25FC.png + emojione/25FD.png + emojione/25FE.png + emojione/26A0.png + emojione/26A1.png + emojione/26AA.png + emojione/26AB.png + emojione/26BD.png + emojione/26BE.png + emojione/26C4.png + emojione/26C5.png + emojione/26CE.png + emojione/26D4.png + emojione/26EA.png + emojione/26F2.png + emojione/26F3.png + emojione/26F5.png + emojione/26FA.png + emojione/26FD.png + emojione/27A1.png + emojione/27B0.png + emojione/27BF.png + emojione/203C.png + emojione/231A.png + emojione/231B.png + emojione/260E.png + emojione/261D.png + emojione/263A.png + emojione/264A.png + emojione/264B.png + emojione/264C.png + emojione/264D.png + emojione/264E.png + emojione/264F.png + emojione/267B.png + emojione/267F.png + emojione/270A.png + emojione/270B.png + emojione/270C.png + emojione/270F.png + emojione/274C.png + emojione/274E.png + emojione/303D.png + emojione/2049.png + emojione/2600.png + emojione/2601.png + emojione/2604.png + emojione/2611.png + emojione/2614.png + emojione/2615.png + emojione/2639.png + emojione/2620.png + emojione/2708.png + emojione/2744.png + emojione/2764.png + emojione/2934.png + emojione/2935.png + emojione/3030.png + emojione/1f910.png + emojione/1f911.png + emojione/1f912.png + emojione/1f913.png + emojione/1f914.png + emojione/1f915.png + emojione/1f916.png + emojione/1f917.png + emojione/1f922.png + emojione/1f923.png + emojione/1f924.png + emojione/1f925.png + emojione/1f927.png + emojione/1f643.png + emojione/emotes.acs + emojione/1F1E6-1F1E8.png + emojione/1F1E6-1F1E9.png + emojione/1F1E6-1F1EA.png + emojione/1F1E6-1F1EB.png + emojione/1F1E6-1F1EC.png + emojione/1F1E6-1F1EE.png + emojione/1F1E6-1F1F1.png + emojione/1F1E6-1F1F2.png + emojione/1F1E6-1F1F4.png + emojione/1f1e6-1f1f6.png + emojione/1F1E6-1F1F7.png + emojione/1f1e6-1f1f8.png + emojione/1F1E6-1F1F9.png + emojione/1F1E6-1F1FA.png + emojione/1F1E6-1F1FC.png + emojione/1f1e6-1f1fd.png + emojione/1F1E6-1F1FF.png + emojione/1F1E7-1F1E6.png + emojione/1F1E7-1F1E7.png + emojione/1F1E7-1F1E9.png + emojione/1F1E7-1F1EA.png + emojione/1F1E7-1F1EB.png + emojione/1F1E7-1F1EC.png + emojione/1F1E7-1F1ED.png + emojione/1F1E7-1F1EE.png + emojione/1F1E7-1F1EF.png + emojione/1f1e7-1f1f1.png + emojione/1F1E7-1F1F2.png + emojione/1F1E7-1F1F3.png + emojione/1F1E7-1F1F4.png + emojione/1f1e7-1f1f6.png + emojione/1F1E7-1F1F7.png + emojione/1F1E7-1F1F8.png + emojione/1F1E7-1F1F9.png + emojione/1f1e7-1f1fb.png + emojione/1F1E7-1F1FC.png + emojione/1F1E7-1F1FE.png + emojione/1F1E7-1F1FF.png + emojione/1F1E8-1F1E6.png + emojione/1f1e8-1f1e8.png + emojione/1F1E8-1F1E9.png + emojione/1F1E8-1F1EB.png + emojione/1F1E8-1F1EC.png + emojione/1F1E8-1F1ED.png + emojione/1F1E8-1F1EE.png + emojione/1f1e8-1f1f0.png + emojione/1F1E8-1F1F1.png + emojione/1F1E8-1F1F2.png + emojione/1F1E8-1F1F3.png + emojione/1F1E8-1F1F4.png + emojione/1f1e8-1f1f5.png + emojione/1F1E8-1F1F7.png + emojione/1F1E8-1F1FA.png + emojione/1F1E8-1F1FB.png + emojione/1f1e8-1f1fc.png + emojione/1f1e8-1f1fd.png + emojione/1F1E8-1F1FE.png + emojione/1F1E8-1F1FF.png + emojione/1F1E9-1F1EA.png + emojione/1f1e9-1f1ec.png + emojione/1F1E9-1F1EF.png + emojione/1F1E9-1F1F0.png + emojione/1F1E9-1F1F2.png + emojione/1F1E9-1F1F4.png + emojione/1F1E9-1F1FF.png + emojione/1f1ea-1f1e6.png + emojione/1F1EA-1F1E8.png + emojione/1F1EA-1F1EA.png + emojione/1F1EA-1F1EC.png + emojione/1F1EA-1F1ED.png + emojione/1F1EA-1F1F7.png + emojione/1F1EA-1F1F8.png + emojione/1F1EA-1F1F9.png + emojione/1f1ea-1f1fa.png + emojione/1F1EB-1F1EE.png + emojione/1F1EB-1F1EF.png + emojione/1F1EB-1F1F0.png + emojione/1F1EB-1F1F2.png + emojione/1F1EB-1F1F4.png + emojione/1F1EB-1F1F7.png + emojione/1F1EC-1F1E6.png + emojione/1F1EC-1F1E7.png + emojione/1F1EC-1F1E9.png + emojione/1F1EC-1F1EA.png + emojione/1f1ec-1f1eb.png + emojione/1f1ec-1f1ec.png + emojione/1F1EC-1F1ED.png + emojione/1F1EC-1F1EE.png + emojione/1F1EC-1F1F1.png + emojione/1F1EC-1F1F2.png + emojione/1F1EC-1F1F3.png + emojione/1f1ec-1f1f5.png + emojione/1F1EC-1F1F6.png + emojione/1F1EC-1F1F7.png + emojione/1f1ec-1f1f8.png + emojione/1F1EC-1F1F9.png + emojione/1F1EC-1F1FA.png + emojione/1F1EC-1F1FC.png + emojione/1F1EC-1F1FE.png + emojione/1F1ED-1F1F0.png + emojione/1f1ed-1f1f2.png + emojione/1F1ED-1F1F3.png + emojione/1F1ED-1F1F7.png + emojione/1F1ED-1F1F9.png + emojione/1F1ED-1F1FA.png + emojione/1f1ee-1f1e8.png + emojione/1F1EE-1F1E9.png + emojione/1F1EE-1F1EA.png + emojione/1F1EE-1F1F1.png + emojione/1f1ee-1f1f2.png + emojione/1F1EE-1F1F3.png + emojione/1f1ee-1f1f4.png + emojione/1F1EE-1F1F6.png + emojione/1F1EE-1F1F7.png + emojione/1F1EE-1F1F8.png + emojione/1F1EE-1F1F9.png + emojione/1F1EF-1F1EA.png + emojione/1F1EF-1F1F2.png + emojione/1F1EF-1F1F4.png + emojione/1F1EF-1F1F5.png + emojione/1F1F0-1F1EA.png + emojione/1F1F0-1F1EC.png + emojione/1F1F0-1F1ED.png + emojione/1F1F0-1F1EE.png + emojione/1F1F0-1F1F2.png + emojione/1F1F0-1F1F3.png + emojione/1F1F0-1F1F5.png + emojione/1F1F0-1F1F7.png + emojione/1F1F0-1F1FC.png + emojione/1F1F0-1F1FE.png + emojione/1F1F0-1F1FF.png + emojione/1F1F1-1F1E6.png + emojione/1F1F1-1F1E7.png + emojione/1F1F1-1F1E8.png + emojione/1F1F1-1F1EE.png + emojione/1F1F1-1F1F0.png + emojione/1F1F1-1F1F7.png + emojione/1F1F1-1F1F8.png + emojione/1F1F1-1F1F9.png + emojione/1F1F1-1F1FA.png + emojione/1F1F1-1F1FB.png + emojione/1F1F1-1F1FE.png + emojione/1F1F2-1F1E6.png + emojione/1F1F2-1F1E8.png + emojione/1F1F2-1F1E9.png + emojione/1F1F2-1F1EA.png + emojione/1f1f2-1f1eb.png + emojione/1F1F2-1F1EC.png + emojione/1F1F2-1F1ED.png + emojione/1F1F2-1F1F0.png + emojione/1F1F2-1F1F1.png + emojione/1F1F2-1F1F2.png + emojione/1F1F2-1F1F3.png + emojione/1F1F2-1F1F4.png + emojione/1f1f2-1f1f5.png + emojione/1f1f2-1f1f6.png + emojione/1F1F2-1F1F7.png + emojione/1F1F2-1F1F8.png + emojione/1F1F2-1F1F9.png + emojione/1F1F2-1F1FA.png + emojione/1F1F2-1F1FB.png + emojione/1F1F2-1F1FC.png + emojione/1F1F2-1F1FD.png + emojione/1F1F2-1F1FE.png + emojione/1F1F2-1F1FF.png + emojione/1F1F3-1F1E6.png + emojione/1F1F3-1F1E8.png + emojione/1F1F3-1F1EA.png + emojione/1f1f3-1f1eb.png + emojione/1F1F3-1F1EC.png + emojione/1F1F3-1F1EE.png + emojione/1F1F3-1F1F1.png + emojione/1F1F3-1F1F4.png + emojione/1F1F3-1F1F5.png + emojione/1F1F3-1F1F7.png + emojione/1F1F3-1F1FA.png + emojione/1F1F3-1F1FF.png + emojione/1F1F4-1F1F2.png + emojione/1F1F5-1F1E6.png + emojione/1F1F5-1F1EA.png + emojione/1F1F5-1F1EB.png + emojione/1F1F5-1F1EC.png + emojione/1F1F5-1F1ED.png + emojione/1F1F5-1F1F0.png + emojione/1F1F5-1F1F1.png + emojione/1f1f5-1f1f2.png + emojione/1f1f5-1f1f3.png + emojione/1F1F5-1F1F7.png + emojione/1F1F5-1F1F8.png + emojione/1F1F5-1F1F9.png + emojione/1F1F5-1F1FC.png + emojione/1F1F5-1F1FE.png + emojione/1F1F6-1F1E6.png + emojione/1f1f7-1f1ea.png + emojione/1F1F7-1F1F4.png + emojione/1F1F7-1F1F8.png + emojione/1F1F7-1F1FA.png + emojione/1F1F7-1F1FC.png + emojione/1F1F8-1F1E6.png + emojione/1F1F8-1F1E7.png + emojione/1F1F8-1F1E8.png + emojione/1F1F8-1F1E9.png + emojione/1F1F8-1F1EA.png + emojione/1F1F8-1F1EC.png + emojione/1F1F8-1F1ED.png + emojione/1F1F8-1F1EE.png + emojione/1f1f8-1f1ef.png + emojione/1F1F8-1F1F0.png + emojione/1F1F8-1F1F1.png + emojione/1F1F8-1F1F2.png + emojione/1F1F8-1F1F3.png + emojione/1F1F8-1F1F4.png + emojione/1F1F8-1F1F7.png + emojione/1f1f8-1f1f8.png + emojione/1F1F8-1F1F9.png + emojione/1F1F8-1F1FB.png + emojione/1f1f8-1f1fd.png + emojione/1F1F8-1F1FE.png + emojione/1F1F8-1F1FF.png + emojione/1f1f9-1f1e6.png + emojione/1f1f9-1f1e8.png + emojione/1F1F9-1F1E9.png + emojione/1f1f9-1f1eb.png + emojione/1F1F9-1F1EC.png + emojione/1F1F9-1F1ED.png + emojione/1F1F9-1F1EF.png + emojione/1f1f9-1f1f0.png + emojione/1F1F9-1F1F1.png + emojione/1F1F9-1F1F2.png + emojione/1F1F9-1F1F3.png + emojione/1F1F9-1F1F4.png + emojione/1F1F9-1F1F7.png + emojione/1F1F9-1F1F9.png + emojione/1F1F9-1F1FB.png + emojione/1F1F9-1F1FC.png + emojione/1F1F9-1F1FF.png + emojione/1F1FA-1F1E6.png + emojione/1F1FA-1F1EC.png + emojione/1f1fa-1f1f2.png + emojione/1F1FA-1F1F8.png + emojione/1F1FA-1F1FE.png + emojione/1F1FA-1F1FF.png + emojione/1F1FB-1F1E6.png + emojione/1F1FB-1F1E8.png + emojione/1F1FB-1F1EA.png + emojione/1f1fb-1f1ec.png + emojione/1F1FB-1F1EE.png + emojione/1F1FB-1F1F3.png + emojione/1F1FB-1F1FA.png + emojione/1F1FC-1F1EB.png + emojione/1F1FC-1F1F8.png + emojione/1F1FD-1F1F0.png + emojione/1F1FE-1F1EA.png + emojione/1f1fe-1f1f9.png + emojione/1F1FF-1F1E6.png + emojione/1F1FF-1F1F2.png + emojione/1F1FF-1F1FC.png + emojione/flags.png + emojione/flags2.png + diff --git a/retroshare-gui/src/gui/emojione/emotes.acs b/retroshare-gui/src/gui/emojione/emotes.acs index f421bb620..6e9007948 100644 --- a/retroshare-gui/src/gui/emojione/emotes.acs +++ b/retroshare-gui/src/gui/emojione/emotes.acs @@ -486,4 +486,220 @@ "emojione/symbols.png"|":atm:":"emojione/1F3E7.png"; "emojione/symbols.png"|":copyright:":"emojione/00A9.png"; "emojione/symbols.png"|":registered:":"emojione/00AE.png"; +"emojione/flags.png"|":au:":"emojione/1F1E6-1F1FA.png"; +"emojione/flags.png"|":at:":"emojione/1F1E6-1F1F9.png"; +"emojione/flags.png"|":be:":"emojione/1F1E7-1F1EA.png"; +"emojione/flags.png"|":br:":"emojione/1F1E7-1F1F7.png"; +"emojione/flags.png"|":ca:":"emojione/1F1E8-1F1E6.png"; +"emojione/flags.png"|":chile:":"emojione/1F1E8-1F1F1.png"; +"emojione/flags.png"|":cn:":"emojione/1F1E8-1F1F3.png"; +"emojione/flags.png"|":dk:":"emojione/1F1E9-1F1F0.png"; +"emojione/flags.png"|":fi:":"emojione/1F1EB-1F1EE.png"; +"emojione/flags.png"|":fr:":"emojione/1F1EB-1F1F7.png"; +"emojione/flags.png"|":de:":"emojione/1F1E9-1F1EA.png"; +"emojione/flags.png"|":hk:":"emojione/1F1ED-1F1F0.png"; +"emojione/flags.png"|":in:":"emojione/1F1EE-1F1F3.png"; +"emojione/flags.png"|":indonesia:":"emojione/1F1EE-1F1E9.png"; +"emojione/flags.png"|":ie:":"emojione/1F1EE-1F1EA.png"; +"emojione/flags.png"|":il:":"emojione/1F1EE-1F1F1.png"; +"emojione/flags.png"|":it:":"emojione/1F1EE-1F1F9.png"; +"emojione/flags.png"|":jp:":"emojione/1F1EF-1F1F5.png"; +"emojione/flags.png"|":kr:":"emojione/1F1F0-1F1F7.png"; +"emojione/flags.png"|":mo:":"emojione/1F1F2-1F1F4.png"; +"emojione/flags.png"|":my:":"emojione/1F1F2-1F1FE.png"; +"emojione/flags.png"|":mx:":"emojione/1F1F2-1F1FD.png"; +"emojione/flags.png"|":nl:":"emojione/1F1F3-1F1F1.png"; +"emojione/flags.png"|":nz:":"emojione/1F1F3-1F1FF.png"; +"emojione/flags.png"|":no:":"emojione/1F1F3-1F1F4.png"; +"emojione/flags.png"|":ph:":"emojione/1F1F5-1F1ED.png"; +"emojione/flags.png"|":pl:":"emojione/1F1F5-1F1F1.png"; +"emojione/flags.png"|":pt:":"emojione/1F1F5-1F1F9.png"; +"emojione/flags.png"|":pr:":"emojione/1F1F5-1F1F7.png"; +"emojione/flags.png"|":ru:":"emojione/1F1F7-1F1FA.png"; +"emojione/flags.png"|":saudi:":"emojione/1F1F8-1F1E6.png"; +"emojione/flags.png"|":sg:":"emojione/1F1F8-1F1EC.png"; +"emojione/flags.png"|":za:":"emojione/1F1FF-1F1E6.png"; +"emojione/flags.png"|":es:":"emojione/1F1EA-1F1F8.png"; +"emojione/flags.png"|":se:":"emojione/1F1F8-1F1EA.png"; +"emojione/flags.png"|":ch:":"emojione/1F1E8-1F1ED.png"; +"emojione/flags.png"|":tr:":"emojione/1F1F9-1F1F7.png"; +"emojione/flags.png"|":gb:":"emojione/1F1EC-1F1E7.png"; +"emojione/flags.png"|":us:":"emojione/1F1FA-1F1F8.png"; +"emojione/flags.png"|":ae:":"emojione/1F1E6-1F1EA.png"; +"emojione/flags.png"|":vn:":"emojione/1F1FB-1F1F3.png"; +"emojione/flags.png"|":af:":"emojione/1F1E6-1F1EB.png"; +"emojione/flags.png"|":al:":"emojione/1F1E6-1F1F1.png"; +"emojione/flags.png"|":dz:":"emojione/1F1E9-1F1FF.png"; +"emojione/flags.png"|":ad:":"emojione/1F1E6-1F1E9.png"; +"emojione/flags.png"|":ao:":"emojione/1F1E6-1F1F4.png"; +"emojione/flags.png"|":ai:":"emojione/1F1E6-1F1EE.png"; +"emojione/flags.png"|":ag:":"emojione/1F1E6-1F1EC.png"; +"emojione/flags.png"|":ar:":"emojione/1F1E6-1F1F7.png"; +"emojione/flags.png"|":am:":"emojione/1F1E6-1F1F2.png"; +"emojione/flags.png"|":aw:":"emojione/1F1E6-1F1FC.png"; +"emojione/flags.png"|":ac:":"emojione/1F1E6-1F1E8.png"; +"emojione/flags.png"|":az:":"emojione/1F1E6-1F1FF.png"; +"emojione/flags.png"|":bs:":"emojione/1F1E7-1F1F8.png"; +"emojione/flags.png"|":bh:":"emojione/1F1E7-1F1ED.png"; +"emojione/flags.png"|":bd:":"emojione/1F1E7-1F1E9.png"; +"emojione/flags.png"|":bb:":"emojione/1F1E7-1F1E7.png"; +"emojione/flags.png"|":by:":"emojione/1F1E7-1F1FE.png"; +"emojione/flags.png"|":bz:":"emojione/1F1E7-1F1FF.png"; +"emojione/flags.png"|":bj:":"emojione/1F1E7-1F1EF.png"; +"emojione/flags.png"|":bm:":"emojione/1F1E7-1F1F2.png"; +"emojione/flags.png"|":bt:":"emojione/1F1E7-1F1F9.png"; +"emojione/flags.png"|":bo:":"emojione/1F1E7-1F1F4.png"; +"emojione/flags.png"|":ba:":"emojione/1F1E7-1F1E6.png"; +"emojione/flags.png"|":bw:":"emojione/1F1E7-1F1FC.png"; +"emojione/flags.png"|":bn:":"emojione/1F1E7-1F1F3.png"; +"emojione/flags.png"|":bg:":"emojione/1F1E7-1F1EC.png"; +"emojione/flags.png"|":bf:":"emojione/1F1E7-1F1EB.png"; +"emojione/flags.png"|":bi:":"emojione/1F1E7-1F1EE.png"; +"emojione/flags.png"|":kh:":"emojione/1F1F0-1F1ED.png"; +"emojione/flags.png"|":cm:":"emojione/1F1E8-1F1F2.png"; +"emojione/flags.png"|":cv:":"emojione/1F1E8-1F1FB.png"; +"emojione/flags.png"|":ky:":"emojione/1F1F0-1F1FE.png"; +"emojione/flags.png"|":cf:":"emojione/1F1E8-1F1EB.png"; +"emojione/flags.png"|":km:":"emojione/1F1F0-1F1F2.png"; +"emojione/flags.png"|":congo:":"emojione/1F1E8-1F1E9.png"; +"emojione/flags.png"|":cg:":"emojione/1F1E8-1F1EC.png"; +"emojione/flags.png"|":td:":"emojione/1F1F9-1F1E9.png"; +"emojione/flags.png"|":cr:":"emojione/1F1E8-1F1F7.png"; +"emojione/flags.png"|":ci:":"emojione/1F1E8-1F1EE.png"; +"emojione/flags.png"|":hr:":"emojione/1F1ED-1F1F7.png"; +"emojione/flags.png"|":cu:":"emojione/1F1E8-1F1FA.png"; +"emojione/flags.png"|":cy:":"emojione/1F1E8-1F1FE.png"; +"emojione/flags.png"|":cz:":"emojione/1F1E8-1F1FF.png"; +"emojione/flags.png"|":dj:":"emojione/1F1E9-1F1EF.png"; +"emojione/flags.png"|":dm:":"emojione/1F1E9-1F1F2.png"; +"emojione/flags.png"|":do:":"emojione/1F1E9-1F1F4.png"; +"emojione/flags.png"|":tl:":"emojione/1F1F9-1F1F1.png"; +"emojione/flags.png"|":ec:":"emojione/1F1EA-1F1E8.png"; +"emojione/flags.png"|":eg:":"emojione/1F1EA-1F1EC.png"; +"emojione/flags.png"|":sv:":"emojione/1F1F8-1F1FB.png"; +"emojione/flags.png"|":gq:":"emojione/1F1EC-1F1F6.png"; +"emojione/flags.png"|":er:":"emojione/1F1EA-1F1F7.png"; +"emojione/flags.png"|":ee:":"emojione/1F1EA-1F1EA.png"; +"emojione/flags.png"|":et:":"emojione/1F1EA-1F1F9.png"; +"emojione/flags.png"|":fk:":"emojione/1F1EB-1F1F0.png"; +"emojione/flags.png"|":fo:":"emojione/1F1EB-1F1F4.png"; +"emojione/flags.png"|":fj:":"emojione/1F1EB-1F1EF.png"; +"emojione/flags.png"|":pf:":"emojione/1F1F5-1F1EB.png"; +"emojione/flags.png"|":ga:":"emojione/1F1EC-1F1E6.png"; +"emojione/flags.png"|":gm:":"emojione/1F1EC-1F1F2.png"; +"emojione/flags.png"|":ge:":"emojione/1F1EC-1F1EA.png"; +"emojione/flags.png"|":gh:":"emojione/1F1EC-1F1ED.png"; +"emojione/flags.png"|":gi:":"emojione/1F1EC-1F1EE.png"; +"emojione/flags.png"|":gr:":"emojione/1F1EC-1F1F7.png"; +"emojione/flags.png"|":gl:":"emojione/1F1EC-1F1F1.png"; +"emojione/flags.png"|":gd:":"emojione/1F1EC-1F1E9.png"; +"emojione/flags.png"|":gu:":"emojione/1F1EC-1F1FA.png"; +"emojione/flags.png"|":gt:":"emojione/1F1EC-1F1F9.png"; +"emojione/flags.png"|":gn:":"emojione/1F1EC-1F1F3.png"; +"emojione/flags.png"|":gw:":"emojione/1F1EC-1F1FC.png"; +"emojione/flags.png"|":gy:":"emojione/1F1EC-1F1FE.png"; +"emojione/flags.png"|":ht:":"emojione/1F1ED-1F1F9.png"; +"emojione/flags.png"|":hn:":"emojione/1F1ED-1F1F3.png"; +"emojione/flags.png"|":hu:":"emojione/1F1ED-1F1FA.png"; +"emojione/flags.png"|":is:":"emojione/1F1EE-1F1F8.png"; +"emojione/flags.png"|":ir:":"emojione/1F1EE-1F1F7.png"; +"emojione/flags2.png"|":iq:":"emojione/1F1EE-1F1F6.png"; +"emojione/flags2.png"|":jm:":"emojione/1F1EF-1F1F2.png"; +"emojione/flags2.png"|":je:":"emojione/1F1EF-1F1EA.png"; +"emojione/flags2.png"|":jo:":"emojione/1F1EF-1F1F4.png"; +"emojione/flags2.png"|":kz:":"emojione/1F1F0-1F1FF.png"; +"emojione/flags2.png"|":ke:":"emojione/1F1F0-1F1EA.png"; +"emojione/flags2.png"|":ki:":"emojione/1F1F0-1F1EE.png"; +"emojione/flags2.png"|":xk:":"emojione/1F1FD-1F1F0.png"; +"emojione/flags2.png"|":kw:":"emojione/1F1F0-1F1FC.png"; +"emojione/flags2.png"|":kg:":"emojione/1F1F0-1F1EC.png"; +"emojione/flags2.png"|":la:":"emojione/1F1F1-1F1E6.png"; +"emojione/flags2.png"|":lv:":"emojione/1F1F1-1F1FB.png"; +"emojione/flags2.png"|":lb:":"emojione/1F1F1-1F1E7.png"; +"emojione/flags2.png"|":ls:":"emojione/1F1F1-1F1F8.png"; +"emojione/flags2.png"|":lr:":"emojione/1F1F1-1F1F7.png"; +"emojione/flags2.png"|":ly:":"emojione/1F1F1-1F1FE.png"; +"emojione/flags2.png"|":li:":"emojione/1F1F1-1F1EE.png"; +"emojione/flags2.png"|":lt:":"emojione/1F1F1-1F1F9.png"; +"emojione/flags2.png"|":lu:":"emojione/1F1F1-1F1FA.png"; +"emojione/flags2.png"|":mk:":"emojione/1F1F2-1F1F0.png"; +"emojione/flags2.png"|":mg:":"emojione/1F1F2-1F1EC.png"; +"emojione/flags2.png"|":mw:":"emojione/1F1F2-1F1FC.png"; +"emojione/flags2.png"|":mv:":"emojione/1F1F2-1F1FB.png"; +"emojione/flags2.png"|":ml:":"emojione/1F1F2-1F1F1.png"; +"emojione/flags2.png"|":mt:":"emojione/1F1F2-1F1F9.png"; +"emojione/flags2.png"|":mh:":"emojione/1F1F2-1F1ED.png"; +"emojione/flags2.png"|":mr:":"emojione/1F1F2-1F1F7.png"; +"emojione/flags2.png"|":mu:":"emojione/1F1F2-1F1FA.png"; +"emojione/flags2.png"|":fm:":"emojione/1F1EB-1F1F2.png"; +"emojione/flags2.png"|":md:":"emojione/1F1F2-1F1E9.png"; +"emojione/flags2.png"|":mc:":"emojione/1F1F2-1F1E8.png"; +"emojione/flags2.png"|":mn:":"emojione/1F1F2-1F1F3.png"; +"emojione/flags2.png"|":me:":"emojione/1F1F2-1F1EA.png"; +"emojione/flags2.png"|":ms:":"emojione/1F1F2-1F1F8.png"; +"emojione/flags2.png"|":ma:":"emojione/1F1F2-1F1E6.png"; +"emojione/flags2.png"|":mz:":"emojione/1F1F2-1F1FF.png"; +"emojione/flags2.png"|":mm:":"emojione/1F1F2-1F1F2.png"; +"emojione/flags2.png"|":na:":"emojione/1F1F3-1F1E6.png"; +"emojione/flags2.png"|":nr:":"emojione/1F1F3-1F1F7.png"; +"emojione/flags2.png"|":np:":"emojione/1F1F3-1F1F5.png"; +"emojione/flags2.png"|":nc:":"emojione/1F1F3-1F1E8.png"; +"emojione/flags2.png"|":ni:":"emojione/1F1F3-1F1EE.png"; +"emojione/flags2.png"|":ne:":"emojione/1F1F3-1F1EA.png"; +"emojione/flags2.png"|":nigeria:":"emojione/1F1F3-1F1EC.png"; +"emojione/flags2.png"|":nu:":"emojione/1F1F3-1F1FA.png"; +"emojione/flags2.png"|":kp:":"emojione/1F1F0-1F1F5.png"; +"emojione/flags2.png"|":om:":"emojione/1F1F4-1F1F2.png"; +"emojione/flags2.png"|":pk:":"emojione/1F1F5-1F1F0.png"; +"emojione/flags2.png"|":pw:":"emojione/1F1F5-1F1FC.png"; +"emojione/flags2.png"|":ps:":"emojione/1F1F5-1F1F8.png"; +"emojione/flags2.png"|":pa:":"emojione/1F1F5-1F1E6.png"; +"emojione/flags2.png"|":pg:":"emojione/1F1F5-1F1EC.png"; +"emojione/flags2.png"|":py:":"emojione/1F1F5-1F1FE.png"; +"emojione/flags2.png"|":pe:":"emojione/1F1F5-1F1EA.png"; +"emojione/flags2.png"|":qa:":"emojione/1F1F6-1F1E6.png"; +"emojione/flags2.png"|":ro:":"emojione/1F1F7-1F1F4.png"; +"emojione/flags2.png"|":rw:":"emojione/1F1F7-1F1FC.png"; +"emojione/flags2.png"|":sh:":"emojione/1F1F8-1F1ED.png"; +"emojione/flags2.png"|":kn:":"emojione/1F1F0-1F1F3.png"; +"emojione/flags2.png"|":lc:":"emojione/1F1F1-1F1E8.png"; +"emojione/flags2.png"|":vc:":"emojione/1F1FB-1F1E8.png"; +"emojione/flags2.png"|":ws:":"emojione/1F1FC-1F1F8.png"; +"emojione/flags2.png"|":sm:":"emojione/1F1F8-1F1F2.png"; +"emojione/flags2.png"|":st:":"emojione/1F1F8-1F1F9.png"; +"emojione/flags2.png"|":sn:":"emojione/1F1F8-1F1F3.png"; +"emojione/flags2.png"|":rs:":"emojione/1F1F7-1F1F8.png"; +"emojione/flags2.png"|":sc:":"emojione/1F1F8-1F1E8.png"; +"emojione/flags2.png"|":sl:":"emojione/1F1F8-1F1F1.png"; +"emojione/flags2.png"|":sk:":"emojione/1F1F8-1F1F0.png"; +"emojione/flags2.png"|":si:":"emojione/1F1F8-1F1EE.png"; +"emojione/flags2.png"|":sb:":"emojione/1F1F8-1F1E7.png"; +"emojione/flags2.png"|":so:":"emojione/1F1F8-1F1F4.png"; +"emojione/flags2.png"|":lk:":"emojione/1F1F1-1F1F0.png"; +"emojione/flags2.png"|":sd:":"emojione/1F1F8-1F1E9.png"; +"emojione/flags2.png"|":sr:":"emojione/1F1F8-1F1F7.png"; +"emojione/flags2.png"|":sz:":"emojione/1F1F8-1F1FF.png"; +"emojione/flags2.png"|":sy:":"emojione/1F1F8-1F1FE.png"; +"emojione/flags2.png"|":tw:":"emojione/1F1F9-1F1FC.png"; +"emojione/flags2.png"|":tj:":"emojione/1F1F9-1F1EF.png"; +"emojione/flags2.png"|":tz:":"emojione/1F1F9-1F1FF.png"; +"emojione/flags2.png"|":th:":"emojione/1F1F9-1F1ED.png"; +"emojione/flags2.png"|":tg:":"emojione/1F1F9-1F1EC.png"; +"emojione/flags2.png"|":to:":"emojione/1F1F9-1F1F4.png"; +"emojione/flags2.png"|":tt:":"emojione/1F1F9-1F1F9.png"; +"emojione/flags2.png"|":tn:":"emojione/1F1F9-1F1F3.png"; +"emojione/flags2.png"|":turkmenistan:":"emojione/1F1F9-1F1F2.png"; +"emojione/flags2.png"|":tuvalu:":"emojione/1F1F9-1F1FB.png"; +"emojione/flags2.png"|":vi:":"emojione/1F1FB-1F1EE.png"; +"emojione/flags2.png"|":ug:":"emojione/1F1FA-1F1EC.png"; +"emojione/flags2.png"|":ua:":"emojione/1F1FA-1F1E6.png"; +"emojione/flags2.png"|":uy:":"emojione/1F1FA-1F1FE.png"; +"emojione/flags2.png"|":uz:":"emojione/1F1FA-1F1FF.png"; +"emojione/flags2.png"|":vu:":"emojione/1F1FB-1F1FA.png"; +"emojione/flags2.png"|":va:":"emojione/1F1FB-1F1E6.png"; +"emojione/flags2.png"|":ve:":"emojione/1F1FB-1F1EA.png"; +"emojione/flags2.png"|":wf:":"emojione/1F1FC-1F1EB.png"; +"emojione/flags2.png"|":eh:":"emojione/1F1EA-1F1ED.png"; +"emojione/flags2.png"|":ye":"emojione/1F1FE-1F1EA.png"; +"emojione/flags2.png"|":zm:":"emojione/1F1FF-1F1F2.png"; } diff --git a/retroshare-gui/src/gui/emojione/flags.png b/retroshare-gui/src/gui/emojione/flags.png new file mode 100644 index 000000000..a86a68534 Binary files /dev/null and b/retroshare-gui/src/gui/emojione/flags.png differ diff --git a/retroshare-gui/src/gui/emojione/flags2.png b/retroshare-gui/src/gui/emojione/flags2.png new file mode 100644 index 000000000..a86a68534 Binary files /dev/null and b/retroshare-gui/src/gui/emojione/flags2.png differ diff --git a/retroshare-gui/src/gui/feeds/GxsChannelGroupItem.cpp b/retroshare-gui/src/gui/feeds/GxsChannelGroupItem.cpp index 4d0b33c8f..edc83c586 100644 --- a/retroshare-gui/src/gui/feeds/GxsChannelGroupItem.cpp +++ b/retroshare-gui/src/gui/feeds/GxsChannelGroupItem.cpp @@ -18,6 +18,7 @@ * * *******************************************************************************/ +#include "gui/gxs/GxsIdDetails.h" #include "GxsChannelGroupItem.h" #include "ui_GxsChannelGroupItem.h" @@ -134,7 +135,7 @@ void GxsChannelGroupItem::fill() if (mGroup.mImage.mData != NULL) { QPixmap chanImage; - chanImage.loadFromData(mGroup.mImage.mData, mGroup.mImage.mSize, "PNG"); + GxsIdDetails::loadPixmapFromData(mGroup.mImage.mData, mGroup.mImage.mSize, chanImage,GxsIdDetails::ORIGINAL); ui->logoLabel->setPixmap(QPixmap(chanImage)); } diff --git a/retroshare-gui/src/gui/feeds/GxsChannelPostItem.cpp b/retroshare-gui/src/gui/feeds/GxsChannelPostItem.cpp index c6c301c46..9b70ca191 100644 --- a/retroshare-gui/src/gui/feeds/GxsChannelPostItem.cpp +++ b/retroshare-gui/src/gui/feeds/GxsChannelPostItem.cpp @@ -22,6 +22,7 @@ #include #include +#include "gui/gxs/GxsIdDetails.h" #include "rshare.h" #include "GxsChannelPostItem.h" #include "ui_GxsChannelPostItem.h" @@ -392,7 +393,7 @@ void GxsChannelPostItem::fill() if(mPost.mThumbnail.mData != NULL) { QPixmap thumbnail; - thumbnail.loadFromData(mPost.mThumbnail.mData, mPost.mThumbnail.mSize, "PNG"); + GxsIdDetails::loadPixmapFromData(mPost.mThumbnail.mData, mPost.mThumbnail.mSize, thumbnail,GxsIdDetails::ORIGINAL); // Wiping data - as its been passed to thumbnail. ui->logoLabel->setPixmap(thumbnail); } diff --git a/retroshare-gui/src/gui/feeds/PostedGroupItem.cpp b/retroshare-gui/src/gui/feeds/PostedGroupItem.cpp index 542e97a11..f0453e4df 100644 --- a/retroshare-gui/src/gui/feeds/PostedGroupItem.cpp +++ b/retroshare-gui/src/gui/feeds/PostedGroupItem.cpp @@ -23,6 +23,7 @@ #include "FeedHolder.h" #include "gui/RetroShareLink.h" +#include "gui/gxs/GxsIdDetails.h" /**** * #define DEBUG_ITEM 1 @@ -137,7 +138,7 @@ void PostedGroupItem::fill() if (mGroup.mGroupImage.mData != NULL) { QPixmap postedImage; - postedImage.loadFromData(mGroup.mGroupImage.mData, mGroup.mGroupImage.mSize, "PNG"); + GxsIdDetails::loadPixmapFromData(mGroup.mGroupImage.mData, mGroup.mGroupImage.mSize, postedImage,GxsIdDetails::ORIGINAL); ui->logoLabel->setPixmap(QPixmap(postedImage)); } else { ui->logoLabel->setPixmap(QPixmap(":/images/posted_64.png")); diff --git a/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp b/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp index 384cddf7e..a7627a967 100644 --- a/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp +++ b/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp @@ -24,6 +24,8 @@ #include #include +#include +#include "gui/common/AvatarDialog.h" #include "GxsIdDetails.h" #include "retroshare-gui/RsAutoUpdatePage.h" @@ -66,10 +68,13 @@ uint32_t GxsIdDetails::mImagesAllocated = 0; time_t GxsIdDetails::mLastIconCacheCleaning = time(NULL); -std::map > GxsIdDetails::mDefaultIconCache ; +std::map[4] > GxsIdDetails::mDefaultIconCache ; -#define ICON_CACHE_STORAGE_TIME 600 -#define DELAY_BETWEEN_ICON_CACHE_CLEANING 300 +QMutex GxsIdDetails::mMutex; +QMutex GxsIdDetails::mIconCacheMutex; + +#define ICON_CACHE_STORAGE_TIME 240 +#define DELAY_BETWEEN_ICON_CACHE_CLEANING 120 void ReputationItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { @@ -184,7 +189,8 @@ void GxsIdDetails::timerEvent(QTimerEvent *event) killTimer(mCheckTimerId); mCheckTimerId = 0; - if (rsIdentity) { + if (rsIdentity) + { QMutexLocker lock(&mMutex); if (mProcessDisableCount == 0) { @@ -236,14 +242,14 @@ void GxsIdDetails::timerEvent(QTimerEvent *event) } } - QMutexLocker lock(&mMutex); + bool empty = false ; + { + QMutexLocker lock(&mMutex); + empty = mPendingData.empty(); + } - if (mPendingData.empty()) { - /* All done */ - } else { - /* Start timer */ + if (!empty) /* Start timer */ doStartTimer(); - } } } @@ -266,7 +272,7 @@ void GxsIdDetails::enableProcess(bool enable) return; } - QMutexLocker lock(&mInstance->mMutex); + QMutexLocker lock(&mMutex); if (enable) { --mInstance->mProcessDisableCount; @@ -292,7 +298,7 @@ bool GxsIdDetails::process(const RsGxsId &id, GxsIdDetailsCallbackFunction callb // remove any existing call for this object. This is needed for when the same widget is used to display IDs that vary in time. { - QMutexLocker lock(&mInstance->mMutex); + QMutexLocker lock(&mMutex); // check if a pending request is not already on its way. If so, replace it. @@ -339,7 +345,7 @@ bool GxsIdDetails::process(const RsGxsId &id, GxsIdDetailsCallbackFunction callb pendingData.mData = data; { - QMutexLocker lock(&mInstance->mMutex); + QMutexLocker lock(&mMutex); // check if a pending request is not already on its way. If so, replace it. @@ -376,79 +382,6 @@ static bool findTagIcon(int tag_class, int /*tag_type*/, QIcon &icon) return true; } -//QImage GxsIdDetails::makeDefaultIcon(const RsGxsId& id) -//{ -// static std::map image_cache ; -// -// std::map::const_iterator it = image_cache.find(id) ; -// -// if(it != image_cache.end()) -// return it->second ; -// -// int S = 128 ; -// QImage pix(S,S,QImage::Format_RGB32) ; -// -// uint64_t n = reinterpret_cast(id.toByteArray())[0] ; -// -// uint8_t a[8] ; -// for(int i=0;i<8;++i) -// { -// a[i] = n&0xff ; -// n >>= 8 ; -// } -// QColor val[16] = { -// QColor::fromRgb( 255, 110, 180), -// QColor::fromRgb( 238, 92, 66), -// QColor::fromRgb( 255, 127, 36), -// QColor::fromRgb( 255, 193, 193), -// QColor::fromRgb( 127, 255, 212), -// QColor::fromRgb( 0, 255, 255), -// QColor::fromRgb( 224, 255, 255), -// QColor::fromRgb( 199, 21, 133), -// QColor::fromRgb( 50, 205, 50), -// QColor::fromRgb( 107, 142, 35), -// QColor::fromRgb( 30, 144, 255), -// QColor::fromRgb( 95, 158, 160), -// QColor::fromRgb( 143, 188, 143), -// QColor::fromRgb( 233, 150, 122), -// QColor::fromRgb( 151, 255, 255), -// QColor::fromRgb( 162, 205, 90), -// }; -// -// int c1 = (a[0]^a[1]) & 0xf ; -// int c2 = (a[1]^a[2]) & 0xf ; -// int c3 = (a[2]^a[3]) & 0xf ; -// int c4 = (a[3]^a[4]) & 0xf ; -// -// for(int i=0;i> 4) + sin( (2*M_PI*i/(float)S) * k1 * f) * cos( (2*M_PI*j/(float)S) * k2 * f) * (a[k1+k2] >> 4) ; -// res2 += cos( (2*M_PI*i/(float)S) * k2 * f) * (a[k1+2] & 0xf) + sin( (2*M_PI*j/(float)S) * k1 * f) * (a[k2+1] >> 4) + sin( (2*M_PI*i/(float)S) * k2 * f) * cos( (2*M_PI*j/(float)S) * k1 * f) * (a[k1^k2] >> 4) ; -// } -// -// uint32_t q = 0 ; -// if(res1 >= 0.0f) q += val[c1].rgb() ; else q += val[c2].rgb() ; -// if(res2 >= 0.0f) q += val[c3].rgb() ; else q += val[c4].rgb() ; -// -// pix.setPixel( i, j, q) ; -// pix.setPixel( S-1-i, j, q) ; -// pix.setPixel( S-1-i, S-1-j, q) ; -// pix.setPixel( i, S-1-j, q) ; -// } -// -// image_cache[id] = pix.scaled(128,128,Qt::KeepAspectRatio,Qt::SmoothTransformation) ; -// -// return image_cache[id] ; -//} - /** * @brief GxsIdDetails::makeIdentIcon * @param id: RsGxsId to compute @@ -457,52 +390,149 @@ static bool findTagIcon(int tag_class, int /*tag_type*/, QIcon &icon) * Bring the source code from this adaptation: * http://francisshanahan.com/identicon5/test.html */ -const QImage& GxsIdDetails::makeDefaultIcon(const RsGxsId& id) +const QPixmap GxsIdDetails::makeDefaultIcon(const RsGxsId& id, AvatarSize size) { + checkCleanImagesCache(); + // We use a cache for images. QImage has its own smart pointer system, but it does not prevent // the same image to be allocated many times. We do this using a cache. The cache is also cleaned-up // on a regular time basis so as to get rid of unused images. time_t now = time(NULL); + // now look for the icon + + QMutexLocker lock(&mIconCacheMutex); + auto& it = mDefaultIconCache[id]; + + if(it[(int)size].second.width() > 0) + { + it[(int)size].first = now; + return it[(int)size].second; + } + + int S =0; + + switch(size) + { + case SMALL: S = 16*3 ; break; + default: + case MEDIUM: S = 32*3 ; break; + case ORIGINAL: + case LARGE: S = 64*3 ; break; + } + + QPixmap image = drawIdentIcon(QString::fromStdString(id.toStdString()),S,true); + + it[(int)size] = std::make_pair(now,image); + + return image; +} + +void GxsIdDetails::checkCleanImagesCache() +{ + time_t now = time(NULL); + // cleanup the cache every 10 mins if(mLastIconCacheCleaning + DELAY_BETWEEN_ICON_CACHE_CLEANING < now) { std::cerr << "(II) Cleaning the icons cache." << std::endl; int nb_deleted = 0; + uint32_t size_deleted = 0; + uint32_t total_size = 0; + + QMutexLocker lock(&mIconCacheMutex); for(auto it(mDefaultIconCache.begin());it!=mDefaultIconCache.end();) - if(it->second.first + ICON_CACHE_STORAGE_TIME < now && it->second.second.isDetached()) - { + { + bool all_empty = true ; + + for(int i=0;i<4;++i) + if(it->second[i].first + ICON_CACHE_STORAGE_TIME < now && it->second[i].second.isDetached()) + { + int s = it->second[i].second.width()*it->second[i].second.height()*4; + + std::cerr << "Deleting pixmap " << it->first << " size " << i << " " << s << " bytes." << std::endl; + + it->second[i].second = QPixmap(); + ++nb_deleted; + size_deleted += s; + } + else + { + all_empty = false; + total_size += it->second[i].second.width()*it->second[i].second.height()*4; + } + + if(all_empty) it = mDefaultIconCache.erase(it); - ++nb_deleted; - } else ++it; + } mLastIconCacheCleaning = now; - std::cerr << "(II) Removed " << nb_deleted << " unused icons. Cache contains " << mDefaultIconCache.size() << " icons"<< std::endl; + std::cerr << "(II) Removed " << nb_deleted << " (" << size_deleted << " bytes) unused icons. Cache contains " << mDefaultIconCache.size() << " icons (" << total_size << " bytes)"<< std::endl; } +} + + +bool GxsIdDetails::loadPixmapFromData(const unsigned char *data,size_t data_len,QPixmap& pixmap, AvatarSize size) +{ + // The trick below converts the data into an Id that can be read in the image cache. Because this method is mainly dedicated to loading + // avatars, we could also use the GxsId as id, but the avatar may change in time, so we actually need to make the id from the data itself. + + assert(Sha1CheckSum::SIZE_IN_BYTES >= RsGxsId::SIZE_IN_BYTES); + + Sha1CheckSum chksum = RsDirUtil::sha1sum(data,data_len); + RsGxsId id(chksum.toByteArray()); + + // We use a cache for images. QImage has its own smart pointer system, but it does not prevent + // the same image to be allocated many times. We do this using a cache. The cache is also cleaned-up + // on a regular time basis so as to get rid of unused images. + + checkCleanImagesCache(); // now look for the icon - auto it = mDefaultIconCache.find(id); + QMutexLocker lock(&mIconCacheMutex); - if(it != mDefaultIconCache.end()) + time_t now = time(NULL); + auto& it = mDefaultIconCache[id]; + + if(it[(int)size].second.width() > 0) { - it->second.first = now; - return it->second.second; + it[(int)size].first = now; + pixmap = it[(int)size].second; + + return true; } - QImage image = drawIdentIcon(QString::fromStdString(id.toStdString()),64*3, true); + if(! pixmap.loadFromData(data,data_len)) + return false; - mDefaultIconCache[id] = std::make_pair(now,image); - it = mDefaultIconCache.find(id); + // This resize is here just to prevent someone to explicitely add a huge blank image to screw up the UI - return it->second.second; + int wanted_S=0; + + switch(size) + { + case ORIGINAL: wanted_S = 0 ;break; + case SMALL: wanted_S = 32 ;break; + default: + case MEDIUM: wanted_S = 64 ;break; + case LARGE: wanted_S = 128 ;break; + } + + if(wanted_S > 0) + pixmap = pixmap.scaled(wanted_S,wanted_S,Qt::IgnoreAspectRatio,Qt::SmoothTransformation); + + mDefaultIconCache[id][(int)size] = std::make_pair(now,pixmap); +#ifdef DEBUG + std::cerr << "Allocated new icon " << id << " size " << (int)size << std::endl; +#endif + return true; } - /** * @brief GxsIdDetails::getSprite * @param shapeType: type of shape (0 to 15) @@ -820,7 +850,7 @@ void GxsIdDetails::drawRotatedPolygon( QPixmap *pixmap, * @param rotate: If the shapes could be rotated * @return QImage of computed hash */ -QImage GxsIdDetails::drawIdentIcon( QString hash, quint16 width, bool rotate) +QPixmap GxsIdDetails::drawIdentIcon( QString hash, quint16 width, bool rotate) { bool ok; quint8 csh = hash.mid(0, 1).toInt(&ok,16);// Corner sprite shape @@ -881,7 +911,7 @@ QImage GxsIdDetails::drawIdentIcon( QString hash, quint16 width, bool rotate) } drawRotatedPolygon(&pixmap, center, size, size, 0, 0, size, fillCenter); - return pixmap.toImage(); + return pixmap; } //static bool CreateIdIcon(const RsGxsId &id, QIcon &idIcon) @@ -1089,11 +1119,11 @@ void GxsIdDetails::getIcons(const RsIdentityDetails &details, QList &icon if(icon_types & ICON_TYPE_AVATAR) { - if(details.mAvatar.mSize == 0 || !pix.loadFromData(details.mAvatar.mData, details.mAvatar.mSize, "PNG")) + if(details.mAvatar.mSize == 0 || !GxsIdDetails::loadPixmapFromData(details.mAvatar.mData, details.mAvatar.mSize, pix)) #if QT_VERSION < 0x040700 - pix = QPixmap::fromImage(makeDefaultIcon(details.mId)); + pix = makeDefaultIcon(details.mId); #else - pix.convertFromImage(makeDefaultIcon(details.mId)); + pix = makeDefaultIcon(details.mId); #endif diff --git a/retroshare-gui/src/gui/gxs/GxsIdDetails.h b/retroshare-gui/src/gui/gxs/GxsIdDetails.h index 9f2269a46..3c04c46eb 100644 --- a/retroshare-gui/src/gui/gxs/GxsIdDetails.h +++ b/retroshare-gui/src/gui/gxs/GxsIdDetails.h @@ -74,6 +74,13 @@ public: GxsIdDetails(); virtual ~GxsIdDetails(); + enum AvatarSize { + SMALL = 0x00, + MEDIUM = 0x01, + LARGE = 0x02, + ORIGINAL= 0x03 + }; + static void initialize(); static void cleanup(); @@ -102,8 +109,11 @@ public: static void GenerateCombinedPixmap(QPixmap &pixmap, const QList &icons, int iconSize); - //static QImage makeDefaultIcon(const RsGxsId& id); - static const QImage& makeDefaultIcon(const RsGxsId& id); + // These two methods use a cache so as to minimize the memory impact of avatars. + + static const QPixmap makeDefaultIcon(const RsGxsId& id, AvatarSize size = MEDIUM); + static bool loadPixmapFromData(const unsigned char *data, size_t data_len, QPixmap& pix, AvatarSize size = MEDIUM); + static void checkCleanImagesCache(); /* Processing */ static void enableProcess(bool enable); @@ -127,7 +137,7 @@ private: quint16 x, quint16 y, qreal shapeangle, qreal angle, quint16 size, QColor fillColor); - static QImage drawIdentIcon(QString hash, quint16 width, bool rotate); + static QPixmap drawIdentIcon(QString hash, quint16 width, bool rotate); private slots: void objectDestroyed(QObject *object); @@ -159,14 +169,15 @@ protected: QMap::iterator mPendingDataIterator; static uint32_t mImagesAllocated; - static std::map > mDefaultIconCache; + static std::map[4] > mDefaultIconCache; static time_t mLastIconCacheCleaning; int mCheckTimerId; int mProcessDisableCount; /* Thread safe */ - QMutex mMutex; + static QMutex mMutex; + static QMutex mIconCacheMutex; }; #endif diff --git a/retroshare-gui/src/gui/gxs/GxsIdTreeWidgetItem.cpp b/retroshare-gui/src/gui/gxs/GxsIdTreeWidgetItem.cpp index bfe8cf052..f6709922a 100644 --- a/retroshare-gui/src/gui/gxs/GxsIdTreeWidgetItem.cpp +++ b/retroshare-gui/src/gui/gxs/GxsIdTreeWidgetItem.cpp @@ -154,25 +154,21 @@ QVariant GxsIdRSTreeWidgetItem::data(int column, int role) const if (role == Qt::ToolTipRole) { QString t = RSTreeWidgetItem::data(column, role).toString(); - QImage pix; + QPixmap pix; - if(mId.isNull()) return RSTreeWidgetItem::data(column, role); - else if( rsReputations->overallReputationLevel(mId) == - RsReputationLevel::LOCALLY_NEGATIVE ) - pix = QImage(BANNED_IMAGE); - else if ( mAvatar.mSize == 0 || - !pix.loadFromData(mAvatar.mData, mAvatar.mSize, "PNG") ) - pix = GxsIdDetails::makeDefaultIcon(mId); + if(mId.isNull()) + return RSTreeWidgetItem::data(column, role); + else if( rsReputations->overallReputationLevel(mId) == RsReputationLevel::LOCALLY_NEGATIVE ) + pix = QPixmap(BANNED_IMAGE); + else if ( mAvatar.mSize == 0 || !GxsIdDetails::loadPixmapFromData(mAvatar.mData, mAvatar.mSize, pix,GxsIdDetails::LARGE) ) + pix = GxsIdDetails::makeDefaultIcon(mId,GxsIdDetails::LARGE); int S = QFontMetricsF(font(column)).height(); QString embeddedImage; - if ( RsHtml::makeEmbeddedImage( - pix.scaled(QSize(4*S,4*S), Qt::KeepAspectRatio, - Qt::SmoothTransformation ), - embeddedImage, 8*S * 8*S ) ) - t = "
    " + embeddedImage + "" + t - + "
    "; + + if ( RsHtml::makeEmbeddedImage( pix.scaled(QSize(4*S,4*S), Qt::KeepAspectRatio, Qt::SmoothTransformation ).toImage(), embeddedImage, 8*S * 8*S ) ) + t = "
    " + embeddedImage + "" + t + "
    "; return t; } diff --git a/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.cpp b/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.cpp index 6ca6a4613..66e871fd1 100644 --- a/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.cpp +++ b/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.cpp @@ -26,6 +26,7 @@ #include #include "CreateGxsChannelMsg.h" +#include "gui/gxs/GxsIdDetails.h" #include "gui/feeds/SubFileItem.h" #include "gui/RetroShareLink.h" #include "util/HandleRichText.h" @@ -771,7 +772,7 @@ void CreateGxsChannelMsg::loadChannelPostInfo(const uint32_t &token) for(std::list::const_iterator it(post.mFiles.begin());it!=post.mFiles.end();++it) addAttachment(it->mHash,it->mName,it->mSize,true,RsPeerId(),true); - picture.loadFromData(post.mThumbnail.mData,post.mThumbnail.mSize,"PNG"); + GxsIdDetails::loadPixmapFromData(post.mThumbnail.mData,post.mThumbnail.mSize,picture,GxsIdDetails::ORIGINAL); thumbnail_label->setPixmap(picture); } diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp index bbcfd16c9..915d490f8 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp @@ -326,7 +326,7 @@ void GxsChannelDialog::loadGroupSummaryToken(const uint32_t &token, std::listmIcon[group.mMeta.mGroupId] = image; } diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelGroupDialog.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelGroupDialog.cpp index 6fb832a69..369d28778 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelGroupDialog.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelGroupDialog.cpp @@ -20,6 +20,7 @@ #include +#include "gui/gxs/GxsIdDetails.h" #include "GxsChannelGroupDialog.h" #include @@ -179,7 +180,8 @@ bool GxsChannelGroupDialog::service_loadGroup(uint32_t token, Mode /*mode*/, RsG if (group.mImage.mData) { QPixmap pixmap; - if (pixmap.loadFromData(group.mImage.mData, group.mImage.mSize, "PNG")) { + + if (GxsIdDetails::loadPixmapFromData(group.mImage.mData, group.mImage.mSize,pixmap,GxsIdDetails::ORIGINAL)) { setLogo(pixmap); } } diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.cpp index 215036c1e..7ab315da4 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.cpp @@ -26,6 +26,7 @@ #include "GxsChannelPostsWidget.h" #include "ui_GxsChannelPostsWidget.h" #include "gui/feeds/GxsChannelPostItem.h" +#include "gui/gxs/GxsIdDetails.h" #include "gui/gxschannels/CreateGxsChannelMsg.h" #include "gui/common/UIStateHelper.h" #include "gui/settings/rsharesettings.h" @@ -238,7 +239,7 @@ void GxsChannelPostsWidget::insertChannelDetails(const RsGxsChannelGroup &group) /* IMAGE */ QPixmap chanImage; if (group.mImage.mData != NULL) { - chanImage.loadFromData(group.mImage.mData, group.mImage.mSize, "PNG"); + GxsIdDetails::loadPixmapFromData(group.mImage.mData, group.mImage.mSize, chanImage,GxsIdDetails::ORIGINAL); } else { chanImage = QPixmap(CHAN_DEFAULT_IMAGE); } diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index c9fc624c1..38495f204 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -103,7 +103,7 @@ int RsGxsForumModel::rowCount(const QModelIndex& parent) const return getChildrenCount(parent.internalPointer()); } -int RsGxsForumModel::columnCount(const QModelIndex &parent) const +int RsGxsForumModel::columnCount(const QModelIndex &/*parent*/) const { return COLUMN_THREAD_NB_COLUMNS ; } @@ -229,6 +229,9 @@ Qt::ItemFlags RsGxsForumModel::flags(const QModelIndex& index) const void *RsGxsForumModel::getChildRef(void *ref,int row) const { + if (row < 0) + return nullptr; + ForumModelIndex entry ; if(!convertRefPointerToTabEntry(ref,entry) || entry >= mPosts.size()) @@ -236,16 +239,20 @@ void *RsGxsForumModel::getChildRef(void *ref,int row) const void *new_ref; - if(mTreeMode == TREE_MODE_FLAT) - if(entry == 0) - { + if(mTreeMode == TREE_MODE_FLAT) + { + if(entry == 0) + { convertTabEntryToRefPointer(row+1,new_ref); - return new_ref; - } + return new_ref; + } else - return NULL ; + { + return NULL ; + } + } - if(row >= mPosts[entry].mChildren.size()) + if(static_cast(row) >= mPosts[entry].mChildren.size()) return NULL; convertTabEntryToRefPointer(mPosts[entry].mChildren[row],new_ref); @@ -296,7 +303,7 @@ int RsGxsForumModel::getChildrenCount(void *ref) const return mPosts[entry].mChildren.size(); } -QVariant RsGxsForumModel::headerData(int section, Qt::Orientation orientation, int role) const +QVariant RsGxsForumModel::headerData(int section, Qt::Orientation /*orientation*/, int role) const { if(role == Qt::DisplayRole) switch(section) @@ -395,7 +402,7 @@ QVariant RsGxsForumModel::data(const QModelIndex &index, int role) const } } -QVariant RsGxsForumModel::textColorRole(const ForumModelPostEntry& fmpe,int column) const +QVariant RsGxsForumModel::textColorRole(const ForumModelPostEntry& fmpe,int /*column*/) const { if( (fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_MISSING)) return QVariant(mTextColorMissing); @@ -416,7 +423,7 @@ QVariant RsGxsForumModel::statusRole(const ForumModelPostEntry& fmpe,int column) return QVariant(fmpe.mMsgStatus); } -QVariant RsGxsForumModel::filterRole(const ForumModelPostEntry& fmpe,int column) const +QVariant RsGxsForumModel::filterRole(const ForumModelPostEntry& fmpe,int /*column*/) const { if(!mFilteringEnabled || (fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_CHILDREN_PASSES_FILTER)) return QVariant(FilterString); @@ -495,7 +502,7 @@ void RsGxsForumModel::setFilter(int column,const QStringList& strings,uint32_t& postMods(); } -QVariant RsGxsForumModel::missingRole(const ForumModelPostEntry& fmpe,int column) const +QVariant RsGxsForumModel::missingRole(const ForumModelPostEntry& fmpe,int /*column*/) const { if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_MISSING) return QVariant(true); @@ -537,7 +544,7 @@ QVariant RsGxsForumModel::toolTipRole(const ForumModelPostEntry& fmpe,int column return QVariant(); } -QVariant RsGxsForumModel::pinnedRole(const ForumModelPostEntry& fmpe,int column) const +QVariant RsGxsForumModel::pinnedRole(const ForumModelPostEntry& fmpe,int /*column*/) const { if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_PINNED) return QVariant(true); @@ -545,7 +552,7 @@ QVariant RsGxsForumModel::pinnedRole(const ForumModelPostEntry& fmpe,int column) return QVariant(false); } -QVariant RsGxsForumModel::backgroundRole(const ForumModelPostEntry& fmpe,int column) const +QVariant RsGxsForumModel::backgroundRole(const ForumModelPostEntry& fmpe,int /*column*/) const { if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_PINNED) return QVariant(QBrush(QColor(255,200,180))); @@ -803,7 +810,7 @@ void RsGxsForumModel::generateMissingItem(const RsGxsMessageId &msgId,ForumModel entry.mReputationWarningLevel = 3; } -void RsGxsForumModel::convertMsgToPostEntry(const RsGxsForumGroup& mForumGroup,const RsMsgMetaData& msg, bool useChildTS, ForumModelPostEntry& fentry) +void RsGxsForumModel::convertMsgToPostEntry(const RsGxsForumGroup& mForumGroup,const RsMsgMetaData& msg, bool /*useChildTS*/, ForumModelPostEntry& fentry) { fentry.mTitle = msg.mMsgName; fentry.mAuthorId = msg.mAuthorId; @@ -877,10 +884,12 @@ void RsGxsForumModel::computeMessagesHierarchy(const RsGxsForumGroup& forum_grou msgs[msgs_metas_array[i].mMsgId] = msgs_metas_array[i] ; } - int count = msgs.size(); - int pos = 0; +#ifdef DEBUG_FORUMS + size_t count = msgs.size(); +#endif +// int pos = 0; // int steps = count / PROGRESSBAR_MAX; - int step = 0; +// int step = 0; initEmptyHierarchy(posts); @@ -947,8 +956,8 @@ void RsGxsForumModel::computeMessagesHierarchy(const RsGxsForumGroup& forum_grou { auto& v(it->second) ; - for(int32_t i=0;ifirst) { RsGxsMessageId sub_msg_id = v[i].second ; @@ -957,14 +966,14 @@ void RsGxsForumModel::computeMessagesHierarchy(const RsGxsForumGroup& forum_grou if(it2 != mPostVersions.end()) { - for(int32_t j=0;jsecond.size();++j) + for(size_t j=0;jsecond.size();++j) if(it2->second[j].second != sub_msg_id) // dont copy it, since it is already present at slot i v.push_back(it2->second[j]) ; mPostVersions.erase(it2) ; // it2 is never equal to it } } - } + } } @@ -989,23 +998,23 @@ void RsGxsForumModel::computeMessagesHierarchy(const RsGxsForumGroup& forum_grou #ifdef DEBUG_FORUMS std::cerr << " most recent version " << (*it)[0].first << " " << (*it)[0].second << std::endl; #endif - for(int32_t i=1;isecond.size();++i) - { + for(size_t i=1;isecond.size();++i) + { msgs.erase(it->second[i].second) ; #ifdef DEBUG_FORUMS - std::cerr << " older version " << (*it)[i].first << " " << (*it)[i].second << std::endl; + std::cerr << " older version " << (*it)[i].first << " " << (*it)[i].second << std::endl; #endif - } + } mTmp[it->second[0].second] = it->second ; // index the versions map by the ID of the most recent post. // Now make sure that message parents are consistent. Indeed, an old post may have the old version of a post as parent. So we need to change that parent // to the newest version. So we create a map of which is the most recent version of each message, so that parent messages can be searched in it. - for(int i=1;isecond.size();++i) - most_recent_versions[it->second[i].second] = it->second[0].second ; - } + for(size_t i=1;isecond.size();++i) + most_recent_versions[it->second[i].second] = it->second[0].second ; + } mPostVersions = mTmp ; // The next step is to find the top level thread messages. These are defined as the messages without @@ -1255,6 +1264,7 @@ QModelIndex RsGxsForumModel::getIndexOfMessage(const RsGxsMessageId& mid) const return QModelIndex(); } +#ifdef DEBUG_FORUMMODEL static void recursPrintModel(const std::vector& entries,ForumModelIndex index,int depth) { const ForumModelPostEntry& e(entries[index]); @@ -1271,7 +1281,6 @@ static void recursPrintModel(const std::vector& entries,For recursPrintModel(entries,e.mChildren[i],depth+1); } -#ifdef DEBUG_FORUMMODEL void RsGxsForumModel::debug_dump() { std::cerr << "Model data dump:" << std::endl; diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index f01c054e8..f3340c887 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -1035,17 +1035,6 @@ void GxsForumThreadWidget::clickedThread(QModelIndex index) #endif } -static void cleanupItems (QList &items) -{ - QList::iterator item; - for (item = items.begin (); item != items.end (); ++item) { - if (*item) { - delete (*item); - } - } - items.clear(); -} - static QString getDurationString(uint32_t days) { switch(days) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumsDialog.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumsDialog.cpp index 116e2fe02..84e903335 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumsDialog.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumsDialog.cpp @@ -125,6 +125,8 @@ QString GxsForumsDialog::icon(IconType type) return ":/icons/png/feed-popular.png"; case ICON_OTHER_GROUP: return ":/icons/png/feed-other.png"; + case ICON_SEARCH: + return ":/images/find.png"; case ICON_DEFAULT: return ":/icons/png/forums-default.png"; } diff --git a/retroshare-gui/src/gui/msgs/MessagesDialog.cpp b/retroshare-gui/src/gui/msgs/MessagesDialog.cpp index 2837b5b3a..978deb8e4 100644 --- a/retroshare-gui/src/gui/msgs/MessagesDialog.cpp +++ b/retroshare-gui/src/gui/msgs/MessagesDialog.cpp @@ -187,9 +187,6 @@ MessagesDialog::MessagesDialog(QWidget *parent) //setting default filter by column as subject ui.filterLineEdit->setCurrentFilter(RsMessageModel::COLUMN_THREAD_SUBJECT); - // load settings - processSettings(true); - /////////////////////////////////////////////////////////////////////////////////////// // Post "load settings" actions (which makes sure they are not affected by settings) // /////////////////////////////////////////////////////////////////////////////////////// @@ -234,6 +231,11 @@ MessagesDialog::MessagesDialog(QWidget *parent) // fill quick view fillQuickView(); + sortColumn(RsMessageModel::COLUMN_THREAD_DATE,Qt::DescendingOrder); + + // load settings + processSettings(true); + //ui.messageTreeWidget->installEventFilter(this); // remove close button of the the first tab @@ -345,9 +347,8 @@ void MessagesDialog::processSettings(bool load) ui.filterLineEdit->setCurrentFilter(Settings->value("filterColumn", RsMessageModel::COLUMN_THREAD_SUBJECT).toInt()); // state of message tree - if (Settings->value("MessageTreeVersion").toInt() == messageTreeVersion) { + if (Settings->value("MessageTreeVersion").toInt() == messageTreeVersion) msgwheader->restoreState(Settings->value("MessageTree").toByteArray()); - } // state of splitter ui.msgSplitter->restoreState(Settings->value("SplitterMsg").toByteArray()); diff --git a/retroshare-gui/src/gui/notifyqt.cpp b/retroshare-gui/src/gui/notifyqt.cpp index 10604fc97..5d1a2396f 100644 --- a/retroshare-gui/src/gui/notifyqt.cpp +++ b/retroshare-gui/src/gui/notifyqt.cpp @@ -750,6 +750,26 @@ void NotifyQt::notifyListChange(int list, int type) return; } +void NotifyQt::notifyPeerConnected(const std::string& peer_id) +{ + { + QMutexLocker m(&_mutex) ; + if(!_enabled) + return ; + } + + emit peerConnected(QString::fromStdString(peer_id)); +} +void NotifyQt::notifyPeerDisconnected(const std::string& peer_id) +{ + { + QMutexLocker m(&_mutex) ; + if(!_enabled) + return ; + } + + emit peerDisconnected(QString::fromStdString(peer_id)); +} void NotifyQt::notifyListPreChange(int list, int /*type*/) { diff --git a/retroshare-gui/src/gui/notifyqt.h b/retroshare-gui/src/gui/notifyqt.h index 38e83037e..de0fb7aca 100644 --- a/retroshare-gui/src/gui/notifyqt.h +++ b/retroshare-gui/src/gui/notifyqt.h @@ -60,6 +60,8 @@ class NotifyQt: public QObject, public NotifyClient void setNetworkDialog(NetworkDialog *c) { cDialog = c; } + virtual void notifyPeerConnected(const std::string& /* peer_id */); + virtual void notifyPeerDisconnected(const std::string& /* peer_id */); virtual void notifyListPreChange(int list, int type); virtual void notifyListChange(int list, int type); virtual void notifyErrorMsg(int list, int sev, std::string msg); @@ -121,6 +123,8 @@ class NotifyQt: public QObject, public NotifyClient // It's beneficial to send info to the GUI using signals, because signals are thread-safe // as they get queued by Qt. // + void peerConnected(const QString&) const ; + void peerDisconnected(const QString&) const ; void hashingInfoChanged(const QString&) const ; void filesPreModChanged(bool) const ; void filesPostModChanged(bool) const ; diff --git a/retroshare-gui/src/gui/qss/stylesheet/qss.default b/retroshare-gui/src/gui/qss/stylesheet/qss.default index 3c33a202e..66422a25f 100644 --- a/retroshare-gui/src/gui/qss/stylesheet/qss.default +++ b/retroshare-gui/src/gui/qss/stylesheet/qss.default @@ -156,7 +156,7 @@ MessagesDialog qproperty-textColorInbox: rgb(49, 106, 197); } -FriendList +NewFriendList { qproperty-textColorStatusOffline: black; qproperty-textColorStatusAway: gray; diff --git a/retroshare-gui/src/gui/settings/CryptoPage.cpp b/retroshare-gui/src/gui/settings/CryptoPage.cpp index 9092fa587..3ac626834 100755 --- a/retroshare-gui/src/gui/settings/CryptoPage.cpp +++ b/retroshare-gui/src/gui/settings/CryptoPage.cpp @@ -41,22 +41,25 @@ CryptoPage::CryptoPage(QWidget * parent, Qt::WindowFlags flags) : ConfigPage(parent, flags) { - /* Invoke the Qt Designer generated object setup routine */ - ui.setupUi(this); + /* Invoke the Qt Designer generated object setup routine */ + ui.setupUi(this); -// connect(ui.copykeyButton, SIGNAL(clicked()), this, SLOT(copyPublicKey())); - connect(ui.saveButton, SIGNAL(clicked()), this, SLOT(fileSaveAs())); - connect(ui._includeSignatures_CB, SIGNAL(toggled(bool)), this, SLOT(load())); - connect(ui._includeAllIPs_CB, SIGNAL(toggled(bool)), this, SLOT(load())); - connect(ui._copyLink_PB, SIGNAL(clicked()), this, SLOT(copyRSLink())); - connect(ui.showStats_PB, SIGNAL(clicked()), this, SLOT(showStats())); + ui._shortFormat_CB->setChecked(true); - // hide profile manager as it causes bugs when generating a new profile. - //ui.profile_Button->hide() ; + // connect(ui.copykeyButton, SIGNAL(clicked()), this, SLOT(copyPublicKey())); + connect(ui.saveButton, SIGNAL(clicked()), this, SLOT(fileSaveAs())); + connect(ui._includeSignatures_CB, SIGNAL(toggled(bool)), this, SLOT(load())); + connect(ui._shortFormat_CB, SIGNAL(toggled(bool)), this, SLOT(load())); + connect(ui._includeAllIPs_CB, SIGNAL(toggled(bool)), this, SLOT(load())); + connect(ui._copyLink_PB, SIGNAL(clicked()), this, SLOT(copyRSLink())); + connect(ui.showStats_PB, SIGNAL(clicked()), this, SLOT(showStats())); - connect(ui.createNewNode_PB,SIGNAL(clicked()), this, SLOT(profilemanager())); + // hide profile manager as it causes bugs when generating a new profile. + //ui.profile_Button->hide() ; - ui.onlinesince->setText(DateTime::formatLongDateTime(Rshare::startupTime())); + connect(ui.createNewNode_PB,SIGNAL(clicked()), this, SLOT(profilemanager())); + + ui.onlinesince->setText(DateTime::formatLongDateTime(Rshare::startupTime())); } void CryptoPage::profilemanager() @@ -97,16 +100,21 @@ CryptoPage::~CryptoPage() void CryptoPage::load() { - ui.certplainTextEdit->setPlainText( - QString::fromUtf8( - rsPeers->GetRetroshareInvite( rsPeers->getOwnId(), ui._includeSignatures_CB->isChecked(), ui._includeAllIPs_CB->isChecked() ).c_str() - ) ); + std::string cert ; + + if(ui._shortFormat_CB->isChecked()) + rsPeers->getShortInvite(cert,rsPeers->getOwnId(), true, !ui._includeAllIPs_CB->isChecked()); + else + cert = rsPeers->GetRetroshareInvite( rsPeers->getOwnId(), ui._includeSignatures_CB->isChecked(), ui._includeAllIPs_CB->isChecked() ); + + ui.certplainTextEdit->setPlainText( QString::fromUtf8( cert.c_str() ) ); RsPeerDetails detail; rsPeers->getPeerDetails(rsPeers->getOwnId(),detail); - ui.certplainTextEdit->setToolTip(ConfCertDialog::getCertificateDescription(detail, ui._includeSignatures_CB->isChecked(), ui._includeAllIPs_CB->isChecked() )); + ui.certplainTextEdit->setToolTip(ConfCertDialog::getCertificateDescription(detail, ui._includeSignatures_CB->isChecked(), ui._shortFormat_CB->isChecked(), ui._includeAllIPs_CB->isChecked() )); } + void CryptoPage::copyRSLink() { diff --git a/retroshare-gui/src/gui/settings/CryptoPage.ui b/retroshare-gui/src/gui/settings/CryptoPage.ui index f96b3935a..0e2af06f2 100755 --- a/retroshare-gui/src/gui/settings/CryptoPage.ui +++ b/retroshare-gui/src/gui/settings/CryptoPage.ui @@ -6,7 +6,7 @@ 0 0 - 989 + 1531 678 @@ -460,6 +460,13 @@ + + + + Short format + + + diff --git a/retroshare-gui/src/gui/settings/GeneralPage.cpp b/retroshare-gui/src/gui/settings/GeneralPage.cpp index 67cd4490c..88b3a52bc 100755 --- a/retroshare-gui/src/gui/settings/GeneralPage.cpp +++ b/retroshare-gui/src/gui/settings/GeneralPage.cpp @@ -81,6 +81,13 @@ GeneralPage::GeneralPage(QWidget * parent, Qt::WindowFlags flags) : ui.checkCloseToTray->setChecked(false) ; // default should be false because some systems to not support this. + if(!QSystemTrayIcon::isSystemTrayAvailable()) + { + ui.checkCloseToTray->setChecked(false) ; // default should be false because some systems to not support this. + ui.checkCloseToTray->setToolTip(tr("No Qt-compatible system tray was found on this system.")); + Settings->setCloseToTray(false); + } + /* Connect signals */ connect(ui.useLocalServer, SIGNAL(toggled(bool)), this,SLOT(updateUseLocalServer())) ; connect(ui.idleSpinBox, SIGNAL(valueChanged(int)), this,SLOT(updateMaxTimeBeforeIdle())) ; diff --git a/retroshare-gui/src/gui/settings/ServerPage.cpp b/retroshare-gui/src/gui/settings/ServerPage.cpp index 69f7e69a4..1f178405d 100755 --- a/retroshare-gui/src/gui/settings/ServerPage.cpp +++ b/retroshare-gui/src/gui/settings/ServerPage.cpp @@ -80,28 +80,37 @@ ServerPage::ServerPage(QWidget * parent, Qt::WindowFlags flags) ui.setupUi(this); manager = NULL ; + mOngoingConnectivityCheck = -1; - if(RsAccounts::isTorAuto()) + if(RsAccounts::isHiddenNode()) { - // Here we use absolute numbers instead of consts defined above, because the consts correspond to the tab number *after* this tab removal. + if(RsAccounts::isTorAuto()) + { + // Here we use absolute numbers instead of consts defined above, because the consts correspond to the tab number *after* this tab removal. - ui.tabWidget->removeTab(TAB_RELAYS) ; // remove relays. Not useful in Tor mode. - ui.tabWidget->removeTab(TAB_IP_FILTERS) ; // remove IP filters. Not useful in Tor mode. + ui.tabWidget->removeTab(TAB_RELAYS) ; // remove relays. Not useful in Tor mode. + ui.tabWidget->removeTab(TAB_IP_FILTERS) ; // remove IP filters. Not useful in Tor mode. - ui.hiddenServiceTab->removeTab(TAB_HIDDEN_SERVICE_I2P_BOB) ; // remove the Automatic I2P/BOB tab + ui.hiddenServiceTab->removeTab(TAB_HIDDEN_SERVICE_I2P_BOB) ; // remove the Automatic I2P/BOB tab - ui.hiddenpage_proxyAddress_i2p->hide() ; - ui.hiddenpage_proxyLabel_i2p->hide() ; - ui.hiddenpage_proxyPort_i2p->hide() ; - ui.label_i2p_outgoing->hide() ; - ui.iconlabel_i2p_outgoing->hide() ; - ui.plainTextEdit->hide() ; - ui.hiddenpage_configuration->hide() ; - ui.l_hiddenpage_configuration->hide() ; - ui.hiddenpageInHelpPlainTextEdit->hide() ; + ui.hiddenpage_proxyAddress_i2p->hide() ; + ui.hiddenpage_proxyLabel_i2p->hide() ; + ui.hiddenpage_proxyPort_i2p->hide() ; + ui.label_i2p_outgoing->hide() ; + ui.iconlabel_i2p_outgoing->hide() ; + ui.plainTextEdit->hide() ; + ui.hiddenpage_configuration->hide() ; + ui.l_hiddenpage_configuration->hide() ; + ui.hiddenpageInHelpPlainTextEdit->hide() ; - ui.hiddenpage_outHeader->setText(tr("Tor has been automatically configured by Retroshare. You shouldn't need to change anything here.")) ; - ui.hiddenpage_inHeader->setText(tr("Tor has been automatically configured by Retroshare. You shouldn't need to change anything here.")) ; + ui.hiddenpage_outHeader->setText(tr("Tor has been automatically configured by Retroshare. You shouldn't need to change anything here.")) ; + ui.hiddenpage_inHeader->setText(tr("Tor has been automatically configured by Retroshare. You shouldn't need to change anything here.")) ; + } + } + else + { + ui.hiddenServiceTab->removeTab(TAB_HIDDEN_SERVICE_I2P_BOB); // warning: the order of operation here is very important. + ui.hiddenServiceTab->removeTab(TAB_HIDDEN_SERVICE_INCOMING); } ui.filteredIpsTable->setHorizontalHeaderItem(COLUMN_RANGE,new QTableWidgetItem(tr("IP Range"))) ; diff --git a/retroshare-gui/src/gui/settings/ServerPage.ui b/retroshare-gui/src/gui/settings/ServerPage.ui index 69935ff58..223820604 100755 --- a/retroshare-gui/src/gui/settings/ServerPage.ui +++ b/retroshare-gui/src/gui/settings/ServerPage.ui @@ -7,7 +7,7 @@ 0 0 1283 - 917 + 929 @@ -26,7 +26,7 @@ - 0 + 1 @@ -539,7 +539,7 @@ behind a firewall or a VPN. - 1 + 0 @@ -549,7 +549,7 @@ behind a firewall or a VPN. - <html><head/><body><p>Configure your Tor and I2P SOCKS proxy here. <br/>If you prefer to use BOB to automatically manage I2P check the other tab.</p></body></html> + <html><head/><body><p>Configure your Tor and I2P SOCKS proxy here. It will allow you to also connect </p><p>to hidden nodes.</p></body></html> diff --git a/retroshare-gui/src/gui/statusbar/hashingstatus.cpp b/retroshare-gui/src/gui/statusbar/hashingstatus.cpp index 18686835a..602b36e89 100644 --- a/retroshare-gui/src/gui/statusbar/hashingstatus.cpp +++ b/retroshare-gui/src/gui/statusbar/hashingstatus.cpp @@ -66,6 +66,7 @@ void HashingStatus::updateHashingInfo(const QString& s) { statusHashing->hide() ; hashloader->hide() ; + setToolTip(QString()); movie->stop() ; } else { diff --git a/retroshare-gui/src/main.cpp b/retroshare-gui/src/main.cpp index dc0f413e6..8da9ab0fc 100644 --- a/retroshare-gui/src/main.cpp +++ b/retroshare-gui/src/main.cpp @@ -21,6 +21,7 @@ *******************************************************************************/ #include "util/stacktrace.h" +#include "util/argstream.h" CrashStackTrace gCrashStackTrace; @@ -32,7 +33,6 @@ CrashStackTrace gCrashStackTrace; #include "gui/FriendsDialog.h" #include "gui/GenCertDialog.h" #include "gui/MainWindow.h" -#include "gui/MessengerWindow.h" #include "gui/NetworkDialog.h" #include "gui/NetworkView.h" #include "gui/QuickStartWizard.h" @@ -51,7 +51,11 @@ CrashStackTrace gCrashStackTrace; #include "util/RsGxsUpdateBroadcast.h" #include "util/rsdir.h" #include "util/rstime.h" +#include "retroshare/rsinit.h" +#ifdef MESSENGER_WINDOW +#include "gui/MessengerWindow.h" +#endif #ifdef ENABLE_WEBUI # include "gui/settings/WebuiPage.h" #endif @@ -226,7 +230,36 @@ feenableexcept(FE_INVALID | FE_DIVBYZERO); /* RetroShare Core Objects */ RsInit::InitRsConfig(); - int initResult = RsInit::InitRetroShare(argc, argv); + + RsConfigOptions conf; + + conf.jsonApiPort = 0 ; // disable JSon API at start. The JSonAPI preference UI will enable it according to saved parameters. + + argstream as(argc,argv); + as >> option('s',"stderr" ,conf.outStderr ,"output to stderr instead of log file." ) + >> option('u',"udp" ,conf.udpListenerOnly,"Only listen to UDP." ) + >> parameter('c',"base-dir" ,conf.optBaseDir ,"directory", "Set base directory." ,false) + >> parameter('l',"log-file" ,conf.logfname ,"logfile" ,"Set Log filename." ,false) + >> parameter('d',"debug-level" ,conf.debugLevel ,"level" ,"Set debug level." ,false) + >> parameter('i',"ip-address" ,conf.forcedInetAddress,"nnn.nnn.nnn.nnn", "Force IP address to use (if cannot be detected)." ,false) + >> parameter('p',"port" ,conf.forcedPort ,"port" ,"Set listenning port to use." ,false) + >> parameter('o',"opmode" ,conf.opModeStr ,"opmode" ,"Set Operating mode (Full, NoTurtle, Gaming, Minimal)." ,false); +#ifdef RS_JSONAPI + as >> parameter('J', "jsonApiPort", conf.jsonApiPort, "jsonApiPort", "Enable JSON API on the specified port", false ) + >> parameter('P', "jsonApiBindAddress", conf.jsonApiBindAddress, "jsonApiBindAddress", "JSON API Bind Address.", false); +#endif // ifdef RS_JSONAPI + +#ifdef LOCALNET_TESTING + as >> parameter('R',"restrict-port" ,portRestrictions ,"port1-port2","Apply port restriction" ,false); +#endif // ifdef LOCALNET_TESTING + +#ifdef RS_AUTOLOGIN + as >> option('a',"auto-login" ,conf.autoLogin ,"AutoLogin (Windows Only) + StartMinimised"); +#endif // ifdef RS_AUTOLOGIN + + conf.main_executable_path = argv[0]; + + int initResult = RsInit::InitRetroShare(conf); if(initResult == RS_INIT_NO_KEYRING) // happens when we already have accounts, but no pgp key. This is when switching to the openpgp-sdk version. { @@ -250,7 +283,7 @@ feenableexcept(FE_INVALID | FE_DIVBYZERO); if(!RsAccounts::CopyGnuPGKeyrings()) return 0 ; - initResult = RsInit::InitRetroShare(argc, argv); + initResult = RsInit::InitRetroShare(conf); displayWarningAboutDSAKeys() ; diff --git a/retroshare-gui/src/qss/blacknight.qss b/retroshare-gui/src/qss/blacknight.qss index 3d56385ab..b20649895 100644 --- a/retroshare-gui/src/qss/blacknight.qss +++ b/retroshare-gui/src/qss/blacknight.qss @@ -132,9 +132,9 @@ selection-background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2 background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:1, y2:0, stop:0 rgb(15, 15, 15), stop:0.10 rgb(0, 0, 0), stop:0.90 rgb(0, 0, 0), stop:1 rgb(15, 15, 15)); } QComboBox::down-arrow{ -image: url(:/qss/simple/combobox/arrow.png); -width: 8px; -height: 8px; + image: url(%THISPATH%/blacknight/down.png); + width: 8px; + height: 8px; } QComboBox::drop-down{ width: 20px; @@ -202,10 +202,10 @@ subcontrol-position: top; subcontrol-origin: margin; } QScrollBar::up-arrow:vertical{ -image: url(qss/blacknight/up.png); + image: url(%THISPATH%/blacknight/up.png); } QScrollBar::down-arrow:vertical{ -image: url(qss/blacknight/down.png); + image: url(%THISPATH%/blacknight/down.png); } QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical{ background: none; @@ -216,47 +216,29 @@ spacing: 2px; QCheckBox::!enabled, QRadioButton::!enabled{ color : rgb(50, 50, 50); } -QCheckBox::indicator:unchecked{ -image: url(qss/blacknight/check_unsel.png); -} -QCheckBox::indicator:unchecked:hover{ -image: url(qss/blacknight/check_unsel.png); -} -QCheckBox::indicator:unchecked:pressed{ -image: url(qss/blacknight/check_unsel.png); -} -QCheckBox::indicator:checked{ -image: url(qss/blacknight/check_sel.png); -} -QCheckBox::indicator:checked:hover{ -image: url(qss/blacknight/check_sel.png); -} -QCheckBox::indicator:checked:!enabled{ -image: url(qss/blacknight/check_sel.png); -} +QCheckBox::indicator:unchecked, +QCheckBox::indicator:unchecked:hover, +QCheckBox::indicator:unchecked:pressed, QCheckBox::indicator:unchecked:!enabled{ -image: url(qss/blacknight/check_unsel.png); + image: url(%THISPATH%/blacknight/check_unsel.png); } -QRadioButton::indicator::unchecked{ -image: url(qss/blacknight/radio_unsel.png); -} -QRadioButton::indicator:unchecked:hover{ -image: url(qss/blacknight/radio_unsel.png); +QCheckBox::indicator:checked, +QCheckBox::indicator:checked:hover, +QCheckBox::indicator:checked:!enabled{ + image: url(%THISPATH%/blacknight/check_sel.png); } +QRadioButton::indicator::unchecked, +QRadioButton::indicator:unchecked:hover, QRadioButton::indicator:unchecked:pressed{ -image: url(qss/blacknight/radio_unsel.png); -} -QRadioButton::indicator::checked{ -image: url(qss/blacknight/radio_sel.png); -} -QRadioButton::indicator:checked:hover{ -image: url(qss/blacknight/radio_sel.png); + image: url(%THISPATH%/blacknight/radio_unsel.png); } +QRadioButton::indicator::checked, +QRadioButton::indicator:checked:hover, QRadioButton::indicator:checked:pressed{ -image: url(qss/blacknight/radio_sel.png); + image: url(%THISPATH%/blacknight/radio_sel.png); } QTreeWidget#contactListTree{ -background: black url(qss/blacknight/clbg.png) repeat-y; +background: black url(%THISPATH%/blacknight/clbg.png) repeat-y; } icqTextBrowser, icqTextEdit{ /* diff --git a/retroshare-gui/src/qss/blue.qss b/retroshare-gui/src/qss/blue.qss index 35e5bc7e7..781e885f7 100644 --- a/retroshare-gui/src/qss/blue.qss +++ b/retroshare-gui/src/qss/blue.qss @@ -34,7 +34,7 @@ QWidget#chatcentralwidget{ } QToolBar#chattoolBar{ - border-image: url(qss/blue/blue.png); + border-image: url(%THISPATH%/blue/blue.png); } @@ -42,17 +42,17 @@ QToolBar#chattoolBar{ /* Customize the toolbar. */ QToolBar#toolBarPage { - border-image: url(qss/blue/blue.png); + border-image: url(%THISPATH%/blue/blue.png); } QToolBar#toolBarAction { - border-image: url(qss/blue/blue.png); + border-image: url(%THISPATH%/blue/blue.png); } QTabBar::tab { - border-image: url(qss/blue/tab1.png); + border-image: url(%THISPATH%/blue/tab1.png); min-width: 8ex; padding: 4px; @@ -66,13 +66,13 @@ QTabBar::tab:!selected { QTabBar::tab:selected, QTabBar::tab:hover { - border-image: url(qss/orangesurfer/tab_hover.png); + border-image: url(%THISPATH%/blue/tab_hover.png); } QTabBar::tab:selected { - border-image: url(qss/blue/tabselected.png); + border-image: url(%THISPATH%/blue/tabselected.png); } QPushButton#okButton { @@ -128,13 +128,13 @@ QStatusBar{ QFrame#messengerframetop{ - border-image: url(qss/blue/blue.png); + border-image: url(%THISPATH%/blue/blue.png); } QFrame#Chatbuttonframe{ - border-image: url(qss/blue/blue.png); + border-image: url(%THISPATH%/blue/blue.png); } @@ -169,7 +169,7 @@ QLabel#fromText{ } QSplitter#splitter{ - border-image: url(qss/blue/blue.png); + border-image: url(%THISPATH%/blue/blue.png); } diff --git a/retroshare-gui/src/qss/blue/tab_hover.png b/retroshare-gui/src/qss/blue/tab_hover.png new file mode 100644 index 000000000..1a5fc3ef4 Binary files /dev/null and b/retroshare-gui/src/qss/blue/tab_hover.png differ diff --git a/retroshare-gui/src/qss/orangesurfer.qss b/retroshare-gui/src/qss/orangesurfer.qss index 84ae1c4fd..e7456a5e7 100644 --- a/retroshare-gui/src/qss/orangesurfer.qss +++ b/retroshare-gui/src/qss/orangesurfer.qss @@ -7,7 +7,7 @@ QFrame#titleBarFrame, QFrame#toolBarFrame { - border-image: url(qss/orangesurfer/main.png); + border-image: url(%THISPATH%/orangesurfer/main.png); } HeaderFrame { @@ -27,25 +27,25 @@ QWidget#chatcentralwidget{ } QToolBar#chattoolBar{ - border-image: url(qss/orangesurfer/main.png); + border-image: url(%THISPATH%/orangesurfer/main.png); } /* Customize the toolbar. */ QToolBar#toolBarPage { - border-image: url(qss/orangesurfer/main.png); + border-image: url(%THISPATH%/orangesurfer/main.png); } QToolBar#toolBarAction { - border-image: url(qss/orangesurfer/main.png); + border-image: url(%THISPATH%/orangesurfer/main.png); } QTabBar::tab { - border-image: url(qss/orangesurfer/tab_normal.png); + border-image: url(%THISPATH%/orangesurfer/tab_normal.png); border-top-left-radius: 4px; border-top-right-radius: 4px; min-width: 8ex; @@ -61,13 +61,13 @@ QTabBar::tab:!selected { QTabBar::tab:selected, QTabBar::tab:hover { - border-image: url(qss/orangesurfer/tab_hover.png); + border-image: url(%THISPATH%/orangesurfer/tab_hover.png); } QTabBar::tab:selected { - border-image: url(qss/orangesurfer/tab_pressed.png); + border-image: url(%THISPATH%/orangesurfer/tab_pressed.png); } @@ -105,7 +105,7 @@ QStatusBar{ } QSizeGrip { - image: url(qss/orangesurfer/sizegrip.png); + image: url(%THISPATH%/orangesurfer/sizegrip.png); width: 16px; height: 16px; } @@ -140,7 +140,7 @@ QTreeWidget::item:selected { /* when user selects item using mouse or keyboard * - border-image: url(qss/gofast/border.png); + border-image: url(%THISPATH%/orangesurfer/border.png); } @@ -157,13 +157,13 @@ QTreeView::item:selected { /* when user selects item using mouse or keyboard */ /*background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #F7B552, stop: 1 #FF5E07);*/ - border-image: url(qss/orangesurfer/border.png); + border-image: url(%THISPATH%/orangesurfer/border.png); } QFrame#messengerframetop{ - border-image: url(qss/orangesurfer/main.png); + border-image: url(%THISPATH%/orangesurfer/main.png); /*background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #F7B552, stop: 1 #FF5E07);*/ @@ -171,7 +171,7 @@ QFrame#messengerframetop{ QFrame#Chatbuttonframe{ - border-image: url(qss/orangesurfer/main.png); + border-image: url(%THISPATH%/orangesurfer/main.png); } diff --git a/retroshare-gui/src/qss/qdarkstyle-v2.qss b/retroshare-gui/src/qss/qdarkstyle-v2.qss new file mode 100644 index 000000000..90324f9ab --- /dev/null +++ b/retroshare-gui/src/qss/qdarkstyle-v2.qss @@ -0,0 +1,2048 @@ +/* QDarkStyleSheet -------------------------------------------------------- + +This is the main style sheet, the palette has nine main colors. +It is based on three selecting colors, three greyish (background) colors +plus three whitish (foreground) colors. Each set of widgets of the same +type have a header like this: + + ------------------ + GroupName -------- + ------------------ + +And each widget is separated with a header like this: + + QWidgetName ------ + +This makes more easy to find and change some css field. The basic +configuration is described bellow. + + SELECTION ------------ + + sel_light #179AE0 #148CD2 (selection/hover/active) + sel_normal #3375A3 #1464A0 (selected) + sel_dark #18465D #14506E (selected disabled) + + FOREGROUND ----------- + + for_light #EFF0F1 #F0F0F0 (texts/labels) + for_normal #AAAAAA (not used yet) + for_dark #505F69 #787878 (disabled texts) + + BACKGROUND ----------- + + bac_light #4D545B #505F69 (unpressed) + bac_normal #31363B #32414B (border, disabled, pressed, checked, toolbars, menus) + bac_dark #232629 #19232D (background) + +If a stranger configuration is required because of a bugfix or anything +else, keep the comment on that line to nobodys changed it, including the +issue number. +--------------------------------------------------------------------------- */ + + + +/* QWidget ---------------------------------------------------------------- */ + +QWidget { + background-color: #19232D; + border: 0px solid #32414B; + padding: 0px; + color: #F0F0F0; + selection-background-color: #1464A0; + selection-color: #F0F0F0; +} + +QWidget:disabled { + background-color: #19232D; + color: #787878; + selection-background-color: #14506E; + selection-color: #787878; +} + +QWidget:item:selected { + background-color: #1464A0; +} + +QWidget:item:hover { + background-color: #148CD2; + color: #32414B; +} + +/* QMainWindow ------------------------------------------------------------ */ +/* This adjusts the splitter in the dock widget, not qsplitter */ + + +QMainWindow::separator { + background-color: #32414B; + border: 0 solid #19232D; + spacing: 0; + padding: 2px; +} + +QMainWindow::separator:hover { + background-color: #505F69; + border: 0px solid #148CD2; +} + +QMainWindow::separator:horizontal { + width: 5px; + margin-top: 2px; + margin-bottom: 2px; + image: url(qss/qdarkstyle/rc/Vsepartoolbar.png); +} + +QMainWindow::separator:vertical { + height: 5px; + margin-left: 2px; + margin-right: 2px; + image: url(qss/qdarkstyle/rc/Hsepartoolbar.png); +} + +/* QToolTip --------------------------------------------------------------- */ + +QToolTip { + background-color: #148CD2; + border: 1px solid #19232D; + color: #19232D; + padding: 0; /*remove padding, for fix combo box tooltip*/ + opacity: 230; /*reducing transparency to read better*/ +} + +/* QStatusBar ------------------------------------------------------------- */ + +QStatusBar { + border: 1px solid #32414B; + background: #32414B; /*fixes spyder #9120,#9121*/ +} + +QStatusBar QToolTip { + background-color: #148CD2; + border: 1px solid #19232D; + color: #19232D; + padding: 0; /*remove padding, for fix combo box tooltip*/ + opacity: 230; /*reducing transparency to read better*/ +} + +QStatusBar QLabel { + background-color: transparent; /*fixes spyder #9120,#9121*/ +} + +/* QCheckBox -------------------------------------------------------------- */ + +QCheckBox { + background-color: #19232D; + color: #F0F0F0; + spacing: 4px; + outline: none; + padding-top: 4px; + padding-bottom: 4px; +} + +QCheckBox:focus { + border: none; +} + +QCheckBox QWidget:disabled { + background-color: #19232D; + color: #787878; +} + +QCheckBox::indicator { + margin-left: 4px; + width: 16px; + height: 16px; +} + +QCheckBox::indicator:unchecked { + image: url(qss/qdarkstyle/rc/checkbox_unchecked.png); +} + +QCheckBox::indicator:unchecked:hover, +QCheckBox::indicator:unchecked:focus, +QCheckBox::indicator:unchecked:pressed { + border: none; + image: url(qss/qdarkstyle/rc/checkbox_unchecked_focus.png); +} + +QCheckBox::indicator:unchecked:disabled { + image: url(qss/qdarkstyle/rc/checkbox_unchecked_disabled.png); +} + +QCheckBox::indicator:checked { + image: url(qss/qdarkstyle/rc/checkbox_checked.png); +} + +QCheckBox::indicator:checked:hover, +QCheckBox::indicator:checked:focus, +QCheckBox::indicator:checked:pressed { + border: none; + image: url(qss/qdarkstyle/rc/checkbox_checked_focus.png); +} + +QCheckBox::indicator:checked:disabled{ + image: url(qss/qdarkstyle/rc/checkbox_checked_disabled.png); +} + +QCheckBox::indicator:indeterminate { + image: url(qss/qdarkstyle/rc/checkbox_indeterminate.png); +} + +QCheckBox::indicator:indeterminate:disabled { + image: url(qss/qdarkstyle/rc/checkbox_indeterminate_disabled.png); +} + +QCheckBox::indicator:indeterminate:focus, +QCheckBox::indicator:indeterminate:hover, +QCheckBox::indicator:indeterminate:pressed { + image: url(qss/qdarkstyle/rc/checkbox_indeterminate_focus.png); +} + +/* QGroupBox -------------------------------------------------------------- */ + +QGroupBox { + font-weight: bold; + border: 1px solid #32414B; + border-radius: 4px; + padding: 4px; + margin-top: 16px; +} + + + +QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top left; + left: 3px; + padding-left: 3px; + padding-right: 5px; + padding-top: 8px; + padding-bottom: 16px; +} + +QGroupBox::indicator { + margin-left: 4px; + width: 16px; + height: 16px; +} + +QGroupBox::indicator { + margin-left: 2px; +} + +QGroupBox::indicator:unchecked:hover, +QGroupBox::indicator:unchecked:focus, +QGroupBox::indicator:unchecked:pressed { + border: none; + image: url(qss/qdarkstyle/rc/checkbox_unchecked_focus.png); +} + +QGroupBox::indicator:checked:hover, +QGroupBox::indicator:checked:focus, +QGroupBox::indicator:checked:pressed { + border: none; + image: url(qss/qdarkstyle/rc/checkbox_checked_focus.png); +} + +QGroupBox::indicator:checked:disabled { + image: url(qss/qdarkstyle/rc/checkbox_checked_disabled.png); +} + +QGroupBox::indicator:unchecked:disabled { + image: url(qss/qdarkstyle/rc/checkbox_unchecked_disabled.png); +} + +/* QRadioButton ----------------------------------------------------------- */ + +QRadioButton { + background-color: #19232D; + color: #F0F0F0; + spacing: 0; + padding: 0; + border: none; + outline: none; +} + +QRadioButton:focus { + border: none; +} + +QRadioButton:disabled { + background-color: #19232D; + color: #787878; + border: none; + outline: none; +} + +QRadioButton QWidget { + background-color: #19232D; + color: #F0F0F0; + spacing: 0px; + padding: 0px; + outline: none; + border: none; +} + +QRadioButton::indicator { + border: none; + outline: none; + margin-bottom: 2px; + width: 25px; + height: 25px; +} + +QRadioButton::indicator:unchecked { + image: url(qss/qdarkstyle/rc/radio_unchecked.png); +} + +QRadioButton::indicator:unchecked:hover, +QRadioButton::indicator:unchecked:focus, +QRadioButton::indicator:unchecked:pressed { + border: none; + outline: none; + image: url(qss/qdarkstyle/rc/radio_unchecked_focus.png); +} + +QRadioButton::indicator:checked { + border: none; + outline: none; + image: url(qss/qdarkstyle/rc/radio_checked.png); +} + +QRadioButton::indicator:checked:hover, +QRadioButton::indicator:checked:focus, +QRadioButton::indicator:checked:pressed { + border: none; + outline: none; + image: url(qss/qdarkstyle/rc/radio_checked_focus.png); +} + +QRadioButton::indicator:checked:disabled { + outline: none; + image: url(qss/qdarkstyle/rc/radio_checked_disabled.png); +} + +QRadioButton::indicator:unchecked:disabled { + image: url(qss/qdarkstyle/rc/radio_unchecked_disabled.png); +} + +/* QMenuBar --------------------------------------------------------------- */ + +QMenuBar { + background-color: #32414B; + padding: 2px; + border: 1px solid #19232D; + color: #F0F0F0; +} + +QMenuBar:focus { + border: 1px solid #148CD2; +} + +QMenuBar::item { + background: transparent; + padding: 4px; +} + +QMenuBar::item:selected { + padding: 4px; + background: transparent; + border: 0px solid #32414B; +} + +QMenuBar::item:pressed { + padding: 4px; + border: 0px solid #32414B; + background-color: #148CD2; + color: #F0F0F0; + margin-bottom: 0px; + padding-bottom: 0px; +} + +/* QMenu ------------------------------------------------------------------ */ + +QMenu { + border: 0px solid #32414B; + color: #F0F0F0; + margin: 0px; +} + +QMenu::separator { + height: 2px; + background-color: #505F69; + color: #F0F0F0; + padding-left: 4px; + margin-left: 2px; + margin-right: 2px; +} + +QMenu::icon { + margin: 0px; + padding-left:4px; +} + +QMenu::item { + padding: 4px 24px 4px 24px; + border: 1px transparent #32414B; /* reserve space for selection border */ +} + +QMenu::item:selected { + color: #F0F0F0; +} + + + +QMenu::indicator { + width: 12px; + height: 12px; + padding-left:6px; +} + +/* non-exclusive indicator = check box style indicator (see QActionGroup::setExclusive) */ + +QMenu::indicator:non-exclusive:unchecked { + image: url(qss/qdarkstyle/rc/checkbox_unchecked.png); +} + +QMenu::indicator:non-exclusive:unchecked:selected { + image: url(qss/qdarkstyle/rc/checkbox_unchecked_disabled.png); +} + +QMenu::indicator:non-exclusive:checked { + image: url(qss/qdarkstyle/rc/checkbox_checked.png); +} + +QMenu::indicator:non-exclusive:checked:selected { + image: url(qss/qdarkstyle/rc/checkbox_checked_disabled.png); +} + +/* exclusive indicator = radio button style indicator (see QActionGroup::setExclusive) */ + +QMenu::indicator:exclusive:unchecked { + image: url(qss/qdarkstyle/rc/radio_unchecked.png); +} + +QMenu::indicator:exclusive:unchecked:selected { + image: url(qss/qdarkstyle/rc/radio_unchecked_disabled.png); +} + +QMenu::indicator:exclusive:checked { + image: url(qss/qdarkstyle/rc/radio_checked.png); +} + +QMenu::indicator:exclusive:checked:selected { + image: url(qss/qdarkstyle/rc/radio_checked_disabled.png); +} + +QMenu::right-arrow { + margin: 5px; + image: url(qss/qdarkstyle/rc/right_arrow.png) +} + +/* QAbstractItemView ------------------------------------------------------ */ + +QAbstractItemView { + alternate-background-color: #19232D; + color: #F0F0F0; + border: 1px solid #32414B; + border-radius: 4px; +} + +QAbstractItemView QLineEdit { + padding: 2px; +} + +/* QAbstractScrollArea ---------------------------------------------------- */ + +QAbstractScrollArea { + background-color: #19232D; + border: 1px solid #32414B; + border-radius: 4px; + padding: 4px; + color: #F0F0F0; +} + +QAbstractScrollArea:disabled { + color: #787878; +} + +/* QScrollArea ------------------------------------------------------------ */ + +QScrollArea QWidget QWidget:disabled { + background-color: #19232D; +} + +/* QScrollBar ------------------------------------------------------------- */ + +QScrollBar:horizontal { + height: 16px; + margin: 2px 16px 2px 16px; + border: 1px solid #32414B; + border-radius: 4px; + background-color: #19232D; +} + +QScrollBar::handle:horizontal { + background-color: #787878; + border: 1px solid #32414B; + border-radius: 4px; + min-width: 8px; + +} + +QScrollBar::handle:horizontal:hover { + background-color: #148CD2; + border: 1px solid #148CD2; + border-radius: 4px; + min-width: 8px; +} + +QScrollBar::add-line:horizontal { + margin: 0px 0px 0px 0px; + border-image: url(qss/qdarkstyle/rc/right_arrow_disabled.png); + width: 10px; + height: 10px; + subcontrol-position: right; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:horizontal { + margin: 0px 3px 0px 3px; + border-image: url(qss/qdarkstyle/rc/left_arrow_disabled.png); + height: 10px; + width: 10px; + subcontrol-position: left; + subcontrol-origin: margin; +} + +QScrollBar::add-line:horizontal:hover, +QScrollBar::add-line:horizontal:on { + border-image: url(qss/qdarkstyle/rc/right_arrow.png); + height: 10px; + width: 10px; + subcontrol-position: right; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:horizontal:hover, +QScrollBar::sub-line:horizontal:on { + border-image: url(qss/qdarkstyle/rc/left_arrow.png); + height: 10px; + width: 10px; + subcontrol-position: left; + subcontrol-origin: margin; +} + +QScrollBar::up-arrow:horizontal, +QScrollBar::down-arrow:horizontal { + background: none; +} + +QScrollBar::add-page:horizontal, +QScrollBar::sub-page:horizontal { + background: none; +} + +QScrollBar:vertical { + background-color: #19232D; + width: 16px; + margin: 16px 2px 16px 2px; + border: 1px solid #32414B; + border-radius: 4px; +} + +QScrollBar::handle:vertical { + background-color: #787878; + border: 1px solid #32414B; + min-height: 8px; + border-radius: 4px; +} + +QScrollBar::handle:vertical:hover { + background-color: #148CD2; + border: 1px solid #148CD2; + border-radius: 4px; + min-height: 8px; + +} + +QScrollBar::sub-line:vertical { + margin: 3px 0px 3px 0px; + border-image: url(qss/qdarkstyle/rc/up_arrow_disabled.png); + height: 10px; + width: 10px; + subcontrol-position: top; + subcontrol-origin: margin; +} + +QScrollBar::add-line:vertical { + margin: 3px 0px 3px 0px; + border-image: url(qss/qdarkstyle/rc/down_arrow_disabled.png); + height: 10px; + width: 10px; + subcontrol-position: bottom; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:vertical:hover, +QScrollBar::sub-line:vertical:on { + border-image: url(qss/qdarkstyle/rc/up_arrow.png); + height: 10px; + width: 10px; + subcontrol-position: top; + subcontrol-origin: margin; +} + +QScrollBar::add-line:vertical:hover, +QScrollBar::add-line:vertical:on { + border-image: url(qss/qdarkstyle/rc/down_arrow.png); + height: 10px; + width: 10px; + subcontrol-position: bottom; + subcontrol-origin: margin; +} + +QScrollBar::up-arrow:vertical, +QScrollBar::down-arrow:vertical { + background: none; +} + +QScrollBar::add-page:vertical, +QScrollBar::sub-page:vertical { + background: none; +} + +/* QTextEdit--------------------------------------------------------------- */ + +QTextEdit { + background-color: #19232D; + color: #F0F0F0; + border: 1px solid #32414B; +} + +QTextEdit:hover { + border: 1px solid #148CD2; + color: #F0F0F0; +} + +QTextEdit:selected { + background: #1464A0; + color: #32414B; +} + +/* QPlainTextEdit --------------------------------------------------------- */ + +QPlainTextEdit { + background-color: #19232D; + color: #F0F0F0; + border-radius: 4px; + border: 1px solid #32414B; +} + +QPlainTextEdit:hover { + border: 1px solid #148CD2; + color: #F0F0F0; +} + +QPlainTextEdit:selected { + background: #1464A0; + color: #32414B; +} + +/* QSizeGrip --------------------------------------------------------------- */ + +QSizeGrip { + image: url(qss/qdarkstyle/rc/sizegrip.png); + width: 12px; + height: 12px; +} + +/* QStackedWidget --------------------------------------------------------- */ + +QStackedWidget { + padding: 4px; + border: 1px solid #32414B; + border: 1px solid #19232D; +} + +/* QToolBar --------------------------------------------------------------- */ + +QToolBar { + background-color: #32414B; + border-bottom: 1px solid #19232D; + padding: 2px; + font-weight: bold; +} + +QToolBar QToolButton{ + background-color: #32414B; +} + +QToolBar::handle:horizontal { + width: 6px; + image: url(qss/qdarkstyle/rc/Hmovetoolbar.png); +} + +QToolBar::handle:vertical { + height: 6px; + image: url(qss/qdarkstyle/rc/Vmovetoolbar.png); +} + +QToolBar::separator:horizontal { + width: 3px; + image: url(qss/qdarkstyle/rc/Hsepartoolbar.png); +} + +QToolBar::separator:vertical { + height: 3px; + image: url(qss/qdarkstyle/rc/Vsepartoolbar.png); +} + +QToolButton#qt_toolbar_ext_button { + background: #32414B; + border: 0px; + color: #F0F0F0; + image: url(qss/qdarkstyle/rc/right_arrow.png); +} + +/* QAbstractSpinBox ------------------------------------------------------- */ + +QAbstractSpinBox { + background-color: #19232D; + border: 1px solid #32414B; + color: #F0F0F0; + padding-top: 2px; /* This fix 103, 111*/ + padding-bottom: 2px; /* This fix 103, 111*/ + padding-left: 4px; + padding-right: 4px; + border-radius: 4px; + /* min-width: 5px; removed to fix 109 */ +} + +QAbstractSpinBox:up-button { + background-color: transparent #19232D; + subcontrol-origin: border; + subcontrol-position: top right; + border-left: 1px solid #32414B; + margin: 1px; +} + +QAbstractSpinBox::up-arrow, +QAbstractSpinBox::up-arrow:disabled, +QAbstractSpinBox::up-arrow:off { + image: url(qss/qdarkstyle/rc/up_arrow_disabled.png); + width: 9px; + height: 9px; +} + +QAbstractSpinBox::up-arrow:hover { + image: url(qss/qdarkstyle/rc/up_arrow.png); +} + +QAbstractSpinBox:down-button { + background-color: transparent #19232D; + subcontrol-origin: border; + subcontrol-position: bottom right; + border-left: 1px solid #32414B; + margin: 1px; +} + +QAbstractSpinBox::down-arrow, +QAbstractSpinBox::down-arrow:disabled, +QAbstractSpinBox::down-arrow:off { + image: url(qss/qdarkstyle/rc/down_arrow_disabled.png); + width: 9px; + height: 9px; +} + +QAbstractSpinBox::down-arrow:hover { + image: url(qss/qdarkstyle/rc/down_arrow.png); +} + +QAbstractSpinBox:hover{ + border: 1px solid #148CD2; + color: #F0F0F0; +} + +QAbstractSpinBox:selected { + background: #1464A0; + color: #32414B; +} + +/* ------------------------------------------------------------------------ */ +/* DISPLAYS --------------------------------------------------------------- */ +/* ------------------------------------------------------------------------ */ + +/* QLabel ----------------------------------------------------------------- */ + +QLabel { + background-color: #19232D; + border: 0px solid #32414B; + padding: 2px; + margin: 0px; + color: #F0F0F0 +} + +QLabel::disabled { + background-color: #19232D; + border: 0px solid #32414B; + color: #787878; +} + +/* QTextBrowser ----------------------------------------------------------- */ + +QTextBrowser { + background-color: #19232D; + border: 1px solid #32414B; + color: #F0F0F0; + border-radius: 4px; +} + +QTextBrowser:disabled { + background-color: #19232D; + border: 1px solid #32414B; + color: #787878; + border-radius: 4px; +} + +QTextBrowser:hover, +QTextBrowser:!hover, +QTextBrowser::selected, +QTextBrowser::pressed { + border: 1px solid #32414B; +} + +/* QGraphicsView --------------------------------------------------------- */ + +QGraphicsView { + background-color: #19232D; + border: 1px solid #32414B; + color: #F0F0F0; + border-radius: 4px; +} + +QGraphicsView:disabled { + background-color: #19232D; + border: 1px solid #32414B; + color: #787878; + border-radius: 4px; +} + +QGraphicsView:hover, +QGraphicsView:!hover, +QGraphicsView::selected, +QGraphicsView::pressed { + border: 1px solid #32414B; +} + +/* QCalendarWidget -------------------------------------------------------- */ + +QCalendarWidget { + border: 1px solid #32414B; + border-radius: 4px; +} + +QCalendarWidget:disabled { + background-color: #19232D; + color: #787878; +} + +/* QLCDNumber ------------------------------------------------------------- */ + +QLCDNumber { + background-color: #19232D; + color: #F0F0F0; +} + +QLCDNumber:disabled { + background-color: #19232D; + color: #787878; +} + +/* QProgressBar ----------------------------------------------------------- */ + +QProgressBar { + background-color: #19232D; + border: 1px solid #32414B; + color: #F0F0F0; + border-radius: 4px; + text-align: center; +} + +QProgressBar:disabled { + background-color: #19232D; + border: 1px solid #32414B; + color: #787878; + border-radius: 4px; + text-align: center; +} + +QProgressBar::chunk { + background-color: #1464A0; + color: #19232D; + border-radius: 4px; +} + +QProgressBar::chunk:disabled { + background-color: #14506E; + color: #787878; + border-radius: 4px; +} + + +/* ------------------------------------------------------------------------ */ +/* BUTTONS ---------------------------------------------------------------- */ +/* ------------------------------------------------------------------------ */ + +/* QPushButton ------------------------------------------------------------ */ + +QPushButton { + background-color: #505F69 ; + border: 1px solid #32414B; + color: #F0F0F0; + border-radius: 4px; + padding: 3px; + outline: none; +} + +QPushButton:disabled { + background-color: #32414B; + border: 1px solid #32414B; + color: #787878; + border-radius: 4px; + padding: 3px; +} + + +QPushButton:checked { + background-color: #32414B; + border: 1px solid #32414B; + border-radius: 4px; + padding: 3px; + outline: none; +} + +QPushButton:checked:disabled { + background-color: #19232D; + border: 1px solid #32414B; + color: #787878; + border-radius: 4px; + padding: 3px; + outline: none; +} + +QPushButton::menu-indicator { + subcontrol-origin: padding; + subcontrol-position: bottom right; + bottom: 4px; +} + +QPushButton:pressed { + background-color: #19232D; + border: 1px solid #19232D; +} + +QPushButton:hover, +QPushButton:checked:hover{ + border: 1px solid #148CD2; + color: #F0F0F0; +} + +QPushButton:pressed:hover{ + border: 1px solid #1464A0; +} + +QPushButton:selected, +QPushButton:checked:selected{ + background: #1464A0; + color: #32414B; +} + +/* QToolButton ------------------------------------------------------------ */ + +QToolButton { + background-color: transparent; + border: 1px solid #32414B; + border-radius: 4px; + margin: 0px; + padding: 2px; +} + +QToolButton:checked { + background-color: #19232D; + border: 1px solid #19232D; +} + +QToolButton:pressed { + background-color: #19232D; + border: 1px solid #19232D; + +} + +QToolButton:disabled { + border: 1px solid #32414B; +} + +QToolButton:hover, +QToolButton:checked:hover{ + border: 1px solid #148CD2; +} +QToolButton:pressed:hover{ + border: 1px solid #1464A0; +} + +/* the subcontrols below are used only in the MenuButtonPopup mode */ + +QToolButton[popupMode="1"] { + padding: 2px; + padding-right: 12px; /* only for MenuButtonPopup */ + border: 1px solid #32414B; /* make way for the popup button */ + border-radius: 4px; +} + +/* The subcontrol below is used only in the InstantPopup or DelayedPopup mode */ + +QToolButton[popupMode="2"] { + padding: 2px; + padding-right: 12px; /* only for InstantPopup */ + border: 1px solid #32414B; /* make way for the popup button */ +} + +QToolButton::menu-button { + padding: 2px; + border-radius: 4px; + border: 1px solid #32414B; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + /* 16px width + 4px for border = 20px allocated above */ + width: 16px; + outline: none; +} + +QToolButton::menu-button:hover, +QToolButton::menu-button:checked:hover { + border: 1px solid #148CD2; +} + +QToolButton::menu-indicator { + image: url(qss/qdarkstyle/rc/down_arrow.png); + top: -8px; /* shift it a bit */ + left: -4px; /* shift it a bit */ +} + +QToolButton::menu-arrow { + image: url(qss/qdarkstyle/rc/down_arrow.png); +} + +QToolButton::menu-arrow:open { + border: 1px solid #32414B; +} + +/* QCommandLinkButton ----------------------------------------------------- */ + +QCommandLinkButton { + background-color: transparent; + border: 1px solid #32414B; + color: #F0F0F0; + border-radius: 4px; + padding: 0px; + margin: 0px; +} + +QCommandLinkButton:disabled { + background-color: transparent; + color: #787878; +} + +/* ------------------------------------------------------------------------ */ +/* INPUTS - NO FIELDS ----------------------------------------------------- */ +/* ------------------------------------------------------------------------ */ + +/* QCombobox -------------------------------------------------------------- */ +QComboBox { + border: 1px solid #32414B; + border-radius: 4px; + selection-background-color: #1464A0; + padding-left: 4px; + padding-right: 4px; + min-height: 1.5em; /* fix #103, #111 */ + /* padding-top: 2px; removed to fix #132 */ + /* padding-bottom: 2px; removed to fix #132 */ + /* min-width: 75px; removed to fix #109 */ +} + +QComboBox QAbstractItemView { + background-color: #19232d; + border-radius: 4px; + border: 1px solid #32414B; + selection-color: #148CD2; + selection-background-color: #32414B; +} + +QComboBox:disabled { + background-color: #19232D; + color: #787878; +} + +QComboBox:hover{ + border: 1px solid #148CD2; +} + +QComboBox:on { + selection-background-color: #19232D; +} + +/* Needed to remove indicator - fix #132 */ +QComboBox::indicator { + background-color:transparent; + selection-background-color:transparent; + color:transparent; + selection-color:transparent; +} + +/* Needed to remove indicator - fix #132 */ +QComboBox::item:alternate { + background: #19232D; +} + +QComboBox::item:checked { + font-weight: bold; +} + +QComboBox::item:selected { + border: 0px solid transparent; +} + +QComboBox::drop-down { + subcontrol-origin: padding; + subcontrol-position: top right; + width: 20px; + border-left-width: 0px; + border-left-color: #32414B; + border-left-style: solid; + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; +} + +QComboBox::down-arrow { + image: url(qss/qdarkstyle/rc/down_arrow_disabled.png); +} + +QComboBox::down-arrow:on, +QComboBox::down-arrow:hover, +QComboBox::down-arrow:focus { + image: url(qss/qdarkstyle/rc/down_arrow.png); +} + +/* QSlider ---------------------------------------------------------------- */ + +QSlider:disabled { + background: #19232D; +} + +QSlider:focus { + border: none; +} + +QSlider::groove:horizontal { + background: #32414B; + border: 1px solid #32414B; + height: 4px; + margin: 0px; + border-radius: 4px; +} + +QSlider::sub-page:horizontal { + background: #1464A0; + border: 1px solid #32414B; + height: 4px; + margin: 0px; + border-radius: 4px; +} + +QSlider::sub-page:horizontal:disabled { + background: #14506E; +} + +QSlider::handle:horizontal { + background: #787878; + border: 1px solid #32414B; + width: 8px; + height: 8px; + margin: -8px 0; + border-radius: 4px; +} + +QSlider::handle:horizontal:hover { + background: #148CD2; + border: 1px solid #148CD2; +} + +QSlider::groove:vertical { + background: #32414B; + border: 1px solid #32414B; + width: 4px; + margin: 0px; + border-radius: 4px; +} + +QSlider::sub-page:vertical { + background: #1464A0; + border: 1px solid #32414B; + width: 4px; + margin: 0px; + border-radius: 4px; +} + +QSlider::sub-page:vertical:disabled { + background: #14506E; +} + +QSlider::handle:vertical { + background: #787878; + border: 1px solid #32414B; + width: 8px; + height: 8px; + margin: 0 -8px; + border-radius: 4px; +} + +QSlider::handle:vertical:hover { + background: #148CD2; + border: 1px solid #148CD2; +} + +/* QLine ------------------------------------------------------------------ */ + +QLineEdit { + background-color: #19232D; + padding-top: 2px; /* This QLineEdit fix 103, 111 */ + padding-bottom: 2px; /* This QLineEdit fix 103, 111 */ + padding-left: 4px; + padding-right: 4px; + border-style: solid; + border: 1px solid #32414B; + border-radius: 4px; + color: #F0F0F0; +} + +QLineEdit:disabled { + background-color: #19232D; + color: #787878; +} + +QLineEdit:hover{ + border: 1px solid #148CD2; + color: #F0F0F0; +} + +QLineEdit:selected{ + background: #1464A0; + color: #32414B; +} + +/* QTabWiget -------------------------------------------------------------- */ + +QTabWidget { + padding: 2px; + selection-background-color: #32414B; +} + + +QTabWidget QWidget QWidget /* add wanted borders fix #141, #126, #123 */ +QTabWidget QFrame { + border: 1px solid #32414B; +} + +QTabWidget QLabel { + border: 0px solid #32414B; /* label derived from frame, remove border #141 */ +} + +QTabWidget::pane { + border: 1px solid #32414B; + border-radius: 4px; + padding: 0px; /* fixes double border inside pane wit pyqt5 */ + margin: 0px; +} + +QTabWidget::pane:selected { + background-color: #32414B; + border: 1px solid #1464A0; +} + +/* QTabBar ---------------------------------------------------------------- */ + +QTabBar { + qproperty-drawBase: 0; + border-radius: 4px; + margin: 0px; + padding: 2px; + border: 0; + + /* left: 5px; move to the right by 5px - removed for fix */ + } + +QTabBar::close-button { + border: 0; + margin: 2px; + padding: 0; + image: url(qss/qdarkstyle/rc/close.png); +} + +QTabBar::close-button:hover { + image: url(qss/qdarkstyle/rc/close-hover.png); +} + +QTabBar::close-button:pressed { + image: url(qss/qdarkstyle/rc/close-pressed.png); +} + +/* QTabBar::tab - selected ----------------------------------------------- */ + +QTabBar::tab:top:selected:disabled { + border-bottom: 3px solid #14506E; + color: #787878; + background-color: #32414B; +} + +QTabBar::tab:bottom:selected:disabled { + border-top: 3px solid #14506E; + color: #787878; + background-color: #32414B; +} + +QTabBar::tab:left:selected:disabled { + border-left: 3px solid #14506E; + color: #787878; + background-color: #32414B; +} + +QTabBar::tab:right:selected:disabled { + border-right: 3px solid #14506E; + color: #787878; + background-color: #32414B; +} + +/* QTabBar::tab - !selected and disabled ---------------------------------- */ + +QTabBar::tab:top:!selected:disabled { + border-bottom: 3px solid #19232D; + color: #787878; + background-color: #19232D; +} + +QTabBar::tab:bottom:!selected:disabled { + border-top: 3px solid #19232D; + color: #787878; + background-color: #19232D; +} + +QTabBar::tab:left:!selected:disabled { + border-right: 3px solid #19232D; + color: #787878; + background-color: #19232D; +} + +QTabBar::tab:right:!selected:disabled { + border-left: 3px solid #19232D; + color: #787878; + background-color: #19232D; +} + +/* QTabBar::tab - selected ----------------------------------------------- */ + +QTabBar::tab:top:!selected { + border-bottom: 2px solid #19232D; + margin-top: 2px; +} + +QTabBar::tab:bottom:!selected { + border-top: 2px solid #19232D; + margin-bottom: 3px; +} + +QTabBar::tab:left:!selected { + border-left: 2px solid #19232D; + margin-right: 2px; +} + +QTabBar::tab:right:!selected { + border-right: 2px solid #19232D; + margin-left: 2px; +} + + +QTabBar::tab:top { + background-color: #32414B; + color: #F0F0F0; + margin-left: 2px; + padding-left: 4px; + padding-right: 4px; + padding-top: 2px; + padding-bottom: 2px; + min-width: 5px; + border-bottom: 3px solid #32414B; + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} + +QTabBar::tab:top:selected { + background-color: #505F69; + color: #F0F0F0; + border-bottom: 3px solid #1464A0; + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} + +QTabBar::tab:top:!selected:hover { + border: 1px solid #148CD2; + border-bottom: 3px solid #148CD2; + padding: 0px; +} + +QTabBar::tab:bottom { + color: #F0F0F0; + border-top: 3px solid #32414B; + background-color: #32414B; + margin-left: 2px; + padding-left: 4px; + padding-right: 4px; + padding-top: 2px; + padding-bottom: 2px; + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; + min-width: 5px; +} + +QTabBar::tab:bottom:selected { + color: #F0F0F0; + background-color: #505F69; + border-top: 3px solid #1464A0; + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; +} + +QTabBar::tab:bottom:!selected:hover { + border: 1px solid #148CD2; + border-top: 3px solid #148CD2; + padding: 0px; +} + +QTabBar::tab:left { + color: #F0F0F0; + background-color: #32414B; + margin-top: 2px; + padding-left: 2px; + padding-right: 2px; + padding-top: 4px; + padding-bottom: 4px; + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; + min-height: 5px; +} + +QTabBar::tab:left:selected { + color: #F0F0F0; + background-color: #505F69; + border-left: 3px solid #1464A0; + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; +} + +QTabBar::tab:left:!selected:hover { + border: 1px solid #148CD2; + border-left: 3px solid #148CD2; + padding: 0px; +} + +QTabBar::tab:right { + color: #F0F0F0; + background-color: #32414B; + margin-top: 2px; + padding-left: 2px; + padding-right: 2px; + padding-top: 4px; + padding-bottom: 4px; + border-top-left-radius: 3px; + border-bottom-left-radius: 3px; + min-height: 5px; +} + +QTabBar::tab:right:selected { + color: #F0F0F0; + background-color: #505F69; + border-right: 3px solid #1464A0; + border-top-left-radius: 3px; + border-bottom-left-radius: 3px; +} + +QTabBar::tab:right:!selected:hover { + border: 1px solid #148CD2; + border-right: 3px solid #148CD2; + padding: 0px; +} + +QTabBar QToolButton::right-arrow:enabled { + image: url(qss/qdarkstyle/rc/right_arrow.png); +} + +QTabBar QToolButton::left-arrow:enabled { + image: url(qss/qdarkstyle/rc/left_arrow.png); +} + +QTabBar QToolButton::right-arrow:disabled { + image: url(qss/qdarkstyle/rc/right_arrow_disabled.png); +} + +QTabBar QToolButton::left-arrow:disabled { + image: url(qss/qdarkstyle/rc/left_arrow_disabled.png); +} + +QTabBar QToolButton{ + background-color: #32414B; /* fixes #136 */ + width: 16px; + height: 16px; +} + +/* QDockWiget ------------------------------------------------------------- */ + +QDockWidget { + outline: 1px solid #32414B; + background-color: #19232D; + border: 1px solid #32414B; + border-radius: 4px; + titlebar-close-icon: url(qss/qdarkstyle/rc/close.png); + titlebar-normal-icon: url(qss/qdarkstyle/rc/undock.png); +} + +QDockWidget::title { + padding: 6px; /* better size for title bar */ + border: none; + background-color: #32414B; +} + +QDockWidget::close-button { + background-color: #32414B; + border-radius: 4px; + border: none; +} + +QDockWidget::close-button:hover { + border: 1px solid #32414B; +} + +QDockWidget::close-button:pressed { + border: 1px solid #32414B; +} + +QDockWidget::float-button { + background-color: #32414B; + border-radius: 4px; + border: none; +} + +QDockWidget::float-button:hover { + border: 1px solid #32414B; +} + +QDockWidget::float-button:pressed { + border: 1px solid #32414B; +} + + +/* QTreeView QTableView QListView ----------------------------------------- */ + +QTreeView:branch:selected, +QTreeView:branch:hover { + background: url(qss/qdarkstyle/rc/transparent.png); +} + +QTreeView::branch:has-siblings:!adjoins-item { + border-image: url(qss/qdarkstyle/rc/transparent.png); +} + +QTreeView::branch:has-siblings:adjoins-item { + border-image: url(qss/qdarkstyle/rc/transparent.png); +} + +QTreeView::branch:!has-children:!has-siblings:adjoins-item { + border-image: url(qss/qdarkstyle/rc/transparent.png); +} + +QTreeView::branch:has-children:!has-siblings:closed, +QTreeView::branch:closed:has-children:has-siblings { + image: url(qss/qdarkstyle/rc/branch_closed.png); +} + +QTreeView::branch:open:has-children:!has-siblings, +QTreeView::branch:open:has-children:has-siblings { + image: url(qss/qdarkstyle/rc/branch_open.png); +} + +QTreeView::branch:has-children:!has-siblings:closed:hover, +QTreeView::branch:closed:has-children:has-siblings:hover { + image: url(qss/qdarkstyle/rc/branch_closed-on.png); +} + +QTreeView::branch:open:has-children:!has-siblings:hover, +QTreeView::branch:open:has-children:has-siblings:hover { + image: url(qss/qdarkstyle/rc/branch_open-on.png); +} + +QListView::item:!selected:hover, +QTreeView::item:!selected:hover, +QTableView::item:!selected:hover, +QColumnView::item:!selected:hover { + outline: 0; + color: #148CD2; + background-color: #32414B; +} + +QListView::item:selected:hover, +QTreeView::item:selected:hover, +QTableView::item:selected:hover, +QColumnView::item:selected:hover { + background: #1464A0; + color: #19232D; +} + +QTreeView::indicator:checked, +QListView::indicator:checked { + image: url(qss/qdarkstyle/rc/checkbox_checked.png); +} + +QTreeView::indicator:unchecked, +QListView::indicator:unchecked { + image: url(qss/qdarkstyle/rc/checkbox_unchecked.png); +} + +QTreeView::indicator:checked:hover, +QTreeView::indicator:checked:focus, +QTreeView::indicator:checked:pressed, +QListView::indicator:checked:hover, +QListView::indicator:checked:focus, +QListView::indicator:checked:pressed { + image: url(qss/qdarkstyle/rc/checkbox_checked_focus.png); +} + +QTreeView::indicator:unchecked:hover, +QTreeView::indicator:unchecked:focus, +QTreeView::indicator:unchecked:pressed, +QListView::indicator:unchecked:hover, +QListView::indicator:unchecked:focus, +QListView::indicator:unchecked:pressed { + image: url(qss/qdarkstyle/rc/checkbox_unchecked_focus.png); +} + +QTreeView::indicator:indeterminate:hover, +QTreeView::indicator:indeterminate:focus, +QTreeView::indicator:indeterminate:pressed, +QListView::indicator:indeterminate:hover, +QListView::indicator:indeterminate:focus, +QListView::indicator:indeterminate:pressed { + image: url(qss/qdarkstyle/rc/checkbox_indeterminate_focus.png); +} + +QTreeView::indicator:indeterminate, +QListView::indicator:indeterminate { + image: url(qss/qdarkstyle/rc/checkbox_indeterminate.png); +} + +QListView, +QTreeView, +QTableView, +QColumnView { + background-color: #19232D; + border: 1px solid #32414B; + color: #F0F0F0; + gridline-color: #32414B; + border-radius: 4px; +} + +QListView:disabled, +QTreeView:disabled, +QTableView:disabled, +QColumnView:disabled { + background-color: #19232D; + color: #787878; +} + +QListView:selected, +QTreeView:selected, +QTableView:selected, +QColumnView:selected { + background: #1464A0; + color: #32414B; +} + +QListView:hover, +QTreeView::hover, +QTableView::hover, +QColumnView::hover { + background-color: #19232D; + border: 1px solid #148CD2; +} + +QListView::item:pressed, +QTreeView::item:pressed, +QTableView::item:pressed, +QColumnView::item:pressed { + background-color: #1464A0; +} + +QListView::item:selected:active, +QTreeView::item:selected:active, +QTableView::item:selected:active, +QColumnView::item:selected:active { + background-color: #1464A0; +} + +QTableCornerButton::section { + background-color: #19232D; + border: 1px transparent #32414B; + border-radius: 0px; +} + +/* QHeaderView ------------------------------------------------------------ */ + +QHeaderView { + background-color: #32414B; + border: 0px transparent #32414B; + padding: 0px; + margin: 0px; + border-radius: 0px; +} + +QHeaderView:disabled { + background-color: #32414B; + border: 1px transparent #32414B; + padding: 2px; +} + +QHeaderView::section { + background-color: #32414B; + color: #F0F0F0; + padding: 2px; + border-radius: 0px; + text-align: left; +} + +QHeaderView::section:checked { + color: #F0F0F0; + background-color: #1464A0; +} + +QHeaderView::section:checked:disabled { + color: #787878; + background-color: #14506E; +} + +QHeaderView::section::horizontal:disabled, +QHeaderView::section::vertical:disabled { + color: #787878; +} + +QHeaderView::section::vertical::first, +QHeaderView::section::vertical::only-one { + border-top: 1px solid #32414B; +} + +QHeaderView::section::vertical { + border-top: 1px solid #19232D; +} + +QHeaderView::section::horizontal::first, +QHeaderView::section::horizontal::only-one { + border-left: 1px solid #32414B; +} + +QHeaderView::section::horizontal { + border-left: 1px solid #19232D; +} + +/* Those settings (border/width/height/background-color) solve bug */ +/* transparent arrow background and size */ + +QHeaderView::down-arrow { + background-color: #32414B; + width: 16px; + height: 16px; + border-right: 1px solid #19232D; + image: url(qss/qdarkstyle/rc/down_arrow.png); +} + +QHeaderView::up-arrow { + background-color: #32414B; + width: 16px; + height: 16px; + border-right: 1px solid #19232D; + image: url(qss/qdarkstyle/rc/up_arrow.png); +} + +/* QToolBox -------------------------------------------------------------- */ + +QToolBox { + padding: 0px; + border: 1px solid #32414B; +} + +QToolBox::selected { + padding: 0px; + border: 2px solid #1464A0; +} + +QToolBox::tab { + background-color: #19232D; + border: 1px solid #32414B; + color: #F0F0F0; + border-top-left-radius: 4px; + border-top-right-radius: 4px; +} + +QToolBox::tab:disabled { + color: #787878; +} + +QToolBox::tab:selected { + background-color: #505F69; + border-bottom: 2px solid #1464A0; +} + +QToolBox::tab:!selected { + background-color: #32414B; + border-bottom: 2px solid #32414B; +} + +QToolBox::tab:selected:disabled { + background-color: #32414B; + border-bottom: 2px solid #14506E; +} + +QToolBox::tab:!selected:disabled { + background-color: #19232D; +} + +QToolBox::tab:hover { + border-color: #148CD2; + border-bottom: 2px solid #148CD2; +} + +QToolBox QScrollArea QWidget QWidget { + padding: 0px; + background-color: #19232D; +} + +/* QFrame ----------------------------------------------------------------- */ + +QFrame { + border-radius: 4px; + border: 1px solid #32414B; +} + +QFrame[frameShape="0"] { + border-radius: 4px; + border: 1px transparent #32414B; +} + +QFrame[height="3"], +QFrame[width="3"] { + background-color: #19232D; +} + +/* QSplitter -------------------------------------------------------------- */ + +QSplitter { + background-color: #32414B; + spacing: 0; + padding: 0; + margin: 0; +} + +QSplitter::separator { + background-color: #32414B; + border: 0 solid #19232D; + spacing: 0; + padding: 1px; + margin: 0; +} + +QSplitter::separator:hover { + background-color: #787878; +} + +QSplitter::separator:horizontal { + width: 5px; + image: url(qss/qdarkstyle/rc/Vsepartoolbar.png); +} + +QSplitter::separator:vertical { + height: 5px; + image: url(qss/qdarkstyle/rc/Hsepartoolbar.png); +} + + +/* QDateEdit-------------------------------------------------------------- */ + +QDateEdit { + selection-background-color: #1464A0; + border-style: solid; + border: 1px solid #32414B; + border-radius: 4px; + padding-top: 2px; /* This fix #103, #111*/ + padding-bottom: 2px; /* This fix #103, #111*/ + padding-left: 4px; + padding-right: 4px; + min-width: 10px; +} + +QDateEdit:on { + selection-background-color: #1464A0; +} + +QDateEdit::drop-down { + subcontrol-origin: padding; + subcontrol-position: top right; + width: 20px; + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; +} + +QDateEdit::down-arrow { + image: url(qss/qdarkstyle/rc/down_arrow_disabled.png); +} + +QDateEdit::down-arrow:on, +QDateEdit::down-arrow:hover, +QDateEdit::down-arrow:focus { + image: url(qss/qdarkstyle/rc/down_arrow.png); +} + +QDateEdit QAbstractItemView { + background-color: #19232D; + border-radius: 4px; + border: 1px solid #32414B; + selection-background-color: #1464A0; +} + +QAbstractView:hover{ + border: 1px solid #148CD2; + color: #F0F0F0; +} + +QAbstractView:selected { + background: #1464A0; + color: #32414B; +} + + +PlotWidget { + padding: 0px; /* to fix cut labels in plots #134 */ +} + +FriendList { + qproperty-textColorStatusAway: lightgray; + qproperty-textColorStatusBusy: lightgray; + qproperty-textColorStatusOnline: green; + qproperty-textColorStatusInactive: lightgray; + qproperty-textColorStatusOffline: gray; +} + +NetworkDialog { + qproperty-backgroundColorSelf: darkred; + qproperty-backgroundColorOwnSign: darkred; + qproperty-backgroundColorAcceptConnection: black; + qproperty-backgroundColorHasSignedMe: darkred; + qproperty-backgroundColorDenied: #201F1F; +} + +RSTreeWidget#idTreeWidget::item:!selected { + color: #C0C0C0; +} + +GxsChannelPostItem > QFrame#mainFrame[new=true] { + border: 3px solid #82B9F4; + border-radius: 10px; +} + +GxsForumThreadWidget QLabel#forumName +{ + qproperty-fontSizeFactor: 140; + color: #0099cc; + font-size: 15px; + font: bold; +} + +QTreeView [new=true]{ + color: #0099cc; + +} + +/* changes for the subscribe Button */ + +PostedListWidget QToolButton#subscribeToolButton { + font: bold; + font-size: 15px; + color: white; + background: #0099cc; + border-radius: 4px; + max-height: 27px; +} + +PostedListWidget QToolButton#subscribeToolButton:hover { + background: #03b1f3; + border-radius: 4px; +} + +GxsForumThreadWidget QToolButton#subscribeToolButton { + font: bold; + font-size: 14px; + color: white; + background: #0099cc; + border-radius: 4px; + max-height: 27px; +} + +GxsForumThreadWidget QToolButton#subscribeToolButton:hover { + background: #03b1f3; + border-radius: 4px; +} + +GxsChannelPostsWidget QToolButton#subscribeToolButton { + font: bold; + font-size: 14px; + color: white; + background: #0099cc; + border-radius: 4px; + max-height: 27px; +} + +GxsChannelPostsWidget QToolButton#subscribeToolButton:hover { + background: #03b1f3; + border-radius: 4px; +} + +GxsChannelPostsWidget QToolButton#subscribeToolButton:pressed { + background: #03b1f3; + border-radius: 4px; + border: 1px solid gray; +} + +GxsChannelPostsWidget QToolButton#subscribeToolButton:disabled { + background: gray; + border-radius: 4px; + border: 1px solid gray; + color: lightgray; +} + +/* only for MenuButtonPopup */ +GxsChannelPostsWidget QToolButton#subscribeToolButton[popupMode="1"] { + padding-right: 0px; +} + +GxsChannelPostsWidget QToolButton#subscribeToolButton::menu-arrow { + image: none; +} + +GxsChannelPostsWidget QToolButton#subscribeToolButton::menu-button { + image: none; + +} \ No newline at end of file diff --git a/retroshare-gui/src/qss/qdarkstyle.qss b/retroshare-gui/src/qss/qdarkstyle.qss index 6c325dc1a..3e0927975 100644 --- a/retroshare-gui/src/qss/qdarkstyle.qss +++ b/retroshare-gui/src/qss/qdarkstyle.qss @@ -216,7 +216,7 @@ QScrollBar::handle:horizontal QScrollBar::sub-line:horizontal { - border-image: url(qdarkstyle/right_arrow_disabled.png); + border-image: url(%THISPATH%/qdarkstyle/right_arrow_disabled.png); width: 10px; height: 10px; subcontrol-position: right; @@ -225,7 +225,7 @@ QScrollBar::sub-line:horizontal QScrollBar::add-line:horizontal { - border-image: url(qdarkstyle/left_arrow_disabled.png); + border-image: url(%THISPATH%/qdarkstyle/left_arrow_disabled.png); height: 10px; width: 10px; subcontrol-position: left; @@ -234,7 +234,7 @@ QScrollBar::add-line:horizontal QScrollBar::sub-line:horizontal:hover,QScrollBar::sub-line:horizontal:on { - border-image: url(qdarkstyle/right_arrow.png); + border-image: url(%THISPATH%/qdarkstyle/right_arrow.png); height: 10px; width: 10px; subcontrol-position: right; @@ -244,7 +244,7 @@ QScrollBar::sub-line:horizontal:hover,QScrollBar::sub-line:horizontal:on QScrollBar::add-line:horizontal:hover, QScrollBar::add-line:horizontal:on { - border-image: url(qdarkstyle/left_arrow.png); + border-image: url(%THISPATH%/qdarkstyle/left_arrow.png); height: 10px; width: 10px; subcontrol-position: left; @@ -282,7 +282,7 @@ QScrollBar::handle:vertical QScrollBar::sub-line:vertical { - border-image: url(qdarkstyle/up_arrow_disabled.png); + border-image: url(%THISPATH%/qdarkstyle/up_arrow_disabled.png); height: 10px; width: 10px; subcontrol-position: top; @@ -292,7 +292,7 @@ QScrollBar::sub-line:vertical QScrollBar::add-line:vertical { - border-image: url(qdarkstyle/down_arrow_disabled.png); + border-image: url(%THISPATH%/qdarkstyle/down_arrow_disabled.png); height: 10px; width: 10px; subcontrol-position: bottom; @@ -302,7 +302,7 @@ QScrollBar::add-line:vertical QScrollBar::sub-line:vertical:hover,QScrollBar::sub-line:vertical:on { - border-image: url(qdarkstyle/up_arrow.png); + border-image: url(%THISPATH%/qdarkstyle/up_arrow.png); height: 10px; width: 10px; subcontrol-position: top; @@ -312,7 +312,7 @@ QScrollBar::sub-line:vertical:hover,QScrollBar::sub-line:vertical:on QScrollBar::add-line:vertical:hover, QScrollBar::add-line:vertical:on { - border-image: url(qdarkstyle/down_arrow.png); + border-image: url(%THISPATH%/qdarkstyle/down_arrow.png); height: 10px; width: 10px; subcontrol-position: bottom; @@ -359,7 +359,7 @@ QCheckBox:disabled } QSizeGrip { - image: url(qdarkstyle/sizegrip.png); + image: url(%THISPATH%/qdarkstyle/sizegrip.png); width: 12px; height: 12px; } @@ -483,16 +483,16 @@ QToolBar { } QToolBar::handle:horizontal { - image: url(qdarkstyle/Hmovetoolbar.png); + image: url(%THISPATH%/qdarkstyle/Hmovetoolbar.png); } QToolBar::handle:vertical { - image: url(qdarkstyle/Vmovetoolbar.png); + image: url(%THISPATH%/qdarkstyle/Vmovetoolbar.png); } QToolBar::separator:horizontal { - image: url(qdarkstyle/Hsepartoolbar.png); + image: url(%THISPATH%/qdarkstyle/Hsepartoolbar.png); } QToolBar::separator:vertical { - image: url(qdarkstyle/Vsepartoolbars.png); + image: url(%THISPATH%/qdarkstyle/Vsepartoolbars.png); } QPushButton @@ -574,13 +574,13 @@ QComboBox::drop-down QComboBox::down-arrow { - image: url(qdarkstyle/down_arrow_disabled.png); + image: url(%THISPATH%/qdarkstyle/down_arrow_disabled.png); } QComboBox::down-arrow:on, QComboBox::down-arrow:hover, QComboBox::down-arrow:focus { - image: url(qdarkstyle/down_arrow.png); + image: url(%THISPATH%/qdarkstyle/down_arrow.png); } QPushButton:pressed @@ -614,31 +614,31 @@ QAbstractSpinBox:down-button } QAbstractSpinBox::up-arrow,QAbstractSpinBox::up-arrow:disabled,QAbstractSpinBox::up-arrow:off { - image: url(qdarkstyle/up_arrow_disabled.png); + image: url(%THISPATH%/qdarkstyle/up_arrow_disabled.png); width: 10px; height: 10px; } QAbstractSpinBox::up-arrow:hover { - image: url(qdarkstyle/up_arrow.png); + image: url(%THISPATH%/qdarkstyle/up_arrow.png); } QAbstractSpinBox::down-arrow,QAbstractSpinBox::down-arrow:disabled,QAbstractSpinBox::down-arrow:off { - image: url(qdarkstyle/down_arrow_disabled.png); + image: url(%THISPATH%/qdarkstyle/down_arrow_disabled.png); width: 10px; height: 10px; } QAbstractSpinBox::down-arrow:hover { - image: url(qdarkstyle/down_arrow.png); + image: url(%THISPATH%/qdarkstyle/down_arrow.png); } QLabel { - border: 0px solid black; + background-color: transparent; /*fixes spyder #9120,#9121*/ } @@ -658,7 +658,7 @@ QTabBar:focus } QTabBar::close-button { - image: url(qdarkstyle/close.png); + image: url(%THISPATH%/qdarkstyle/close.png); background: transparent; icon-size: 10px; padding: 5px; @@ -795,26 +795,26 @@ QTabBar::tab:right:selected } QTabBar QToolButton::right-arrow:enabled { - image: url(qdarkstyle/right_arrow.png); + image: url(%THISPATH%/qdarkstyle/right_arrow.png); } QTabBar QToolButton::left-arrow:enabled { - image: url(qdarkstyle/left_arrow.png); + image: url(%THISPATH%/qdarkstyle/left_arrow.png); } QTabBar QToolButton::right-arrow:disabled { - image: url(qdarkstyle/right_arrow_disabled.png); + image: url(%THISPATH%/qdarkstyle/right_arrow_disabled.png); } QTabBar QToolButton::left-arrow:disabled { - image: url(qdarkstyle/left_arrow_disabled.png); + image: url(%THISPATH%/qdarkstyle/left_arrow_disabled.png); } QDockWidget { border: 1px solid #403F3F; - titlebar-close-icon: url(qdarkstyle/close.png); - titlebar-normal-icon: url(qdarkstyle/undock.png); + titlebar-close-icon: url(%THISPATH%/qdarkstyle/close.png); + titlebar-normal-icon: url(%THISPATH%/qdarkstyle/undock.png); } QDockWidget::close-button, QDockWidget::float-button { @@ -869,39 +869,39 @@ NetworkDialog { QTreeView:branch:selected, QTreeView:branch:hover { - background: url(qdarkstyle/transparent.png); + background: url(%THISPATH%/qdarkstyle/transparent.png); } QTreeView::branch:has-siblings:!adjoins-item { - border-image: url(qdarkstyle/transparent.png); + border-image: url(%THISPATH%/qdarkstyle/transparent.png); } QTreeView::branch:has-siblings:adjoins-item { - border-image: url(qdarkstyle/transparent.png); + border-image: url(%THISPATH%/qdarkstyle/transparent.png); } QTreeView::branch:!has-children:!has-siblings:adjoins-item { - border-image: url(qdarkstyle/transparent.png); + border-image: url(%THISPATH%/qdarkstyle/transparent.png); } QTreeView::branch:has-children:!has-siblings:closed, QTreeView::branch:closed:has-children:has-siblings { - image: url(qdarkstyle/branch_closed.png); + image: url(%THISPATH%/qdarkstyle/branch_closed.png); } QTreeView::branch:open:has-children:!has-siblings, QTreeView::branch:open:has-children:has-siblings { - image: url(qdarkstyle/branch_open.png); + image: url(%THISPATH%/qdarkstyle/branch_open.png); } QTreeView::branch:has-children:!has-siblings:closed:hover, QTreeView::branch:closed:has-children:has-siblings:hover { - image: url(qdarkstyle/branch_closed-on.png); + image: url(%THISPATH%/qdarkstyle/branch_closed-on.png); } QTreeView::branch:open:has-children:!has-siblings:hover, QTreeView::branch:open:has-children:has-siblings:hover { - image: url(qdarkstyle/branch_open-on.png); + image: url(%THISPATH%/qdarkstyle/branch_open-on.png); } QListView::item:!selected:hover, QTableView::item:!selected:hover, QTreeView::item:!selected:hover { @@ -986,7 +986,7 @@ QToolButton::menu-button { } QToolButton::menu-arrow { - image: url(qdarkstyle/down_arrow.png); + image: url(%THISPATH%/qdarkstyle/down_arrow.png); } QToolButton::menu-arrow:open { @@ -1068,11 +1068,11 @@ QHeaderView::section:checked /* style the sort indicator */ QHeaderView::down-arrow { - image: url(qdarkstyle/down_arrow.png); + image: url(%THISPATH%/qdarkstyle/down_arrow.png); } QHeaderView::up-arrow { - image: url(qdarkstyle/up_arrow.png); + image: url(%THISPATH%/qdarkstyle/up_arrow.png); } @@ -1138,3 +1138,74 @@ OpModeStatus[opMode="Minimal"] { [WrongValue="true"] { background-color: #702020; } + +/* changes for the subscribe Button */ + +PostedListWidget QToolButton#subscribeToolButton { + font: bold; + font-size: 15px; + color: white; + background: #0099cc; + border-radius: 4px; + max-height: 27px; +} + +PostedListWidget QToolButton#subscribeToolButton:hover { + background: #03b1f3; + border-radius: 4px; +} + +GxsForumThreadWidget QToolButton#subscribeToolButton { + font: bold; + font-size: 14px; + color: white; + background: #0099cc; + border-radius: 4px; + max-height: 27px; +} + +GxsForumThreadWidget QToolButton#subscribeToolButton:hover { + background: #03b1f3; + border-radius: 4px; +} + +GxsChannelPostsWidget QToolButton#subscribeToolButton { + font: bold; + font-size: 14px; + color: white; + background: #0099cc; + border-radius: 4px; + max-height: 27px; +} + +GxsChannelPostsWidget QToolButton#subscribeToolButton:hover { + background: #03b1f3; + border-radius: 4px; +} + +GxsChannelPostsWidget QToolButton#subscribeToolButton:pressed { + background: #03b1f3; + border-radius: 4px; + border: 1px solid gray; +} + +GxsChannelPostsWidget QToolButton#subscribeToolButton:disabled { + background: gray; + border-radius: 4px; + border: 1px solid gray; + color: lightgray; +} + +/* only for MenuButtonPopup */ +GxsChannelPostsWidget QToolButton#subscribeToolButton[popupMode="1"] { + padding-right: 0px; +} + +GxsChannelPostsWidget QToolButton#subscribeToolButton::menu-arrow { + image: none; +} + +GxsChannelPostsWidget QToolButton#subscribeToolButton::menu-button { + image: none; + +} diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/Hmovetoolbar.png b/retroshare-gui/src/qss/qdarkstyle/rc/Hmovetoolbar.png new file mode 100644 index 000000000..cead99ed1 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/Hmovetoolbar.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/Hsepartoolbar.png b/retroshare-gui/src/qss/qdarkstyle/rc/Hsepartoolbar.png new file mode 100644 index 000000000..7f183c8b3 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/Hsepartoolbar.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/Vmovetoolbar.png b/retroshare-gui/src/qss/qdarkstyle/rc/Vmovetoolbar.png new file mode 100644 index 000000000..ac6a655e2 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/Vmovetoolbar.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/Vsepartoolbar.png b/retroshare-gui/src/qss/qdarkstyle/rc/Vsepartoolbar.png new file mode 100644 index 000000000..7bf62f168 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/Vsepartoolbar.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/branch_closed-on.png b/retroshare-gui/src/qss/qdarkstyle/rc/branch_closed-on.png new file mode 100644 index 000000000..d081e9b3b Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/branch_closed-on.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/branch_closed.png b/retroshare-gui/src/qss/qdarkstyle/rc/branch_closed.png new file mode 100644 index 000000000..d652159a3 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/branch_closed.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/branch_open-on.png b/retroshare-gui/src/qss/qdarkstyle/rc/branch_open-on.png new file mode 100644 index 000000000..ec372b27d Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/branch_open-on.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/branch_open.png b/retroshare-gui/src/qss/qdarkstyle/rc/branch_open.png new file mode 100644 index 000000000..66f8e1ac6 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/branch_open.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_checked.png b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_checked.png new file mode 100644 index 000000000..4007c2ed3 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_checked.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_checked@2x.png b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_checked@2x.png new file mode 100644 index 000000000..b9c3204f1 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_checked@2x.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_checked_disabled.png b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_checked_disabled.png new file mode 100644 index 000000000..4762561b3 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_checked_disabled.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_checked_disabled@2x.png b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_checked_disabled@2x.png new file mode 100644 index 000000000..98bf5470c Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_checked_disabled@2x.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_checked_focus.png b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_checked_focus.png new file mode 100644 index 000000000..91cb16c9f Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_checked_focus.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_checked_focus@2x.png b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_checked_focus@2x.png new file mode 100644 index 000000000..04b3bb514 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_checked_focus@2x.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_indeterminate.png b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_indeterminate.png new file mode 100644 index 000000000..6b846365c Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_indeterminate.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_indeterminate@2x.png b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_indeterminate@2x.png new file mode 100644 index 000000000..baa502017 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_indeterminate@2x.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_indeterminate_disabled.png b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_indeterminate_disabled.png new file mode 100644 index 000000000..435048a08 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_indeterminate_disabled.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_indeterminate_disabled@2x.png b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_indeterminate_disabled@2x.png new file mode 100644 index 000000000..3e7f76c7c Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_indeterminate_disabled@2x.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_indeterminate_focus.png b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_indeterminate_focus.png new file mode 100644 index 000000000..4bf4d53c1 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_indeterminate_focus.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_indeterminate_focus@2x.png b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_indeterminate_focus@2x.png new file mode 100644 index 000000000..1f5cb3e88 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_indeterminate_focus@2x.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_unchecked.png b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_unchecked.png new file mode 100644 index 000000000..54044babf Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_unchecked.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_unchecked@2x.png b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_unchecked@2x.png new file mode 100644 index 000000000..1259a9841 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_unchecked@2x.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_unchecked_disabled.png b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_unchecked_disabled.png new file mode 100644 index 000000000..75f049024 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_unchecked_disabled.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_unchecked_disabled@2x.png b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_unchecked_disabled@2x.png new file mode 100644 index 000000000..e4ecef9d5 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_unchecked_disabled@2x.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_unchecked_focus.png b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_unchecked_focus.png new file mode 100644 index 000000000..5b0a18f01 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_unchecked_focus.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_unchecked_focus@2x.png b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_unchecked_focus@2x.png new file mode 100644 index 000000000..14bec86c2 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/checkbox_unchecked_focus@2x.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/close-hover.png b/retroshare-gui/src/qss/qdarkstyle/rc/close-hover.png new file mode 100644 index 000000000..fdbaf9bf0 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/close-hover.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/close-pressed.png b/retroshare-gui/src/qss/qdarkstyle/rc/close-pressed.png new file mode 100644 index 000000000..9b243bfe8 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/close-pressed.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/close.png b/retroshare-gui/src/qss/qdarkstyle/rc/close.png new file mode 100644 index 000000000..89407de72 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/close.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/down_arrow.png b/retroshare-gui/src/qss/qdarkstyle/rc/down_arrow.png new file mode 100644 index 000000000..e271f7f90 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/down_arrow.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/down_arrow_disabled.png b/retroshare-gui/src/qss/qdarkstyle/rc/down_arrow_disabled.png new file mode 100644 index 000000000..5805d9842 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/down_arrow_disabled.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/left_arrow.png b/retroshare-gui/src/qss/qdarkstyle/rc/left_arrow.png new file mode 100644 index 000000000..f808d2d72 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/left_arrow.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/left_arrow_disabled.png b/retroshare-gui/src/qss/qdarkstyle/rc/left_arrow_disabled.png new file mode 100644 index 000000000..f5b9af8a3 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/left_arrow_disabled.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/radio_checked.png b/retroshare-gui/src/qss/qdarkstyle/rc/radio_checked.png new file mode 100644 index 000000000..368acce58 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/radio_checked.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/radio_checked@2x.png b/retroshare-gui/src/qss/qdarkstyle/rc/radio_checked@2x.png new file mode 100644 index 000000000..b5f5eed9b Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/radio_checked@2x.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/radio_checked_disabled.png b/retroshare-gui/src/qss/qdarkstyle/rc/radio_checked_disabled.png new file mode 100644 index 000000000..73ff735f2 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/radio_checked_disabled.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/radio_checked_disabled@2x.png b/retroshare-gui/src/qss/qdarkstyle/rc/radio_checked_disabled@2x.png new file mode 100644 index 000000000..827e5928b Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/radio_checked_disabled@2x.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/radio_checked_focus.png b/retroshare-gui/src/qss/qdarkstyle/rc/radio_checked_focus.png new file mode 100644 index 000000000..ad6d2cf82 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/radio_checked_focus.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/radio_checked_focus@2x.png b/retroshare-gui/src/qss/qdarkstyle/rc/radio_checked_focus@2x.png new file mode 100644 index 000000000..7e5930563 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/radio_checked_focus@2x.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/radio_unchecked.png b/retroshare-gui/src/qss/qdarkstyle/rc/radio_unchecked.png new file mode 100644 index 000000000..82f2abb8c Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/radio_unchecked.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/radio_unchecked@2x.png b/retroshare-gui/src/qss/qdarkstyle/rc/radio_unchecked@2x.png new file mode 100644 index 000000000..793719b3b Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/radio_unchecked@2x.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/radio_unchecked_disabled.png b/retroshare-gui/src/qss/qdarkstyle/rc/radio_unchecked_disabled.png new file mode 100644 index 000000000..5c54ee9df Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/radio_unchecked_disabled.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/radio_unchecked_disabled@2x.png b/retroshare-gui/src/qss/qdarkstyle/rc/radio_unchecked_disabled@2x.png new file mode 100644 index 000000000..d50153d1d Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/radio_unchecked_disabled@2x.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/radio_unchecked_focus.png b/retroshare-gui/src/qss/qdarkstyle/rc/radio_unchecked_focus.png new file mode 100644 index 000000000..f42d85c7f Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/radio_unchecked_focus.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/radio_unchecked_focus@2x.png b/retroshare-gui/src/qss/qdarkstyle/rc/radio_unchecked_focus@2x.png new file mode 100644 index 000000000..0927b4959 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/radio_unchecked_focus@2x.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/right_arrow.png b/retroshare-gui/src/qss/qdarkstyle/rc/right_arrow.png new file mode 100644 index 000000000..9b0a4e6a7 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/right_arrow.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/right_arrow_disabled.png b/retroshare-gui/src/qss/qdarkstyle/rc/right_arrow_disabled.png new file mode 100644 index 000000000..5c0bee402 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/right_arrow_disabled.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/sizegrip.png b/retroshare-gui/src/qss/qdarkstyle/rc/sizegrip.png new file mode 100644 index 000000000..350583aaa Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/sizegrip.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/stylesheet-branch-end.png b/retroshare-gui/src/qss/qdarkstyle/rc/stylesheet-branch-end.png new file mode 100644 index 000000000..cb5d3b51f Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/stylesheet-branch-end.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/stylesheet-branch-more.png b/retroshare-gui/src/qss/qdarkstyle/rc/stylesheet-branch-more.png new file mode 100644 index 000000000..62711409d Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/stylesheet-branch-more.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/stylesheet-vline.png b/retroshare-gui/src/qss/qdarkstyle/rc/stylesheet-vline.png new file mode 100644 index 000000000..87536cce1 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/stylesheet-vline.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/transparent.png b/retroshare-gui/src/qss/qdarkstyle/rc/transparent.png new file mode 100644 index 000000000..483df2513 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/transparent.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/undock.png b/retroshare-gui/src/qss/qdarkstyle/rc/undock.png new file mode 100644 index 000000000..58cde37b8 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/undock.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/up_arrow.png b/retroshare-gui/src/qss/qdarkstyle/rc/up_arrow.png new file mode 100644 index 000000000..abcc72452 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/up_arrow.png differ diff --git a/retroshare-gui/src/qss/qdarkstyle/rc/up_arrow_disabled.png b/retroshare-gui/src/qss/qdarkstyle/rc/up_arrow_disabled.png new file mode 100644 index 000000000..b9c8e3b53 Binary files /dev/null and b/retroshare-gui/src/qss/qdarkstyle/rc/up_arrow_disabled.png differ diff --git a/retroshare-gui/src/qss/qlive.qss b/retroshare-gui/src/qss/qlive.qss index b5e7a45a8..90ee24663 100644 --- a/retroshare-gui/src/qss/qlive.qss +++ b/retroshare-gui/src/qss/qlive.qss @@ -10,7 +10,7 @@ QDialog{ QFrame#titleBarFrame, QFrame#toolBarFrame { - border-image: url(qss/qlive/qb.png); + border-image: url(%THISPATH%/qlive/qb.png); } HeaderFrame { @@ -20,17 +20,17 @@ HeaderFrame { /* Customize the toolbar. */ QToolBar#toolBarAction { - border-image: url(qss/qlive/qb.png); + border-image: url(%THISPATH%/qlive/qb.png); } QToolBar#toolBarPage { - border-image: url(qss/qlive/qb.png); + border-image: url(%THISPATH%/qlive/qb.png); } QToolBar#chattoolBar{ - border-image: url(qss/qlive/qb.png); + border-image: url(%THISPATH%/qlive/qb.png); } @@ -72,13 +72,13 @@ QTreeView::item:selected { /* when user selects item using mouse or keyboard */ QFrame#messengerframetop{ - border-image: url(qss/qlive/qb.png); + border-image: url(%THISPATH%/qlive/qb.png); } QFrame#Chatbuttonframe{ - border-image: url(qss/qlive/qb.png); + border-image: url(%THISPATH%/qlive/qb.png); } @@ -113,6 +113,6 @@ QLabel#fromText{ } QStatusBar{ - border-image: url(qss/qlive/qb.png); + border-image: url(%THISPATH%/qlive/qb.png); } diff --git a/retroshare-gui/src/qss/redscorpion.qss b/retroshare-gui/src/qss/redscorpion.qss index 4946745ca..7b47f360b 100644 --- a/retroshare-gui/src/qss/redscorpion.qss +++ b/retroshare-gui/src/qss/redscorpion.qss @@ -191,27 +191,27 @@ QFrame#Chatbuttonframe{ } QFrame#frame_2{ - border-image: url(qss/redscorpion/red.png); + border-image: url(%THISPATH%/redscorpion/red.png); border: 1px solid #CCCCCC; } QFrame#buttonframe{ - border-image: url(qss/redscorpion/red.png); + border-image: url(%THISPATH%/redscorpion/red.png); border: 1px solid #CCCCCC; } QFrame#frame{ - border-image: url(qss/redscorpion/red.png); + border-image: url(%THISPATH%/redscorpion/red.png); border: 1px solid #CCCCCC; } QFrame#chheaderframe{ - border-image: url(qss/redscorpion/red.png); + border-image: url(%THISPATH%/redscorpion/red.png); border: 1px solid #CCCCCC; diff --git a/retroshare-gui/src/qss/silver.qss b/retroshare-gui/src/qss/silver.qss index 3d8d30909..2683ad533 100644 --- a/retroshare-gui/src/qss/silver.qss +++ b/retroshare-gui/src/qss/silver.qss @@ -22,18 +22,18 @@ HeaderFrame { /* Customize the toolbar. */ QToolBar#toolBarAction { - border-image: url(qss/silver/silver.png); + border-image: url(%THISPATH%/silver/silver.png); } /* Customize the toolbar. */ QToolBar#toolBarPage { - border-image: url(qss/silver/silver.png); + border-image: url(%THISPATH%/silver/silver.png); } QToolBar#chattoolBar{ - border-image: url(qss/silver/silver.png); + border-image: url(%THISPATH%/silver/silver.png); } @@ -92,7 +92,7 @@ QStatusBar{ QFrame#messengerframetop{ - border-image: url(qss/silver/silver.png); + border-image: url(%THISPATH%/silver/silver.png); /*background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, @@ -101,7 +101,7 @@ QFrame#messengerframetop{ QFrame#Chatbuttonframe{ - border-image: url(qss/silver/silver.png); + border-image: url(%THISPATH%/silver/silver.png); } diff --git a/retroshare-gui/src/qss/uus.qss b/retroshare-gui/src/qss/uus.qss index 3827ac94e..1c56e4c1f 100644 --- a/retroshare-gui/src/qss/uus.qss +++ b/retroshare-gui/src/qss/uus.qss @@ -8,7 +8,7 @@ QFrame#titleBarFrame, QFrame#toolBarFrame { - border-image: url(qss/uus/uus.png); + border-image: url(%THISPATH%/uus/uus.png); } FriendsDialog QFrame#headFrame { @@ -31,16 +31,16 @@ QDialog{ /* Customize the toolbar. */ QToolBar#toolBarAction { - border-image: url(qss/uus/uus.png); + border-image: url(%THISPATH%/uus/uus.png); } QToolBar#toolBarPage { - border-image: url(qss/uus/uus.png); + border-image: url(%THISPATH%/uus/uus.png); } QToolBar#chattoolBar{ - border-image: url(qss/uus/uus.png); + border-image: url(%THISPATH%/uus/uus.png); } @@ -161,7 +161,7 @@ color: white; } QStatusBar{ - border-image: url(qss/uus/uus.png); + border-image: url(%THISPATH%/uus/uus.png); } @@ -214,7 +214,7 @@ QToolTip{ QFrame#messengerframetop{ - border-image: url(qss/uus/uus.png); + border-image: url(%THISPATH%/uus/uus.png); /*background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #F7B552, stop: 1 #FF5E07);*/ diff --git a/retroshare-gui/src/qss/wx.qss b/retroshare-gui/src/qss/wx.qss index b214c6766..39b5d8130 100644 --- a/retroshare-gui/src/qss/wx.qss +++ b/retroshare-gui/src/qss/wx.qss @@ -1,13 +1,13 @@ /* Customize the toolbar. */ QToolBar { - border-image: url(qss/wx/wx.png); + border-image: url(%THISPATH%/wx/wx.png); } QFrame#titleBarFrame, QFrame#toolBarFrame { - border-image: url(qss/wx/wx.png); + border-image: url(%THISPATH%/wx/wx.png); } @@ -43,7 +43,7 @@ QPushButton#applyButton { QFrame#messengerframetop{ - border-image: url(qss/wx/wx.png); + border-image: url(%THISPATH%/wx/wx.png); /*background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #F7B552, stop: 1 #FF5E07);*/ @@ -51,7 +51,7 @@ QFrame#messengerframetop{ QFrame#Chatbuttonframe{ - border-image: url(qss/wx/wx.png); + border-image: url(%THISPATH%/wx/wx.png); } diff --git a/retroshare-gui/src/qss/yaba.qss b/retroshare-gui/src/qss/yaba.qss index a9b1e80db..98a09b8de 100644 --- a/retroshare-gui/src/qss/yaba.qss +++ b/retroshare-gui/src/qss/yaba.qss @@ -6,7 +6,7 @@ QFrame#titleBarFrame, QFrame#toolBarFrame { - border-image: url(qss/yaba/yaba.png); + border-image: url(%THISPATH%/yaba/yaba.png); } HeaderFrame { @@ -41,31 +41,31 @@ ChannelFeed QFrame#headerFrame { /* Customize the toolbar. */ QToolBar#toolBarAction { - border-image: url(qss/yaba/yaba.png); + border-image: url(%THISPATH%/yaba/yaba.png); } QToolBar#toolBarPage { - border-image: url(qss/yaba/yaba.png); + border-image: url(%THISPATH%/yaba/yaba.png); } QFrame#frame_2{ - border-image: url(qss/yaba/yaba3.png); + border-image: url(%THISPATH%/yaba/yaba3.png); } QFrame#buttonframe{ - border-image: url(qss/yaba/yaba3.png); + border-image: url(%THISPATH%/yaba/yaba3.png); } QFrame#chheaderframe{ - border-image: url(qss/yaba/yaba3.png); + border-image: url(%THISPATH%/yaba/yaba3.png); } QFrame#frame{ - border-image: url(qss/yaba/yaba3.png); + border-image: url(%THISPATH%/yaba/yaba3.png); } @@ -158,7 +158,7 @@ QTreeView::item:selected { /* when user selects item using mouse or keyboard */ QFrame#messengerframetop{ - border-image: url(qss/yaba/yaba.png); + border-image: url(%THISPATH%/yaba/yaba.png); /*background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #F7B552, stop: 1 #FF5E07);*/ @@ -166,7 +166,7 @@ QFrame#messengerframetop{ QFrame#Chatbuttonframe{ - border-image: url(qss/yaba/yaba.png); + border-image: url(%THISPATH%/yaba/yaba.png); } @@ -202,7 +202,7 @@ QLabel#fromText{ } QToolBar#chattoolBar{ - border-image: url(qss/yaba/yaba.png); + border-image: url(%THISPATH%/yaba/yaba.png); } diff --git a/retroshare-gui/src/qss/yeah.qss b/retroshare-gui/src/qss/yeah.qss index e625c1867..558aa2b3a 100644 --- a/retroshare-gui/src/qss/yeah.qss +++ b/retroshare-gui/src/qss/yeah.qss @@ -29,7 +29,7 @@ QDialog{ /* Customize the toolbar. */ QToolBar { - border-image: url(qss/yeah/yeah.png); + border-image: url(%THISPATH%/yeah/yeah.png); } @@ -127,7 +127,7 @@ QTreeView::item:selected { /* when user selects item using mouse or keyboard */ QFrame#messengerframetop{ - border-image: url(qss/yeah/yeah.png); + border-image: url(%THISPATH%/yeah/yeah.png); /*background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #F7B552, stop: 1 #FF5E07);*/ @@ -135,7 +135,7 @@ QFrame#messengerframetop{ QFrame#Chatbuttonframe{ - border-image: url(qss/yeah/yeah.png); + border-image: url(%THISPATH%/yeah/yeah.png); } diff --git a/retroshare-gui/src/retroshare-gui.pro b/retroshare-gui/src/retroshare-gui.pro index 70050a727..6597d652e 100644 --- a/retroshare-gui/src/retroshare-gui.pro +++ b/retroshare-gui/src/retroshare-gui.pro @@ -43,6 +43,46 @@ rs_jsonapi { FORMS *= gui/settings/JsonApiPage.ui } +# Auto detect installed version of cmark +rs_gui_cmark { + DEFINES *= USE_CMARK + no_rs_cross_compiling { + message("Using compiled cmark") + CMARK_SRC_PATH=$$clean_path($${RS_SRC_PATH}/supportlibs/cmark) + CMARK_BUILD_PATH=$$clean_path($${RS_BUILD_PATH}/supportlibs/cmark/build) + INCLUDEPATH *= $$clean_path($${CMARK_SRC_PATH}/src/) + DEPENDPATH *= $$clean_path($${CMARK_SRC_PATH}/src/) + QMAKE_LIBDIR *= $$clean_path($${CMARK_BUILD_PATH}/) + # Using sLibs would fail as libcmark.a is generated at compile-time + LIBS *= -L$$clean_path($${CMARK_BUILD_PATH}/src/) -lcmark + + DUMMYCMARKINPUT = FORCE + CMAKE_GENERATOR_OVERRIDE="" + win32-g++:CMAKE_GENERATOR_OVERRIDE="-G \"MSYS Makefiles\"" + gencmarklib.name = Generating libcmark. + gencmarklib.input = DUMMYCMARKINPUT + gencmarklib.output = $$clean_path($${CMARK_BUILD_PATH}/src/libcmark.a) + gencmarklib.CONFIG += target_predeps combine + gencmarklib.variable_out = PRE_TARGETDEPS + gencmarklib.commands = \ + cd $${RS_SRC_PATH} && ( \ + git submodule update --init supportlibs/cmark ; \ + cd $${CMARK_SRC_PATH} ; \ + true ) && \ + mkdir -p $${CMARK_BUILD_PATH} && cd $${CMARK_BUILD_PATH} && \ + cmake \ + -DCMAKE_CXX_COMPILER=$$QMAKE_CXX \ + $${CMAKE_GENERATOR_OVERRIDE} \ + -DCMAKE_INSTALL_PREFIX=. \ + -B. \ + -H$$shell_path($${CMARK_SRC_PATH}) && \ + $(MAKE) + QMAKE_EXTRA_COMPILERS += gencmarklib + } else { + message("Using systems cmark") + sLibs *= libcmark + } +} FORMS += TorControl/TorControlWindow.ui SOURCES += TorControl/TorControlWindow.cpp @@ -53,7 +93,7 @@ HEADERS += TorControl/TorControlWindow.h greaterThan(QT_MAJOR_VERSION, 4) { # Qt 5 - QT += uitools widgets multimedia printsupport + QT += widgets multimedia printsupport linux-* { QT += x11extras } @@ -81,7 +121,7 @@ MOC_DIR = temp/moc ################################# Linux ########################################## # Put lib dir in QMAKE_LFLAGS so it appears before -L/usr/lib linux-* { - CONFIG += link_pkgconfig + CONFIG += link_pkgconfig #CONFIG += version_detail_bash_script QMAKE_CXXFLAGS *= -D_FILE_OFFSET_BITS=64 @@ -92,6 +132,10 @@ linux-* { DEFINES *= HAVE_XSS # for idle time, libx screensaver extensions } +rs_sanitize { + LIBS *= -lasan -lubsan +} + unix { target.path = "$${BIN_DIR}" INSTALLS += target @@ -359,7 +403,6 @@ HEADERS += rshare.h \ gui/AboutDialog.h \ gui/AboutWidget.h \ gui/NetworkView.h \ - gui/MessengerWindow.h \ gui/FriendsDialog.h \ gui/ServicePermissionDialog.h \ gui/RemoteDirModel.h \ @@ -519,7 +562,8 @@ HEADERS += rshare.h \ gui/common/GroupTreeWidget.h \ gui/common/RSTreeView.h \ gui/common/AvatarWidget.h \ - gui/common/FriendList.h \ + gui/common/FriendListModel.h \ + gui/common/NewFriendList.h \ gui/common/FriendSelectionWidget.h \ gui/common/FriendSelectionDialog.h \ gui/common/HashBox.h \ @@ -617,7 +661,6 @@ FORMS += gui/StartDialog.ui \ gui/FileTransfer/BannedFilesDialog.ui \ gui/MainWindow.ui \ gui/NetworkView.ui \ - gui/MessengerWindow.ui \ gui/FriendsDialog.ui \ gui/ShareManager.ui \ # gui/ShareDialog.ui \ @@ -685,7 +728,7 @@ FORMS += gui/StartDialog.ui \ gui/groups/CreateGroup.ui \ gui/common/GroupTreeWidget.ui \ gui/common/AvatarWidget.ui \ - gui/common/FriendList.ui \ + gui/common/NewFriendList.ui \ gui/common/FriendSelectionWidget.ui \ gui/common/HashBox.ui \ gui/common/RSImageBlockWidget.ui \ @@ -734,7 +777,6 @@ SOURCES += main.cpp \ gui/mainpagestack.cpp \ gui/MainWindow.cpp \ gui/NetworkView.cpp \ - gui/MessengerWindow.cpp \ gui/FriendsDialog.cpp \ gui/ServicePermissionDialog.cpp \ gui/RemoteDirModel.cpp \ @@ -839,7 +881,8 @@ SOURCES += main.cpp \ gui/common/GroupTreeWidget.cpp \ gui/common/RSTreeView.cpp \ gui/common/AvatarWidget.cpp \ - gui/common/FriendList.cpp \ + gui/common/FriendListModel.cpp \ + gui/common/NewFriendList.cpp \ gui/common/FriendSelectionWidget.cpp \ gui/common/FriendSelectionDialog.cpp \ gui/common/HashBox.cpp \ @@ -1000,6 +1043,17 @@ unfinishedtranslations { } +messenger { + SOURCES += gui/MessengerWindow.cpp \ + gui/common/FriendList.cpp + HEADERS += gui/MessengerWindow.h \ + gui/common/FriendList.h + FORMS += gui/MessengerWindow.ui \ + gui/common/FriendList.ui + + DEFiNES += MESSENGER_WINDOW +} + # Shifted Qt4.4 dependancies to here. # qmake CONFIG=pluginmgr @@ -1385,44 +1439,3 @@ gxsgui { } - -cmark { - DEFINES *= USE_CMARK - - HEADERS += \ - ../../supportlibs/cmark/src/buffer.h \ - ../../supportlibs/cmark/src/chunk.h \ - ../../supportlibs/cmark/src/cmark.h \ - ../../supportlibs/cmark/src/cmark_ctype.h \ - ../../supportlibs/cmark/src/houdini.h \ - ../../supportlibs/cmark/src/inlines.h \ - ../../supportlibs/cmark/src/iterator.h \ - ../../supportlibs/cmark/src/node.h \ - ../../supportlibs/cmark/src/parser.h \ - ../../supportlibs/cmark/src/references.h \ - ../../supportlibs/cmark/src/render.h \ - ../../supportlibs/cmark/src/scanners.h \ - ../../supportlibs/cmark/src/utf8.h \ - - SOURCES += \ - ../../supportlibs/cmark/src/blocks.c \ - ../../supportlibs/cmark/src/buffer.c \ - ../../supportlibs/cmark/src/cmark.c \ - ../../supportlibs/cmark/src/cmark_ctype.c \ - ../../supportlibs/cmark/src/commonmark.c \ - ../../supportlibs/cmark/src/houdini_href_e.c \ - ../../supportlibs/cmark/src/houdini_html_e.c \ - ../../supportlibs/cmark/src/houdini_html_u.c \ - ../../supportlibs/cmark/src/html.c \ - ../../supportlibs/cmark/src/inlines.c \ - ../../supportlibs/cmark/src/iterator.c \ - ../../supportlibs/cmark/src/latex.c \ - ../../supportlibs/cmark/src/man.c \ - ../../supportlibs/cmark/src/node.c \ - ../../supportlibs/cmark/src/references.c \ - ../../supportlibs/cmark/src/render.c \ - ../../supportlibs/cmark/src/scanners.c \ - ../../supportlibs/cmark/src/utf8.c \ - ../../supportlibs/cmark/src/xml.c \ - -} diff --git a/retroshare-gui/src/rshare.cpp b/retroshare-gui/src/rshare.cpp index 74fe3b6a7..872273613 100644 --- a/retroshare-gui/src/rshare.cpp +++ b/retroshare-gui/src/rshare.cpp @@ -755,6 +755,9 @@ void Rshare::loadStyleSheet(const QString &sheetName) styleSheet += QLatin1String(file.readAll()) + "\n"; file.close(); } + + /* replace %THISPATH% by file path so url can get relative files */ + styleSheet = styleSheet.replace("url(%THISPATH%",QString("url(%1").arg(fileInfo.absolutePath())); } } } diff --git a/retroshare-gui/src/util/HandleRichText.cpp b/retroshare-gui/src/util/HandleRichText.cpp index 302bf56ef..7818c984d 100644 --- a/retroshare-gui/src/util/HandleRichText.cpp +++ b/retroshare-gui/src/util/HandleRichText.cpp @@ -35,9 +35,7 @@ #ifdef USE_CMARK //Include for CMark -// This needs to be fixed: use system library if available, etc. -#include -#include +#include #endif #include @@ -593,7 +591,7 @@ QString RsHtml::formatText(QTextDocument *textDocument, const QString &text, ulo // Parse CommonMark int options = CMARK_OPT_DEFAULT; cmark_parser *parser = cmark_parser_new(options); - cmark_parser_feed(parser, formattedText.toStdString().c_str(),formattedText.length()); + cmark_parser_feed(parser, formattedText.toStdString().c_str(),static_cast(formattedText.length())); cmark_node *document = cmark_parser_finish(parser); cmark_parser_free(parser); char *result; @@ -601,7 +599,6 @@ QString RsHtml::formatText(QTextDocument *textDocument, const QString &text, ulo // Get result as html formattedText = QString::fromUtf8(result); //Clean - cmark_node_mem(document)->free(result); cmark_node_free(document); //Get document formed HTML textBrowser.setHtml(formattedText); diff --git a/retroshare-gui/src/util/PixmapMerging.cpp b/retroshare-gui/src/util/PixmapMerging.cpp index cf41dd5fe..168fad7ab 100644 --- a/retroshare-gui/src/util/PixmapMerging.cpp +++ b/retroshare-gui/src/util/PixmapMerging.cpp @@ -18,23 +18,27 @@ * * *******************************************************************************/ +#ifdef UNUSED_CODE +#include #include #include #include -QPixmap PixmapMerging::merge(const std::string & foregroundPixmapData, const std::string & backgroundPixmapFilename) { - QImage foregroundImage; - foregroundImage.loadFromData((uchar *) foregroundPixmapData.c_str(), foregroundPixmapData.size()); +QPixmap PixmapMerging::merge(const std::string & foregroundPixmapData, const std::string & backgroundPixmapFilename) +{ + QPixmap foregroundImage; + GxsIdDetails::loadPixmapFromData((uchar *) foregroundPixmapData.c_str(), foregroundPixmapData.size(),foregroundImage); QPixmap backgroundPixmap = QPixmap(QString::fromStdString(backgroundPixmapFilename)); if (!foregroundImage.isNull()) { QPainter painter(&backgroundPixmap); - painter.drawImage(0, 0, - foregroundImage.scaled(backgroundPixmap.size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + painter.drawPixmap(0, 0, foregroundImage.scaled(backgroundPixmap.size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); painter.end(); } return backgroundPixmap; } + +#endif diff --git a/retroshare-gui/src/util/PixmapMerging.h b/retroshare-gui/src/util/PixmapMerging.h index b151789b3..217652f23 100644 --- a/retroshare-gui/src/util/PixmapMerging.h +++ b/retroshare-gui/src/util/PixmapMerging.h @@ -21,6 +21,7 @@ #ifndef PIXMAPMERGING_H #define PIXMAPMERGING_H +#ifdef UNUSED_CODE #include #include @@ -49,4 +50,6 @@ public: RSQTUTIL_API static QPixmap merge(const std::string & foregroundPixmapData, const std::string & backgroundPixmapFilename); }; + +#endif #endif //PIXMAPMERGING_H diff --git a/retroshare-gui/src/util/imageutil.cpp b/retroshare-gui/src/util/imageutil.cpp index 7d609c6c8..cefa22906 100644 --- a/retroshare-gui/src/util/imageutil.cpp +++ b/retroshare-gui/src/util/imageutil.cpp @@ -108,17 +108,22 @@ bool ImageUtil::optimizeSize(QString &html, const QImage& original, QImage &opti // std::cout << "maxW: " << maxwidth << " minW: " << minwidth << std::endl; int region = 500; bool success = false; + int latestgood = 0; do { double m = (maxsize - minsize) / ((double)maxwidth * (double)maxwidth / whratio - (double)minwidth * (double)minwidth / whratio); double b = maxsize - m * ((double)maxwidth * (double)maxwidth / whratio); double a = ((double)(maxBytes - region/2) - b) / m; //maxBytes - region/2 target the center of the accepted region int nextwidth = (int)sqrt(a * whratio); - double nextsize = (double)checkSize(html, optimized = original.scaledToWidth(nextwidth, Qt::SmoothTransformation).convertToFormat(QImage::Format_Indexed8, ct), maxBytes); + int nextsize = checkSize(html, optimized = original.scaledToWidth(nextwidth, Qt::SmoothTransformation).convertToFormat(QImage::Format_Indexed8, ct), maxBytes); if(nextsize <= maxBytes) { minsize = nextsize; minwidth = nextwidth; - if(nextsize >= (maxBytes - region)) //the file size is close anough to the limit + if(nextsize >= (maxBytes - region) || //the file size is close enough to the limit + latestgood >= nextsize) { //The algorithm does not converge anymore success = true; + } else { + latestgood = nextsize; + } } else { maxsize = nextsize; maxwidth = nextwidth; diff --git a/retroshare-nogui/src/retroshare-nogui.pro b/retroshare-nogui/src/retroshare-nogui.pro index 8758f36c5..698a4c58e 100644 --- a/retroshare-nogui/src/retroshare-nogui.pro +++ b/retroshare-nogui/src/retroshare-nogui.pro @@ -58,6 +58,9 @@ linux-g++-64 { OBJECTS_DIR = temp/linux-g++-64/obj } +rs_sanitize { + LIBS *= -lasan -lubsan +} #################### Cross compilation for windows under Linux ################### win32-x-g++ { diff --git a/retroshare-nogui/src/retroshare.cc b/retroshare-nogui/src/retroshare.cc index 7a88e72d1..1e90edd7d 100644 --- a/retroshare-nogui/src/retroshare.cc +++ b/retroshare-nogui/src/retroshare.cc @@ -57,8 +57,10 @@ int main(int argc, char **argv) { -#ifdef ENABLE_WEBUI + RsConfigOptions conf; + conf.main_executable_path = argv[0]; +#ifdef ENABLE_WEBUI std::string docroot = resource_api::getDefaultDocroot(); uint16_t httpPort = 0; std::string listenAddress; @@ -77,8 +79,9 @@ int main(int argc, char **argv) std::cerr << args.usage() << std::endl; // print libretroshare command line args and exit RsInit::InitRsConfig(); - RsInit::InitRetroShare(argc, argv, true); - return 0; + + RsInit::InitRetroShare(conf); + return 0; } resource_api::ApiServer api; @@ -126,7 +129,7 @@ int main(int argc, char **argv) bool strictCheck = true; RsInit::InitRsConfig(); - int initResult = RsInit::InitRetroShare(argc, argv, strictCheck); + int initResult = RsInit::InitRetroShare(conf); if (initResult < 0) { /* Error occured */ diff --git a/retroshare-service/src/retroshare-service.cc b/retroshare-service/src/retroshare-service.cc index bcacb5880..d21291c99 100644 --- a/retroshare-service/src/retroshare-service.cc +++ b/retroshare-service/src/retroshare-service.cc @@ -1,6 +1,6 @@ /* * RetroShare Service - * Copyright (C) 2016-2018 Gioacchino Mazzurco + * Copyright (C) 2016-2019 Gioacchino Mazzurco * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -17,61 +17,301 @@ */ #include "util/stacktrace.h" +#include "util/argstream.h" +#include "util/rskbdinput.h" +#include "retroshare/rsinit.h" -CrashStackTrace gCrashStackTrace; +#ifdef RS_JSONAPI +#include "jsonapi/jsonapi.h" +#endif -#include +static CrashStackTrace gCrashStackTrace; + +#include #include -#include -#include +#include +#include #ifdef __ANDROID__ # include +# include +# include +# include + +# include "util/androiddebug.h" #endif // def __ANDROID__ #include "retroshare/rsinit.h" #include "retroshare/rsiface.h" +#include "util/rsdebug.h" + +#ifdef RS_SERVICE_TERMINAL_LOGIN +class RsServiceNotify: public NotifyClient +{ +public: + RsServiceNotify() = default; + virtual ~RsServiceNotify() = default; + + virtual bool askForPassword( + const std::string& title, const std::string& question, + bool /*prev_is_bad*/, std::string& password, bool& cancel ) + { + std::string question1 = title + + "\nPlease enter your PGP password for key:\n " + + question + " :"; + password = RsUtil::rs_getpass(question1.c_str()) ; + cancel = false ; + + return !password.empty(); + } +}; +#endif // def RS_SERVICE_TERMINAL_LOGIN #ifdef __ANDROID__ -# include "util/androiddebug.h" -#endif +void signalHandler(int /*signal*/) { QCoreApplication::exit(0); } +#else +static std::atomic keepRunning(true); +static int receivedSignal = 0; + +void signalHandler(int signal) +{ + if(RsControl::instance()->isReady()) + RsControl::instance()->rsGlobalShutDown(); + receivedSignal = signal; + keepRunning = false; +} +#endif // def __ANDROID__ -#ifndef RS_JSONAPI -# error Inconsistent build configuration retroshare_service needs rs_jsonapi -#endif int main(int argc, char* argv[]) { #ifdef __ANDROID__ AndroidStdIOCatcher dbg; (void) dbg; QAndroidService app(argc, argv); -#else // def __ANDROID__ - QCoreApplication app(argc, argv); #endif // def __ANDROID__ - signal(SIGINT, QCoreApplication::exit); - signal(SIGTERM, QCoreApplication::exit); + signal(SIGINT, signalHandler); + signal(SIGTERM, signalHandler); #ifdef SIGBREAK - signal(SIGBREAK, QCoreApplication::exit); + signal(SIGBREAK, signalHandler); #endif // ifdef SIGBREAK + RsInfo() << "\n" << + "+================================================================+\n" + "| o---o o |\n" + "| \\ / - Retroshare Service - / \\ |\n" + "| o o---o |\n" + "+================================================================+" + << std::endl << std::endl; + RsInit::InitRsConfig(); - - // clumsy way to enable JSON API by default - if(!QCoreApplication::arguments().contains("--jsonApiPort")) - { - int argc2 = argc + 2; - char* argv2[argc2]; for (int i = 0; i < argc; ++i ) argv2[i] = argv[i]; - char opt[] = "--jsonApiPort"; - char val[] = "9092"; - argv2[argc] = opt; - argv2[argc+1] = val; - RsInit::InitRetroShare(argc2, argv2, true); - } - else RsInit::InitRetroShare(argc, argv, true); - RsControl::earlyInitNotificationSystem(); + +#ifdef __APPLE__ + // TODO: is this still needed with argstream? + /* HACK to avoid stupid OSX Finder behaviour + * remove the commandline arguments - if we detect we are launched from + * Finder, and we have the unparsable "-psn_0_12332" option. + * this is okay, as you cannot pass commandline arguments via Finder anyway + */ + if ((argc >= 2) && (0 == strncmp(argv[1], "-psn", 4))) argc = 1; +#endif + + std::string prefUserString; + RsConfigOptions conf; + +#ifdef RS_JSONAPI + conf.jsonApiPort = JsonApiServer::DEFAULT_PORT; // enable JSonAPI by default +#endif + + argstream as(argc,argv); + as >> option( 's', "stderr", conf.outStderr, + "output to stderr instead of log file." ) + >> option( 'u',"udp", conf.udpListenerOnly, + "Only listen to UDP." ) + >> parameter( 'c',"base-dir", conf.optBaseDir, "directory", + "Set base directory.", false ) + >> parameter( 'l', "log-file", conf.logfname, "logfile", + "Set Log filename.", false ) + >> parameter( 'd', "debug-level", conf.debugLevel, "level", + "Set debug level.", false ) + >> parameter( 'i', "ip-address", conf.forcedInetAddress, "IP", + "Force IP address to use (if cannot be detected).", false ) + >> parameter( 'o', "opmode", conf.opModeStr, "opmode", + "Set Operating mode (Full, NoTurtle, Gaming, Minimal).", + false ) + >> parameter( 'p', "port", conf.forcedPort, "port", + "Set listenning port to use.", false ); + +#ifdef RS_SERVICE_TERMINAL_LOGIN + as >> parameter( 'U', "user-id", prefUserString, "ID", + "[node Id] Selected account to use and asks for passphrase" + ". Use \"-U list\" in order to list available accounts.", + false ); +#endif // RS_SERVICE_TERMINAL_LOGIN + +#ifdef RS_JSONAPI + as >> parameter( 'J', "jsonApiPort", conf.jsonApiPort, "TCP Port", + "Enable JSON API on the specified port", false ) + >> parameter( 'P', "jsonApiBindAddress", conf.jsonApiBindAddress, + "TCP bind address", "JSON API Bind Address default " + "127.0.0.1.", false ); +#endif // def RS_JSONAPI + +#if defined(RS_JSONAPI) && defined(RS_WEBUI) \ + && defined(RS_SERVICE_TERMINAL_WEBUI_PASSWORD) + bool askWebUiPassword = false; + as >> option( 'W', "webui-password", askWebUiPassword, + "Ask WebUI password on the console." ); +#endif /* defined(RS_JSONAPI) && defined(RS_WEBUI) \ + && defined(RS_SERVICE_TERMINAL_WEBUI_PASSWORD) */ + + +#ifdef LOCALNET_TESTING + as >> parameter( 'R', "restrict-port" , portRestrictions, "port1-port2", + "Apply port restriction", false); +#endif // ifdef LOCALNET_TESTING + +#ifdef RS_AUTOLOGIN + as >> option( 'a', "auto-login", conf.autoLogin, + "enable auto-login." ); +#endif // ifdef RS_AUTOLOGIN + + as >> help( 'h', "help", "Display this Help" ); + as.defaultErrorHandling(true, true); + +#if defined(RS_JSONAPI) && defined(RS_WEBUI) \ + && defined(RS_SERVICE_TERMINAL_WEBUI_PASSWORD) + std::string webui_pass1 = "Y"; + if(askWebUiPassword) + { + std::string webui_pass2 = "N"; + + while(keepRunning) + { + webui_pass1 = RsUtil::rs_getpass( + "Please register a password for the web interface: " ); + webui_pass2 = RsUtil::rs_getpass( + "Please enter the same password again : " ); + + if(webui_pass1 != webui_pass2) + { + std::cout << "Passwords do not match!" << std::endl; + continue; + } + if(webui_pass1.empty()) + { + std::cout << "Password cannot be empty!" << std::endl; + continue; + } + + break; + } + } +#endif /* defined(RS_JSONAPI) && defined(RS_WEBUI) + && defined(RS_SERVICE_TERMINAL_WEBUI_PASSWORD) */ + + conf.main_executable_path = argv[0]; + + int initResult = RsInit::InitRetroShare(conf); + if(initResult != RS_INIT_OK) + { + RsErr() << "Retroshare core initalization failed with: " << initResult + << std::endl; + return -initResult; + } + +#ifdef RS_SERVICE_TERMINAL_LOGIN + if(!prefUserString.empty()) // Login from terminal requested + { + if(prefUserString == "list") + { + std::cout << std::endl << std::endl + << "Available accounts:" << std::endl; + + std::vector locations; + rsLoginHelper->getLocations(locations); + + int accountCountDigits = static_cast( + ceil(log(locations.size())/log(10.0)) ); + + for( uint32_t i=0; i= locations.size())) + { + std::cout << "Please enter account number: "; + std::cout.flush(); + + std::string inputStr; + std::getline(std::cin, inputStr); + + nacc = static_cast(atoi(inputStr.c_str())-1); + if(nacc < locations.size()) + { + prefUserString = locations[nacc].mLocationId.toStdString(); + break; + } + nacc=0; // allow to continue if something goes wrong. + } + } + + + RsPeerId ssl_id(prefUserString); + if(ssl_id.isNull()) + { + RsErr() << "Invalid User location id: a hexadecimal ID is expected." + << std::endl; + return -EINVAL; + } + + RsServiceNotify* notify = new RsServiceNotify(); + rsNotify->registerNotifyClient(notify); + + // supply empty passwd so that it is properly asked 3 times on console + RsInit::LoadCertificateStatus result = + rsLoginHelper->attemptLogin(ssl_id, ""); + + switch(result) + { + case RsInit::OK: break; + case RsInit::ERR_ALREADY_RUNNING: + RsErr() << "Another RetroShare using the same profile is already " + "running on your system. Please close that instance " + "first." << std::endl << "Lock file: " + << RsInit::lockFilePath() << std::endl; + return -RsInit::ERR_ALREADY_RUNNING; + case RsInit::ERR_CANT_ACQUIRE_LOCK: + RsErr() << "An unexpected error occurred when Retroshare tried to " + "acquire the single instance lock file." << std::endl + << "Lock file: " << RsInit::lockFilePath() << std::endl; + return -RsInit::ERR_CANT_ACQUIRE_LOCK; + case RsInit::ERR_UNKNOWN: // Fall-throug + default: + RsErr() << "Cannot login. Check your passphrase." << std::endl + << std::endl; + return -result; + } + } +#endif // def RS_SERVICE_TERMINAL_LOGIN + +#if defined(RS_JSONAPI) && defined(RS_WEBUI) \ + && defined(RS_SERVICE_TERMINAL_WEBUI_PASSWORD) + if(jsonApiServer && !webui_pass1.empty()) + jsonApiServer->authorizeToken("webui:"+webui_pass1); +#endif /* defined(RS_JSONAPI) && defined(RS_WEBUI) \ + && defined(RS_SERVICE_TERMINAL_WEBUI_PASSWORD) */ + +#ifdef __ANDROID__ rsControl->setShutdownCallback(QCoreApplication::exit); + QObject::connect( &app, &QCoreApplication::aboutToQuit, [](){ @@ -79,4 +319,12 @@ int main(int argc, char* argv[]) RsControl::instance()->rsGlobalShutDown(); } ); return app.exec(); +#else // def __ANDROID__ + rsControl->setShutdownCallback([&](int){keepRunning = false;}); + + while(keepRunning) + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + + return 0; +#endif } diff --git a/retroshare-service/src/retroshare-service.pro b/retroshare-service/src/retroshare-service.pro index 612288d9b..2353b1f14 100644 --- a/retroshare-service/src/retroshare-service.pro +++ b/retroshare-service/src/retroshare-service.pro @@ -40,3 +40,75 @@ unix { target.path = "$${RS_BIN_DIR}" INSTALLS += target } + +macx { + # ENABLE THIS OPTION FOR Univeral Binary BUILD. + #CONFIG += ppc x86 + #QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.4 + LIBS += -lz + #LIBS += -lssl -lcrypto -lz -lgpgme -lgpg-error -lassuan + + for(lib, LIB_DIR):exists($$lib/libminiupnpc.a){ LIBS += $$lib/libminiupnpc.a} + + LIBS += -framework CoreFoundation + LIBS += -framework Security + LIBS += -framework Carbon + + for(lib, LIB_DIR):LIBS += -L"$$lib" + for(bin, BIN_DIR):LIBS += -L"$$bin" + + DEPENDPATH += . $$INC_DIR + INCLUDEPATH += . $$INC_DIR +} + +win32-g++ { + CONFIG(debug, debug|release) { + # show console output + CONFIG += console + } else { + CONFIG -= console + } + + # Switch on extra warnings + QMAKE_CFLAGS += -Wextra + QMAKE_CXXFLAGS += -Wextra + + CONFIG(debug, debug|release) { + } else { + # Tell linker to use ASLR protection + QMAKE_LFLAGS += -Wl,-dynamicbase + # Tell linker to use DEP protection + QMAKE_LFLAGS += -Wl,-nxcompat + } + + # Fix linking error (ld.exe: Error: export ordinal too large) due to too + # many exported symbols. + QMAKE_LFLAGS+=-Wl,--exclude-libs,ALL + + # Switch off optimization for release version + QMAKE_CXXFLAGS_RELEASE -= -O2 + QMAKE_CXXFLAGS_RELEASE += -O0 + QMAKE_CFLAGS_RELEASE -= -O2 + QMAKE_CFLAGS_RELEASE += -O0 + + # Switch on optimization for debug version + #QMAKE_CXXFLAGS_DEBUG += -O2 + #QMAKE_CFLAGS_DEBUG += -O2 + + OBJECTS_DIR = temp/obj + + dLib = ws2_32 gdi32 uuid ole32 iphlpapi crypt32 winmm + LIBS *= $$linkDynamicLibs(dLib) + + # export symbols for the plugins + LIBS += -Wl,--export-all-symbols,--out-implib,lib/libretroshare-service.a + + # create lib directory + isEmpty(QMAKE_SH) { + QMAKE_PRE_LINK = $(CHK_DIR_EXISTS) lib $(MKDIR) lib + } else { + QMAKE_PRE_LINK = $(CHK_DIR_EXISTS) lib || $(MKDIR) lib + } +} + + diff --git a/retroshare.pri b/retroshare.pri index 2f2dac230..b43736a0c 100644 --- a/retroshare.pri +++ b/retroshare.pri @@ -1,19 +1,20 @@ ################################################################################ # retroshare.pri # -# Copyright (C) 2018, Retroshare team # +# Copyright (C) 2004-2019, Retroshare Team # +# Copyright (C) 2016-2019, Gioacchino Mazzurco # # # # This program is free software: you can redistribute it and/or modify # -# it under the terms of the GNU Affero General Public License as # +# it under the terms of the GNU Lesser General Public License as # # published by the Free Software Foundation, either version 3 of the # # License, or (at your option) any later version. # # # # This program is distributed in the hope that it will be useful, # # but WITHOUT ANY WARRANTY; without even the implied warranty of # -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # # GNU Lesser General Public License for more details. # # # # You should have received a copy of the GNU Lesser General Public License # -# along with this program. If not, see . # +# along with this program. If not, see . # ################################################################################ ################################################################################ @@ -28,20 +29,18 @@ CONFIG *= retroshare_gui no_retroshare_gui:CONFIG -= retroshare_gui +# Enable GXS distant syncronization CONFIG *= gxsdistsync -# disabled by the time we fix compilation -CONFIG *= no_cmark - # To disable RetroShare-nogui append the following # assignation to qmake command line "CONFIG+=no_retroshare_nogui" -CONFIG *= retroshare_nogui -no_retroshare_nogui:CONFIG -= retroshare_nogui +CONFIG *= no_retroshare_nogui +retroshare_nogui:CONFIG -= no_retroshare_nogui # To disable cmark append the following # assignation to qmake command line "CONFIG+=no_cmark" -CONFIG *= cmark -no_cmark:CONFIG -= cmark +CONFIG *= no_rs_gui_cmark +rs_gui_cmark:CONFIG -= no_rs_gui_cmark # To enable RetroShare plugins append the following # assignation to qmake command line "CONFIG+=retroshare_plugins" @@ -66,13 +65,12 @@ retroshare_qml_app:CONFIG -= no_retroshare_qml_app # To enable RetroShare service append the following assignation to # qmake command line "CONFIG+=retroshare_service" -CONFIG *= no_retroshare_service +CONFIG *= retroshare_service retroshare_service:CONFIG -= no_retroshare_service -# To disable libresapi append the following assignation to qmake command line -#"CONFIG+=no_libresapi" -CONFIG *= libresapi -no_libresapi:CONFIG -= libresapi +# To enable libresapi (deprecated) append the following assignation to qmake command line +CONFIG+=no_libresapi +libresapi:CONFIG -= no_libresapi # To enable libresapi via local socket (unix domain socket or windows named # pipes) append the following assignation to qmake command line @@ -87,8 +85,8 @@ libresapi_settings:CONFIG -= no_libresapi_settings # To disable libresapi via HTTP (based on libmicrohttpd) append the following # assignation to qmake command line "CONFIG+=no_libresapihttpserver" -CONFIG *= libresapihttpserver -no_libresapihttpserver:CONFIG -= libresapihttpserver +CONFIG *= no_libresapihttpserver +libresapihttpserver:CONFIG -= no_libresapihttpserver # To disable SQLCipher support append the following assignation to qmake # command line "CONFIG+=no_sqlcipher" @@ -142,6 +140,10 @@ rs_async_chat:CONFIG -= no_rs_async_chat CONFIG *= direct_chat no_direct_chat:CONFIG -= direct_chat +# To enable messemger window which has been deprecated since RetroShare 0.6.6 append +# the following assignation to qmake command line "CONFIG+=messenger" +# CONFIG *= messenger + # To disable bitdht append the following assignation to qmake command line # "CONFIG+=no_bitdht" CONFIG *= bitdht @@ -167,10 +169,30 @@ CONFIG *= no_rs_deep_search rs_deep_search:CONFIG -= no_rs_deep_search # To enable native dialogs append the following assignation to qmake command -#line "CONFIG+=rs_use_native_dialogs" +# line "CONFIG+=rs_use_native_dialogs" CONFIG *= no_rs_use_native_dialogs rs_use_native_dialogs:CONFIG -= no_rs_use_native_dialogs +# To disable broadcast discovery append the following assignation to qmake +# command line "CONFIG+=no_rs_broadcast_discovery" +CONFIG *= rs_broadcast_discovery +no_rs_broadcast_discovery:CONFIG -= rs_broadcast_discovery + +# To enable webui append the following assignation to qmake +# command line "CONFIG+=rs_webui" +CONFIG *= no_rs_webui +rs_webui:CONFIG -= no_rs_webui + +# To enable webui append the following assignation to qmake +# command line "CONFIG+=rs_service_webui_terminal_password" +CONFIG *= no_rs_service_webui_terminal_password +rs_service_webui_terminal_password:CONFIG -= no_rs_service_webui_terminal_password + +# To enable retroshare-service terminal login append the following assignation +# to qmake command line "CONFIG+=rs_service_terminal_login" +CONFIG *= no_rs_service_terminal_login +rs_service_terminal_login:CONFIG -= no_rs_service_terminal_login + # Specify host precompiled jsonapi-generator path, appending the following # assignation to qmake command line # 'JSONAPI_GENERATOR_EXE=/myBuildDir/jsonapi-generator'. Required for JSON API @@ -198,10 +220,17 @@ rs_use_native_dialogs:CONFIG -= no_rs_use_native_dialogs # use (pthread, "") usually depends on platform. isEmpty(RS_THREAD_LIB):RS_THREAD_LIB = pthread -# Specify UPnP library to use appending the following assignation to qmake -# command line 'RS_UPNP_LIB=miniupnpc' the name of the UPNP library to use -# (miniupnpc, "upnp ixml threadutil") usually depends on platform. -isEmpty(RS_UPNP_LIB):RS_UPNP_LIB = upnp ixml threadutil +# Specify UPnP library to use, appending the following assignation to qmake +# command line +# 'RS_UPNP_LIB=none' do not compile UPnP support +# 'RS_UPNP_LIB=miniupnpc' to use miniupnpc +# 'RS_UPNP_LIB="upnp ixml threadutil"' to use libupnp-1.6.x +# 'RS_UPNP_LIB="upnp ixml"' to use libupnp-1.8.x +# Which library is better suited usually depends on the platform. +# See http://miniupnp.free.fr/ and http://pupnp.sourceforge.net/ for more +# information about the libraries. Autodetection is attempted by default. +#RS_UPNP_LIB= + ########################################################################################################################################################### # @@ -297,7 +326,7 @@ defineReplace(linkStaticLibs) { return($$retSlib) } -## This function return pretarget deps for the static the libraries contained in +## This function return pretarget deps for the static libraries contained in ## the variable given as paramether. defineReplace(pretargetStaticLibs) { libsVarName = $$1 @@ -327,6 +356,20 @@ defineReplace(linkDynamicLibs) { return($$retDlib) } +## On some environements qmake chose a C++ compiler as C compiler, this breaks +## some sub targets, such as those based on cmake which test for chosen C +## compiler to be a proper C compiler. This function try to deduce the correct C +## compiler also in those cases, and return it. So you can use +## $$fixQmakeCC($$QMAKE_CC) in those cases instead of plain $$QMAKE_CC +defineReplace(fixQmakeCC) { + retVal = $$1 + contains(1, .*\+\+$):retVal=$$str_member($$1, 0 ,-3) + contains(1, .*g\+\+$):retVal=$$str_member($$1, 0 ,-3)cc + contains(1, .*g\+\+-[0-9]$):retVal=$$str_member($$1, 0 ,-5)cc$$str_member($$1, -2 ,-1) + contains(1, .*clang\+\+$):retVal=$$str_member($$1, 0 ,-3) + return($$retVal) +} + ################################################################################ ## Statements and variables that depends on build options (CONFIG) goes here ### ################################################################################ @@ -405,9 +448,9 @@ gxsdistsync:DEFINES *= RS_USE_GXS_DISTANT_SYNC wikipoos:DEFINES *= RS_USE_WIKI rs_gxs:DEFINES *= RS_ENABLE_GXS rs_gxs_send_all:DEFINES *= RS_GXS_SEND_ALL -libresapilocalserver:DEFINES *= LIBRESAPI_LOCAL_SERVER -libresapi_settings:DEFINES *= LIBRESAPI_SETTINGS -libresapihttpserver:DEFINES *= ENABLE_WEBUI +rs_webui:DEFINES *= RS_WEBUI +rs_service_webui_terminal_password:DEFINES *= RS_SERVICE_TERMINAL_WEBUI_PASSWORD +rs_service_terminal_login:DEFINES *= RS_SERVICE_TERMINAL_LOGIN sqlcipher { DEFINES -= NO_SQLCIPHER @@ -420,7 +463,7 @@ no_sqlcipher { rs_autologin { DEFINES *= RS_AUTOLOGIN - RS_AUTOLOGIN_WARNING_MSG = \ + RS_AUTOLOGIN_WARNING_MSG = QMAKE: \ You have enabled RetroShare auto-login, this is discouraged. The usage \ of auto-login on some linux distributions may allow someone having \ access to your session to steal the SSL keys of your node location and \ @@ -435,11 +478,15 @@ rs_onlyhiddennode { message("QMAKE: You have enabled only hidden node.") } +rs_sanitize { + QMAKE_CXXFLAGS *= -fsanitize=address -fsanitize=bounds -fsanitize=undefined +} + no_rs_deprecatedwarning { QMAKE_CXXFLAGS += -Wno-deprecated QMAKE_CXXFLAGS += -Wno-deprecated-declarations DEFINES *= RS_NO_WARN_DEPRECATED - message("QMAKE: You have disabled deprecated warnings.") + warning("QMAKE: You have disabled deprecated warnings.") } no_rs_cppwarning { @@ -447,7 +494,7 @@ no_rs_cppwarning { QMAKE_CXXFLAGS += -Wno-inconsistent-missing-override DEFINES *= RS_NO_WARN_CPP - message("QMAKE: You have disabled C preprocessor warnings.") + warning("QMAKE: You have disabled C preprocessor warnings.") } rs_gxs_trans { @@ -464,7 +511,7 @@ bitdht { } direct_chat { - warning("You have enabled RetroShare direct chat which is deprecated!") + warning("QMAKE: You have enabled RetroShare direct chat which is deprecated!") DEFINES *= RS_DIRECT_CHAT } @@ -484,6 +531,37 @@ to contain the path to an host executable jsonapi-generator") DEFINES *= RS_JSONAPI } +libresapilocalserver { + warning("QMAKE: you have enabled libresapilocalserver which is deprecated") + DEFINES *= LIBRESAPI_LOCAL_SERVER +} + +libresapi_settings { + warning("QMAKE: you have enabled libresapi_settings which is deprecated") + DEFINES *= LIBRESAPI_SETTINGS +} + +libresapihttpserver { + warning("QMAKE: you have enabled libresapihttpserver which is deprecated") + DEFINES *= ENABLE_WEBUI +} + +retroshare_nogui { + warning("QMAKE: you have enabled retroshare_nogui which is deprecated") +} + +retroshare_android_service { + warning("QMAKE: you have enabled retroshare_android_service which is deprecated") +} + +retroshare_android_notify_service { + warning("QMAKE: you have enabled retroshare_android_notify_service which is deprecated") +} + +retroshare_qml_app { + warning("QMAKE: you have enabled retroshare_qml_app which is deprecated") +} + rs_deep_search { DEFINES *= RS_DEEP_SEARCH @@ -496,6 +574,8 @@ rs_deep_search { rs_use_native_dialogs:DEFINES *= RS_NATIVEDIALOGS +rs_broadcast_discovery:DEFINES *= RS_BROADCAST_DISCOVERY + debug { QMAKE_CXXFLAGS -= -O2 -fomit-frame-pointer QMAKE_CFLAGS -= -O2 -fomit-frame-pointer @@ -685,6 +765,34 @@ macx-* { QT += macextras } +# If not yet defined attempt UPnP library autodetection should works at least +# for miniupnc libupnp-1.6.x and libupnp-1.8.x +isEmpty(RS_UPNP_LIB) { + __TEMP_UPNP_LIBS = upnp ixml threadutil + for(mLib, __TEMP_UPNP_LIBS) { + attemptPath=$$findFileInPath(lib$${mLib}.a, QMAKE_LIBDIR) + isEmpty(attemptPath):attemptPath=$$findFileInPath(lib$${mLib}.so, QMAKE_LIBDIR) + !isEmpty(attemptPath):RS_UPNP_LIB += $${mLib} + } + + isEmpty(RS_UPNP_LIB) { + __TEMP_UPNP_LIBS=$$findFileInPath(libminiupnpc.a, QMAKE_LIBDIR) + !isEmpty(__TEMP_UPNP_LIBS):RS_UPNP_LIB=miniupnpc + __TEMP_UPNP_LIBS=$$findFileInPath(libminiupnpc.so, QMAKE_LIBDIR) + !isEmpty(__TEMP_UPNP_LIBS):RS_UPNP_LIB=miniupnpc + } + + isEmpty(RS_UPNP_LIB) { + warning("RS_UPNP_LIB detection failed, UPnP support disabled!") + } else { + message("Autodetected RS_UPNP_LIB=$$RS_UPNP_LIB") + } +} + +equals(RS_UPNP_LIB, none):RS_UPNP_LIB= +equals(RS_UPNP_LIB, miniupnpc):DEFINES*=RS_USE_LIBMINIUPNPC +contains(RS_UPNP_LIB, upnp):DEFINES*=RS_USE_LIBUPNP + ## Retrocompatibility assignations, get rid of this ASAP isEmpty(BIN_DIR) : BIN_DIR = $${RS_BIN_DIR} diff --git a/supportlibs/udp-discovery-cpp b/supportlibs/udp-discovery-cpp new file mode 160000 index 000000000..f3a3103a6 --- /dev/null +++ b/supportlibs/udp-discovery-cpp @@ -0,0 +1 @@ +Subproject commit f3a3103a6c52e5707629e8d0a7e279a7758fe845