mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-06-21 04:44:25 -04:00
merged upstream/master
This commit is contained in:
commit
6419b03a2a
131 changed files with 6081 additions and 1473 deletions
|
@ -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
|
||||
|
||||
|
|
16
appveyor.yml
16
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 #
|
||||
|
@ -137,6 +146,7 @@ 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
|
||||
|
||||
|
@ -236,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
|
||||
|
|
|
@ -21,15 +21,15 @@ 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.8.4"
|
||||
define_default_value LIBUPNP_SOURCE_SHA256 976c3e4555604cdd8391ed2f359c08c9dead3b6bf131c24ce78e64d6669af2ed
|
||||
|
@ -38,7 +38,7 @@ 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"
|
||||
|
@ -81,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"
|
||||
|
@ -101,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} \
|
||||
|
@ -111,6 +126,11 @@ build_toolchain()
|
|||
## This avoid <cmath> 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
|
||||
|
@ -119,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"
|
||||
|
@ -202,6 +228,12 @@ 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
|
||||
|
||||
|
@ -226,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
|
||||
|
||||
|
@ -243,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
|
||||
|
@ -256,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*
|
||||
|
@ -274,6 +319,12 @@ build_sqlite()
|
|||
|
||||
build_sqlcipher()
|
||||
{
|
||||
echo "build_sqlcipher()
|
||||
################################################################################
|
||||
################################################################################
|
||||
################################################################################
|
||||
"
|
||||
|
||||
B_dir="sqlcipher-${SQLCIPHER_SOURCE_VERSION}"
|
||||
rm -rf $B_dir
|
||||
|
||||
|
@ -284,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 \
|
||||
|
@ -297,6 +356,12 @@ build_sqlcipher()
|
|||
|
||||
build_libupnp()
|
||||
{
|
||||
echo "build_libupnp()
|
||||
################################################################################
|
||||
################################################################################
|
||||
################################################################################
|
||||
"
|
||||
|
||||
B_dir="pupnp-release-${LIBUPNP_SOURCE_VERSION}"
|
||||
B_ext=".tar.gz"
|
||||
B_file="${B_dir}${B_ext}"
|
||||
|
@ -312,9 +377,9 @@ build_libupnp()
|
|||
## 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 \
|
||||
./configure --with-pic --enable-static --disable-shared --disable-samples \
|
||||
--disable-largefile \
|
||||
--prefix="${PREFIX}" --host=${ANDROID_NDK_ARCH}-linux
|
||||
--prefix="${PREFIX}" --host=${cArch}-linux
|
||||
make -j${HOST_NUM_CPU}
|
||||
make install
|
||||
cd ..
|
||||
|
@ -322,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 \
|
||||
|
@ -332,17 +403,26 @@ 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/"
|
||||
|
@ -351,6 +431,12 @@ build_restbed()
|
|||
|
||||
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
|
||||
|
@ -359,7 +445,9 @@ build_udp-discovery-cpp()
|
|||
|
||||
B_dir="udp-discovery-cpp-build"
|
||||
rm -rf ${B_dir}; mkdir ${B_dir}; cd ${B_dir}
|
||||
cmake -DCMAKE_INSTALL_PREFIX="${PREFIX}" -B. -H../udp-discovery-cpp
|
||||
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/"
|
||||
|
@ -368,6 +456,12 @@ build_udp-discovery-cpp()
|
|||
|
||||
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 \
|
||||
|
@ -379,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
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 35923c31918c0497827a6c22381178b63b10f6e0
|
||||
Subproject commit a8c1d3bca9de4c93d0212ed9dcda22fe06c833ec
|
|
@ -18,8 +18,8 @@
|
|||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
registerHandler("$%apiPath%$",
|
||||
[$%captureVars%$](const std::shared_ptr<rb::Session> session)
|
||||
registerHandler( "$%apiPath%$",
|
||||
[this](const std::shared_ptr<rb::Session> session)
|
||||
{
|
||||
const std::multimap<std::string, std::string> headers
|
||||
{
|
||||
|
@ -29,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<rb::Session> session,
|
||||
const rb::Bytes& body )
|
||||
{
|
||||
|
@ -44,17 +44,24 @@ $%paramsDeclaration%$
|
|||
$%inputParamsDeserialization%$
|
||||
|
||||
const std::weak_ptr<rb::Session> weakSession(session);
|
||||
$%callbackName%$ = [weakSession]($%callbackParams%$)
|
||||
$%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%$
|
||||
|
@ -67,5 +74,4 @@ $%outputParamsSerialization%$
|
|||
session->yield(message.str());
|
||||
$%sessionDelayedClose%$
|
||||
} );
|
||||
}, $%requiresAuth%$);
|
||||
|
||||
}, $%requiresAuth%$ );
|
||||
|
|
|
@ -92,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))
|
||||
|
@ -320,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;
|
||||
|
||||
|
@ -381,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);
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
registerHandler("$%apiPath%$",
|
||||
[$%captureVars%$](const std::shared_ptr<rb::Session> session)
|
||||
registerHandler( "$%apiPath%$",
|
||||
[](const std::shared_ptr<rb::Session> session)
|
||||
{
|
||||
size_t reqSize = session->get_request()->get_header("Content-Length", 0);
|
||||
session->fetch( reqSize, [](
|
||||
|
@ -46,5 +46,5 @@ $%outputParamsSerialization%$
|
|||
// return them to the API caller
|
||||
DEFAULT_API_CALL_JSON_RETURN(rb::OK);
|
||||
} );
|
||||
}, $%requiresAuth%$);
|
||||
}, $%requiresAuth%$ );
|
||||
|
||||
|
|
|
@ -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<RsPeerId>::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<ChatLobbyId,ChatLobbyEntry>::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<RsItem*>& 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<const RsSubscribedChatLobbyConfigItem*>(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 ;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<RsPeerId>& 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) ;
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
*******************************************************************************/
|
||||
|
||||
#include <stdexcept>
|
||||
#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<uint64_t>(j,ctx,lobby_Id,"lobby_Id") ;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -968,16 +968,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
|
||||
|
|
|
@ -109,8 +109,8 @@ class p3FileDatabase: public p3Service, public p3Config, public ftSearch //, pub
|
|||
virtual int SearchKeywords(const std::list<std::string>& keywords, std::list<DirDetails>& results,FileSearchFlags flags,const RsPeerId& peer_id) ;
|
||||
virtual int SearchBoolExp(RsRegularExpression::Expression *exp, std::list<DirDetails>& 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
|
||||
//
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright 2008 by Robert Fernie <retroshare@lunamutt.com> *
|
||||
* Copyright (C) 2008 Robert Fernie <retroshare@lunamutt.com> *
|
||||
* Copyright (C) 2018-2019 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* *
|
||||
* 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<int>(time(nullptr) + period);
|
||||
|
||||
{
|
||||
RS_STACK_MUTEX(extMutex);
|
||||
mToHash.push_back(details); /* add into queue */
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -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<uint32_t>(period), flags );
|
||||
}
|
||||
|
||||
bool ftServer::ExtraFileStatus(std::string localpath, FileInfo &info)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -100,8 +100,9 @@ void DiscPgpInfo::mergeFriendList(const std::set<PGPID> &friends)
|
|||
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)
|
||||
p3Service(), mRsEventsHandle(0), mPeerMgr(peerMgr), mLinkMgr(linkMgr),
|
||||
mNetMgr(netMgr), mServiceCtrl(sc), mGixs(gixs), mDiscMtx("p3discovery2"),
|
||||
mLastPgpUpdate(0)
|
||||
{
|
||||
Dbg3() << __PRETTY_FUNCTION__ << std::endl;
|
||||
|
||||
|
@ -111,9 +112,12 @@ p3discovery2::p3discovery2(
|
|||
// Add self into PGP FriendList.
|
||||
mFriendList[AuthGPG::getAuthGPG()->getGPGOwnId()] = DiscPgpInfo();
|
||||
|
||||
rsEvents->registerEventsHandler(
|
||||
[this](const RsEvent& event){ rsEventsHandler(event); },
|
||||
mRsEventsHandle );
|
||||
if(rsEvents)
|
||||
rsEvents->registerEventsHandler(
|
||||
[this](std::shared_ptr<const RsEvent> event)
|
||||
{
|
||||
rsEventsHandler(*event);
|
||||
}, mRsEventsHandle ); // mRsEventsHandle is zeroed in initializer list
|
||||
}
|
||||
|
||||
|
||||
|
@ -1240,12 +1244,9 @@ void p3discovery2::recvInvite(
|
|||
std::unique_ptr<RsGossipDiscoveryInviteItem> inviteItem )
|
||||
{
|
||||
typedef RsGossipDiscoveryFriendInviteReceivedEvent Evt_t;
|
||||
|
||||
// Ensure rsEvents is not deleted while we use it
|
||||
std::shared_ptr<RsEvents> lockedRsEvents = rsEvents;
|
||||
if(lockedRsEvents)
|
||||
lockedRsEvents->postEvent(
|
||||
std::unique_ptr<Evt_t>(new Evt_t(inviteItem->mInvite)) );
|
||||
if(rsEvents)
|
||||
rsEvents->postEvent(
|
||||
std::shared_ptr<Evt_t>(new Evt_t(inviteItem->mInvite)) );
|
||||
}
|
||||
|
||||
void p3discovery2::rsEventsHandler(const RsEvent& event)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright (C) 2016-2017 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* Copyright (C) 2016-2019 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* *
|
||||
* 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"
|
||||
|
@ -621,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;
|
||||
}
|
||||
|
@ -964,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:
|
||||
|
@ -986,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<uint>(pr.mailItem.cryptoType)
|
||||
<< " dropping mail!" << std::endl;
|
||||
|
@ -1040,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)
|
||||
{
|
||||
|
@ -1051,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:
|
||||
|
@ -1067,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<uint>(pr.status)
|
||||
RsErr() << __PRETTY_FUNCTION__ << " processing:" << pr.mailItem.mailId
|
||||
<< " failed with: " << static_cast<uint>(pr.status)
|
||||
<< std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void p3GxsTrans::notifyClientService(const OutgoingRecord& pr)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright (C) 2016-2017 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* Copyright (C) 2016-2019 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* *
|
||||
* 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 <stdint.h>
|
||||
#include <cstdint>
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
|
||||
|
@ -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
|
||||
|
|
|
@ -289,7 +289,8 @@ JsonApiServer::JsonApiServer(uint16_t port, const std::string& bindAddress,
|
|||
};
|
||||
session->yield(rb::OK, headers);
|
||||
|
||||
size_t reqSize = session->get_request()->get_header("Content-Length", 0);
|
||||
size_t reqSize = static_cast<size_t>(
|
||||
session->get_request()->get_header("Content-Length", 0) );
|
||||
session->fetch( reqSize, [this](
|
||||
const std::shared_ptr<rb::Session> session,
|
||||
const rb::Bytes& body )
|
||||
|
@ -302,24 +303,28 @@ JsonApiServer::JsonApiServer(uint16_t port, const std::string& bindAddress,
|
|||
|
||||
const std::weak_ptr<rb::Session> weakSession(session);
|
||||
RsEventsHandlerId_t hId = rsEvents->generateUniqueHandlerId();
|
||||
std::function<void(const RsEvent&)> multiCallback =
|
||||
[weakSession, hId](const RsEvent& event)
|
||||
std::function<void(std::shared_ptr<const RsEvent>)> multiCallback =
|
||||
[this, weakSession, hId](std::shared_ptr<const RsEvent> event)
|
||||
{
|
||||
auto session = weakSession.lock();
|
||||
if(!session || session->is_closed())
|
||||
mService.schedule( [weakSession, hId, event]()
|
||||
{
|
||||
if(rsEvents) rsEvents->unregisterEventsHandler(hId);
|
||||
return;
|
||||
}
|
||||
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<RsEvent&>(event), "event" );
|
||||
RsGenericSerializer::SerializeContext ctx;
|
||||
RsTypeSerializer::serial_process(
|
||||
RsGenericSerializer::TO_JSON, ctx,
|
||||
*const_cast<RsEvent*>(event.get()), "event" );
|
||||
|
||||
std::stringstream message;
|
||||
message << "data: " << compactJSON << ctx.mJson << "\n\n";
|
||||
session->yield(message.str());
|
||||
std::stringstream message;
|
||||
message << "data: " << compactJSON << ctx.mJson << "\n\n";
|
||||
|
||||
session->yield(message.str());
|
||||
} );
|
||||
};
|
||||
|
||||
bool retval = rsEvents->registerEventsHandler(multiCallback, hId);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -311,7 +311,7 @@ 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*/ )
|
||||
std::string locationName )
|
||||
{
|
||||
/* single call here si don't need to invoke mutex yet */
|
||||
static int initLib = 0;
|
||||
|
@ -520,6 +520,8 @@ int AuthSSLimpl::InitAuth(
|
|||
else
|
||||
std::cerr << std::endl;
|
||||
|
||||
mOwnLocationName = locationName;
|
||||
|
||||
init = 1;
|
||||
return 1;
|
||||
}
|
||||
|
@ -575,7 +577,7 @@ const RsPeerId& AuthSSLimpl::OwnId()
|
|||
}
|
||||
|
||||
std::string AuthSSLimpl::getOwnLocation()
|
||||
{ return RsX509Cert::getCertLocation(*mOwnCert); }
|
||||
{ return mOwnLocationName; }
|
||||
|
||||
std::string AuthSSLimpl::SaveOwnCertificateToString()
|
||||
{ return saveX509ToPEM(mOwnCert); }
|
||||
|
|
|
@ -98,7 +98,7 @@ public:
|
|||
virtual bool active() = 0;
|
||||
virtual int InitAuth(
|
||||
const char* srvr_cert, const char* priv_key, const char* passwd,
|
||||
std::string alternative_location_name ) = 0;
|
||||
std::string locationName ) = 0;
|
||||
virtual bool CloseAuth() = 0;
|
||||
|
||||
/*********** Overloaded Functions from p3AuthMgr **********/
|
||||
|
@ -198,7 +198,7 @@ public:
|
|||
|
||||
bool active() override;
|
||||
int InitAuth( const char *srvr_cert, const char *priv_key,
|
||||
const char *passwd, std::string alternative_location_name )
|
||||
const char *passwd, std::string locationName )
|
||||
override;
|
||||
|
||||
bool CloseAuth() override;
|
||||
|
@ -278,6 +278,14 @@ private:
|
|||
RsPeerId mOwnId;
|
||||
X509* mOwnCert;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
|
|
@ -477,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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) ; }
|
||||
|
|
|
@ -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 */) ;
|
||||
|
|
|
@ -46,19 +46,17 @@ extern std::shared_ptr<RsBroadcastDiscovery> rsBroadcastDiscovery;
|
|||
|
||||
struct RsBroadcastDiscoveryResult : RsSerializable
|
||||
{
|
||||
PGPFingerprintType mPgpFingerprint;
|
||||
RsPeerId mSslId;
|
||||
std::string mProfileName;
|
||||
RsUrl locator;
|
||||
RsUrl mLocator;
|
||||
|
||||
/// @see RsSerializable
|
||||
void serial_process( RsGenericSerializer::SerializeJob j,
|
||||
RsGenericSerializer::SerializeContext& ctx) override
|
||||
{
|
||||
RS_SERIAL_PROCESS(mPgpFingerprint);
|
||||
RS_SERIAL_PROCESS(mSslId);
|
||||
RS_SERIAL_PROCESS(mProfileName);
|
||||
RS_SERIAL_PROCESS(locator);
|
||||
RS_SERIAL_PROCESS(mLocator);
|
||||
}
|
||||
|
||||
RsBroadcastDiscoveryResult() = default;
|
||||
|
|
|
@ -37,7 +37,7 @@ class RsEvents;
|
|||
* TODO: this should become std::weak_ptr once we have a reasonable services
|
||||
* management.
|
||||
*/
|
||||
extern std::shared_ptr<RsEvents> rsEvents;
|
||||
extern RsEvents* rsEvents;
|
||||
|
||||
/**
|
||||
* @brief Events types.
|
||||
|
@ -116,21 +116,20 @@ public:
|
|||
* @return False on error, true otherwise.
|
||||
*/
|
||||
virtual bool postEvent(
|
||||
std::unique_ptr<RsEvent> event,
|
||||
std::shared_ptr<const RsEvent> 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, ensuring the function
|
||||
* returns only after the event has been handled.
|
||||
* 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(
|
||||
const RsEvent& event,
|
||||
std::shared_ptr<const RsEvent> event,
|
||||
std::string& errorMessage = RS_DEFAULT_STORAGE_PARAM(std::string)
|
||||
) = 0;
|
||||
|
||||
|
@ -155,7 +154,7 @@ public:
|
|||
* @return False on error, true otherwise.
|
||||
*/
|
||||
virtual bool registerEventsHandler(
|
||||
std::function<void(const RsEvent&)> multiCallback,
|
||||
std::function<void(std::shared_ptr<const RsEvent>)> multiCallback,
|
||||
RsEventsHandlerId_t& hId = RS_DEFAULT_STORAGE_PARAM(RsEventsHandlerId_t, 0)
|
||||
) = 0;
|
||||
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright 2008-2008 by Robert Fernie <retroshare@lunamutt.com> *
|
||||
* Copyright (C) 2008 Robert Fernie <retroshare@lunamutt.com> *
|
||||
* Copyright (C) 2018-2019 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* *
|
||||
* 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
|
||||
|
|
|
@ -1,6 +1,37 @@
|
|||
/*******************************************************************************
|
||||
* libretroshare/src/retroshare: rsflags.h *
|
||||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright 2012-2019 by Retroshare Team <contact@retroshare.cc> *
|
||||
* *
|
||||
* 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 <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cstdint>
|
||||
|
||||
/* 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
|
||||
|
|
|
@ -142,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
|
||||
|
@ -155,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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright (C) 2012 by Robert Fernie <retroshare@lunamutt.com> *
|
||||
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* Copyright (C) 2012-2014 Robert Fernie <retroshare@lunamutt.com> *
|
||||
* Copyright (C) 2018-2019 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* *
|
||||
* 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<RsGxsId>& moderatorsIds = std::set<RsGxsId>(),
|
||||
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<RsGxsMessageId>& msgsIds,
|
||||
const std::set<RsGxsMessageId>& msgsIds,
|
||||
std::vector<RsGxsForumMsg>& 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<RsGxsForumGroup> &groups) = 0;
|
||||
|
@ -203,4 +275,3 @@ public:
|
|||
RS_DEPRECATED_FOR(editForum)
|
||||
virtual bool updateGroup(uint32_t &token, RsGxsForumGroup &group) = 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -91,6 +91,7 @@ struct RsGxsChanges : RsEvent
|
|||
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);
|
||||
|
@ -99,7 +100,7 @@ struct RsGxsChanges : RsEvent
|
|||
RS_SERIAL_PROCESS(mDistantSearchReqs);
|
||||
}
|
||||
|
||||
RsTokenService* mService; // Weak pointer, not serialized
|
||||
RsTokenService* mService; /// Weak pointer, not serialized
|
||||
};
|
||||
|
||||
/*!
|
||||
|
|
|
@ -140,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.
|
||||
|
@ -169,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
|
||||
|
|
|
@ -1,3 +1,23 @@
|
|||
/*******************************************************************************
|
||||
* libretroshare/src/retroshare: rsgxstrans.h *
|
||||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright (C) 2016-2019 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* *
|
||||
* 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 <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
#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:
|
||||
|
|
|
@ -244,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. */
|
||||
|
@ -380,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
|
||||
|
@ -400,7 +409,7 @@ struct RsIdentity : RsGxsIfaceHelper
|
|||
* @param[out] ids storage for the ids
|
||||
* @return false on error, true otherwise
|
||||
*/
|
||||
virtual bool getOwnSignedIds(std::vector<RsGxsId> ids) = 0;
|
||||
virtual bool getOwnSignedIds(std::vector<RsGxsId>& ids) = 0;
|
||||
|
||||
/**
|
||||
* @brief Get own pseudonimous (unsigned) ids
|
||||
|
@ -408,7 +417,7 @@ struct RsIdentity : RsGxsIfaceHelper
|
|||
* @param[out] ids storage for the ids
|
||||
* @return false on error, true otherwise
|
||||
*/
|
||||
virtual bool getOwnPseudonimousIds(std::vector<RsGxsId> ids) = 0;
|
||||
virtual bool getOwnPseudonimousIds(std::vector<RsGxsId>& ids) = 0;
|
||||
|
||||
/**
|
||||
* @brief Check if an id is own
|
||||
|
@ -468,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
|
||||
|
@ -503,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(
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
/*******************************************************************************
|
||||
* libretroshare/src/retroshare: rsinit.h *
|
||||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright 2004-2006 by Robert Fernie <retroshare@lunamutt.com> *
|
||||
* Copyright (C) 2004-2014 Robert Fernie <retroshare@lunamutt.com> *
|
||||
* Copyright (C) 2016-2019 Gioacchino Mazzurco <gio@altermundi.net> *
|
||||
* *
|
||||
* 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 <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
#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
|
||||
|
@ -30,13 +31,6 @@
|
|||
#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
|
||||
|
||||
#include <stdint.h>
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
@ -340,5 +334,3 @@ struct RsLoginHelper
|
|||
*/
|
||||
bool isLoggedIn();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -470,6 +470,8 @@ public:
|
|||
std::map<RsGxsId, rstime_t> 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) {
|
||||
|
@ -831,6 +833,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}
|
||||
|
|
|
@ -212,6 +212,8 @@ 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 */) {}
|
||||
|
|
|
@ -231,7 +231,7 @@ 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<RsPgpId> gpgSigners;
|
||||
|
||||
|
@ -499,9 +499,9 @@ public:
|
|||
virtual RsPgpId getGPGId(const RsPeerId& sslId) = 0;
|
||||
virtual bool isKeySupported(const RsPgpId& gpg_ids) = 0;
|
||||
virtual bool getGPGAcceptedList(std::list<RsPgpId> &gpg_ids) = 0;
|
||||
virtual bool getGPGSignedList(std::list<RsPgpId> &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<RsPgpId> &gpg_ids) = 0;
|
||||
virtual bool getGPGAllList(std::list<RsPgpId> &gpg_ids) = 0;
|
||||
virtual bool getGPGSignedList(std::list<RsPgpId> &gpg_ids) = 0;// keys signed by our own PGP key.
|
||||
virtual bool getGPGValidList(std::list<RsPgpId> &gpg_ids) = 0;// all PGP keys without filtering
|
||||
virtual bool getGPGAllList(std::list<RsPgpId> &gpg_ids) = 0;// all PGP keys as well
|
||||
virtual bool getAssociatedSSLIds(const RsPgpId& gpg_id, std::list<RsPeerId>& ids) = 0;
|
||||
virtual bool gpgSignData(const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen, std::string reason = "") = 0;
|
||||
|
||||
|
|
|
@ -347,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"))
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -488,7 +488,8 @@ m_timeout(1801),
|
|||
m_SCPD(NULL)
|
||||
{
|
||||
int errcode;
|
||||
|
||||
m_SID[0]=0;
|
||||
|
||||
std::vector<char> vscpdURL(URLBase.length() + m_SCPDURL.length() + 1);
|
||||
char *scpdURL = &vscpdURL[0];
|
||||
errcode = UpnpResolveURL(
|
||||
|
@ -1333,6 +1334,12 @@ int CUPnPControlPoint::Callback(
|
|||
std::string devType(upnpCP->m_upnpLib.
|
||||
Element_GetChildValueByTag(rootDevice, "deviceType"));
|
||||
|
||||
#ifdef UPNP_DEBUG
|
||||
std::cerr << "CUPnPControlPoint::Callback() EventType==UPNP_DISCOVERY_SEARCH_RESULT" << std::endl
|
||||
<< "urlBase:" << urlBase << std::endl
|
||||
<< "devType:" << devType << std::endl;
|
||||
#endif
|
||||
|
||||
// Only add device if it is an InternetGatewayDevice
|
||||
if (stdStringIsEqualCI(devType, upnpCP->m_upnpLib.UPNP_DEVICE_IGW))
|
||||
{
|
||||
|
@ -1351,6 +1358,10 @@ int CUPnPControlPoint::Callback(
|
|||
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
|
||||
}
|
||||
|
||||
// Free the XML doc tree
|
||||
|
@ -1359,6 +1370,13 @@ int CUPnPControlPoint::Callback(
|
|||
}
|
||||
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;
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
extern std::string stdEmptyString;
|
||||
#endif // UPNP_C
|
||||
|
||||
//#define UPNP_DEBUG 1
|
||||
|
||||
/**
|
||||
* Case insensitive std::string comparison
|
||||
|
@ -255,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; }
|
||||
|
|
|
@ -35,8 +35,6 @@
|
|||
#include "pqi/p3linkmgr.h"
|
||||
#include "pqi/p3netmgr.h"
|
||||
|
||||
int rsserverzone = 101;
|
||||
|
||||
#include "util/rsdebug.h"
|
||||
|
||||
#include "retroshare/rsevents.h"
|
||||
|
@ -86,7 +84,7 @@ RsServer::RsServer() :
|
|||
{
|
||||
{
|
||||
RsEventsService* tmpRsEvtPtr = new RsEventsService();
|
||||
rsEvents.reset(tmpRsEvtPtr);
|
||||
rsEvents = tmpRsEvtPtr;
|
||||
startServiceThread(tmpRsEvtPtr, "RsEventsService");
|
||||
}
|
||||
|
||||
|
@ -271,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
|
||||
}
|
||||
|
|
|
@ -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) ;
|
||||
|
|
|
@ -147,6 +147,7 @@ class p3Msgs: public RsMsgs
|
|||
virtual void denyLobbyInvite(const ChatLobbyId& id) ;
|
||||
virtual void getPendingChatLobbyInvites(std::list<ChatLobbyInvite>& 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&) ;
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
/*******************************************************************************
|
||||
* libretroshare/src/retroshare: rsinit.cc *
|
||||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright 2004-2006 by Robert Fernie <retroshare@lunamutt.com> *
|
||||
* Copyright (C) 2004-2014 Robert Fernie <retroshare@lunamutt.com> *
|
||||
* Copyright (C) 2016-2019 Gioacchino Mazzurco <gio@altermundi.net> *
|
||||
* *
|
||||
* 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 <unistd.h>
|
||||
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright (C) 2017 Cyril Soler <csoler@users.sourceforge.net> *
|
||||
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* Copyright (C) 2017 Cyril Soler <csoler@users.sourceforge.net> *
|
||||
* Copyright (C) 2018-2019 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* *
|
||||
* 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 <rapid_json/prettywriter.h>
|
||||
#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<rapidjson::SizeType>(membername.length()),
|
||||
allocator );
|
||||
|
||||
rapidjson::Value value;
|
||||
value.SetString( member.c_str(),
|
||||
static_cast<rapidjson::SizeType>(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<rapidjson::SizeType>(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<rapidjson::SizeType>(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<uint8_t>(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<uint16_t>(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 //
|
||||
//============================================================================//
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright (C) 2017 Cyril Soler <csoler@users.sourceforge.net> *
|
||||
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* Copyright (C) 2017 Cyril Soler <csoler@users.sourceforge.net> *
|
||||
* Copyright (C) 2018-2019 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* *
|
||||
* 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 <typeinfo> // for typeid
|
||||
#include <type_traits>
|
||||
|
@ -907,6 +908,8 @@ protected:
|
|||
static bool from_JSON( const std::string& memberName,
|
||||
t_RsTlvList<TLV_CLASS,TLV_TYPE>& member,
|
||||
RsJson& jDoc );
|
||||
|
||||
RS_SET_CONTEXT_DEBUG_LEVEL(1)
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -40,7 +40,6 @@ struct BroadcastDiscoveryPack : RsSerializable
|
|||
{
|
||||
BroadcastDiscoveryPack() : mLocalPort(0) {}
|
||||
|
||||
RsPgpFingerprint mPgpFingerprint;
|
||||
RsPeerId mSslId;
|
||||
uint16_t mLocalPort;
|
||||
std::string mProfileName;
|
||||
|
@ -48,7 +47,6 @@ struct BroadcastDiscoveryPack : RsSerializable
|
|||
void serial_process( RsGenericSerializer::SerializeJob j,
|
||||
RsGenericSerializer::SerializeContext& ctx ) override
|
||||
{
|
||||
RS_SERIAL_PROCESS(mPgpFingerprint);
|
||||
RS_SERIAL_PROCESS(mSslId);
|
||||
RS_SERIAL_PROCESS(mLocalPort);
|
||||
RS_SERIAL_PROCESS(mProfileName);
|
||||
|
@ -57,7 +55,6 @@ struct BroadcastDiscoveryPack : RsSerializable
|
|||
static BroadcastDiscoveryPack fromPeerDetails(const RsPeerDetails& pd)
|
||||
{
|
||||
BroadcastDiscoveryPack bdp;
|
||||
bdp.mPgpFingerprint = pd.fpr;
|
||||
bdp.mSslId = pd.id;
|
||||
bdp.mLocalPort = pd.localPort;
|
||||
bdp.mProfileName = pd.name;
|
||||
|
@ -103,12 +100,12 @@ BroadcastDiscoveryService::BroadcastDiscoveryService(
|
|||
mUdcParameters.set_port(port);
|
||||
mUdcParameters.set_application_id(appId);
|
||||
|
||||
mUdcEndpoint.Start(mUdcParameters, "");
|
||||
mUdcPeer.Start(mUdcParameters, "");
|
||||
updatePublishedData();
|
||||
}
|
||||
|
||||
BroadcastDiscoveryService::~BroadcastDiscoveryService()
|
||||
{ mUdcEndpoint.Stop(true); }
|
||||
{ mUdcPeer.Stop(true); }
|
||||
|
||||
std::vector<RsBroadcastDiscoveryResult>
|
||||
BroadcastDiscoveryService::getDiscoveredPeers()
|
||||
|
@ -126,7 +123,7 @@ void BroadcastDiscoveryService::updatePublishedData()
|
|||
{
|
||||
RsPeerDetails od;
|
||||
mRsPeers.getPeerDetails(mRsPeers.getOwnId(), od);
|
||||
mUdcEndpoint.SetUserData(
|
||||
mUdcPeer.SetUserData(
|
||||
BroadcastDiscoveryPack::fromPeerDetails(od).serializeToString());
|
||||
}
|
||||
|
||||
|
@ -137,7 +134,7 @@ void BroadcastDiscoveryService::data_tick()
|
|||
if( mUdcParameters.can_discover() &&
|
||||
!mRsPeers.isHiddenNode(mRsPeers.getOwnId()) )
|
||||
{
|
||||
auto currentEndpoints = mUdcEndpoint.ListDiscovered();
|
||||
auto currentEndpoints = mUdcPeer.ListDiscovered();
|
||||
std::map<UDC::IpPort, std::string> currentMap;
|
||||
std::map<UDC::IpPort, std::string> updateMap;
|
||||
|
||||
|
@ -163,23 +160,20 @@ void BroadcastDiscoveryService::data_tick()
|
|||
createResult(pp.first, pp.second);
|
||||
|
||||
const bool isFriend = mRsPeers.isFriend(rbdr.mSslId);
|
||||
if( isFriend && rbdr.locator.hasPort() &&
|
||||
if( isFriend && rbdr.mLocator.hasPort() &&
|
||||
!mRsPeers.isOnline(rbdr.mSslId) )
|
||||
{
|
||||
mRsPeers.setLocalAddress(
|
||||
rbdr.mSslId, rbdr.locator.host(),
|
||||
rbdr.locator.port() );
|
||||
rbdr.mSslId, rbdr.mLocator.host(),
|
||||
rbdr.mLocator.port() );
|
||||
mRsPeers.connectAttempt(rbdr.mSslId);
|
||||
}
|
||||
else if(!isFriend)
|
||||
{
|
||||
typedef RsBroadcastDiscoveryPeerFoundEvent Evt_t;
|
||||
|
||||
// Ensure rsEvents is not deleted while we use it
|
||||
std::shared_ptr<RsEvents> lockedRsEvents = rsEvents;
|
||||
if(lockedRsEvents)
|
||||
lockedRsEvents->postEvent(
|
||||
std::unique_ptr<Evt_t>(new Evt_t(rbdr)) );
|
||||
if(rsEvents)
|
||||
rsEvents->postEvent(
|
||||
std::shared_ptr<Evt_t>(new Evt_t(rbdr)) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -199,10 +193,9 @@ RsBroadcastDiscoveryResult BroadcastDiscoveryService::createResult(
|
|||
BroadcastDiscoveryPack::fromSerializedString(uData);
|
||||
|
||||
RsBroadcastDiscoveryResult rbdr;
|
||||
rbdr.mPgpFingerprint = bdp.mPgpFingerprint;
|
||||
rbdr.mSslId = bdp.mSslId;
|
||||
rbdr.mProfileName = bdp.mProfileName;
|
||||
rbdr.locator.
|
||||
rbdr.mLocator.
|
||||
setScheme("ipv4").
|
||||
setHost(UDC::IpToString(ipp.ip())).
|
||||
setPort(bdp.mLocalPort);
|
||||
|
|
|
@ -22,10 +22,11 @@
|
|||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
#include <endpoint.hpp>
|
||||
#include <memory>
|
||||
#include <forward_list>
|
||||
|
||||
#include <udp_discovery_peer.hpp>
|
||||
|
||||
#include "retroshare/rsbroadcastdiscovery.h"
|
||||
#include "util/rsthreads.h"
|
||||
|
||||
|
@ -52,8 +53,8 @@ protected:
|
|||
|
||||
void updatePublishedData();
|
||||
|
||||
UDC::EndpointParameters mUdcParameters;
|
||||
UDC::Endpoint mUdcEndpoint;
|
||||
UDC::PeerParameters mUdcParameters;
|
||||
UDC::Peer mUdcPeer;
|
||||
|
||||
std::map<UDC::IpPort, std::string> mDiscoveredData;
|
||||
RsMutex mDiscoveredDataMutex;
|
||||
|
|
|
@ -306,18 +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 )
|
||||
{
|
||||
check_result = RSBANLIST_CHECK_RESULT_NOCHECK;
|
||||
if(!mIPFilteringEnabled) return true;
|
||||
|
||||
sockaddr_storage addr; sockaddr_storage_copy(dAddr, addr);
|
||||
|
||||
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
|
||||
|
@ -409,6 +414,7 @@ bool p3BanList::isAddressAccepted(
|
|||
check_result = RSBANLIST_CHECK_RESULT_ACCEPTED;
|
||||
return true ;
|
||||
}
|
||||
|
||||
void p3BanList::getWhiteListedIps(std::list<BanListPeer> &lst)
|
||||
{
|
||||
RS_STACK_MUTEX(mBanMtx) ;
|
||||
|
@ -582,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.
|
||||
|
|
|
@ -105,7 +105,6 @@ public:
|
|||
|
||||
*/
|
||||
virtual int tick();
|
||||
virtual int status();
|
||||
|
||||
int sendPackets();
|
||||
bool processIncoming();
|
||||
|
|
|
@ -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<RsGxsChannelGroup> channelsInfo;
|
||||
if(!getChannelsInfo(std::list<RsGxsGroupId>({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<RsGxsMessageId>({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<RsGxsMessageId> s({origCommentId});
|
||||
std::vector<RsGxsChannelPost> posts;
|
||||
std::vector<RsGxsComment> 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); }
|
||||
|
||||
|
||||
/********************************************************************************************/
|
||||
|
|
|
@ -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 <map>
|
||||
|
@ -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
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright 2012-2012 Robert Fernie <retroshare@lunamutt.com> *
|
||||
* Copyright (C) 2012-2014 Robert Fernie <retroshare@lunamutt.com> *
|
||||
* Copyright (C) 2018-2019 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* *
|
||||
* 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 <retroshare/rsidentity.h>
|
||||
#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<RsGxsForumMsg> &
|
|||
|
||||
/********************************************************************************************/
|
||||
|
||||
bool p3GxsForums::createForumV2(
|
||||
const std::string& name, const std::string& description,
|
||||
const RsGxsId& authorId, const std::set<RsGxsId>& 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<uint32_t>(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<RsGxsForumMsg> msgs;
|
||||
if( getForumContent(forumId, std::set<RsGxsMessageId>({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<RsGxsForumGroup> forumInfo;
|
||||
if(!getForumsInfo(std::list<RsGxsGroupId>({forumId}), forumInfo))
|
||||
return failure( "Forum with Id " + forumId.toStdString()
|
||||
+ " does not exist locally." );
|
||||
|
||||
if(!origPostId.isNull())
|
||||
{
|
||||
std::vector<RsGxsForumMsg> msgs;
|
||||
if( getForumContent( forumId,
|
||||
std::set<RsGxsMessageId>({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<RsGxsMessageId>& msgs_to_request,
|
||||
std::vector<RsGxsForumMsg>& msgs )
|
||||
const RsGxsGroupId& forumId,
|
||||
const std::set<RsGxsMessageId>& msgs_to_request,
|
||||
std::vector<RsGxsForumMsg>& 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;
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright 2012-2012 Robert Fernie <retroshare@lunamutt.com> *
|
||||
* Copyright (C) 2012-2014 Robert Fernie <retroshare@lunamutt.com> *
|
||||
* Copyright (C) 2018-2019 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* *
|
||||
* 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 <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
#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 <map>
|
||||
#include <string>
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
#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<RsItem *>& loadList); // @see p3Config::loadList(std::list<RsItem *>&)
|
||||
|
||||
public:
|
||||
/// @see RsGxsForums::createForum
|
||||
/// @see RsGxsForums::createForumV2
|
||||
bool createForumV2(
|
||||
const std::string& name, const std::string& description,
|
||||
const RsGxsId& authorId = RsGxsId(),
|
||||
const std::set<RsGxsId>& moderatorsIds = std::set<RsGxsId>(),
|
||||
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<RsGroupMetaData>& forums);
|
||||
|
@ -78,7 +100,7 @@ public:
|
|||
/// @see RsGxsForums::getForumContent
|
||||
virtual bool getForumContent(
|
||||
const RsGxsGroupId& forumId,
|
||||
std::set<RsGxsMessageId>& msgs_to_request,
|
||||
const std::set<RsGxsMessageId>& msgs_to_request,
|
||||
std::vector<RsGxsForumMsg>& msgs );
|
||||
|
||||
/// @see RsGxsForums::markRead
|
||||
|
@ -130,5 +152,3 @@ bool generateGroup(uint32_t &token, std::string groupName);
|
|||
std::map<RsGxsGroupId,rstime_t> mKnownForums ;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
/*******************************************************************************
|
||||
* libretroshare/src/services: p3idservice.cc *
|
||||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright 2012-2012 Robert Fernie <retroshare@lunamutt.com> *
|
||||
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* Copyright (C) 2012-2014 Robert Fernie <retroshare@lunamutt.com> *
|
||||
* Copyright (C) 2017-2019 Gioacchino Mazzurco <gio@altermundi.net> *
|
||||
* *
|
||||
* 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 <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
/// RetroShare GXS identities service
|
||||
|
||||
|
||||
#include <unistd.h>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <cstdio>
|
||||
|
||||
#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 <retroshare/rspeers.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <stdio.h>
|
||||
|
||||
/****
|
||||
* #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<RsGxsId> ids)
|
||||
bool p3IdService::getOwnSignedIds(std::vector<RsGxsId>& ids)
|
||||
{
|
||||
ids.clear();
|
||||
|
||||
|
@ -769,27 +767,29 @@ bool p3IdService::getOwnSignedIds(std::vector<RsGxsId> 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<RsGxsId> ids)
|
||||
bool p3IdService::getOwnPseudonimousIds(std::vector<RsGxsId>& ids)
|
||||
{
|
||||
ids.clear();
|
||||
std::vector<RsGxsId> signedV;
|
||||
|
||||
// this implicitely ensure ids are already loaded ;)
|
||||
if(!getOwnSignedIds(signedV)) return false;
|
||||
|
||||
std::set<RsGxsId> 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,75 @@ 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;
|
||||
|
||||
|
||||
LabelCreateIdentityCleanup:
|
||||
if(!pseudonimous && !pgpPassword.empty())
|
||||
{
|
||||
rsNotify->setDisableAskPassword(false);
|
||||
rsNotify->clearPgpPassphrase();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool p3IdService::createIdentity(uint32_t& token, RsIdentityParameters ¶ms)
|
||||
|
@ -1151,6 +1186,16 @@ static void mergeIds(std::map<RsGxsId,std::list<RsPeerId> >& idmap,const RsGxsId
|
|||
old_peers.push_back(*it) ;
|
||||
}
|
||||
|
||||
bool p3IdService::requestIdentity(const RsGxsId& id)
|
||||
{
|
||||
RsIdentityUsage usageInfo( RsServiceType::GXSID,
|
||||
RsIdentityUsage::IDENTITY_DATA_UPDATE );
|
||||
std::list<RsPeerId> onlinePeers;
|
||||
|
||||
return rsPeers && rsPeers->getOnlineList(onlinePeers)
|
||||
&& requestKey(id, onlinePeers, usageInfo);
|
||||
}
|
||||
|
||||
bool p3IdService::requestKey(const RsGxsId &id, const std::list<RsPeerId>& peers,const RsIdentityUsage& use_info)
|
||||
{
|
||||
if(id.isNull())
|
||||
|
@ -3297,13 +3342,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<RsGxsIdGroupItem *>(grpItem);
|
||||
if (!item)
|
||||
|
@ -3313,30 +3355,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<RsGxsId, RsTlvPrivateRSAKey>::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<RsGxsId, RsTlvPrivateRSAKey>::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 +3419,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 +3434,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 +3461,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<const void*>(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<const void*>(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<char>(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 +3534,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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -4678,12 +4722,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<uint32_t>(service); // G10h4ck: Why uint32 if it's 16 bits?
|
||||
hs << static_cast<uint8_t>(code);
|
||||
hs << gid;
|
||||
hs << mid;
|
||||
hs << static_cast<uint64_t>(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<RsServiceType>(service)), mUsageCode(code),
|
||||
mGrpId(gid), mMsgId(mid), mAdditionalId(additional_id), mComment(comment)
|
||||
{
|
||||
#ifdef DEBUG_IDS
|
||||
std::cerr << "New identity usage: " << std::endl;
|
||||
|
@ -4700,7 +4766,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 ;
|
||||
|
@ -4715,4 +4781,5 @@ RsIdentityUsage::RsIdentityUsage(
|
|||
}
|
||||
|
||||
RsIdentityUsage::RsIdentityUsage() :
|
||||
mServiceId(0), mUsageCode(UNKNOWN_USAGE), mAdditionalId(0) {}
|
||||
mServiceId(RsServiceType::NONE), mUsageCode(UNKNOWN_USAGE), mAdditionalId(0)
|
||||
{}
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
/*******************************************************************************
|
||||
* libretroshare/src/services: p3idservice.h *
|
||||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright 2012-2012 Robert Fernie <retroshare@lunamutt.com> *
|
||||
* Copyright (C) 2012-2014 Robert Fernie <retroshare@lunamutt.com> *
|
||||
* Copyright (C) 2017-2019 Gioacchino Mazzurco <gio@altermundi.net> *
|
||||
* *
|
||||
* 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 <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
#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 <map>
|
||||
#include <string>
|
||||
|
||||
#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<RsGxsId> ids) override;
|
||||
bool getOwnSignedIds(std::vector<RsGxsId>& ids) override;
|
||||
|
||||
/// @see RsIdentity
|
||||
bool getOwnPseudonimousIds(std::vector<RsGxsId> ids) override;
|
||||
bool getOwnPseudonimousIds(std::vector<RsGxsId>& ids) override;
|
||||
|
||||
virtual bool getOwnIds(std::list<RsGxsId> &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
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -25,36 +25,43 @@
|
|||
#include "services/rseventsservice.h"
|
||||
|
||||
|
||||
/*extern*/ std::shared_ptr<RsEvents> rsEvents(nullptr);
|
||||
/*extern*/ RsEvents* rsEvents = nullptr;
|
||||
RsEvent::~RsEvent() {};
|
||||
RsEvents::~RsEvents() {};
|
||||
|
||||
bool isEventValid(const RsEvent& event, std::string& errorMessage)
|
||||
bool isEventValid(
|
||||
std::shared_ptr<const RsEvent> event, std::string& errorMessage )
|
||||
{
|
||||
if(event.mType <= RsEventType::NONE)
|
||||
if(!event)
|
||||
{
|
||||
errorMessage = "Event is null!";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(event->mType <= RsEventType::NONE)
|
||||
{
|
||||
errorMessage = "Event has type NONE: " +
|
||||
std::to_string(
|
||||
static_cast<std::underlying_type<RsEventType>::type >(
|
||||
event.mType ) );
|
||||
event->mType ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
if(event.mType >= RsEventType::MAX)
|
||||
if(event->mType >= RsEventType::MAX)
|
||||
{
|
||||
errorMessage = "Event has type >= RsEventType::MAX: " +
|
||||
std::to_string(
|
||||
static_cast<std::underlying_type<RsEventType>::type >(
|
||||
event.mType ) );
|
||||
event->mType ) );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RsEventsService::postEvent( std::unique_ptr<RsEvent> event,
|
||||
bool RsEventsService::postEvent( std::shared_ptr<const RsEvent> event,
|
||||
std::string& errorMessage )
|
||||
{
|
||||
if(!isEventValid(*event, errorMessage))
|
||||
if(!isEventValid(event, errorMessage))
|
||||
{
|
||||
std::cerr << __PRETTY_FUNCTION__ << " Error: "<< errorMessage
|
||||
<< std::endl;
|
||||
|
@ -62,17 +69,16 @@ bool RsEventsService::postEvent( std::unique_ptr<RsEvent> event,
|
|||
}
|
||||
|
||||
RS_STACK_MUTEX(mEventQueueMtx);
|
||||
mEventQueue.push_back(std::move(event));
|
||||
mEventQueue.push_back(event);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RsEventsService::sendEvent( const RsEvent& event,
|
||||
bool RsEventsService::sendEvent( std::shared_ptr<const RsEvent> event,
|
||||
std::string& errorMessage )
|
||||
{
|
||||
if(!isEventValid(event, errorMessage))
|
||||
{
|
||||
std::cerr << __PRETTY_FUNCTION__ << " Error: "<< errorMessage
|
||||
<< std::endl;
|
||||
RsErr() << __PRETTY_FUNCTION__ << " "<< errorMessage << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -93,12 +99,12 @@ RsEventsHandlerId_t RsEventsService::generateUniqueHandlerId_unlocked()
|
|||
}
|
||||
|
||||
bool RsEventsService::registerEventsHandler(
|
||||
std::function<void(const RsEvent&)> multiCallback,
|
||||
std::function<void(std::shared_ptr<const RsEvent>)> multiCallback,
|
||||
RsEventsHandlerId_t& hId )
|
||||
{
|
||||
RS_STACK_MUTEX(mHandlerMapMtx);
|
||||
if(!hId) hId = generateUniqueHandlerId_unlocked();
|
||||
mHandlerMap[hId] = std::move(multiCallback);
|
||||
mHandlerMap[hId] = multiCallback;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -116,19 +122,19 @@ void RsEventsService::data_tick()
|
|||
auto nextRunAt = std::chrono::system_clock::now() +
|
||||
std::chrono::milliseconds(1);
|
||||
|
||||
std::unique_ptr<RsEvent> eventPtr(nullptr);
|
||||
std::shared_ptr<const RsEvent> eventPtr(nullptr);
|
||||
size_t futureEventsCounter = 0;
|
||||
|
||||
dispatchEventFromQueueLock:
|
||||
mEventQueueMtx.lock();
|
||||
if(mEventQueue.size() > futureEventsCounter)
|
||||
{
|
||||
eventPtr = std::move(mEventQueue.front());
|
||||
eventPtr = mEventQueue.front();
|
||||
mEventQueue.pop_front();
|
||||
|
||||
if(eventPtr->mTimePoint >= nextRunAt)
|
||||
{
|
||||
mEventQueue.push_back(std::move(eventPtr));
|
||||
mEventQueue.push_back(eventPtr);
|
||||
++futureEventsCounter;
|
||||
}
|
||||
}
|
||||
|
@ -137,17 +143,17 @@ dispatchEventFromQueueLock:
|
|||
if(eventPtr)
|
||||
{
|
||||
/* It is relevant that this stays out of mEventQueueMtx */
|
||||
handleEvent(*eventPtr);
|
||||
eventPtr.reset(nullptr); // ensure memory is freed before sleep
|
||||
handleEvent(eventPtr);
|
||||
eventPtr = nullptr; // ensure refcounter is decremented before sleep
|
||||
goto dispatchEventFromQueueLock;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_until(nextRunAt);
|
||||
}
|
||||
|
||||
void RsEventsService::handleEvent(const RsEvent& event)
|
||||
void RsEventsService::handleEvent(std::shared_ptr<const RsEvent> event)
|
||||
{
|
||||
std::function<void(const RsEvent&)> mCallback;
|
||||
std::function<void(std::shared_ptr<const RsEvent>)> mCallback;
|
||||
|
||||
mHandlerMapMtx.lock();
|
||||
auto cbpt = mHandlerMap.begin();
|
||||
|
@ -165,7 +171,7 @@ getHandlerFromMapLock:
|
|||
if(mCallback)
|
||||
{
|
||||
mCallback(event); // It is relevant that this happens outside mutex
|
||||
mCallback = std::function<void(const RsEvent&)>(nullptr);
|
||||
mCallback = std::function<void(std::shared_ptr<const RsEvent>)>(nullptr);
|
||||
goto getHandlerFromMapLock;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include "retroshare/rsevents.h"
|
||||
#include "util/rsthreads.h"
|
||||
#include "util/rsdebug.h"
|
||||
|
||||
class RsEventsService :
|
||||
public RsEvents, public RsTickingThread
|
||||
|
@ -38,13 +39,13 @@ public:
|
|||
|
||||
/// @see RsEvents
|
||||
bool postEvent(
|
||||
std::unique_ptr<RsEvent> event,
|
||||
std::shared_ptr<const RsEvent> event,
|
||||
std::string& errorMessage = RS_DEFAULT_STORAGE_PARAM(std::string)
|
||||
) override;
|
||||
|
||||
/// @see RsEvents
|
||||
bool sendEvent(
|
||||
const RsEvent& event,
|
||||
std::shared_ptr<const RsEvent> event,
|
||||
std::string& errorMessage = RS_DEFAULT_STORAGE_PARAM(std::string)
|
||||
) override;
|
||||
|
||||
|
@ -53,7 +54,7 @@ public:
|
|||
|
||||
/// @see RsEvents
|
||||
bool registerEventsHandler(
|
||||
std::function<void(const RsEvent&)> multiCallback,
|
||||
std::function<void(std::shared_ptr<const RsEvent>)> multiCallback,
|
||||
RsEventsHandlerId_t& hId = RS_DEFAULT_STORAGE_PARAM(RsEventsHandlerId_t, 0)
|
||||
) override;
|
||||
|
||||
|
@ -63,15 +64,18 @@ public:
|
|||
protected:
|
||||
RsMutex mHandlerMapMtx;
|
||||
RsEventsHandlerId_t mLastHandlerId;
|
||||
std::map< RsEventsHandlerId_t, std::function<void(const RsEvent&)> >
|
||||
mHandlerMap;
|
||||
std::map<
|
||||
RsEventsHandlerId_t,
|
||||
std::function<void(std::shared_ptr<const RsEvent>)> > mHandlerMap;
|
||||
|
||||
RsMutex mEventQueueMtx;
|
||||
std::deque< std::unique_ptr<RsEvent> > mEventQueue;
|
||||
std::deque< std::shared_ptr<const RsEvent> > mEventQueue;
|
||||
|
||||
/// @see RsTickingThread
|
||||
void data_tick() override;
|
||||
|
||||
void handleEvent(const RsEvent& event);
|
||||
void handleEvent(std::shared_ptr<const RsEvent> event);
|
||||
RsEventsHandlerId_t generateUniqueHandlerId_unlocked();
|
||||
|
||||
RS_SET_CONTEXT_DEBUG_LEVEL(3)
|
||||
};
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright 2012 Christopher Evi-Parker <retroshare@lunamutt.com> *
|
||||
* Copyright (C) 2012 Christopher Evi-Parker <retroshare@lunamutt.com> *
|
||||
* Copyright (C) 2019 Gioacchino Mazzurco <gio@altermundi.net> *
|
||||
* *
|
||||
* 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 <iostream>
|
||||
#include <sstream>
|
||||
#include <memory.h>
|
||||
#include "util/rstime.h"
|
||||
#include <inttypes.h>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
#include <cerrno>
|
||||
|
||||
#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<int>(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<int>(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
|
||||
|
|
|
@ -19,8 +19,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
#ifndef RSSQLITE_H
|
||||
#define RSSQLITE_H
|
||||
#pragma once
|
||||
|
||||
#ifdef NO_SQLCIPHER
|
||||
#include <sqlite3.h>
|
||||
|
@ -32,9 +31,10 @@
|
|||
#include <set>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#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
|
||||
|
|
|
@ -242,6 +242,10 @@ RsTickingThread::RsTickingThread()
|
|||
#endif
|
||||
}
|
||||
|
||||
RsTickingThread::~RsTickingThread()
|
||||
{
|
||||
fullstop();
|
||||
}
|
||||
void RsSingleJobThread::runloop()
|
||||
{
|
||||
run() ;
|
||||
|
|
|
@ -287,6 +287,7 @@ class RsTickingThread: public RsThread
|
|||
{
|
||||
public:
|
||||
RsTickingThread();
|
||||
virtual ~RsTickingThread();
|
||||
|
||||
void shutdown();
|
||||
void fullstop();
|
||||
|
|
|
@ -23,12 +23,10 @@
|
|||
#include <cstdio>
|
||||
#include <csignal>
|
||||
#include <cstdlib>
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined(__linux__) && defined(__GLIBC__)
|
||||
|
||||
#include <execinfo.h>
|
||||
#include <cxxabi.h>
|
||||
#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 <execinfo.h>
|
||||
#include <cxxabi.h>
|
||||
|
||||
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 <unwind.h>
|
||||
#include <dlfcn.h>
|
||||
#include <cxxabi.h>
|
||||
|
||||
struct RsAndroidBacktraceState
|
||||
{
|
||||
void** current;
|
||||
void** end;
|
||||
};
|
||||
|
||||
static inline _Unwind_Reason_Code android_unwind_callback(
|
||||
struct _Unwind_Context* context, void* arg )
|
||||
{
|
||||
RsAndroidBacktraceState* state = static_cast<RsAndroidBacktraceState*>(arg);
|
||||
uintptr_t pc = _Unwind_GetIP(context);
|
||||
if(pc)
|
||||
{
|
||||
if (state->current == state->end) return _URC_END_OF_STACK;
|
||||
|
||||
*state->current++ = reinterpret_cast<void*>(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<int>(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);
|
||||
|
||||
|
|
|
@ -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<ChatLobbyDialog*>(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<ChatLobbyId,ChatLobbyInfoStruct>::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(")"));
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "FriendsDialog.h"
|
||||
#include "NetworkView.h"
|
||||
#include "NetworkDialog.h"
|
||||
#include "gui/common/NewFriendList.h"
|
||||
#include "gui/Identity/IdDialog.h"
|
||||
/* Images for Newsfeed icons */
|
||||
//#define IMAGE_NEWSFEED ""
|
||||
|
@ -73,10 +74,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
|
||||
|
@ -93,47 +92,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<int> sizes;
|
||||
sizes << height() << 100; // Qt calculates the right sizes
|
||||
ui.splitter_2->setSizes(sizes);*/
|
||||
|
||||
loadmypersonalstatus();
|
||||
|
||||
|
@ -141,9 +108,9 @@ QList<int> 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();
|
||||
|
|
|
@ -145,17 +145,14 @@
|
|||
</property>
|
||||
<item row="0" column="0" rowspan="2">
|
||||
<widget class="AvatarWidget" name="avatar">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>61</width>
|
||||
<height>61</height>
|
||||
</size>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>61</width>
|
||||
<height>61</height>
|
||||
</size>
|
||||
<property name="scaledContents">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -199,7 +196,7 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="FriendList" name="friendList" native="true">
|
||||
<widget class="NewFriendList" name="friendList" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
|
@ -353,11 +350,6 @@
|
|||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>StyledLabel</class>
|
||||
<extends>QLabel</extends>
|
||||
<header>gui/common/StyledLabel.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>AvatarWidget</class>
|
||||
<extends>QLabel</extends>
|
||||
|
@ -365,9 +357,14 @@
|
|||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>FriendList</class>
|
||||
<class>StyledLabel</class>
|
||||
<extends>QLabel</extends>
|
||||
<header>gui/common/StyledLabel.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ChatWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>gui/common/FriendList.h</header>
|
||||
<header location="global">gui/chat/ChatWidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
|
@ -382,9 +379,9 @@
|
|||
<header>gui/common/StyledElidedLabel.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ChatWidget</class>
|
||||
<class>NewFriendList</class>
|
||||
<extends>QWidget</extends>
|
||||
<header location="global">gui/chat/ChatWidget.h</header>
|
||||
<header>gui/common/NewFriendList.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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())) ;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -31,10 +31,13 @@
|
|||
#include <retroshare/rsplugin.h>
|
||||
#include <retroshare/rsconfig.h>
|
||||
|
||||
#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()
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
@ -111,20 +112,16 @@ void IdentityWidget::updateData(const RsGxsIdGroup &gxs_group_info)
|
|||
ui->labelKeyId->setVisible(false);
|
||||
|
||||
/// (TODO) Get real ident icon
|
||||
QImage image;
|
||||
QPixmap pixmap;
|
||||
|
||||
if(!( (_group_info.mImage.mSize > 0) && image.loadFromData(_group_info.mImage.mData, _group_info.mImage.mSize, "PNG") ))
|
||||
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)
|
||||
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));
|
||||
|
||||
//}//if (_group_info != gxs_group_info)
|
||||
_avatar = pixmap.toImage();
|
||||
_scene->clear();
|
||||
_scene->addPixmap(pixmap.scaled(ui->graphicsView->width(),ui->graphicsView->height()));
|
||||
emit imageUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
void IdentityWidget::updateData(const RsPeerDetails &pgp_details)
|
||||
|
@ -136,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);
|
||||
|
@ -210,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)
|
||||
{
|
||||
|
@ -227,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()
|
||||
{
|
||||
|
|
|
@ -426,15 +426,15 @@ void PeopleDialog::iw_AddButtonClickedExt()
|
|||
{
|
||||
IdentityWidget *dest=
|
||||
qobject_cast<IdentityWidget *>(QObject::sender());
|
||||
if (dest) {
|
||||
if (dest)
|
||||
{
|
||||
QMenu contextMnu( this );
|
||||
|
||||
QMenu *mnu = contextMnu.addMenu(QIcon(":/icons/png/circles.png"),tr("Invite to Circle")) ;
|
||||
|
||||
std::map<RsGxsGroupId, CircleWidget*>::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<RsGxsId> 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()
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <QPixmap>
|
||||
|
||||
#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)
|
||||
{
|
||||
|
|
|
@ -165,7 +165,7 @@ void PostedDialog::loadGroupSummaryToken(const uint32_t &token, std::list<RsGrou
|
|||
|
||||
if (group.mGroupImage.mData != NULL) {
|
||||
QPixmap image;
|
||||
image.loadFromData(group.mGroupImage.mData, group.mGroupImage.mSize, "PNG");
|
||||
GxsIdDetails::loadPixmapFromData(group.mGroupImage.mData, group.mGroupImage.mSize, image,GxsIdDetails::ORIGINAL);
|
||||
postedData->mIcon[group.mMeta.mGroupId] = image;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <QBuffer>
|
||||
|
||||
#include "PostedGroupDialog.h"
|
||||
#include "gui/gxs/GxsIdDetails.h"
|
||||
|
||||
#include <retroshare/rswiki.h>
|
||||
#include <iostream>
|
||||
|
@ -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"));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<ChatLobbyWidget*>(MainWindow::getPage(MainWindow::ChatLobby))->setCurrentChatPage(this) ;
|
||||
MainPage *p = MainWindow::getPage(MainWindow::ChatLobby);
|
||||
|
||||
if(p != NULL)
|
||||
dynamic_cast<ChatLobbyWidget*>(p)->setCurrentChatPage(this) ;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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("<b>Mark this selected text</b><br><i>Ctrl+M</i>"));
|
||||
|
||||
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<QPushButton*>(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();
|
||||
|
|
|
@ -159,6 +159,8 @@ private slots:
|
|||
|
||||
void smileyWidget();
|
||||
void addSmiley();
|
||||
void stickerWidget();
|
||||
void sendSticker();
|
||||
|
||||
void addExtraFile();
|
||||
void addExtraPicture();
|
||||
|
|
|
@ -343,6 +343,32 @@ border-image: url(:/images/closepressed.png)
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="stickerButton">
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Insert sticker</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../icons.qrc">
|
||||
<normaloff>:/icons/png/new.png</normaloff>:/icons/png/new.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>28</width>
|
||||
<height>28</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="attachPictureButton">
|
||||
<property name="focusPolicy">
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include <QPixmap>
|
||||
#include <QCloseEvent>
|
||||
#include <QMenu>
|
||||
|
||||
#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()
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
<height>451</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">MainWindow</string>
|
||||
</property>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -18,12 +18,15 @@
|
|||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
#include <QBuffer>
|
||||
|
||||
#include <rshare.h>
|
||||
#include <retroshare/rsstatus.h>
|
||||
#include <retroshare/rspeers.h>
|
||||
#include <retroshare/rsmsgs.h>
|
||||
|
||||
#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)
|
||||
|
|
|
@ -21,23 +21,40 @@
|
|||
#include <QApplication>
|
||||
#include <QDesktopWidget>
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
#include <QGridLayout>
|
||||
#include <QHash>
|
||||
#include <QIcon>
|
||||
#include <QPushButton>
|
||||
#include <QTabWidget>
|
||||
#include <QWidget>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include <iostream>
|
||||
#include <math.h>
|
||||
|
||||
#include "Emoticons.h"
|
||||
#include "util/HandleRichText.h"
|
||||
#include "retroshare/rsinit.h"
|
||||
|
||||
#define ICONNAME "groupicon.png"
|
||||
|
||||
static QHash<QString, QPair<QVector<QString>, QHash<QString, QString> > > Smileys;
|
||||
static QVector<QString> grpOrdered;
|
||||
static QVector<QString > StickerGroups;
|
||||
static QStringList filters;
|
||||
static QHash<QString, QString> 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; i<subfolders.length(); i++)
|
||||
loadSticker(subfolders[i].filePath());
|
||||
}
|
||||
|
||||
void Emoticons::showStickerWidget(QWidget *parent, QWidget *button, const char *slotAddMethod, bool above)
|
||||
{
|
||||
QWidget *smWidget = new QWidget(parent, Qt::Popup) ;
|
||||
smWidget->setAttribute(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<QString> 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<QPushButton *> children = container->findChildren<QPushButton *>();
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()));
|
||||
|
@ -553,275 +552,6 @@ static void getNameWidget(QTreeWidget *treeWidget, QTreeWidgetItem *item, Elided
|
|||
}
|
||||
}
|
||||
|
||||
struct PgpItemInfo
|
||||
{
|
||||
PgpItemInfo() : gpg_connected(false),gpg_online(false),gpg_hasPrivateChat(false),bestPeerState(0),bestRSState(0) {}
|
||||
|
||||
bool gpg_connected ;
|
||||
bool gpg_online ;
|
||||
bool gpg_hasPrivateChat ;
|
||||
int bestPeerState ;
|
||||
unsigned int bestRSState ;
|
||||
QString bestCustomStateString;// for gpg item
|
||||
std::list<RsPeerId> sslContacts;
|
||||
QDateTime bestLastContact;
|
||||
QString bestIP;
|
||||
QPixmap bestAvatar;
|
||||
};
|
||||
|
||||
void FriendList::manageProfileLocations(QTreeWidgetItem *gpgItem,const RsPgpId& gpg_id,PgpItemInfo& info)
|
||||
{
|
||||
std::vector<RsPeerId> privateChatIds;
|
||||
ChatUserNotify::getPeersWithWaitingChat(privateChatIds);
|
||||
|
||||
int columnCount = ui->peerTreeWidget->columnCount();
|
||||
|
||||
for (auto sslIt ( info.sslContacts.begin()); sslIt != info.sslContacts.end(); ++sslIt)
|
||||
{
|
||||
QTreeWidgetItem *sslItem = NULL;
|
||||
RsPeerId sslId = *sslIt;
|
||||
|
||||
// find the corresponding sslItem child item of the gpg item
|
||||
bool newChild = true;
|
||||
int childCount = gpgItem->childCount();
|
||||
for (int childIndex = 0; childIndex < childCount; ++childIndex) {
|
||||
// we assume, that only ssl items are child of the gpg item, so we don't need to test the type
|
||||
if (getRsId(gpgItem->child(childIndex)) == sslId.toStdString()) {
|
||||
sslItem = gpgItem->child(childIndex);
|
||||
newChild = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RsPeerDetails sslDetail;
|
||||
if (!rsPeers->getPeerDetails(sslId, sslDetail) || !rsPeers->isFriend(sslId)) {
|
||||
#ifdef FRIENDS_DEBUG
|
||||
std::cerr << "Removing widget from the view : id : " << sslId << std::endl;
|
||||
#endif
|
||||
// child has disappeared, remove it from the gpg_item
|
||||
if (sslItem) {
|
||||
gpgItem->removeChild(sslItem);
|
||||
delete(sslItem);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (newChild) {
|
||||
sslItem = new RSTreeWidgetItem(mCompareRole, TYPE_SSL); //set type to 1 for custom popup menu
|
||||
|
||||
#ifdef FRIENDS_DEBUG
|
||||
std::cerr << "FriendList::insertPeers() inserting sslItem." << std::endl;
|
||||
#endif
|
||||
|
||||
/* Add ssl child to the list. Add here, because for setHidden the item must be added */
|
||||
gpgItem->addChild(sslItem);
|
||||
|
||||
/* Sort data */
|
||||
for (int i = 0; i < columnCount; ++i) {
|
||||
sslItem->setData(i, ROLE_SORT_GROUP, 2);
|
||||
sslItem->setData(i, ROLE_SORT_STANDARD_GROUP, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* not displayed, used to find back the item */
|
||||
QString strID = QString::fromStdString(sslDetail.id.toStdString());
|
||||
sslItem->setData(COLUMN_DATA, ROLE_ID, strID);
|
||||
sslItem->setText(COLUMN_ID, strID);
|
||||
sslItem->setData(COLUMN_ID, ROLE_SORT_NAME, strID);
|
||||
sslItem->setData(COLUMN_ID, ROLE_FILTER, strID);
|
||||
|
||||
/* Custom state string */
|
||||
QString customStateString;
|
||||
if (sslDetail.state & RS_PEER_STATE_CONNECTED) {
|
||||
customStateString = QString::fromUtf8(rsMsgs->getCustomStateString(sslDetail.id).c_str());
|
||||
}
|
||||
|
||||
QPixmap sslAvatar;
|
||||
AvatarDefs::getAvatarFromSslId(RsPeerId(sslDetail.id.toStdString()), sslAvatar);
|
||||
|
||||
/* last contact */
|
||||
QDateTime sslLastContact = QDateTime::fromTime_t(sslDetail.lastConnect);
|
||||
sslItem->setData(COLUMN_LAST_CONTACT, Qt::DisplayRole, QVariant(sslLastContact));
|
||||
sslItem->setData(COLUMN_LAST_CONTACT, ROLE_SORT_NAME, QVariant(sslLastContact));
|
||||
if (sslLastContact > info.bestLastContact) {
|
||||
info.bestLastContact = sslLastContact;
|
||||
}
|
||||
|
||||
/* IP */
|
||||
QString sslIP = (sslDetail.state & RS_PEER_STATE_CONNECTED) ? StatusDefs::connectStateIpString(sslDetail) : QString("---");
|
||||
sslItem->setText(COLUMN_IP, sslIP);
|
||||
sslItem->setData(COLUMN_IP, ROLE_SORT_NAME, sslIP);
|
||||
|
||||
/* change color and icon */
|
||||
QPixmap sslOverlayIcon;
|
||||
QFont sslFont;
|
||||
QColor sslColor;
|
||||
int peerState = 0;
|
||||
QString connectStateString;
|
||||
if (sslDetail.state & RS_PEER_STATE_CONNECTED)
|
||||
{
|
||||
// get the status info for this ssl id
|
||||
int rsState = 0;
|
||||
|
||||
StatusInfo status_info ;
|
||||
rsStatus->getStatus(sslDetail.id,status_info);
|
||||
|
||||
rsState = status_info.status;
|
||||
switch (rsState) {
|
||||
case RS_STATUS_INACTIVE:
|
||||
peerState = PEER_STATE_INACTIVE;
|
||||
break;
|
||||
|
||||
case RS_STATUS_ONLINE:
|
||||
peerState = PEER_STATE_ONLINE;
|
||||
break;
|
||||
|
||||
case RS_STATUS_AWAY:
|
||||
peerState = PEER_STATE_AWAY;
|
||||
break;
|
||||
|
||||
case RS_STATUS_BUSY:
|
||||
peerState = PEER_STATE_BUSY;
|
||||
break;
|
||||
}
|
||||
|
||||
/* find the best ssl contact for the gpg item */
|
||||
if (info.bestPeerState == 0 || peerState < info.bestPeerState) {
|
||||
/* first ssl contact or higher state */
|
||||
info.bestPeerState = peerState;
|
||||
info.bestRSState = rsState;
|
||||
info.bestCustomStateString = customStateString;
|
||||
info.bestIP = sslIP;
|
||||
if (!sslAvatar.isNull()) {
|
||||
info.bestAvatar = sslAvatar;
|
||||
}
|
||||
} else if (peerState == info.bestPeerState) {
|
||||
/* equal state */
|
||||
if (info.bestCustomStateString.isEmpty() && !customStateString.isEmpty()) {
|
||||
/* when customStateString is shown in name item, use sslId with customStateString.
|
||||
second with a custom state string ... use second */
|
||||
info.bestPeerState = peerState;
|
||||
info.bestRSState = rsState;
|
||||
info.bestCustomStateString = customStateString;
|
||||
}
|
||||
if (info.bestAvatar.isNull() && !sslAvatar.isNull()) {
|
||||
/* Use available avatar */
|
||||
info.bestAvatar = sslAvatar;
|
||||
}
|
||||
}
|
||||
|
||||
sslItem->setHidden(false);
|
||||
info.gpg_connected = true;
|
||||
|
||||
sslOverlayIcon = QPixmap(StatusDefs::imageStatus(info.bestRSState));
|
||||
|
||||
connectStateString = StatusDefs::name(rsState);
|
||||
|
||||
if (rsState == 0) {
|
||||
sslFont.setBold(true);
|
||||
sslColor = mTextColorStatus[RS_STATUS_ONLINE];
|
||||
} else {
|
||||
sslFont = StatusDefs::font(rsState);
|
||||
sslColor = mTextColorStatus[rsState];
|
||||
}
|
||||
} else if (sslDetail.state & RS_PEER_STATE_ONLINE) {
|
||||
sslItem->setHidden(mHideUnconnected);
|
||||
info.gpg_online = true;
|
||||
peerState = PEER_STATE_AVAILABLE;
|
||||
|
||||
if (sslDetail.connectState) {
|
||||
sslOverlayIcon = QPixmap(":/images/connect_creating.png");
|
||||
} else {
|
||||
sslOverlayIcon = QPixmap(StatusDefs::imageStatus(RS_STATUS_ONLINE));
|
||||
}
|
||||
|
||||
connectStateString = StatusDefs::name(RS_STATUS_ONLINE);
|
||||
|
||||
sslFont.setBold(true);
|
||||
sslColor = mTextColorStatus[RS_STATUS_ONLINE];
|
||||
} else {
|
||||
peerState = PEER_STATE_OFFLINE;
|
||||
sslItem->setHidden(mHideUnconnected);
|
||||
if (sslDetail.connectState) {
|
||||
sslOverlayIcon = QPixmap(":/images/connect_creating.png");
|
||||
} else {
|
||||
sslOverlayIcon = QPixmap(StatusDefs::imageStatus(RS_STATUS_OFFLINE));
|
||||
}
|
||||
|
||||
connectStateString = StatusDefs::connectStateWithoutTransportTypeString(sslDetail);
|
||||
|
||||
sslFont.setBold(false);
|
||||
sslColor = mTextColorStatus[RS_STATUS_OFFLINE];
|
||||
}
|
||||
|
||||
/* Location */
|
||||
QString sslName = QString::fromUtf8(sslDetail.location.c_str());
|
||||
QString sslText;
|
||||
|
||||
if (mShowState) {
|
||||
if (!connectStateString.isEmpty()) {
|
||||
sslText = connectStateString;
|
||||
if (!customStateString.isEmpty()) {
|
||||
sslText += " [" + customStateString + "]";
|
||||
}
|
||||
} else {
|
||||
if (!customStateString.isEmpty()) {
|
||||
sslText = customStateString;
|
||||
}
|
||||
}
|
||||
|
||||
sslItem->setToolTip(COLUMN_NAME, "");
|
||||
} else {
|
||||
if (!customStateString.isEmpty()) {
|
||||
sslText = customStateString;
|
||||
}
|
||||
|
||||
/* Show the state as tooltip */
|
||||
sslItem->setToolTip(COLUMN_NAME, connectStateString);
|
||||
}
|
||||
|
||||
/* Create or get ssl label */
|
||||
ElidedLabel *sslNameLabel = NULL;
|
||||
ElidedLabel *sslTextLabel = NULL;
|
||||
|
||||
getNameWidget(ui->peerTreeWidget, sslItem, sslNameLabel, sslTextLabel);
|
||||
|
||||
if (sslNameLabel) {
|
||||
sslNameLabel->setText(sslName);
|
||||
sslNameLabel->setFont(sslFont);
|
||||
|
||||
QPalette palette = sslNameLabel->palette();
|
||||
palette.setColor(sslNameLabel->foregroundRole(), sslColor);
|
||||
|
||||
sslNameLabel->setPalette(palette);
|
||||
}
|
||||
if (sslTextLabel) {
|
||||
sslTextLabel->setText(sslText);
|
||||
sslTextLabel->setVisible(!sslText.isEmpty());
|
||||
}
|
||||
|
||||
// Filter
|
||||
sslItem->setData(COLUMN_NAME, ROLE_FILTER, sslName);
|
||||
|
||||
if (std::find(privateChatIds.begin(), privateChatIds.end(), sslDetail.id) != privateChatIds.end()) {
|
||||
// private chat is available
|
||||
sslOverlayIcon = QPixmap(":/images/chat.png");
|
||||
info.gpg_hasPrivateChat = true;
|
||||
}
|
||||
sslItem->setIcon(COLUMN_NAME, createAvatar(sslAvatar, sslOverlayIcon));
|
||||
|
||||
/* Sort data */
|
||||
sslItem->setData(COLUMN_NAME, ROLE_SORT_NAME, sslName);
|
||||
|
||||
for (int i = 0; i < columnCount; ++i) {
|
||||
sslItem->setData(i, ROLE_SORT_STATE, peerState);
|
||||
|
||||
sslItem->setTextColor(i, sslColor);
|
||||
sslItem->setFont(i, sslFont);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of peers from the RsIface.
|
||||
* Adds all friend gpg ids, with their nodes as children to the peerTreeWidget.
|
||||
|
@ -839,8 +569,8 @@ void FriendList::insertPeers()
|
|||
|
||||
int columnCount = ui->peerTreeWidget->columnCount();
|
||||
|
||||
//std::list<StatusInfo> statusInfo;
|
||||
//rsStatus->getStatusList(statusInfo);
|
||||
std::list<StatusInfo> statusInfo;
|
||||
rsStatus->getStatusList(statusInfo);
|
||||
|
||||
if (!rsPeers) {
|
||||
/* not ready yet! */
|
||||
|
@ -849,6 +579,9 @@ void FriendList::insertPeers()
|
|||
}
|
||||
|
||||
// get peers with waiting incoming chats
|
||||
std::vector<RsPeerId> privateChatIds;
|
||||
ChatUserNotify::getPeersWithWaitingChat(privateChatIds);
|
||||
|
||||
// get existing groups
|
||||
std::list<RsGroupInfo> groupInfoList;
|
||||
std::list<RsGroupInfo>::iterator groupIt;
|
||||
|
@ -858,8 +591,7 @@ void FriendList::insertPeers()
|
|||
std::list<RsPgpId>::iterator gpgIt;
|
||||
rsPeers->getGPGAcceptedList(gpgFriends);
|
||||
|
||||
// add own gpg id, if we have more than on node (ssl client)
|
||||
|
||||
//add own gpg id, if we have more than on node (ssl client)
|
||||
std::list<RsPeerId> ownSslContacts;
|
||||
RsPgpId ownId = rsPeers->getGPGOwnId();
|
||||
rsPeers->getAssociatedSSLIds(ownId, ownSslContacts);
|
||||
|
@ -867,24 +599,6 @@ void FriendList::insertPeers()
|
|||
gpgFriends.push_back(ownId);
|
||||
}
|
||||
|
||||
// Also add SSL peers which PGP key is not available yet.
|
||||
|
||||
std::list<RsPeerId> ssl_friends ;
|
||||
rsPeers->getFriendList(ssl_friends);
|
||||
std::map<RsPgpId,std::list<RsPeerDetails> > pgp_friends_without_validation;
|
||||
|
||||
std::cerr << "List of accepted ssl peers: " << std::endl;
|
||||
for(auto it(ssl_friends.begin());it!=ssl_friends.end();++it)
|
||||
{
|
||||
RsPeerDetails pd;
|
||||
if(rsPeers->getPeerDetails(*it,pd) && pd.skip_signature_validation)
|
||||
{
|
||||
std::cerr << " adding " << *it << " - " << pd.gpg_id << std::endl;
|
||||
gpgFriends.push_back(pd.gpg_id);
|
||||
pgp_friends_without_validation[pd.gpg_id].push_back(pd);
|
||||
}
|
||||
}
|
||||
|
||||
/* get a link to the table */
|
||||
QTreeWidget *peerTreeWidget = ui->peerTreeWidget;
|
||||
|
||||
|
@ -1086,8 +800,7 @@ void FriendList::insertPeers()
|
|||
}
|
||||
|
||||
RsPeerDetails detail;
|
||||
if (pgp_friends_without_validation.find(gpgId) == pgp_friends_without_validation.end() &&
|
||||
(!rsPeers->getGPGDetails(gpgId, detail) || !detail.accept_connection) && detail.gpg_id != ownId) {
|
||||
if ((!rsPeers->getGPGDetails(gpgId, detail) || !detail.accept_connection) && detail.gpg_id != ownId) {
|
||||
// don't accept anymore connection, remove from the view
|
||||
if (gpgItem) {
|
||||
if (groupItem) {
|
||||
|
@ -1096,13 +809,10 @@ void FriendList::insertPeers()
|
|||
delete (peerTreeWidget->takeTopLevelItem(peerTreeWidget->indexOfTopLevelItem(gpgItem)));
|
||||
}
|
||||
}
|
||||
|
||||
// We still want to add the item if it is unvalidated, in which case getGPGDetails returns false.
|
||||
continue;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (gpgItem == NULL)
|
||||
{
|
||||
if (gpgItem == NULL) {
|
||||
// create gpg item and add it to tree
|
||||
gpgItem = new RSTreeWidgetItem(mCompareRole, TYPE_GPG); //set type to 0 for custom popup menu
|
||||
|
||||
|
@ -1117,7 +827,7 @@ void FriendList::insertPeers()
|
|||
gpgItem->setTextAlignment(COLUMN_NAME, Qt::AlignLeft | Qt::AlignVCenter);
|
||||
|
||||
/* not displayed, used to find back the item */
|
||||
QString strID = QString::fromStdString(gpgId.toStdString());
|
||||
QString strID = QString::fromStdString(detail.gpg_id.toStdString());
|
||||
gpgItem->setData(COLUMN_DATA, ROLE_ID, strID);
|
||||
gpgItem->setText(COLUMN_ID, strID);
|
||||
gpgItem->setData(COLUMN_ID, ROLE_SORT_NAME, strID);
|
||||
|
@ -1147,22 +857,263 @@ void FriendList::insertPeers()
|
|||
}
|
||||
|
||||
// update the childs (ssl certs)
|
||||
bool gpg_connected = false;
|
||||
bool gpg_online = false;
|
||||
bool gpg_hasPrivateChat = false;
|
||||
int bestPeerState = 0; // for gpg item
|
||||
unsigned int bestRSState = 0; // for gpg item
|
||||
QString bestCustomStateString;// for gpg item
|
||||
std::list<RsPeerId> sslContacts;
|
||||
QDateTime bestLastContact;
|
||||
QString bestIP;
|
||||
QPixmap bestAvatar;
|
||||
|
||||
PgpItemInfo info;
|
||||
rsPeers->getAssociatedSSLIds(detail.gpg_id, sslContacts);
|
||||
for (std::list<RsPeerId>::iterator sslIt = sslContacts.begin(); sslIt != sslContacts.end(); ++sslIt) {
|
||||
QTreeWidgetItem *sslItem = NULL;
|
||||
RsPeerId sslId = *sslIt;
|
||||
|
||||
auto itt = pgp_friends_without_validation.find(gpgId);
|
||||
if(itt != pgp_friends_without_validation.end())
|
||||
{
|
||||
info.sslContacts.clear();
|
||||
for(auto itt2(itt->second.begin());itt2!=itt->second.end();++itt2)
|
||||
info.sslContacts.push_back(itt2->id);
|
||||
// find the corresponding sslItem child item of the gpg item
|
||||
bool newChild = true;
|
||||
childCount = gpgItem->childCount();
|
||||
for (int childIndex = 0; childIndex < childCount; ++childIndex) {
|
||||
// we assume, that only ssl items are child of the gpg item, so we don't need to test the type
|
||||
if (getRsId(gpgItem->child(childIndex)) == sslId.toStdString()) {
|
||||
sslItem = gpgItem->child(childIndex);
|
||||
newChild = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
detail.name = gpgId.toStdString() + tr(" (Unverified yet)").toStdString();
|
||||
RsPeerDetails sslDetail;
|
||||
if (!rsPeers->getPeerDetails(sslId, sslDetail) || !rsPeers->isFriend(sslId)) {
|
||||
#ifdef FRIENDS_DEBUG
|
||||
std::cerr << "Removing widget from the view : id : " << sslId << std::endl;
|
||||
#endif
|
||||
// child has disappeared, remove it from the gpg_item
|
||||
if (sslItem) {
|
||||
gpgItem->removeChild(sslItem);
|
||||
delete(sslItem);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (newChild) {
|
||||
sslItem = new RSTreeWidgetItem(mCompareRole, TYPE_SSL); //set type to 1 for custom popup menu
|
||||
|
||||
#ifdef FRIENDS_DEBUG
|
||||
std::cerr << "FriendList::insertPeers() inserting sslItem." << std::endl;
|
||||
#endif
|
||||
|
||||
/* Add ssl child to the list. Add here, because for setHidden the item must be added */
|
||||
gpgItem->addChild(sslItem);
|
||||
|
||||
/* Sort data */
|
||||
for (int i = 0; i < columnCount; ++i) {
|
||||
sslItem->setData(i, ROLE_SORT_GROUP, 2);
|
||||
sslItem->setData(i, ROLE_SORT_STANDARD_GROUP, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* not displayed, used to find back the item */
|
||||
QString strID = QString::fromStdString(sslDetail.id.toStdString());
|
||||
sslItem->setData(COLUMN_DATA, ROLE_ID, strID);
|
||||
sslItem->setText(COLUMN_ID, strID);
|
||||
sslItem->setData(COLUMN_ID, ROLE_SORT_NAME, strID);
|
||||
sslItem->setData(COLUMN_ID, ROLE_FILTER, strID);
|
||||
|
||||
/* Custom state string */
|
||||
QString customStateString;
|
||||
if (sslDetail.state & RS_PEER_STATE_CONNECTED) {
|
||||
customStateString = QString::fromUtf8(rsMsgs->getCustomStateString(sslDetail.id).c_str());
|
||||
}
|
||||
|
||||
QPixmap sslAvatar;
|
||||
AvatarDefs::getAvatarFromSslId(RsPeerId(sslDetail.id.toStdString()), sslAvatar);
|
||||
|
||||
/* last contact */
|
||||
QDateTime sslLastContact = QDateTime::fromTime_t(sslDetail.lastConnect);
|
||||
sslItem->setData(COLUMN_LAST_CONTACT, Qt::DisplayRole, QVariant(sslLastContact));
|
||||
sslItem->setData(COLUMN_LAST_CONTACT, ROLE_SORT_NAME, QVariant(sslLastContact));
|
||||
if (sslLastContact > bestLastContact) {
|
||||
bestLastContact = sslLastContact;
|
||||
}
|
||||
|
||||
/* IP */
|
||||
QString sslIP = (sslDetail.state & RS_PEER_STATE_CONNECTED) ? StatusDefs::connectStateIpString(sslDetail) : QString("---");
|
||||
sslItem->setText(COLUMN_IP, sslIP);
|
||||
sslItem->setData(COLUMN_IP, ROLE_SORT_NAME, sslIP);
|
||||
|
||||
/* change color and icon */
|
||||
QPixmap sslOverlayIcon;
|
||||
QFont sslFont;
|
||||
QColor sslColor;
|
||||
int peerState = 0;
|
||||
QString connectStateString;
|
||||
if (sslDetail.state & RS_PEER_STATE_CONNECTED) {
|
||||
// get the status info for this ssl id
|
||||
int rsState = 0;
|
||||
std::list<StatusInfo>::iterator it;
|
||||
for (it = statusInfo.begin(); it != statusInfo.end(); ++it) {
|
||||
if (it->id == sslId) {
|
||||
rsState = it->status;
|
||||
switch (rsState) {
|
||||
case RS_STATUS_INACTIVE:
|
||||
peerState = PEER_STATE_INACTIVE;
|
||||
break;
|
||||
|
||||
case RS_STATUS_ONLINE:
|
||||
peerState = PEER_STATE_ONLINE;
|
||||
break;
|
||||
|
||||
case RS_STATUS_AWAY:
|
||||
peerState = PEER_STATE_AWAY;
|
||||
break;
|
||||
|
||||
case RS_STATUS_BUSY:
|
||||
peerState = PEER_STATE_BUSY;
|
||||
break;
|
||||
}
|
||||
|
||||
/* find the best ssl contact for the gpg item */
|
||||
if (bestPeerState == 0 || peerState < bestPeerState) {
|
||||
/* first ssl contact or higher state */
|
||||
bestPeerState = peerState;
|
||||
bestRSState = rsState;
|
||||
bestCustomStateString = customStateString;
|
||||
bestIP = sslIP;
|
||||
if (!sslAvatar.isNull()) {
|
||||
bestAvatar = sslAvatar;
|
||||
}
|
||||
} else if (peerState == bestPeerState) {
|
||||
/* equal state */
|
||||
if (bestCustomStateString.isEmpty() && !customStateString.isEmpty()) {
|
||||
/* when customStateString is shown in name item, use sslId with customStateString.
|
||||
second with a custom state string ... use second */
|
||||
bestPeerState = peerState;
|
||||
bestRSState = rsState;
|
||||
bestCustomStateString = customStateString;
|
||||
}
|
||||
if (bestAvatar.isNull() && !sslAvatar.isNull()) {
|
||||
/* Use available avatar */
|
||||
bestAvatar = sslAvatar;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sslItem->setHidden(false);
|
||||
gpg_connected = true;
|
||||
|
||||
sslOverlayIcon = QPixmap(StatusDefs::imageStatus(bestRSState));
|
||||
|
||||
connectStateString = StatusDefs::name(rsState);
|
||||
|
||||
if (rsState == 0) {
|
||||
sslFont.setBold(true);
|
||||
sslColor = mTextColorStatus[RS_STATUS_ONLINE];
|
||||
|
||||
} else {
|
||||
sslFont = StatusDefs::font(rsState);
|
||||
sslColor = mTextColorStatus[rsState];
|
||||
}
|
||||
} else if (sslDetail.state & RS_PEER_STATE_ONLINE) {
|
||||
sslItem->setHidden(mHideUnconnected);
|
||||
gpg_online = true;
|
||||
peerState = PEER_STATE_AVAILABLE;
|
||||
|
||||
if (sslDetail.connectState) {
|
||||
sslOverlayIcon = QPixmap(":/images/connect_creating.png");
|
||||
} else {
|
||||
sslOverlayIcon = QPixmap(StatusDefs::imageStatus(RS_STATUS_ONLINE));
|
||||
}
|
||||
|
||||
connectStateString = StatusDefs::name(RS_STATUS_ONLINE);
|
||||
|
||||
sslFont.setBold(true);
|
||||
sslColor = mTextColorStatus[RS_STATUS_ONLINE];
|
||||
} else {
|
||||
peerState = PEER_STATE_OFFLINE;
|
||||
sslItem->setHidden(mHideUnconnected);
|
||||
if (sslDetail.connectState) {
|
||||
sslOverlayIcon = QPixmap(":/images/connect_creating.png");
|
||||
} else {
|
||||
sslOverlayIcon = QPixmap(StatusDefs::imageStatus(RS_STATUS_OFFLINE));
|
||||
}
|
||||
|
||||
connectStateString = StatusDefs::connectStateWithoutTransportTypeString(sslDetail);
|
||||
|
||||
sslFont.setBold(false);
|
||||
sslColor = mTextColorStatus[RS_STATUS_OFFLINE];
|
||||
}
|
||||
|
||||
/* Location */
|
||||
QString sslName = QString::fromUtf8(sslDetail.location.c_str());
|
||||
QString sslText;
|
||||
|
||||
if (mShowState) {
|
||||
if (!connectStateString.isEmpty()) {
|
||||
sslText = connectStateString;
|
||||
if (!customStateString.isEmpty()) {
|
||||
sslText += " [" + customStateString + "]";
|
||||
}
|
||||
} else {
|
||||
if (!customStateString.isEmpty()) {
|
||||
sslText = customStateString;
|
||||
}
|
||||
}
|
||||
|
||||
sslItem->setToolTip(COLUMN_NAME, "");
|
||||
} else {
|
||||
if (!customStateString.isEmpty()) {
|
||||
sslText = customStateString;
|
||||
}
|
||||
|
||||
/* Show the state as tooltip */
|
||||
sslItem->setToolTip(COLUMN_NAME, connectStateString);
|
||||
}
|
||||
|
||||
/* Create or get ssl label */
|
||||
ElidedLabel *sslNameLabel = NULL;
|
||||
ElidedLabel *sslTextLabel = NULL;
|
||||
|
||||
getNameWidget(ui->peerTreeWidget, sslItem, sslNameLabel, sslTextLabel);
|
||||
|
||||
if (sslNameLabel) {
|
||||
sslNameLabel->setText(sslName);
|
||||
sslNameLabel->setFont(sslFont);
|
||||
|
||||
QPalette palette = sslNameLabel->palette();
|
||||
palette.setColor(sslNameLabel->foregroundRole(), sslColor);
|
||||
|
||||
sslNameLabel->setPalette(palette);
|
||||
}
|
||||
if (sslTextLabel) {
|
||||
sslTextLabel->setText(sslText);
|
||||
sslTextLabel->setVisible(!sslText.isEmpty());
|
||||
}
|
||||
|
||||
// Filter
|
||||
sslItem->setData(COLUMN_NAME, ROLE_FILTER, sslName);
|
||||
|
||||
if (std::find(privateChatIds.begin(), privateChatIds.end(), sslDetail.id) != privateChatIds.end()) {
|
||||
// private chat is available
|
||||
sslOverlayIcon = QPixmap(":/images/chat.png");
|
||||
gpg_hasPrivateChat = true;
|
||||
}
|
||||
sslItem->setIcon(COLUMN_NAME, createAvatar(sslAvatar, sslOverlayIcon));
|
||||
|
||||
/* Sort data */
|
||||
sslItem->setData(COLUMN_NAME, ROLE_SORT_NAME, sslName);
|
||||
|
||||
for (int i = 0; i < columnCount; ++i) {
|
||||
sslItem->setData(i, ROLE_SORT_STATE, peerState);
|
||||
|
||||
sslItem->setTextColor(i, sslColor);
|
||||
sslItem->setFont(i, sslFont);
|
||||
}
|
||||
}
|
||||
else
|
||||
rsPeers->getAssociatedSSLIds(gpgId, info.sslContacts);
|
||||
|
||||
manageProfileLocations(gpgItem,gpgId,info);
|
||||
|
||||
QString gpgName = QString::fromUtf8(detail.name.c_str());
|
||||
QString gpgText;
|
||||
|
@ -1172,38 +1123,38 @@ void FriendList::insertPeers()
|
|||
bool showInfoAtGpgItem = !gpgItem->isExpanded();
|
||||
|
||||
QPixmap gpgOverlayIcon;
|
||||
if (info.gpg_connected) {
|
||||
if (gpg_connected) {
|
||||
gpgItem->setHidden(false);
|
||||
|
||||
++onlineCount;
|
||||
|
||||
if (info.bestPeerState == 0) {
|
||||
if (bestPeerState == 0) {
|
||||
// show as online
|
||||
info.bestPeerState = PEER_STATE_ONLINE;
|
||||
info.bestRSState = RS_STATUS_ONLINE;
|
||||
bestPeerState = PEER_STATE_ONLINE;
|
||||
bestRSState = RS_STATUS_ONLINE;
|
||||
}
|
||||
|
||||
gpgColor = mTextColorStatus[info.bestRSState];
|
||||
gpgFont = StatusDefs::font(info.bestRSState);
|
||||
gpgColor = mTextColorStatus[bestRSState];
|
||||
gpgFont = StatusDefs::font(bestRSState);
|
||||
|
||||
if (showInfoAtGpgItem) {
|
||||
gpgOverlayIcon = QPixmap(StatusDefs::imageStatus(info.bestRSState));
|
||||
gpgOverlayIcon = QPixmap(StatusDefs::imageStatus(bestRSState));
|
||||
|
||||
if (mShowState) {
|
||||
gpgText = StatusDefs::name(info.bestRSState);
|
||||
if (!info.bestCustomStateString.isEmpty()) {
|
||||
gpgText += " [" + info.bestCustomStateString + "]";
|
||||
gpgText = StatusDefs::name(bestRSState);
|
||||
if (!bestCustomStateString.isEmpty()) {
|
||||
gpgText += " [" + bestCustomStateString + "]";
|
||||
}
|
||||
} else {
|
||||
if (!info.bestCustomStateString.isEmpty()) {
|
||||
gpgText = info.bestCustomStateString;
|
||||
if (!bestCustomStateString.isEmpty()) {
|
||||
gpgText = bestCustomStateString;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (info.gpg_online) {
|
||||
} else if (gpg_online) {
|
||||
gpgItem->setHidden(mHideUnconnected);
|
||||
++onlineCount;
|
||||
info.bestPeerState = PEER_STATE_AVAILABLE;
|
||||
bestPeerState = PEER_STATE_AVAILABLE;
|
||||
|
||||
gpgFont.setBold(true);
|
||||
gpgColor = mTextColorStatus[RS_STATUS_ONLINE];
|
||||
|
@ -1216,7 +1167,7 @@ void FriendList::insertPeers()
|
|||
gpgOverlayIcon = QPixmap(IMAGE_AVAILABLE);
|
||||
}
|
||||
} else {
|
||||
info.bestPeerState = PEER_STATE_OFFLINE;
|
||||
bestPeerState = PEER_STATE_OFFLINE;
|
||||
gpgItem->setHidden(mHideUnconnected);
|
||||
|
||||
gpgFont = StatusDefs::font(RS_STATUS_OFFLINE);
|
||||
|
@ -1231,11 +1182,11 @@ void FriendList::insertPeers()
|
|||
}
|
||||
}
|
||||
|
||||
if (info.gpg_hasPrivateChat) {
|
||||
if (gpg_hasPrivateChat) {
|
||||
gpgOverlayIcon = QPixmap(":/images/chat.png");
|
||||
}
|
||||
|
||||
gpgItem->setIcon(COLUMN_NAME, createAvatar(info.bestAvatar.isNull() ? QPixmap(AVATAR_DEFAULT_IMAGE) : info.bestAvatar, gpgOverlayIcon));
|
||||
gpgItem->setIcon(COLUMN_NAME, createAvatar(bestAvatar.isNull() ? QPixmap(AVATAR_DEFAULT_IMAGE) : bestAvatar, gpgOverlayIcon));
|
||||
|
||||
/* Create or get gpg label */
|
||||
ElidedLabel *gpgNameLabel = NULL;
|
||||
|
@ -1260,16 +1211,16 @@ void FriendList::insertPeers()
|
|||
// Filter
|
||||
gpgItem->setData(COLUMN_NAME, ROLE_FILTER, gpgName);
|
||||
|
||||
gpgItem->setData(COLUMN_LAST_CONTACT, Qt::DisplayRole, showInfoAtGpgItem ? QVariant(info.bestLastContact) : "");
|
||||
gpgItem->setData(COLUMN_LAST_CONTACT, ROLE_SORT_NAME, QVariant(info.bestLastContact));
|
||||
gpgItem->setText(COLUMN_IP, showInfoAtGpgItem ? info.bestIP : "");
|
||||
gpgItem->setData(COLUMN_IP, ROLE_SORT_NAME, info.bestIP);
|
||||
gpgItem->setData(COLUMN_LAST_CONTACT, Qt::DisplayRole, showInfoAtGpgItem ? QVariant(bestLastContact) : "");
|
||||
gpgItem->setData(COLUMN_LAST_CONTACT, ROLE_SORT_NAME, QVariant(bestLastContact));
|
||||
gpgItem->setText(COLUMN_IP, showInfoAtGpgItem ? bestIP : "");
|
||||
gpgItem->setData(COLUMN_IP, ROLE_SORT_NAME, bestIP);
|
||||
|
||||
/* Sort data */
|
||||
gpgItem->setData(COLUMN_NAME, ROLE_SORT_NAME, gpgName);
|
||||
|
||||
for (int i = 0; i < columnCount; ++i) {
|
||||
gpgItem->setData(i, ROLE_SORT_STATE, info.bestPeerState);
|
||||
gpgItem->setData(i, ROLE_SORT_STATE, bestPeerState);
|
||||
|
||||
gpgItem->setTextColor(i, gpgColor);
|
||||
gpgItem->setFont(i, gpgFont);
|
||||
|
@ -2014,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;
|
||||
|
|
1220
retroshare-gui/src/gui/common/FriendListModel.cpp
Normal file
1220
retroshare-gui/src/gui/common/FriendListModel.cpp
Normal file
File diff suppressed because it is too large
Load diff
235
retroshare-gui/src/gui/common/FriendListModel.h
Normal file
235
retroshare-gui/src/gui/common/FriendListModel.h
Normal file
|
@ -0,0 +1,235 @@
|
|||
/*******************************************************************************
|
||||
* retroshare-gui/src/gui/msgs/RsFriendListModel.h *
|
||||
* *
|
||||
* Copyright 2019 by Cyril Soler <csoler@users.sourceforge.net> *
|
||||
* *
|
||||
* 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 <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QModelIndex>
|
||||
#include <QColor>
|
||||
|
||||
#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<uint32_t> child_profile_indices; // index in the array of hierarchical profiles
|
||||
};
|
||||
struct HierarchicalProfileInformation
|
||||
{
|
||||
RsProfileDetails profile_info;
|
||||
std::vector<uint32_t> 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<EntryIndex>& 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<RsPgpId,uint32_t>::const_iterator checkProfileIndex(const RsPgpId& pgp_id,
|
||||
std::map<RsPgpId,uint32_t>& pgp_indices,
|
||||
std::vector<HierarchicalProfileInformation>& mProfiles,
|
||||
bool create);
|
||||
|
||||
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<uint8_t> static bool convertIndexToInternalId(const EntryIndex& e,quintptr& ref);
|
||||
template<uint8_t> 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<HierarchicalGroupInformation> mGroups;
|
||||
mutable std::vector<HierarchicalProfileInformation> mProfiles;
|
||||
mutable std::vector<HierarchicalNodeInformation> 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<EntryIndex> mTopLevel;
|
||||
|
||||
// keeps track of expanded/collapsed items, so as to only show icon for collapsed profiles
|
||||
|
||||
std::set<std::string> mExpandedProfiles;
|
||||
};
|
||||
|
1511
retroshare-gui/src/gui/common/NewFriendList.cpp
Normal file
1511
retroshare-gui/src/gui/common/NewFriendList.cpp
Normal file
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue