diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..eb9b055b3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +/RetroShare.pro.user +*.o +moc_*.cpp +qrc_*.cpp +ui_*.h +Makefile.* +*~ +Thumbs.db diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..d2d2c2781 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,69 @@ +language: cpp + +compiler: + - gcc + +before_install: + - echo $LANG + - echo $LC_ALL + - sudo apt-get update + - sudo apt-get install build-essential checkinstall cmake g++ git libavcodec-dev libavformat-dev libbz2-dev libcurl4-openssl-dev libdc1394-22-dev libglib2.0-dev libcv-dev libopencv-highgui-dev libhighgui-dev + - sudo apt-get install libgnome-keyring-dev libgstreamer-plugins-base0.10-dev libgstreamer0.10-dev libjasper-dev libjpeg-dev libmicrohttpd-dev libopencv-dev libprotobuf-dev libqt4-dev + - sudo apt-get install libspeex-dev libspeexdsp-dev libsqlite3-dev libssl-dev libswscale-dev + - sudo apt-get install libtbb-dev libtiff4-dev libupnp-dev libv4l-dev libxine-dev libxslt1-dev libxss-dev make pkg-config protobuf-compiler python-dev python-numpy subversion git yasm qtmobility-dev +# - if [ $TRAVIS_OS_NAME == linux ]; then sudo apt-get update && sudo apt-get install -y llvm-3.4 llvm-3.4-dev; fi +# - rvm use $RVM --install --binary --fuzzy +# - gem update --system +# - gem --version + +env: + global: + # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created + # via the "travis encrypt" command using the project repo's public key + - secure: "auwuhxelaMriNaXzT8I03xrh1s+STicNyNToOWFCAYKxkWWQ4WeaCO6kRDmQrejhizMUILGU+s4FrWTEhDsviftGAF86EgzxxbSBfsHHAP4t2C0pcXX8/WxEoh1IrUs7iGCIpl7O2cvWqGidc20ROeptSEd1uQgkHnn14D9A2YmXf8g52PzqivKkb6HKfkVTPdmNJkMBT5eDtEw6DIk+DvnvRo6b6uanvVAKS9CBwXOdA3rLzaD9bz0LrdL9X1CNoTkGROyez0Lsc4zTr70id2Xfp1MMmJAV6hgQy+iwE37wRyrxJf3dkh5SUAAMUC9Xnvh/iBKNQKdQGhj2WGcV7GZV9k6u9DA1w2H0kcrwt9KHUXdhEQ67yr6Boa9ZFwdDb5VIOtC6iHAoDZXharHhiuxi0K/bCtwNAajrMjBCm9mWhEKvtoxUUYxAJajhJkkO3ERaOU3zHE+06esDzGozd2YOEH8a74HhYy4xvhR05Yj00hAWLS2kIaUITiqmBf6Yuh5XwH7KCDcapxF59ROWqyicdwtbfWpvN8IvFuGKyxYuEfoT8WxZ4lZpo4Q9CrTB7gedJYJxYNfZE/okWoFBb4cpPI94PHo3DZPR7lVyQ60RNyeR0nOeqf8NW8cBT1G4jw3u1LEyAdyvup+54aALw0DCVyoDojSXB8s+AlQG2JE=" + +addons: + coverity_scan: + project: + name: "RetroShare/RetroShare" + description: "RetroShare Build submitted via Travis CI" + build_command_prepend: "qmake CONFIG+=NO_SQLCIPHER; make clean" + build_command: "make -j 4" + branch_pattern: coverity_scan + +before_script: + - qmake CONFIG+=NO_SQLCIPHER + +#script: make +script: if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then make ; fi + + +#after_success: +# - if [ $TRAVIS_BRANCH == $TRAVIS_TAG ]; then rake deploy; fi + +#branches: +# only: +# - master +# - travis + +notifications: + email: false + irc: + channels: + - "chat.freenode.net#retroshare" + template: + - "%{repository}/%{branch} (%{commit} - %{author}): %{build_url}: %{message}" + - "Message: %{commit_message}" + - "Commit details: %{compare_url}" +# webhooks: +# urls: +# - https://webhooks.gitter.im/e/9502afd22ca6c8e85fb3 +# on_success: change +# on_failure: always +# on_start: always + +#env: +# - RVM=2.0.0 LANG="en_US.UTF-8" + +os: + - linux diff --git a/README.md b/README.md new file mode 100644 index 000000000..4072f6a3f --- /dev/null +++ b/README.md @@ -0,0 +1,120 @@ +RetroShare +============================== +RetroShare is a decentralized, private and secure commmunication and sharing platform. RetroShare provides filesharing, chat, messages, forums and channels. + +Compilation on Linux +---------------------------- + +1. Install package dependencies: + * Debian/Ubuntu + ```bash + sudo apt-get install libglib2.0-dev libupnp-dev qt4-dev-tools \ + libqt4-dev libssl-dev libxss-dev libgnome-keyring-dev libbz2-dev \ + libqt4-opengl-dev libqtmultimediakit1 qtmobility-dev \ + libspeex-dev libspeexdsp-dev libxslt1-dev libcurl4-openssl-dev \ + libopencv-dev tcl8.5 libmicrohttpd-dev + ``` + * openSUSE + ```bash + sudo zypper install gcc-c++ libqt4-devel libgnome-keyring-devel \ + glib2-devel speex-devel libssh-devel protobuf-devel libcurl-devel \ + libxml2-devel libxslt-devel sqlcipher-devel libmicrohttpd-devel \ + opencv-devel speexdsp-devel libupnp-devel + ``` + * Arch Linux + ```bash + pacman -S base-devel libgnome-keyring libmicrohttpd libupnp libxslt \ + libxss opencv qt4 speex sqlcipher + ``` + +2. Checkout the source code + ```bash + mkdir ~/retroshare + cd ~/retroshare + git clone https://github.com/RetroShare/RetroShare.git trunk + ``` + +3. Compile + ```bash + cd trunk + qmake CONFIG+=debug + make + ``` + +4. Install + ```bash + sudo make install + ``` + + The executables produced will be: + + /usr/bin/RetroShare06 + /usr/bin/RetroShare06-nogui + +Compile only retroshare-nogui +----------------------------- +If you want to run RetroShare on a server and don’t need the gui and plugins, +you can run the following commands to only compile/install the nogui version: + +```bash +qmake +make retroshare-nogui +sudo make retroshare-nogui-install_subtargets +``` + +For packagers +------------- +Packagers can use PREFIX and LIB\_DIR to customize the installation paths: +```bash +qmake PREFIX=/usr LIB_DIR=/usr/lib64 "CONFIG-=debug" "CONFIG+=release" +make +make INSTALL_ROOT=${PKGDIR} install +``` + +If libsqlcipher is not available as a package +--------------------------------------------- + +You need to place sqlcipher so that the hierarchy is: + + retroshare + | + +--- trunk + | + +--- lib + | + +---- sqlcipher +```bash +mkdir lib +cd lib +git clone git://github.com/sqlcipher/sqlcipher.git +cd sqlcipher +./configure --enable-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC" LDFLAGS="-lcrypto" +make +cd .. +``` + +Using retroshare-nogui & webUI +------------------------------ + +The webUI needs to be enabled as a parameter option in retroshare-nogui: + +```bash +./retroshare-nogui --webinterface 9090 --docroot /usr/share/RetroShare06/webui/ +``` + +The webUI is only accessible on localhost:9090 (unless you canged that +option in the GUI). It is advised to keep it that way so that your RS +cannot be controlled using an untrusted connection. + +To access your web UI from a distance, just open a SSH tunnel on it: + +```bash +distant_machine:~/ > ssh rs_host -L 9090:localhost:9090 -N +``` + +"rs_host" is the machine running retroshare-nogui. Then on the distant machine, access your webUI on + + + http://localhost:9090 + +That also works with a retroshare GUI of course. diff --git a/README.txt b/README.txt deleted file mode 100644 index 07a43335a..000000000 --- a/README.txt +++ /dev/null @@ -1,67 +0,0 @@ -To compile: - -- install the package dependencies. On ubuntu: - # sudo apt-get install libglib2.0-dev libupnp-dev qt4-dev-tools \ - libqt4-dev libssl-dev libxss-dev libgnome-keyring-dev libbz2-dev \ - libqt4-opengl-dev libqtmultimediakit1 qtmobility-dev \ - libspeex-dev libspeexdsp-dev libxslt1-dev libprotobuf-dev \ - protobuf-compiler cmake libcurl4-openssl-dev - -- create project directory (e.g. ~/retroshare) and check out the source code - # mkdir ~/retroshare - # cd ~/retroshare && svn co svn://svn.code.sf.net/p/retroshare/code/trunk trunk - -- create a new directory named lib - # mkdir lib - -- get source code for libssh-0.5.4, unzip it, and create build directory (if needed) - - # cd lib - # wget http://git.libssh.org/projects/libssh.git/snapshot/libssh-libssh-0.6.4.zip - # tar zxvf libssh-0.6.4.tar.gz - # cd libssh-0.6.4 - # mkdir build - # cd build - # cmake -DWITH_STATIC_LIB=ON -DWITH_GSSAPI=OFF .. - # make - # cd ../../.. - -- get source code for sqlcipher, and build it (only needed for GXS) - - # cd lib - # git clone git://github.com/sqlcipher/sqlcipher.git - # cd sqlcipher - # ./configure --enable-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC" \ - LDFLAGS="-lcrypto" - # make - # cd .. - -- go to your svn base directory - # cd trunk - # qmake CONFIG=release - # make -j 4 - - => the executable produced will be - trunk/retroshare-gui/src/Retroshare - trunk/retroshare-nogui/src/retroshare-nogui - -- to use the SSH RS server (nogui): - - # ssh-keygen -t rsa -f rs_ssh_host_rsa_key # this makes a RSA - # ./retroshare-nogui -G # generates a login+passwd hash for the RSA key used. - # ./retroshare-nogui -S 7022 -U[SSLid] -P [Passwd hash] - -- to connect from a remote place to the server by SSH: - - # ssh -T -p 7022 [user]@[host] - - and use the command line interface to control your RS instance. - -List of non backward compatible changes for V0.6: -================================================ - -- in rscertificate.cc, enable V_06_USE_CHECKSUM -- in p3charservice, remove all usage of _deprecated items -- turn file transfer into a service. Will break item IDs, but cleanup and - simplify lots of code. - diff --git a/RetroShare.pro b/RetroShare.pro index 27d7915a9..4a1be6b49 100644 --- a/RetroShare.pro +++ b/RetroShare.pro @@ -1,13 +1,37 @@ +!include("retroshare.pri"): error("Could not include file retroshare.pri") + TEMPLATE = subdirs -CONFIG += ordered - SUBDIRS += \ - openpgpsdk/src/openpgpsdk.pro \ - supportlibs/pegmarkdown/pegmarkdown.pro \ - libbitdht/src/libbitdht.pro \ - libretroshare/src/libretroshare.pro \ - libresapi/src/libresapi.pro \ - retroshare-gui/src/retroshare-gui.pro \ - retroshare-nogui/src/retroshare-nogui.pro \ - plugins/plugins.pro + openpgpsdk \ + libbitdht \ + libretroshare \ + libresapi \ + pegmarkdown \ + retroshare_gui \ + retroshare_nogui \ + plugins + +openpgpsdk.file = openpgpsdk/src/openpgpsdk.pro + +libbitdht.file = libbitdht/src/libbitdht.pro + +libretroshare.file = libretroshare/src/libretroshare.pro +libretroshare.depends = openpgpsdk libbitdht + +libresapi.file = libresapi/src/libresapi.pro +libresapi.depends = libretroshare + +pegmarkdown.file = supportlibs/pegmarkdown/pegmarkdown.pro + +retroshare_gui.file = retroshare-gui/src/retroshare-gui.pro +retroshare_gui.depends = libretroshare libresapi pegmarkdown +retroshare_gui.target = retroshare-gui + +retroshare_nogui.file = retroshare-nogui/src/retroshare-nogui.pro +retroshare_nogui.depends = libretroshare libresapi +retroshare_nogui.target = retroshare-nogui + +plugins.file = plugins/plugins.pro +plugins.depends = retroshare_gui +plugins.target = plugins diff --git a/TODO.txt b/TODO.txt index c33834fb6..ef4d189fb 100644 --- a/TODO.txt +++ b/TODO.txt @@ -63,7 +63,7 @@ GUI 0013 [ ] new design, new icons, minimal UI (from purplehaze420) comment: use webui as base for minimal ui cyril: we cannot change everything now. But purplehaze420 said he would provide a consistent set of icons. That would be great. -0014 [ ] go to Settings -> Permissions: wait for scrollbars to appear go back to any other setting (e.g. Notify): the page now +0014 [X] go to Settings -> Permissions: wait for scrollbars to appear go back to any other setting (e.g. Notify): the page now needs the same space as the permission matrix (happens on windows + linux; can be "fixed" by closing and reopen the setting window) (from sehraf) diff --git a/build-all-mingw32make.bat b/build-all-mingw32make.bat index 67aa98694..819642b46 100644 --- a/build-all-mingw32make.bat +++ b/build-all-mingw32make.bat @@ -1,10 +1,8 @@ set QTDIR=C:\Qt\4.8.6 set MINGW=C:\MinGW +set GIT=C:\Program Files\Git -set PATH=%QTDIR%\bin;%MINGW%\bin;%PATH% - -"C:\Program Files\TortoiseSVN\bin\SubWCRev" . libretroshare\src\retroshare\rsversion.in libretroshare\src\retroshare\rsversion.h -"C:\Program Files\TortoiseSVN\bin\SubWCRev" . retroshare-gui\src\retroshare.in retroshare-gui\src\retroshare.nsi +set PATH=%QTDIR%\bin;%MINGW%\bin;%GIT%\bin;%PATH% @echo off @@ -65,12 +63,19 @@ qmake openpgpsdk.pro mingw32-make +cd ..\..\libresapi\src + +if not %clean%x==x mingw32-make clean + +qmake libresapi.pro + +mingw32-make %%a cd ..\..\libretroshare\src if not %clean%x==x mingw32-make clean -qmake libretroshare.pro +qmake libretroshare.pro "CONFIG+=version_detail_bash_script" mingw32-make %%a @@ -97,7 +102,7 @@ cd ..\..\retroshare-gui\src if not %clean%x==x mingw32-make clean -qmake retroshare-gui.pro +qmake retroshare-gui.pro "CONFIG+=version_detail_bash_script" mingw32-make %%a diff --git a/build_scripts/Debian+Ubuntu/changelog b/build_scripts/Debian+Ubuntu/changelog index 601c16e6f..ff2101d8a 100644 --- a/build_scripts/Debian+Ubuntu/changelog +++ b/build_scripts/Debian+Ubuntu/changelog @@ -1,4 +1,232 @@ -retroshare06 (0.6.0-0.XXXXXX~YYYYYY) YYYYYY; urgency=low +retroshare06 (0.6.0-1.XXXXXX~YYYYYY) YYYYYY; urgency=low + + a276986 ( ) Merge pull request #60 from PhenomRetroShare/Fix_AllowChatTextFormatOption + 88a6931 (GUI ) Allow Chat Text Format Option working. + 0b5b20d ( ) Merge pull request #59 from AsamK/qmake_improvements + 0409dd8 ( ) Merge pull request #58 from AsamK/debian_make_install + 21e99cf (Packaging ) Use explicit dependencies instead of CONFIG += ordered + f002310 (Packaging ) Remove libpegmarkdown from win32 retroshare-nogui build + 2337b46 (Packaging ) Specify plugins as plugins to qmake + ecb5d93 (GUI ) changed default color for the system chat bubble + d51b4b2 (Packaging ) Adapt debian/ubuntu package files to use "make install" + c07bef3 (GUI ) Fixed Create Lobby Dialog's window size + a45de1d (Chat ) Merge pull request #57 from csoler/v0.6-SignedLobbies + 40bffc3 (Chat ) fixed last GUI bugs for authed lobbies + 6d01461 (Chat ) fixed a few GUI bits for non anonymous chat lobbies + 627dcc0 (Forums ) Merge pull request #50 from chozabu/forum_additions + 7270ba9 (Chat ) Merge pull request #56 from AsamK/distant_chat_history + 5dad168 (Chat ) Implement history for distant chat + d7531b3 ( ) Merge pull request #54 from cavebeat/coverity + 9240512 ( ) Merge pull request #55 from AsamK/install_stylesheets + 622e942 (GUI ) Remove Thumbs.db files and add to .gitignore + 699213a (Packaging ) Load chat styles also from DATA_DIR/stylesheets + 66ba687 (Packaging ) Install qss and chat styles + 4d7f92e (GXS/NXS ) Removed unnecessary select of groups in RsGxsNetService::locked_genReqGrpTransaction. + 753846b (GXS/SQL ) Added count of requests and results to debug output in RsDataService::retrieveGxsGrpMetaData + d118a13 (GXS/NXS ) Fixed adding of empty group id to notify when removing a group. + 4cc1df3 (GXS/NXS ) Ignore updates of not existing groups in RsGenExchange::processGrpMask. Solves: "Error code: no such column: su + d8aa712 (Packaging ) travis/coverity tokens updated + 6e1a8fa ( ) Merge pull request #21 from AsamK/lobby_history + 040b4fb (Chat ) implemented gp-authed lobbies. Still needs some GUI + b8459b3 ( ) Merge pull request #44 from AsamK/improve_qmake + c622ca0 (Packaging ) Issue compile error if DATA_DIR is not set + ef499cd ( ) Merge pull request #46 from PhenomRetroShare/Fix_ChatWidgetSearchTextThreshold + 668394d ( ) Merge pull request #47 from PhenomRetroShare/AddHTML_TextOptimization_0.6 + 6ba2f68 ( ) Merge pull request #45 from PhenomRetroShare/Fix_ChatWidgetLastCursorFormatting + 1736ad8 ( ) Merge pull request #11 from cavebeat/coverity_scan + a39663d ( ) Merge branch 'master' of https://github.com/RetroShare/RetroShare + 17af892 (GUI ) set a default minimum column header size for comments. + c29ae55 (Code cleaning ) Merge pull request #38 from cavebeat/rm_linkscloud + 1a1a2aa (GXS/NXS ) Lowered update of server sync TS from 10 seconds to 60 seconds. + 641a433 (GUI ) Fixed filter in FriendList. + 217c9b9 ( ) Merge branch 'master' of https://github.com/RetroShare/RetroShare + 9d65b08 (GUI ) set default background color for system messages at private chat window + da66ac5 (GXS ) GxsGroupFrameDialog: Fixed restore of active group tree item when subscrube/unsubscribe a group. + 185220b (GUI ) enable customisation of columns in forum thread widget + 389f2f0 (GXS/SQL ) Removed delete of message files in RsDataService::resetDataStore. + 836b866 ( ) Merge pull request #37 from sehraf/pr-friendlist_import_export-V2 + 5aaf3e6 (Packaging ) Move data dir from build_scripts/ to root and adapt RedHat build files + 4dbffe0 ( ) Merge pull request #48 from PhenomRetroShare/AddRetroShareLinkOpenFileWhenExists + 5c67941 ( ) Update README.md + 5ae5d76 (Packaging ) Make file names consistent with packaging + 91e19fc (Packaging ) Disable installing of headers and libretroshare.a + d4a36ed (Packaging ) Make data and plugin directory configurable at compile time + 6b7a6e2 (Packaging ) Make RS installable with "make install" + fa54fce ( ) Merge pull request #49 from heini/redhat_build + 1fcae61 (GXS/SQL ) Removed static defines for column numbers in RsDataService and replaced it with members. Initialized members wh + 531ce34 ( ) Merge branch 'master' into AddRetroShareLinkOpenFileWhenExists + 860292d ( ) Merge branch 'master' into AddHTML_TextOptimization_0.6 + 70b9c45 ( ) Merge branch 'master' into Fix_ChatWidgetSearchTextThreshold + 79fb8df ( ) Merge branch 'master' into Fix_ChatWidgetLastCursorFormatting + e9aa4ff ( ) Merge pull request #3 from chozabu/copy_version_info_button + d1deef0 (GUI ) fixed new lines in certificate string + 7bd41e9 ( ) Merge pull request #4 from chozabu/grouter_stats_basic_names + 7fe46ed (Packaging ) Provide RedHat family packaging script. + f30ed24 (GXS/SQL ) Moved gxs data from files into database - Added update to RsDataService - Added new table "DATABASE_RELEASE" to + b1aae2d ( ) Merge branch 'master' into AddRetroShareLinkOpenFileWhenExists + 0234734 (GUI ) When the file in the link already exists, RS open it. + 791fb78 (GUI ) renaming details and details2 for better clarification + ad499e6 (GUI ) renamed 'pubkey' to 'certificate' and removed empty location names + 6893c58 ( ) Merge pull request #42 from cavebeat/comma + c66de1c (Packaging ) fixed comma in README for debian + f58e347 ( ) Merge pull request #23 from AsamK/patch-1 + 326a330 (GUI ) Fix ChatWidget last cursor formatting. To test it, search a text that will be colored a end. New messages lose + c44afc0 ( ) Merge branch 'master' into Fix_ChatWidgetSearchTextThreshold + b1fd290 ( ) Merge branch 'master' into AddHTML_TextOptimization_0.6 + eb4313f ( ) merge before commit + 58d29c3 (Bug fix ) fixed error message in pqissl::cansend() + 5c97010 (GUI ) Fix ChatWidget search text label threshold. + 5a32cca (Packaging ) README: Fix executable name + 339558f (Packaging ) Update and rename README.txt to README.md + 6ac107a (GXS/SQL ) Added method "tableExist" to RetroDb. + 3665238 (GXS/SQL ) Added new methods for transaction to RetroDb. + 4309642 ( ) merging before commit + 58c70ca ( ) moved [not] operator inside parenthesis. Does not change anything except improving readability + dea7c77 (Global router ) fixed missing removal of deleted data causing a crash when large messages cause an error in Global Router + 334ddf8 (GUI ) Enabled sort by columns other than name combined with sort by state in FriendList. + 176c3ab (GUI ) FriendSelectionWidget: - Added sort by state - Moved buttons "All"/"None" into context menu + 4923c47 (GUI ) RSTreeWidget: - Added possibility to add own actions to header context menu - Added resort of items + 02775c6 (GUI ) Add HTML Text Optimization by exporting styles. + 1d9e398 (Code cleaning ) removed LinksCloud LinksCloud has been replaced by Posted and is hosted for archiving reasons in https://github + 04a1c10 (GUI ) fixed UTF-8 group names + 941959c (GUI ) conversion from QSettings to XML + 48c3eed (Packaging ) Removed "CONFIG += console" for Windows release build. + 3b40f0e (GUI ) FriendList: - Show information of the "best" ssl item on the gpg item only when the gpg item is not expanded. - + 42bbf76 (GUI ) fixed display of software revision in main window (patch from ASmith) + 80d765e (GUI ) small fix + 3634981 (GUI ) added import/export friendlist + 4d7f733 (Packaging ) fixed bug in git parameter in packaging script + 9734f32 (Packaging ) updated ubuntu changelog. improved ubuntu packaging script + + -- Cyril Soler Sun, 16 Aug 2015 20:00:00 +0100 + +retroshare06 (0.6.0-1.20150816~9734f32a) trusty; urgency=low + + f6b830d (branch merging) Merge pull request #35 from hunbernd/chat-fix + 16859a1 (GUI ) Fix: chatlobby toaster not working + 2e08dde (Bug fix ) additional check for pqissl::sockfd before using it (patch from Jenster) + 384e7ba (GXS ) Reworked processing of requests in RsGxsDataAccess to prevent freezes of the gui. + 4a50a62 (Git management) Merge branch 'master' of https://github.com/RetroShare/RetroShare + 6eccd57 (Git management) merging before commit + 3084d2a (Debug info ) improved security message in console for whitelisted peers + 0402e53 (GUI ) Fix: empty line duplication bug + 4095d9d (GXS ) Switched retrieve of posts in GxsMessageFramePostWidget from "requestMsgRelatedInfo" to "requestMsgInfo". + b1101ed (GXS ) Prevent selecting data from the database in RsGxsNetService::syncWithPeers without online friends. + 3731617 (Debug info ) Fixed typo in debug output. + e667071 (GUI ) Moved IP Filter Widgets into Tabs + caa97cc (GXS ) Added database name to the debug output in RsDataService. + 2a6b623 (GXS ) Added extended debug outputs of times in RsDataService. + 7472f81 (Git management) Merge branch 'master' of https://github.com/RetroShare/RetroShare + 9d291aa (GUI ) update windows build scripts changed gxs id icon for linked with profile. + a765016 (GUI ) Moved column show/hide from context menu of the tree to the context menu of the header in IdDialog. + e73e68d (GUI ) Reduced the size of the status icon on the avatar image in FriendList. + 442ec23 (GXS ) Added index in database for column grpId in table MESSAGES. + b8edb75 (GXS ) Optimized SELECT creation in RetroDb::sqlQuery + ab538c6 (GXS ) Avoid error messages "table already exists" in RsDataService::initialise by using "IF NOT EXISTS" + 783465b (GUI ) forget to commit this, for the Search Filter DHT IPs + 13e77fb (Bugs ) Merge pull request #19 from sehraf/pr-fix_crash_on_shutdown + 9d0b066 (Bugs ) Fixed hide offline friends in ServicePermissionsPage + c919786 (GUI ) Fixed typo. Updated english translation. + d5c95c4 (GUI ) Fixed layout of the ServicePermissionsPage + 9265145 (GUI ) Updated english translation + 87f2e6d (GUI ) FriendList: - Removed avatar column, state column. Added combined avatar and status icon + ec67ee0 (VOIP ) added graph display of instantly required bandwidth for VOIP, in preparation to chosing new + video codec. GUI layout + d5c33f5 (Packaging ) fixed windows build script + c168765 (GUI ) Added tab for the DHT TreeWidgets for better view Added a search Filter for DHT IP addresses + 48bb8b4 (Git management) sequel to 6b2ed2fb2d84d7e48b15fa917aa4eb8015922d15 + fabc3a3 (Git management) added some rules to .gitignore + 168eb45 (Debug info ) removed debug info about missing keys; added debug info about deserialization checking of string + 311358b (Git management) merged changes from master + a87adb8 (Debug info ) improved README file + 51ab1fc (Debug info ) updated readme file + 43db562 (Packaging ) Fixed build script for Windows installer + 789df68 (Packaging ) Added update of version information for Windows build - Added template file version.html.in - Removed RS_BUILD_NUM + 1412dc6 (Packaging ) Removed utopic, added new ppa name + + -- Cyril Soler Sun, 16 Aug 2015 20:00:00 +0100 + +retroshare06 (0.6.0-1.20150802.34ec6dfd~precise) precise; urgency=low + + GUI + - improved filtering method against lol bombs. Thx to ConcernedCitizen for pointing this out + - fix #21 typo "defaut" instead of "default" in switch statement in RSGraphWidget (patch from Chozabu) + - moved all bw graph files in statistics. Removed outqueue info widget. Created new cpp files to host the bw graph code. + Started minimal UI to display bw information. The goal is t + - fixed position of scaled/highlighted nodes in node graph (patch from Chozabu) + - fixed a few bugs in statistics GUI. Still misses names and proper curve display + - Enabled Messenger Window in system tray icon. + - Fixed overlay icon (star) for tray icon. + - fixed up various places in the GUI for high DPI screens (new icons and icon qrc file generation script, font-size based widgets, etc) + - disable update of group messages for IdService since it is unused and takes some bandwidth + - fixed typo in server page "127.0.01" + - Added stylesheet to plugins. + - Moved fix font from GenCertDialog to qss (Modified patch from Henry). Added defaults to ui without style sheet + - Fixed typo in string (Patch from Henry). + - Added customize of columns to RSTreeWidget. + - added back functionality to choose DL directory for each channel + - Removed generate of channel messages. + - FriendList: - Added customize of columns with RSTreeWidget. - Reduced display menu. + - Optimized fill of forums when modifying the read state. + - Fixed compile with Qt 5 + - Added disable/enable of GxsIdDetails process. Disabled GxsIdDetails process when filling gxs id's in forums. + - Optimized load of forums by moving the avatar handling for the tooltip to the tooltip creation. + + + added correct image file for finished transfers + + - added correct image file for finished transfers + + Backend / Coverity bug fixes + - removed old function entry to collect outqueue stats. + - removed unused method for OutQueue statistics; improved BW curve display; fixed a few display bugs + - Added missing initialization in - pqissl - pqissludp - PeerConnectStateBox - RsTlvBanListEntry - RsServer + TcpStream - PGPCertificateInfo - peerConnectAddress - AudioInputConfig + - Fixed usage of member _thread_id in RsMutex + - Removed unused member from ProfileManager. + - Added missing restore of ostream format (std::dec) in rschatitems.cc. + - Added missing restore of ostream format (std::dec) in CreateLobbyDialog::createLobby. + - Fixed crash in ChatMsgItem::removeItem when "mParent == NULL". + - Added missing restore of ostream format (std::dec) in p3ServiceServer::sendItem. + - Fixed crash in ChatLobbyUserNotify::subMenuClicked when using "Remove All" of the chat lobby notifier. + - Fixed possible crash in DetailsDialog::setFileHash by checking return value of dynamic_cast. + - Fixed possible crash in ftServer::receiveTurtleData by checking return value of dynamic_cast. + - Fixed possible crash in ftServer::handleIncoming by checking return value of dynamic_cast. + - Fixed possible crash in ServiceControlSerialiser by checking return value of dynamic_cast. + - Fixed possible crash in RsFileTransferSerialiser by checking return value of dynamic_cast. + - Fixed possible crash in ChatLobbyDialog::init by checking return value of dynamic_cast. + - Fixed possible crash in RsGRouterSerialiser by checking return value of dynamic_cast. + - added basic functions to collect bandwidth info in pqistreamer both ways; added a sorting method in BWGraphSource + to create curves from extracted BW info. Still not yet functiona + - Fixed possible crash in RsGxsIdSerialiser by checking return value of dynamic_cast. + - Fixed possible crash in p3GRouter by checking return value of dynamic_cast. + - Removed dead code from ImHistoryBrowser::fillItem. + - Removed potentially unintentional integer overflow in NxsBandwidthRecorder::recordEvent. + - Added initialize of RsGxsChannelPost members. + - fixed potential integer problem in image de-serialization (reported by HM) + - Added initialize of RsVOIPPingItem members + - fixed potential integer problems in de-serialization of different TLV items (patch from Henry) + + Plugins + - fix #20 crash on shutdown with plugins enabled. Settings window did leak plugin config pages (patch from hunbernd) + + WebUI + - allow only whitelisted link protocols to prevent javascript in links + - improved error message in webui: show full path of file if read failed + - make link detection work if the message ends with + - added chat + - fix serialisation of floating point numbers in SuperEasyJSON for german locale. JSON expects decimal points, but german locale used comma. + + GXS IDs + - added additional key checking for IDs received during distant chat DH handshake + - added methods to check public/private keys for consistent fingerprint and content. Should be later used to check GXS keys when they arrive from neighbor nodes. + + Distant chat + - Added check of function parameter to DistantChatService::handleRecvDHPublicKey. + + -- Cyril Soler Sun, 02 Aug 2015 16:00:00 +0100 + +retroshare06 (0.6.0-0.8551~precise) precise; urgency=low GUI diff --git a/build_scripts/Debian+Ubuntu/clean.sh b/build_scripts/Debian+Ubuntu/clean.sh index 8eeaf34f4..6e68064f9 100755 --- a/build_scripts/Debian+Ubuntu/clean.sh +++ b/build_scripts/Debian+Ubuntu/clean.sh @@ -1,11 +1,11 @@ #!/bin/sh rm -f ./libssh-0.5.4.tar.gz.* -rm -f ./retroshare06_0.6.0-0.*_source.build -rm -f ./retroshare06_0.6.0-0.*_source.changes -rm -f ./retroshare06_0.6.0-0.*.tar.gz -rm -f ./retroshare06_0.6.0-0.*.diff.gz -rm -f ./retroshare06_0.6.0-0.*.dsc +rm -f ./retroshare06_0.6.0-1.*_source.build +rm -f ./retroshare06_0.6.0-1.*_source.changes +rm -f ./retroshare06_0.6.0-1.*.tar.gz +rm -f ./retroshare06_0.6.0-1.*.diff.gz +rm -f ./retroshare06_0.6.0-1.*.dsc rm -f *.upload rm -f *~ diff --git a/build_scripts/Debian+Ubuntu/control.precise b/build_scripts/Debian+Ubuntu/control.precise index b008cf5fa..70d77ea50 100644 --- a/build_scripts/Debian+Ubuntu/control.precise +++ b/build_scripts/Debian+Ubuntu/control.precise @@ -2,7 +2,7 @@ Source: retroshare06 Section: devel Priority: standard Maintainer: Cyril Soler -Build-Depends: debhelper (>= 7), libglib2.0-dev, libupnp-dev, qt4-dev-tools, libqt4-dev, libssl-dev, libxss-dev, libgnome-keyring-dev, libbz2-dev, libqt4-opengl-dev, libqtmultimediakit1, qtmobility-dev, libspeex-dev, libspeexdsp-dev, libxslt1-dev, cmake, libcurl4-openssl-dev, libcv-dev, libopencv-core-dev, libopencv-contrib-dev, libhighgui-dev, tcl8.5, libsqlcipher-dev, libmicrohttpd-dev +Build-Depends: debhelper (>= 7), libglib2.0-dev, libupnp-dev, qt4-dev-tools, libqt4-dev, libssl-dev, libxss-dev, libgnome-keyring-dev, libbz2-dev, libqt4-opengl-dev, libqtmultimediakit1, qtmobility-dev, libspeex-dev, libspeexdsp-dev, libxslt1-dev, cmake, libcurl4-openssl-dev, libcv-dev, libopencv-core-dev, libopencv-contrib-dev, libhighgui-dev, tcl8.5, libsqlcipher-dev, libmicrohttpd-dev, libavcodec-dev Standards-Version: 3.9.3 Homepage: http://retroshare.sourceforge.net diff --git a/build_scripts/Debian+Ubuntu/control.squeeze_bubba3 b/build_scripts/Debian+Ubuntu/control.squeeze_bubba3 index 244bdb2a0..c72507d0f 100644 --- a/build_scripts/Debian+Ubuntu/control.squeeze_bubba3 +++ b/build_scripts/Debian+Ubuntu/control.squeeze_bubba3 @@ -2,7 +2,7 @@ Source: retroshare06 Section: devel Priority: standard Maintainer: Cyril Soler -Build-Depends: debhelper (>= 7), libglib2.0-dev, libupnp-dev, qt4-dev-tools, libqt4-dev, libssl-dev, libxss-dev, libgnome-keyring-dev, libbz2-dev, libqt4-opengl-dev, libqt4-multimedia, libspeex-dev, libspeexdsp-dev, libxslt1-dev, cmake, libcurl4-openssl-dev, libcv-dev, libcvaux-dev, libhighgui-dev, tcl8.5, libmicrohttpd-dev, libsqlite3-dev +Build-Depends: debhelper (>= 7), libglib2.0-dev, libupnp-dev, qt4-dev-tools, libqt4-dev, libssl-dev, libxss-dev, libgnome-keyring-dev, libbz2-dev, libqt4-opengl-dev, libqt4-multimedia, libspeex-dev, libspeexdsp-dev, libxslt1-dev, cmake, libcurl4-openssl-dev, libcv-dev, libcvaux-dev, libhighgui-dev, tcl8.5, libmicrohttpd-dev, libsqlite3-dev, libavcodec-dev Standards-Version: 3.9.3 Homepage: http://retroshare.sourceforge.net diff --git a/build_scripts/Debian+Ubuntu/control.ubuntu_lucid b/build_scripts/Debian+Ubuntu/control.ubuntu_lucid index 1188ca8a0..ae12f4247 100644 --- a/build_scripts/Debian+Ubuntu/control.ubuntu_lucid +++ b/build_scripts/Debian+Ubuntu/control.ubuntu_lucid @@ -2,7 +2,7 @@ Source: retroshare Section: devel Priority: standard Maintainer: Cyril Soler -Build-Depends: debhelper (>= 7), libglib2.0-dev, libupnp-dev, qt4-dev-tools, libqt4-dev, libssl-dev, libxss-dev, libgnome-keyring-dev, libbz2-dev, libqt4-opengl-dev, libspeex-dev, libspeexdsp-dev, libxslt1-dev, libprotobuf-dev, protobuf-compiler, cmake, libcurl4-openssl-dev +Build-Depends: debhelper (>= 7), libglib2.0-dev, libupnp-dev, qt4-dev-tools, libqt4-dev, libssl-dev, libxss-dev, libgnome-keyring-dev, libbz2-dev, libqt4-opengl-dev, libspeex-dev, libspeexdsp-dev, libxslt1-dev, libprotobuf-dev, protobuf-compiler, cmake, libcurl4-openssl-dev, libavcodec-dev Standards-Version: 3.9.1 Homepage: http://retroshare.sourceforge.net diff --git a/build_scripts/Debian+Ubuntu/debian/control b/build_scripts/Debian+Ubuntu/debian/control index 357150da5..b251bb923 100644 --- a/build_scripts/Debian+Ubuntu/debian/control +++ b/build_scripts/Debian+Ubuntu/debian/control @@ -2,7 +2,7 @@ Source: retroshare06 Section: devel Priority: standard Maintainer: Cyril Soler -Build-Depends: debhelper (>= 7), libglib2.0-dev, libupnp-dev, qt4-dev-tools, libqt4-dev, libssl-dev, libxss-dev, libgnome-keyring-dev, libbz2-dev, libqt4-opengl-dev, libqtmultimediakit1, qtmobility-dev, libspeex-dev, libspeexdsp-dev, libxslt1-dev, cmake, libcurl4-openssl-dev, libopencv-dev, tcl8.5, libsqlcipher-dev, libmicrohttpd-dev +Build-Depends: debhelper (>= 7), libglib2.0-dev, libupnp-dev, qt4-dev-tools, libqt4-dev, libssl-dev, libxss-dev, libgnome-keyring-dev, libbz2-dev, libqt4-opengl-dev, libqtmultimediakit1, qtmobility-dev, libspeex-dev, libspeexdsp-dev, libxslt1-dev, cmake, libcurl4-openssl-dev, libopencv-dev, tcl8.5, libsqlcipher-dev, libmicrohttpd-dev, libavcodec-dev Standards-Version: 3.9.3 Homepage: http://retroshare.sourceforge.net diff --git a/build_scripts/Debian+Ubuntu/debian/dirs b/build_scripts/Debian+Ubuntu/debian/dirs deleted file mode 100644 index bac28ebe3..000000000 --- a/build_scripts/Debian+Ubuntu/debian/dirs +++ /dev/null @@ -1,10 +0,0 @@ -usr/bin -usr/sbin -usr/share/pixmaps -usr/share/applications/ -usr/share/RetroShare06/ -usr/share/RetroShare06/webui/ -usr/share/RetroShare06/sounds/ -usr/share/icons/hicolor/24x24/apps/ -usr/share/icons/hicolor/48x48/apps/ -usr/share/icons/hicolor/64x64/apps/ diff --git a/build_scripts/Debian+Ubuntu/debian/retroshare06-feedreader-plugin.install b/build_scripts/Debian+Ubuntu/debian/retroshare06-feedreader-plugin.install index e97cbc926..5fc9c6571 100644 --- a/build_scripts/Debian+Ubuntu/debian/retroshare06-feedreader-plugin.install +++ b/build_scripts/Debian+Ubuntu/debian/retroshare06-feedreader-plugin.install @@ -1,2 +1 @@ -usr/lib/retroshare/extensions6/libFeedReader.so - +debian/tmp/usr/lib/retroshare/extensions6/libFeedReader.so* diff --git a/build_scripts/Debian+Ubuntu/debian/retroshare06-nogui.install b/build_scripts/Debian+Ubuntu/debian/retroshare06-nogui.install index 552f3b781..c60111bf3 100644 --- a/build_scripts/Debian+Ubuntu/debian/retroshare06-nogui.install +++ b/build_scripts/Debian+Ubuntu/debian/retroshare06-nogui.install @@ -1,6 +1,3 @@ -usr/bin -usr/bin/RetroShare-nogui -usr/share -usr/share/RetroShare -usr/share/RetroShare/bdboot.txt - +debian/tmp/usr/bin/RetroShare06-nogui +debian/tmp/usr/share/RetroShare06/bdboot.txt +debian/tmp/usr/share/RetroShare06/webui/* diff --git a/build_scripts/Debian+Ubuntu/debian/retroshare06-voip-plugin.install b/build_scripts/Debian+Ubuntu/debian/retroshare06-voip-plugin.install index e7bfcd259..48f8bdbab 100644 --- a/build_scripts/Debian+Ubuntu/debian/retroshare06-voip-plugin.install +++ b/build_scripts/Debian+Ubuntu/debian/retroshare06-voip-plugin.install @@ -1,2 +1 @@ -usr/lib/retroshare/extensions6/libVOIP.so - +debian/tmp/usr/lib/retroshare/extensions6/libVOIP.so* diff --git a/build_scripts/Debian+Ubuntu/debian/retroshare06.install b/build_scripts/Debian+Ubuntu/debian/retroshare06.install index 992a44333..089770666 100644 --- a/build_scripts/Debian+Ubuntu/debian/retroshare06.install +++ b/build_scripts/Debian+Ubuntu/debian/retroshare06.install @@ -1,10 +1,6 @@ -usr/share/applications/retroshare.desktop -usr/share/pixmaps/retroshare.xpm -usr/share/RetroShare/bdboot.txt -usr/share/icons/hicolor/48x48/apps/retroshare.png -usr/share/icons/hicolor/24x24/apps/retroshare.png -usr/share/icons/hicolor/64x64/apps/retroshare.png -usr/bin -usr/bin/RetroShare -usr/bin/RetroShare-nogui - +debian/tmp/usr/bin/RetroShare06 +debian/tmp/usr/bin/RetroShare06-nogui +debian/tmp/usr/share/applications/retroshare06.desktop +debian/tmp/usr/share/icons/hicolor/* +debian/tmp/usr/share/pixmaps/retroshare06.xpm +debian/tmp/usr/share/RetroShare06/* diff --git a/build_scripts/Debian+Ubuntu/debian/rules b/build_scripts/Debian+Ubuntu/debian/rules index de9a3cb38..69487e51a 100755 --- a/build_scripts/Debian+Ubuntu/debian/rules +++ b/build_scripts/Debian+Ubuntu/debian/rules @@ -1,14 +1,14 @@ #!/usr/bin/make -f -builddir: - mkdir -p builddir - -builddir/Makefile: builddir +configure: configure-stamp +configure-stamp: + dh_testdir + cd src && qmake-qt4 "CONFIG-=debug" "CONFIG+=release" PREFIX=/usr LIB_DIR=/usr/lib RetroShare.pro touch $@ -build: build-stamp -build-stamp: builddir/Makefile +build: build-stamp +build-stamp: configure-stamp dh_testdir # Add here commands to compile the package. # cd libssh-0.6.4 && mkdir -p build && cd build && cmake -DWITH_STATIC_LIB=ON .. && make @@ -17,68 +17,24 @@ build-stamp: builddir/Makefile # cp -r libssh-0.6.4 lib/ #cp -r sqlcipher lib/ #cd src/rsctrl/src && make - cd src && qmake-qt4 CONFIG=release RetroShare.pro && make + cd src && $(MAKE) touch $@ clean: dh_testdir dh_testroot - rm -f build-stamp + rm -f configure-stamp build-stamp # Add here commands to clean up after the build process. - rm -rf builddir + [ ! -f src/Makefile ] || (cd src && $(MAKE) distclean) dh_clean install: build dh_testdir dh_testroot dh_clean -k - dh_installdirs - install -D -m 644 src/data/retroshare.desktop $(CURDIR)/debian/retroshare06/usr/share/applications/retroshare06.desktop - install -D -m 644 src/data/24x24/retroshare.png $(CURDIR)/debian/retroshare06/usr/share/icons/hicolor/24x24/apps/retroshare06.png - install -D -m 644 src/data/48x48/retroshare.png $(CURDIR)/debian/retroshare06/usr/share/icons/hicolor/48x48/apps/retroshare06.png - install -D -m 644 src/data/64x64/retroshare.png $(CURDIR)/debian/retroshare06/usr/share/icons/hicolor/64x64/apps/retroshare06.png - install -D -m 644 src/data/retroshare.xpm $(CURDIR)/debian/retroshare06/usr/share/pixmaps/retroshare06.xpm - install -D -m 644 src/plugins/VOIP/libVOIP.so.1.0.0 $(CURDIR)/debian/retroshare06-voip-plugin/usr/lib/retroshare/extensions6/libVOIP.so - install -D -m 644 src/plugins/FeedReader/libFeedReader.so.1.0.0 $(CURDIR)/debian/retroshare06-feedreader-plugin/usr/lib/retroshare/extensions6/libFeedReader.so - install -D -m 644 src/libbitdht/src/bitdht/bdboot.txt $(CURDIR)/debian/retroshare06-nogui/usr/share/RetroShare06/bdboot.txt - install -D -m 644 src/libbitdht/src/bitdht/bdboot.txt $(CURDIR)/debian/retroshare06/usr/share/RetroShare06/bdboot.txt - install -D -m 755 src/retroshare-nogui/src/retroshare-nogui $(CURDIR)/debian/retroshare06-nogui/usr/bin/RetroShare06-nogui - install -D -m 755 src/retroshare-nogui/src/retroshare-nogui $(CURDIR)/debian/retroshare06/usr/bin/RetroShare06-nogui - install -D -m 755 src/retroshare-gui/src/RetroShare $(CURDIR)/debian/retroshare06/usr/bin/RetroShare06 - install -D -m 644 src/libresapi/src/webfiles/JSXTransformer.js $(CURDIR)/debian/retroshare06/usr/share/RetroShare06/webui/JSXTransformer.js - install -D -m 644 src/libresapi/src/webfiles/RsApi.js $(CURDIR)/debian/retroshare06/usr/share/RetroShare06/webui/RsApi.js - install -D -m 644 src/libresapi/src/webfiles/RsXHRConnection.js $(CURDIR)/debian/retroshare06/usr/share/RetroShare06/webui/RsXHRConnection.js - install -D -m 644 src/libresapi/src/webfiles/green-black.css $(CURDIR)/debian/retroshare06/usr/share/RetroShare06/webui/green-black.css - install -D -m 644 src/libresapi/src/webfiles/gui.jsx $(CURDIR)/debian/retroshare06/usr/share/RetroShare06/webui/gui.jsx - install -D -m 644 src/libresapi/src/webfiles/index.html $(CURDIR)/debian/retroshare06/usr/share/RetroShare06/webui/index.html - install -D -m 644 src/libresapi/src/webfiles/react.js $(CURDIR)/debian/retroshare06/usr/share/RetroShare06/webui/react.js - install -D -m 644 src/retroshare-gui/src/gui/images/logo/logo_splash.png $(CURDIR)/debian/retroshare06/usr/share/RetroShare06/webui/img/logo_splash.png - install -D -m 644 src/libresapi/src/webfiles/JSXTransformer.js $(CURDIR)/debian/retroshare06-nogui/usr/share/RetroShare06/webui/JSXTransformer.js - install -D -m 644 src/libresapi/src/webfiles/RsApi.js $(CURDIR)/debian/retroshare06-nogui/usr/share/RetroShare06/webui/RsApi.js - install -D -m 644 src/libresapi/src/webfiles/RsXHRConnection.js $(CURDIR)/debian/retroshare06-nogui/usr/share/RetroShare06/webui/RsXHRConnection.js - install -D -m 644 src/libresapi/src/webfiles/green-black.css $(CURDIR)/debian/retroshare06-nogui/usr/share/RetroShare06/webui/green-black.css - install -D -m 644 src/libresapi/src/webfiles/gui.jsx $(CURDIR)/debian/retroshare06-nogui/usr/share/RetroShare06/webui/gui.jsx - install -D -m 644 src/libresapi/src/webfiles/index.html $(CURDIR)/debian/retroshare06-nogui/usr/share/RetroShare06/webui/index.html - install -D -m 644 src/libresapi/src/webfiles/react.js $(CURDIR)/debian/retroshare06-nogui/usr/share/RetroShare06/webui/react.js - install -D -m 644 src/retroshare-gui/src/gui/images/logo/logo_splash.png $(CURDIR)/debian/retroshare06-nogui/usr/share/RetroShare06/webui/img/logo_splash.png - install -D -m 644 src/retroshare-gui/src/sounds/alert.wav $(CURDIR)/debian/retroshare06/usr/share/RetroShare06/sounds/alert.wav - install -D -m 644 src/retroshare-gui/src/sounds/chat1.wav $(CURDIR)/debian/retroshare06/usr/share/RetroShare06/sounds/chat1.wav - install -D -m 644 src/retroshare-gui/src/sounds/chat2.wav $(CURDIR)/debian/retroshare06/usr/share/RetroShare06/sounds/chat2.wav - install -D -m 644 src/retroshare-gui/src/sounds/file.wav $(CURDIR)/debian/retroshare06/usr/share/RetroShare06/sounds/file.wav - install -D -m 644 src/retroshare-gui/src/sounds/ft_complete.wav $(CURDIR)/debian/retroshare06/usr/share/RetroShare06/sounds/ft_complete.wav - install -D -m 644 src/retroshare-gui/src/sounds/ft_incoming.wav $(CURDIR)/debian/retroshare06/usr/share/RetroShare06/sounds/ft_incoming.wav - install -D -m 644 src/retroshare-gui/src/sounds/incomingchat.wav $(CURDIR)/debian/retroshare06/usr/share/RetroShare06/sounds/incomingchat.wav - install -D -m 644 src/retroshare-gui/src/sounds/notify.wav $(CURDIR)/debian/retroshare06/usr/share/RetroShare06/sounds/notify.wav - install -D -m 644 src/retroshare-gui/src/sounds/offline.wav $(CURDIR)/debian/retroshare06/usr/share/RetroShare06/sounds/offline.wav - install -D -m 644 src/retroshare-gui/src/sounds/online1.wav $(CURDIR)/debian/retroshare06/usr/share/RetroShare06/sounds/online1.wav - install -D -m 644 src/retroshare-gui/src/sounds/online2.wav $(CURDIR)/debian/retroshare06/usr/share/RetroShare06/sounds/online2.wav - install -D -m 644 src/retroshare-gui/src/sounds/receive.wav $(CURDIR)/debian/retroshare06/usr/share/RetroShare06/sounds/receive.wav - install -D -m 644 src/retroshare-gui/src/sounds/send1.wav $(CURDIR)/debian/retroshare06/usr/share/RetroShare06/sounds/send1.wav - install -D -m 644 src/retroshare-gui/src/sounds/send2.wav $(CURDIR)/debian/retroshare06/usr/share/RetroShare06/sounds/send2.wav - install -D -m 644 src/retroshare-gui/src/sounds/startup.wav $(CURDIR)/debian/retroshare06/usr/share/RetroShare06/sounds/startup.wav + #dh_installdirs + cd src && $(MAKE) INSTALL_ROOT=$(CURDIR)/debian/tmp install -# Add here commands to install the package into debian/your_appname -# cd builddir && $(MAKE) INSTALL_ROOT=$(CURDIR)/debian/$(APPNAME) install # Build architecture-independent files here. binary-indep: build install # We have nothing to do by default. @@ -87,9 +43,10 @@ binary-indep: build install binary-arch: build install dh_testdir dh_testroot - dh_installdocs - dh_installexamples - dh_installman + dh_install --list-missing + #dh_installdocs + #dh_installexamples + #dh_installman dh_link dh_strip dh_compress @@ -102,4 +59,3 @@ binary-arch: build install binary: binary-indep binary-arch .PHONY: build clean binary-indep binary-arch binary install configure - diff --git a/build_scripts/Debian+Ubuntu/makeSourcePackage.sh b/build_scripts/Debian+Ubuntu/makeSourcePackage.sh index 5998c3ac9..78efdf17e 100755 --- a/build_scripts/Debian+Ubuntu/makeSourcePackage.sh +++ b/build_scripts/Debian+Ubuntu/makeSourcePackage.sh @@ -2,12 +2,12 @@ ###################### PARAMETERS #################### version="0.6.0" -svnpath="svn://csoler@svn.code.sf.net/p/retroshare/code/" +gitpath="https://github.com/RetroShare/RetroShare.git" workdir=retroshare06-${version} #bubba3="Y" # comment out to compile for bubba3 ###################################################### -echo This script is going to build the debian source package for RetroShare, from the SVN repository. +echo This script is going to build the debian source package for RetroShare, from the Git repository. if test -d "${workdir}" ; then echo Removing the ${workdir} directory... @@ -15,14 +15,15 @@ if test -d "${workdir}" ; then fi # Parse options -svnrev="" +rev="" dist="" # This is the key for "Cyril Soler " -gpgkey="C737CA98" +gpgkey="0932399B" + while [ ${#} -gt 0 ]; do case ${1} in "-rev") shift - svnrev=${1} + rev=${1} shift ;; "-distribution") shift @@ -46,46 +47,52 @@ while [ ${#} -gt 0 ]; do done if test "${dist}" = "" ; then - dist="precise trusty utopic vivid" + dist="precise trusty vivid" fi +echo Attempting to get revision number... +ccount=`git rev-list --count --all` +ccount=`expr $ccount + 8613 - 8267` + +date=`git log --pretty=format:"%ai" | head -1 | cut -d\ -f1 | sed -e s/-//g` +time=`git log --pretty=format:"%aD" | head -1 | cut -d\ -f5 | sed -e s/://g` +hhsh=`git log --pretty=format:"%H" | head -1 | cut -c1-8` + +rev=${date}.${hhsh} + echo " "Using PGP key id : ${gpgkey} echo " "Using distributions: ${dist} -echo " "Using svn : ${rev} - -echo Updating SVN... -svn update - -if test "${svnrev}" = "" ; then - echo Attempting to get SVN revision number... - svnrev=`svn info|awk '/^Revision:/ {print $NF}'` -else - echo SVN number has been provided. Forcing update. -fi +echo " "Commit count : ${ccount} +echo " "Date : ${date} +echo " "Time : ${time} +echo " "Hash : ${hhsh} +echo " "Using revision : ${rev} echo Done. -version="${version}"."${svnrev}" +version="${version}"."${rev}" echo Got version number ${version}. echo Please check that the changelog is up to date. echo Hit ENTER if this is correct. Otherwise hit Ctrl+C read tmp -packages="." - -echo SVN number is ${svnrev} -echo Version is ${version} - echo Extracting base archive... mkdir -p ${workdir}/src -cp -r data ${workdir}/src/ -cp -r debian ${workdir}/debian - echo Checking out latest snapshot... cd ${workdir}/src -svn co -r${svnrev} ${svnpath}/trunk/ . +git clone --depth 1 https://github.com/RetroShare/RetroShare.git . cd - +if ! test -d ${workdir}/src/libretroshare/; then + echo Git clone failed. + exit +fi + +#cp -r data ${workdir}/src/ +cp -r debian ${workdir}/debian + +#svn co -r${rev} ${svnpath}/trunk/ . + # VOIP tweak cp ${workdir}/src/retroshare-gui/src/gui/chat/PopupChatDialog.ui ${workdir}/src/plugins/VOIP/gui/PopupChatDialog.ui @@ -107,16 +114,18 @@ cd ${workdir} echo Setting version numbers... # setup version numbers -sed -e "s%RS_REVISION_NUMBER.*%RS_REVISION_NUMBER ${svnrev}%" src/libretroshare/src/retroshare/rsversion.in > src/libretroshare/src/retroshare/rsversion.h +sed -e "s%RS_REVISION_NUMBER.*%RS_REVISION_NUMBER 0x${hhsh}%" src/libretroshare/src/retroshare/rsversion.in > src/libretroshare/src/retroshare/rsversion.h # Various cleaning echo Cleaning... -find . -depth -name ".svn" -a -type d -exec rm -rf {} \; # remove all svn repositories + +\rm -rf src/.git +#find . -depth -name ".svn" -a -type d -exec rm -rf {} \; # remove all svn repositories echo Calling debuild... for i in ${dist}; do echo copying changelog for ${i} - sed -e s/XXXXXX/"${svnrev}"/g -e s/YYYYYY/"${i}"/g ../changelog > debian/changelog + sed -e s/XXXXXX/"${rev}"/g -e s/YYYYYY/"${i}"/g ../changelog > debian/changelog if test "${i}" = "lucid" ; then cp ../control.ubuntu_lucid debian/control diff --git a/build_scripts/Debian+Ubuntu/ppa_upload.sh b/build_scripts/Debian+Ubuntu/ppa_upload.sh index 617a611d5..e6897618a 100644 --- a/build_scripts/Debian+Ubuntu/ppa_upload.sh +++ b/build_scripts/Debian+Ubuntu/ppa_upload.sh @@ -1,3 +1,2 @@ #!/bin/sh -Apply dput ppa:csoler-users/retroshare-snapshots retroshare_0.5.5#.changes -Apply dput ppa:csoler-users/retroshare-unstable retroshare06_0.6.0-0.#.changes +Apply dput ppa:retroshare/unstable retroshare06_0.6.0-1.#.changes diff --git a/build_scripts/RedHat+Fedora/00Readme b/build_scripts/RedHat+Fedora/00Readme new file mode 100644 index 000000000..f1b74889c --- /dev/null +++ b/build_scripts/RedHat+Fedora/00Readme @@ -0,0 +1,14 @@ +This is the build directory for RPM based Linux distributions like RedHat +Enterprise Linux and compatible distributions (CentOS, Oracle Linux, ...) or +Fedora. + +To create an RPM package (as well as Source RPM) for your distribution, just +run the makePackages.sh script found in this directory, like so: + + ./makepackages.sh + +The script needs the rpmbuild command, which is part of the rpm-build package. + +In case any build dependency is missing, the rpmbuild command will fail. Just +install the missing package(s) and restart the script (Hint: all needed +packages are listed in the provided retroshare06.spec file.) diff --git a/build_scripts/RedHat+Fedora/data/retroshare.desktop b/build_scripts/RedHat+Fedora/data/retroshare.desktop new file mode 100644 index 000000000..504ca9048 --- /dev/null +++ b/build_scripts/RedHat+Fedora/data/retroshare.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Version=1.0 +Name=RetroShare06 +Comment=Securely share files with your friends +Exec=/usr/bin/RetroShare06 +Icon=/usr/share/pixmaps/retroshare06.xpm +Terminal=false +Type=Application +Categories=Network;P2P; diff --git a/build_scripts/RedHat+Fedora/makePackages.sh b/build_scripts/RedHat+Fedora/makePackages.sh new file mode 100755 index 000000000..805209895 --- /dev/null +++ b/build_scripts/RedHat+Fedora/makePackages.sh @@ -0,0 +1,85 @@ +#!/bin/bash + +###################### PARAMETERS #################### +VERSION="0.6.0" +###################################################### +dirs -c + +echo "This script is going to build the RedHat family source package for RetroShare, from a clone of the GitHub repository." + +# Parse options +while [[ ${#} > 0 ]] +do + case ${1} in + "-h") shift + echo "Package building script for RedHat family distributions" + echo "Usage:" + echo " ${0}" + exit 1 + ;; + "*") echo "Unknown option" + exit 1 + ;; + esac +done + +GITROOT=$(git rev-parse --show-toplevel) +DATE=$(git log --pretty=format:"%ai" | head -1 | cut -d\ -f1 | sed -e s/-//g) +HASH=$(git log --pretty=format:"%H" | head -1 | cut -c1-8) +REV=${DATE}.${HASH} +FULL_VERSION=${VERSION}.${REV} + +echo "Using version number: ${VERSION}" +echo "Using revision: ${REV}" +echo "Hit ENTER if this is correct. Otherwise hit Ctrl+C" +read tmp + +WORKDIR="retroshare06-${FULL_VERSION}" + +if [[ -d ${WORKDIR} ]] +then + echo "Removing the directory ${WORKDIR}..." + rm -rf ${WORKDIR} +fi +mkdir -p ${WORKDIR}/src + +echo "Copying sources into workdir..." +rsync -rc --exclude build_scripts ${GITROOT}/* ${WORKDIR}/src +rsync -rc --copy-links data ${WORKDIR}/src +pushd ${WORKDIR} >/dev/null + +# Cloning sqlcipher +echo "Cloning sqlcipher repository..." +mkdir lib +pushd lib >/dev/null +git clone https://github.com/sqlcipher/sqlcipher.git +pushd sqlcipher >/dev/null +git checkout v3.3.1 +rm -rf .git +popd >/dev/null +popd >/dev/null + +# VOIP tweak +cp src/retroshare-gui/src/gui/chat/PopupChatDialog.ui src/plugins/VOIP/gui/PopupChatDialog.ui + +# cleaning up protobof generated files +rm -f src/retroshare-nogui/src/rpc/proto/gencc/*.pb.h +rm -f src/retroshare-nogui/src/rpc/proto/gencc/*.pb.cc + +# setup version numbers +echo "Setting version numbers..." +sed -e "s%RS_REVISION_NUMBER.*%RS_REVISION_NUMBER 0x${HASH}%" src/libretroshare/src/retroshare/rsversion.in >src/libretroshare/src/retroshare/rsversion.h +popd >/dev/null + +echo "Creating RPMs..." +[[ -d rpm-build/rpm ]] || mkdir -p rpm-build/rpm +pushd rpm-build/rpm >/dev/null +for DIR in BUILD RPMS SOURCES SPECS SRPMS +do + [[ -d ${DIR} ]] || mkdir ${DIR} +done +popd >/dev/null +tar -zcf rpm-build/rpm/SOURCES/${WORKDIR}.tar.gz ${WORKDIR} +rpmbuild --define="%rev ${REV}" --define="%_usrsrc $PWD/rpm-build" --define="%_topdir %{_usrsrc}/rpm" -ba retroshare06.spec +rm -rf ${WORKDIR} +exit 0 diff --git a/build_scripts/RedHat+Fedora/retroshare06.spec b/build_scripts/RedHat+Fedora/retroshare06.spec new file mode 100644 index 000000000..d6ef0ff9f --- /dev/null +++ b/build_scripts/RedHat+Fedora/retroshare06.spec @@ -0,0 +1,99 @@ +Summary: Secure communication with friends +Name: retroshare06 +Version: 0.6.0.%{rev} +Release: 1%{?dist} +License: GPLv3 +Group: Productivity/Networking/Other +URL: http://retroshare.sourceforge.net/ +Source0: %{name}-%{version}.tar.gz +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root +Requires: qt-x11 +BuildRequires: gcc-c++ qt-devel desktop-file-utils libgnome-keyring-devel glib2-devel libssh-devel protobuf-devel libcurl-devel libxml2-devel libxslt-devel openssl-devel libXScrnSaver-devel libupnp-devel bzip2-devel libmicrohttpd-devel +# This is because of sqlcipher: +BuildRequires: tcl + +%description +RetroShare is a decentralized, private and secure commmunication and sharing platform. RetroShare provides filesharing, chat, messages, forums and channels. + +Authors: +see http://retroshare.sourceforge.net/team.html + +%package nogui +Summary: RetroShare cli client +Group: Productivity/Network/Other +Requires: openssl +Conflicts: %name = %{version} + +%description nogui +This is the command-line client for RetroShare network. This client can be contacted and talked-to using SSL. Clients exist for portable devices running e.g. Android. + +%package voip-plugin +Summary: RetroShare VOIP plugin +Group: Productivity/Networking/Other +Requires: %name = %{version} +BuildRequires: opencv-devel speex-devel +%if 0%{?fedora} >= 22 +BuildRequires: speexdsp-devel +%endif + +%description voip-plugin +This package provides a plugin for RetroShare, a secured Friend-to-Friend communication platform. The plugin adds voice-over-IP functionality to the private chat window. Both friends chatting together need the plugin installed to be able to talk together. + +%package feedreader-plugin +Summary: RetroShare FeedReader plugin +Group: Productivity/Networking/Other +Requires: %name = %{version} + +%description feedreader-plugin +This package provides a plugin for RetroShare, a secured Friend-to-Friend communication platform. The plugin adds a RSS feed reader tab to retroshare. + +%prep +%setup -q + +%build +cd lib/sqlcipher +./configure --disable-shared --enable-static --enable-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC" LDFLAGS="-lcrypto" +make +cd - +cd src +qmake-qt4 "CONFIG-=debug" "CONFIG+=release" PREFIX=%{_prefix} LIB_DIR=%{_libdir} RetroShare.pro +make +cd - + +%install +rm -rf $RPM_BUILD_ROOT +cd src +make INSTALL_ROOT=$RPM_BUILD_ROOT install +#menu +desktop-file-validate $RPM_BUILD_ROOT%{_datadir}/applications/retroshare06.desktop + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root,-) +%{_bindir}/RetroShare06 +%defattr(644, root, root) +%{_datadir}/pixmaps/%{name}.xpm +%{_datadir}/icons/hicolor +%{_datadir}/applications/%{name}.desktop +%{_datadir}/RetroShare06 + +%files nogui +%defattr(-, root, root) +%{_bindir}/RetroShare06-nogui +%defattr(644, root, root) +%{_datadir}/RetroShare06 + +%files voip-plugin +%defattr(-, root, root) +%{_libdir}/retroshare/extensions6/libVOIP.so* + +%files feedreader-plugin +%defattr(-, root, root) +%{_libdir}/retroshare/extensions6/libFeedReader.so* + +%changelog +* Sat Apr 4 2015 Heini - +- Initial build. + diff --git a/build_scripts/Windows/GetRsVersion.bat b/build_scripts/Windows/GetRsVersion.bat new file mode 100644 index 000000000..153b5969d --- /dev/null +++ b/build_scripts/Windows/GetRsVersion.bat @@ -0,0 +1,43 @@ +@:: Usage: +@:: call GetRsVersion.bat Define Variable + +@setlocal +@echo off + +set Define=%~1 +if "%Define%"=="" ( + echo. + echo Parameter error + endlocal + exit /B1 +) + +set Variable=%~2 +if "%Variable%"=="" ( + echo. + echo Parameter error + endlocal + exit /B1 +) + +set Result= +set VersionFile="%~dp0..\..\libretroshare\src\retroshare\rsversion.h" + +if not exist "%VersionFile%" ( + echo. + echo Version file doesn't exist. + echo %VersionFile% + endlocal + exit /B1 +) + +for /F "usebackq tokens=1,2,3" %%A in (%VersionFile%) do ( + if "%%A"=="#define" ( + if "%%B"=="%Define%" ( + set Result=%%~C + ) + ) +) + +endlocal & set %Variable%=%Result% +exit /B 0 \ No newline at end of file diff --git a/build_scripts/Windows/make_installer.bat b/build_scripts/Windows/make_installer.bat index e2f8cfc14..42b3776e9 100644 --- a/build_scripts/Windows/make_installer.bat +++ b/build_scripts/Windows/make_installer.bat @@ -24,32 +24,27 @@ if "%MinGWDir%" NEQ "" set NSIS_PARAM=%NSIS_PARAM% /DMINGWDIR="%MinGWDir%" if "%OutDir%" NEQ "" set NSIS_PARAM=%NSIS_PARAM% /DOUTDIR="%OutDir%" :: Scan version from source +set Revision= set BuildAdd= -set VersionFile="%SourceDir%\libretroshare\src\retroshare\rsversion.h" +call "%~dp0GetRsVersion.bat" RS_REVISION_STRING Revision +if errorlevel 1 goto exit +call "%~dp0GetRsVersion.bat" RS_BUILD_NUMBER_ADD BuildAdd +if errorlevel 1 goto exit -if not exist "%VersionFile%" ( +if "%Revision%"=="" ( echo. - echo Version file doesn't exist. + echo Version not found in echo %VersionFile% - goto :exit + goto exit ) - -for /F "usebackq tokens=1,2,3" %%A in (%VersionFile%) do ( - if "%%A"=="#define" ( - if "%%B"=="RS_BUILD_NUMBER_ADD" ( - set BuildAdd=%%~C - ) - ) -) - if "%BuildAdd%"=="" ( echo. echo Version not found in echo %VersionFile% - goto :exit + goto exit ) -set NSIS_PARAM=%NSIS_PARAM% /DBUILDADD=%BuildAdd% +set NSIS_PARAM=%NSIS_PARAM% /DREVISION=%Revision% /DBUILDADD=%BuildAdd% :: Create installer "%NSIS_EXE%" %NSIS_PARAM% "%~dp0retroshare.nsi" diff --git a/build_scripts/Windows/retroshare.nsi b/build_scripts/Windows/retroshare.nsi index d6f6f9f9c..aa27dc1eb 100644 --- a/build_scripts/Windows/retroshare.nsi +++ b/build_scripts/Windows/retroshare.nsi @@ -39,10 +39,10 @@ !endif # Get version from executable -!GetDllVersion "${RELEASEDIR}\retroshare-gui\src\release\RetroShare.exe" VERSION_ +!GetDllVersion "${RELEASEDIR}\retroshare-gui\src\release\RetroShare06.exe" VERSION_ !define VERSION ${VERSION_1}.${VERSION_2}.${VERSION_3}${BUILDADD} -!define REVISION ${VERSION_4} +;!define REVISION ${VERSION_4} # Check version !ifndef REVISION @@ -53,6 +53,9 @@ !error "REVISION is not defined" !endif +# Date +!define /date Date "%Y%m%d" + # Application name and version !define APPNAME "RetroShare" !define APPNAMEANDVERSION "${APPNAME} ${VERSION}" @@ -68,7 +71,7 @@ # Main Install settings Name "${APPNAMEANDVERSION}" InstallDirRegKey HKLM "Software\${APPNAME}" "" -OutFile "${OUTDIR_}RetroShare_${VERSION}_${REVISION}_setup.exe" +OutFile "${OUTDIR_}RetroShare-${VERSION}-${Date}-${REVISION}-setup.exe" BrandingText "${APPNAMEANDVERSION}" RequestExecutionlevel highest # Use compression @@ -172,8 +175,8 @@ Section $(Section_Main) Section_Main ; Main binaries SetOutPath "$INSTDIR" - File "${RELEASEDIR}\retroshare-gui\src\release\RetroShare.exe" - File "${RELEASEDIR}\retroshare-nogui\src\release\retroshare-nogui.exe" + File /oname=RetroShare.exe "${RELEASEDIR}\retroshare-gui\src\release\RetroShare06.exe" + File /oname=retroshare-nogui.exe "${RELEASEDIR}\retroshare-nogui\src\release\RetroShare06-nogui.exe" ; Qt binaries File "${QTDIR}\bin\QtCore4.dll" diff --git a/build_scripts/Debian+Ubuntu/data/retroshare.png b/data/128x128/apps/retroshare06.png similarity index 100% rename from build_scripts/Debian+Ubuntu/data/retroshare.png rename to data/128x128/apps/retroshare06.png diff --git a/build_scripts/Debian+Ubuntu/data/24x24/retroshare.png b/data/24x24/apps/retroshare06.png similarity index 100% rename from build_scripts/Debian+Ubuntu/data/24x24/retroshare.png rename to data/24x24/apps/retroshare06.png diff --git a/build_scripts/Debian+Ubuntu/data/48x48/retroshare.png b/data/48x48/apps/retroshare06.png similarity index 100% rename from build_scripts/Debian+Ubuntu/data/48x48/retroshare.png rename to data/48x48/apps/retroshare06.png diff --git a/build_scripts/Debian+Ubuntu/data/64x64/retroshare.png b/data/64x64/apps/retroshare06.png similarity index 100% rename from build_scripts/Debian+Ubuntu/data/64x64/retroshare.png rename to data/64x64/apps/retroshare06.png diff --git a/build_scripts/Debian+Ubuntu/data/retroshare.desktop b/data/retroshare06.desktop similarity index 100% rename from build_scripts/Debian+Ubuntu/data/retroshare.desktop rename to data/retroshare06.desktop diff --git a/build_scripts/Debian+Ubuntu/data/retroshare.xpm b/data/retroshare06.xpm similarity index 100% rename from build_scripts/Debian+Ubuntu/data/retroshare.xpm rename to data/retroshare06.xpm diff --git a/libbitdht/src/libbitdht.pro b/libbitdht/src/libbitdht.pro index 6f705fa7d..7d6dca1d6 100644 --- a/libbitdht/src/libbitdht.pro +++ b/libbitdht/src/libbitdht.pro @@ -1,3 +1,5 @@ +!include("../../retroshare.pri"): error("Could not include file ../../retroshare.pri") + TEMPLATE = lib CONFIG += staticlib CONFIG -= qt @@ -37,6 +39,13 @@ linux-g++-64 { OBJECTS_DIR = temp/linux-g++-64/obj } +unix { + data_files.path = "$${DATA_DIR}" + data_files.files = bitdht/bdboot.txt + INSTALLS += data_files +} + + #################### Cross compilation for windows under Linux #################### win32-x-g++ { diff --git a/libresapi/src/api/ApiServer.cpp b/libresapi/src/api/ApiServer.cpp index 994df8a75..842308e2b 100644 --- a/libresapi/src/api/ApiServer.cpp +++ b/libresapi/src/api/ApiServer.cpp @@ -225,6 +225,7 @@ public: ApiServerMainModules(ResourceRouter& router, StateTokenServer* sts, const RsPlugInInterfaces &ifaces): mPeersHandler(sts, ifaces.mNotify, ifaces.mPeers, ifaces.mMsgs), mIdentityHandler(ifaces.mIdentity), + mForumHandler(ifaces.mGxsForums), mServiceControlHandler(rsServiceControl), // TODO: don't use global variable here mFileSearchHandler(sts, ifaces.mNotify, ifaces.mTurtle, ifaces.mFiles), mTransfersHandler(sts, ifaces.mFiles), @@ -238,6 +239,8 @@ public: &PeersHandler::handleRequest); router.addResourceHandler("identity", dynamic_cast(&mIdentityHandler), &IdentityHandler::handleRequest); + router.addResourceHandler("forums", dynamic_cast(&mForumHandler), + &ForumHandler::handleRequest); router.addResourceHandler("servicecontrol", dynamic_cast(&mServiceControlHandler), &ServiceControlHandler::handleRequest); router.addResourceHandler("filesearch", dynamic_cast(&mFileSearchHandler), @@ -250,6 +253,7 @@ public: PeersHandler mPeersHandler; IdentityHandler mIdentityHandler; + ForumHandler mForumHandler; ServiceControlHandler mServiceControlHandler; FileSearchHandler mFileSearchHandler; TransfersHandler mTransfersHandler; diff --git a/libresapi/src/api/ApiServer.h b/libresapi/src/api/ApiServer.h index becb21641..10b4c92b0 100644 --- a/libresapi/src/api/ApiServer.h +++ b/libresapi/src/api/ApiServer.h @@ -5,6 +5,7 @@ #include "ApiTypes.h" #include "PeersHandler.h" #include "IdentityHandler.h" +#include "ForumHandler.h" #include "ServiceControlHandler.h" #include "StateTokenServer.h" #include "FileSearchHandler.h" diff --git a/libresapi/src/api/ForumHandler.cpp b/libresapi/src/api/ForumHandler.cpp new file mode 100644 index 000000000..3a628a5a5 --- /dev/null +++ b/libresapi/src/api/ForumHandler.cpp @@ -0,0 +1,148 @@ +#include "ForumHandler.h" + +#include +#include + +#include "Operators.h" +#include "ApiTypes.h" +#include "GxsResponseTask.h" +#ifndef WINDOWS_SYS +#include "unistd.h" +#endif + +namespace resource_api +{ +ForumHandler::ForumHandler(RsGxsForums* forums): + mRsGxsForums(forums) +{ + addResourceHandler("*", this, &ForumHandler::handleWildcard); +} + +void ForumHandler::handleWildcard(Request &req, Response &resp) +{ + bool ok = true; + if(!req.mPath.empty()) + { + std::string str = req.mPath.top(); + req.mPath.pop(); + if(str != "") + { + //assume we have a groupID + RsGxsGroupId grpId(str); + std::list groupIds; + groupIds.push_back(grpId); + + uint32_t token; + RsTokReqOptions opts; + opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA; + mRsGxsForums->getTokenService()->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, groupIds); + + time_t start = time(NULL); + while((mRsGxsForums->getTokenService()->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + &&(mRsGxsForums->getTokenService()->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_FAILED) + &&((time(NULL) < (start+10))) + ) + { + #ifdef WINDOWS_SYS + Sleep(500); + #else + usleep(500*1000) ; + #endif + } + + if(mRsGxsForums->getTokenService()->requestStatus(token) == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + { + std::vector grps; + ok &= mRsGxsForums->getMsgData(token, grps); + for(std::vector::iterator vit = grps.begin(); vit != grps.end(); vit++) + { + RsGxsForumMsg& grp = *vit; + KeyValueReference group_id("group_id", grp.mMeta.mGroupId); + resp.mDataStream.getStreamToMember() + << group_id + << makeKeyValueReference("name", grp.mMeta.mMsgName) + << makeKeyValueReference("id", grp.mMeta.mMsgId) + << makeKeyValueReference("parent_id", grp.mMeta.mParentId) + << makeKeyValueReference("author_id", grp.mMeta.mAuthorId) + << makeKeyValueReference("orig_msg_id", grp.mMeta.mOrigMsgId) + << makeKeyValueReference("thread_id", grp.mMeta.mThreadId) + << makeKeyValueReference("message", grp.mMsg); + } + } + else + { + ok = false; + } + + } + + } + else + { + // no more path element + RsTokReqOptions opts; + opts.mReqType = GXS_REQUEST_TYPE_GROUP_DATA; + uint32_t token; + mRsGxsForums->getTokenService()->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts); + + time_t start = time(NULL); + while((mRsGxsForums->getTokenService()->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + &&(mRsGxsForums->getTokenService()->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_FAILED) + &&((time(NULL) < (start+10))) + ) + { + #ifdef WINDOWS_SYS + Sleep(500); + #else + usleep(500*1000) ; + #endif + } + if(mRsGxsForums->getTokenService()->requestStatus(token) == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + { + std::vector grps; + ok &= mRsGxsForums->getGroupData(token, grps); + for(std::vector::iterator vit = grps.begin(); vit != grps.end(); vit++) + { + RsGxsForumGroup& grp = *vit; + KeyValueReference id("id", grp.mMeta.mGroupId); + KeyValueReference vis_msg("visible_msg_count", grp.mMeta.mVisibleMsgCount); + //KeyValueReference pgp_id("pgp_id",grp.mPgpId ); + // not very happy about this, i think the flags should stay hidden in rsidentities + bool own = (grp.mMeta.mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_ADMIN); + bool pgp_linked = (grp.mMeta.mGroupFlags & RSGXSID_GROUPFLAG_REALID); + bool subscribed = IS_GROUP_SUBSCRIBED(grp.mMeta.mSubscribeFlags); + resp.mDataStream.getStreamToMember() + << id + //<< pgp_id + << makeKeyValueReference("name", grp.mMeta.mGroupName) + //<< makeKeyValueReference("last_post", grp.mMeta.mLastPost) + << makeKeyValueReference("pop", grp.mMeta.mPop) + //<< makeKeyValueReference("publish_ts", grp.mMeta.mPublishTs) + << vis_msg + << makeKeyValueReference("group_status", grp.mMeta.mGroupStatus) + << makeKeyValueReference("author_id", grp.mMeta.mAuthorId) + << makeKeyValueReference("parent_grp_id", grp.mMeta.mParentGrpId) + << makeKeyValueReference("description", grp.mDescription) + << makeKeyValueReference("own", own) + << makeKeyValueReference("subscribed", subscribed) + << makeKeyValueReference("pgp_linked", pgp_linked); + } + } + else + { + ok = false; + } + } + + + if(ok) + { + resp.setOk(); + } + else + { + resp.setFail(); + } +} + +} // namespace resource_api diff --git a/libresapi/src/api/ForumHandler.h b/libresapi/src/api/ForumHandler.h new file mode 100644 index 000000000..e44b19818 --- /dev/null +++ b/libresapi/src/api/ForumHandler.h @@ -0,0 +1,20 @@ +#ifndef FORUMHANDLER_H +#define FORUMHANDLER_H + +#include "ResourceRouter.h" + +class RsGxsForums; + +namespace resource_api +{ + +class ForumHandler : public ResourceRouter +{ +public: + ForumHandler(RsGxsForums* forums); +private: + RsGxsForums* mRsGxsForums; + void handleWildcard(Request& req, Response& resp); +}; +} // namespace resource_api +#endif // FORUMHANDLER_H diff --git a/libresapi/src/libresapi.pro b/libresapi/src/libresapi.pro index b71f50f24..a45255e45 100644 --- a/libresapi/src/libresapi.pro +++ b/libresapi/src/libresapi.pro @@ -1,3 +1,5 @@ +!include("../../retroshare.pri"): error("Could not include file ../../retroshare.pri") + TEMPLATE = lib CONFIG += staticlib CONFIG -= qt @@ -8,6 +10,16 @@ CONFIG += libmicrohttpd INCLUDEPATH += ../../libretroshare/src +unix { + webui_files.path = "$${DATA_DIR}/webui" + webui_files.files = webfiles/* + INSTALLS += webui_files + + webui_img_files.path = "$${DATA_DIR}/webui/img" + webui_img_files.files = ../../retroshare-gui/src/gui/images/logo/logo_splash.png + INSTALLS += webui_img_files +} + win32{ DEFINES *= WINDOWS_SYS INCLUDEPATH += $$PWD/../../../libs/include @@ -29,6 +41,7 @@ SOURCES += \ api/PeersHandler.cpp \ api/Operators.cpp \ api/IdentityHandler.cpp \ + api/ForumHandler.cpp \ api/ServiceControlHandler.cpp \ api/StateTokenServer.cpp \ api/GxsResponseTask.cpp \ @@ -49,6 +62,7 @@ HEADERS += \ api/PeersHandler.h \ api/Operators.h \ api/IdentityHandler.h \ + api/ForumHandler.h \ api/ServiceControlHandler.h \ api/GxsMetaOperators.h \ api/StateTokenServer.h \ diff --git a/libretroshare/src/chat/distantchat.cc b/libretroshare/src/chat/distantchat.cc index 399baf20a..e69e9aad8 100644 --- a/libretroshare/src/chat/distantchat.cc +++ b/libretroshare/src/chat/distantchat.cc @@ -1019,8 +1019,8 @@ bool DistantChatService::getDistantChatStatus(const RsGxsId& gxs_id,uint32_t& st { status = it->second.status ; - if(from_gxs_id != NULL) - *from_gxs_id = it->second.own_gxs_id ; + if(from_gxs_id != NULL) + *from_gxs_id = it->second.own_gxs_id ; return true ; } diff --git a/libretroshare/src/chat/distributedchat.cc b/libretroshare/src/chat/distributedchat.cc index 8e759fadc..7a683c2eb 100644 --- a/libretroshare/src/chat/distributedchat.cc +++ b/libretroshare/src/chat/distributedchat.cc @@ -46,7 +46,7 @@ static const time_t CONNECTION_CHALLENGE_MAX_MSG_AGE = 30 ; // maximum age o 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 time_t MAX_KEEP_MSG_RECORD = 1200 ; // keep msg record for 1200 secs max. +static const time_t MAX_KEEP_MSG_RECORD = 1200 ; // keep msg record for 1200 secs max. static const time_t MAX_KEEP_INACTIVE_NICKNAME = 180 ; // keep inactive nicknames for 3 mn max. static const time_t MAX_DELAY_BETWEEN_LOBBY_KEEP_ALIVE = 120 ; // send keep alive packet every 2 minutes. static const time_t MAX_KEEP_PUBLIC_LOBBY_RECORD = 60 ; // keep inactive lobbies records for 60 secs max. @@ -57,11 +57,11 @@ 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_PERIOD = 10 ; // duration window for max number of messages before messages get dropped. -#define IS_PUBLIC_LOBBY(flags) (flags & RS_CHAT_LOBBY_FLAGS_PUBLIC ) -#define IS_ANONYMOUS_LOBBY(flags) (flags & RS_CHAT_LOBBY_FLAGS_ANONYMOUS) -#define IS_CONNEXION_CHALLENGE(flags) (flags & RS_CHAT_LOBBY_FLAGS_CHALLENGE) +#define IS_PUBLIC_LOBBY(flags) (flags & RS_CHAT_LOBBY_FLAGS_PUBLIC ) +#define IS_PGP_SIGNED_LOBBY(flags) (flags & RS_CHAT_LOBBY_FLAGS_PGP_SIGNED) +#define IS_CONNEXION_CHALLENGE(flags) (flags & RS_CHAT_LOBBY_FLAGS_CHALLENGE ) -#define EXTRACT_PRIVACY_FLAGS(flags) (ChatLobbyFlags(flags.toUInt32()) & RS_CHAT_LOBBY_FLAGS_PUBLIC) +#define EXTRACT_PRIVACY_FLAGS(flags) (ChatLobbyFlags(flags.toUInt32()) * (RS_CHAT_LOBBY_FLAGS_PUBLIC | RS_CHAT_LOBBY_FLAGS_PGP_SIGNED)) DistributedChatService::DistributedChatService(uint32_t serv_type,p3ServiceControl *sc,p3HistoryMgr *hm, RsGixs *is) : mServType(serv_type),mDistributedChatMtx("Distributed Chat"), mServControl(sc), mHistMgr(hm),mGixs(is) @@ -144,7 +144,37 @@ bool DistributedChatService::handleRecvChatLobbyMsgItem(RsChatMsgItem *ci) std::cerr << std::endl; return false; } + + ChatLobbyFlags fl ; + + // delete items that are not for us, as early as possible. + { + RsStackMutex stack(mDistributedChatMtx); /********** STACK LOCKED MTX ******/ + // send upward for display + + std::map::const_iterator it = _chat_lobbys.find(cli->lobby_id) ; + + if(it == _chat_lobbys.end()) + { +#ifdef DEBUG_CHAT_LOBBIES + std::cerr << "Chatlobby for id " << std::hex << item->lobby_id << " has no record. Dropping the msg." << std::dec << std::endl; +#endif + return false; + } + fl = it->second.lobby_flags ; + } + if(IS_PGP_SIGNED_LOBBY(fl)) + { + RsIdentityDetails details; + + if(!rsIdentity->getIdDetails(cli->signature.keyId,details) || !details.mPgpKnown) + { + std::cerr << "(WW) Received a lobby msg/item that is not PGP-authed (id=" << cli->signature.keyId << "), whereas the lobby flags require it. Rejecting!" << std::endl; + + return false ; + } + } if(!bounceLobbyObject(cli,cli->PeerId())) // forwards the message to friends, keeps track of subscribers, etc. return false; @@ -157,7 +187,7 @@ bool DistributedChatService::handleRecvChatLobbyMsgItem(RsChatMsgItem *ci) //name = cli->nick; //popupChatFlag = RS_POPUP_CHATLOBBY; - RsServer::notify()->AddPopupMessage(RS_POPUP_CHATLOBBY, cli->signature.keyId.toStdString(), cli->nick, cli->message); /* notify private chat message */ + RsServer::notify()->AddPopupMessage(RS_POPUP_CHATLOBBY, virtual_peer_id.toStdString(), cli->signature.keyId.toStdString(), cli->message); /* notify private chat message */ return true ; } @@ -181,33 +211,34 @@ bool DistributedChatService::checkSignature(RsChatLobbyBouncingObject *obj,const std::cerr << " signature id: " << obj->signature.keyId << std::endl; #endif - if(!obj->serialise_signed_part(memory,size)) - { - std::cerr << " (EE) Cannot serialise message item. " << std::endl; - return false ; - } + if(!obj->serialise_signed_part(memory,size)) + { + std::cerr << " (EE) Cannot serialise message item. " << std::endl; + return false ; + } - uint32_t error_status ; + uint32_t error_status ; - if(!mGixs->validateData(memory,obj->signed_serial_size(),obj->signature,false,error_status)) - { - bool res = false ; + if(!mGixs->validateData(memory,obj->signed_serial_size(),obj->signature,false,error_status)) + { + bool res = false ; - switch(error_status) - { - case RsGixs::RS_GIXS_ERROR_KEY_NOT_AVAILABLE: + switch(error_status) + { + case RsGixs::RS_GIXS_ERROR_KEY_NOT_AVAILABLE: #ifdef DEBUG_CHAT_LOBBIES - std::cerr << "(WW) Key is not is cache. Cannot verify." << std::endl; + std::cerr << "(WW) Key is not is cache. Cannot verify." << std::endl; #endif - res =true ; - break ; - case RsGixs::RS_GIXS_ERROR_SIGNATURE_MISMATCH: std::cerr << "(EE) Signature mismatch. Spoofing/MITM?." << std::endl; - res =false ; - break ; - default: break ; - } - return res; - } + res =true ; + break ; + case RsGixs::RS_GIXS_ERROR_SIGNATURE_MISMATCH: std::cerr << "(EE) Signature mismatch. Spoofing/MITM?." << std::endl; + res =false ; + break ; + default: break ; + } + return res; + } + #ifdef DEBUG_CHAT_LOBBIES std::cerr << " signature: CHECKS" << std::endl; @@ -249,11 +280,11 @@ void DistributedChatService::locked_printDebugInfo() const { std::cerr << " Lobby id\t\t: " << std::hex << it->first << std::dec << std::endl; std::cerr << " Lobby name\t\t: " << it->second.lobby_name << std::endl; - std::cerr << " Lobby topic\t\t: " << it->second.lobby_topic << std::endl; - std::cerr << " nick name\t\t: " << it->second.gxs_id << std::endl; - std::cerr << " Lobby type\t\t: " << ((IS_PUBLIC_LOBBY(it->second.lobby_flags))?"Public":"Private") << std::endl; - std::cerr << " Lobby policy\t\t: " << ((IS_ANONYMOUS_LOBBY(it->second.lobby_flags))?"Unsigned":"Signature required") << std::endl; - std::cerr << " Lobby peer id\t: " << it->second.virtual_peer_id << std::endl; + std::cerr << " Lobby topic\t\t: " << it->second.lobby_topic << std::endl; + std::cerr << " nick name\t\t: " << it->second.gxs_id << std::endl; + std::cerr << " Lobby type\t\t: " << ((IS_PUBLIC_LOBBY(it->second.lobby_flags))?"Public":"Private") << std::endl; + std::cerr << " Lobby security\t\t: " << ((IS_PGP_SIGNED_LOBBY(it->second.lobby_flags))?"PGP-signed IDs required":"Anon IDs accepted") << std::endl; + std::cerr << " Lobby peer id\t: " << it->second.virtual_peer_id << std::endl; std::cerr << " Challenge count\t: " << it->second.connexion_challenge_count << std::endl; std::cerr << " Last activity\t: " << now - it->second.last_activity << " seconds ago." << std::endl; std::cerr << " Cached messages\t: " << it->second.msg_cache.size() << std::endl; @@ -268,7 +299,7 @@ void DistributedChatService::locked_printDebugInfo() const std::cerr << " Participating nick names: " << std::endl; - for(std::map::const_iterator it2(it->second.gxs_ids.begin());it2!=it->second.gxs_ids.end();++it2) + for(std::map::const_iterator it2(it->second.gxs_ids.begin());it2!=it->second.gxs_ids.end();++it2) std::cerr << " " << it2->first << ": " << now - it2->second << " secs ago" << std::endl; } @@ -446,7 +477,7 @@ void DistributedChatService::handleRecvChatLobbyListRequest(RsChatLobbyListReque info.name = it->second.lobby_name ; info.topic = it->second.lobby_topic ; info.count = it->second.gxs_ids.size() ; - info.flags = it->second.lobby_flags ; + info.flags = ChatLobbyFlags(EXTRACT_PRIVACY_FLAGS(it->second.lobby_flags)) ; item->lobbies.push_back(info) ; } @@ -496,7 +527,7 @@ void DistributedChatService::handleRecvChatLobbyList(RsChatLobbyListItem *item) rec.total_number_of_peers = std::max(rec.total_number_of_peers,item->lobbies[i].count) ; rec.last_report_time = now ; - rec.lobby_flags = item->lobbies[i].flags ; + rec.lobby_flags = EXTRACT_PRIVACY_FLAGS(item->lobbies[i].flags) ; std::map::const_iterator it(_known_lobbies_flags.find(item->lobbies[i].id)) ; @@ -596,19 +627,24 @@ void DistributedChatService::addTimeShiftStatistics(int D) void DistributedChatService::handleRecvChatLobbyEventItem(RsChatLobbyEventItem *item) { + ChatLobbyFlags fl ; + // delete items that are not for us, as early as possible. { RsStackMutex stack(mDistributedChatMtx); /********** STACK LOCKED MTX ******/ // send upward for display - if(_chat_lobbys.find(item->lobby_id) == _chat_lobbys.end()) + std::map::const_iterator it = _chat_lobbys.find(item->lobby_id) ; + + if(it == _chat_lobbys.end()) { #ifdef DEBUG_CHAT_LOBBIES std::cerr << "Chatlobby for id " << std::hex << item->lobby_id << " has no record. Dropping the msg." << std::dec << std::endl; #endif return ; } + fl = it->second.lobby_flags ; } @@ -624,7 +660,18 @@ void DistributedChatService::handleRecvChatLobbyEventItem(RsChatLobbyEventItem * std::cerr << std::endl; return ; } + + if(IS_PGP_SIGNED_LOBBY(fl)) + { + RsIdentityDetails details; + if(!rsIdentity->getIdDetails(item->signature.keyId,details) || !details.mPgpKnown) + { + std::cerr << "(WW) Received a lobby msg/item that is not PGP-authed (ID=" << item->signature.keyId << "), whereas the lobby flags require it. Rejecting!" << std::endl; + + return ; + } + } addTimeShiftStatistics((int)now - (int)item->sendTime) ; if(now+100 > (time_t) item->sendTime + MAX_KEEP_MSG_RECORD) // the message is older than the max cache keep minus 100 seconds ! It's too old, and is going to make an echo! @@ -912,10 +959,8 @@ bool DistributedChatService::locked_initLobbyBouncableObject(const ChatLobbyId& // now sign the object, if the lobby expects it - if(!IS_ANONYMOUS_LOBBY(lobby.lobby_flags)) - { uint32_t size = item.signed_serial_size() ; - unsigned char *memory = (unsigned char *)malloc(size) ; + RsTemporaryMemory memory(size) ; if(!item.serialise_signed_part(memory,size)) { @@ -934,12 +979,9 @@ bool DistributedChatService::locked_initLobbyBouncableObject(const ChatLobbyId& default: std::cerr << "(EE) Cannot sign item: unknown error" << std::endl; break ; } - free(memory) ; return false ; } - - #ifdef DEBUG_CHAT_LOBBIES std::cerr << " signature done." << std::endl; @@ -953,8 +995,6 @@ bool DistributedChatService::locked_initLobbyBouncableObject(const ChatLobbyId& std::cerr << " Item dump:" << std::endl; item.print(std::cerr,2) ; #endif - free(memory) ; - } return true ; } diff --git a/libretroshare/src/grouter/p3grouter.cc b/libretroshare/src/grouter/p3grouter.cc index 77bcdad05..421d2c97c 100644 --- a/libretroshare/src/grouter/p3grouter.cc +++ b/libretroshare/src/grouter/p3grouter.cc @@ -587,7 +587,8 @@ RsGRouterAbstractMsgItem *GRouterDataInfo::addDataChunk(RsGRouterTransactionChun std::cerr << " ERROR: chunk numbering is wrong. Dropping." << std::endl; delete chunk ; delete incoming_data_buffer ; - return NULL; + incoming_data_buffer = NULL ; + return NULL; } incoming_data_buffer->chunk_data = (uint8_t*)realloc((uint8_t*)incoming_data_buffer->chunk_data,incoming_data_buffer->chunk_size + chunk->chunk_size) ; memcpy(&incoming_data_buffer->chunk_data[incoming_data_buffer->chunk_size],chunk->chunk_data,chunk->chunk_size) ; diff --git a/libretroshare/src/gxs/rsdataservice.cc b/libretroshare/src/gxs/rsdataservice.cc index 340ecfbe9..01af6efd3 100644 --- a/libretroshare/src/gxs/rsdataservice.cc +++ b/libretroshare/src/gxs/rsdataservice.cc @@ -24,23 +24,33 @@ * */ +/***** + * #define RS_DATA_SERVICE_DEBUG 1 + * #define RS_DATA_SERVICE_DEBUG_TIME 1 + ****/ #include #include #include +#ifdef RS_DATA_SERVICE_DEBUG_TIME +#include +#endif + #include "rsdataservice.h" +#include "util/rsstring.h" #define MSG_TABLE_NAME std::string("MESSAGES") #define GRP_TABLE_NAME std::string("GROUPS") +#define DATABASE_RELEASE_TABLE_NAME std::string("DATABASE_RELEASE") #define GRP_LAST_POST_UPDATE_TRIGGER std::string("LAST_POST_UPDATE") +#define MSG_INDEX_GRPID std::string("INDEX_MESSAGES_GRPID") // generic -#define KEY_NXS_FILE std::string("nxsFile") -#define KEY_NXS_FILE_OFFSET std::string("fileOffset") -#define KEY_NXS_FILE_LEN std::string("nxsFileLen") +#define KEY_NXS_DATA std::string("nxsData") +#define KEY_NXS_DATA_LEN std::string("nxsDataLen") #define KEY_NXS_IDENTITY std::string("identity") #define KEY_GRP_ID std::string("grpId") #define KEY_ORIG_GRP_ID std::string("origGrpId") @@ -53,6 +63,10 @@ #define KEY_NXS_HASH std::string("hash") #define KEY_RECV_TS std::string("recv_time_stamp") +// remove later +#define KEY_NXS_FILE_OLD std::string("nxsFile") +#define KEY_NXS_FILE_OFFSET_OLD std::string("fileOffset") +#define KEY_NXS_FILE_LEN_OLD std::string("nxsFileLen") // grp table columns #define KEY_KEY_SET std::string("keySet") @@ -72,7 +86,6 @@ #define KEY_GRP_LAST_POST std::string("lastPost") #define KEY_GRP_REP_CUTOFF std::string("rep_cutoff") - // msg table columns #define KEY_MSG_ID std::string("msgId") #define KEY_ORIG_MSG_ID std::string("origMsgId") @@ -84,65 +97,10 @@ #define KEY_MSG_STATUS std::string("msgStatus") #define KEY_CHILD_TS std::string("childTs") - - - -/*** actual data col numbers ***/ - -// generic -#define COL_ACT_GROUP_ID 0 -#define COL_NXS_FILE 1 -#define COL_NXS_FILE_OFFSET 2 -#define COL_NXS_FILE_LEN 3 -#define COL_META_DATA 4 -#define COL_ACT_MSG_ID 5 - -/*** meta column numbers ***/ - -// grp col numbers - -#define COL_KEY_SET 6 -#define COL_GRP_SUBCR_FLAG 7 -#define COL_GRP_POP 8 -#define COL_MSG_COUNT 9 -#define COL_GRP_STATUS 10 -#define COL_GRP_NAME 11 -#define COL_GRP_LAST_POST 12 -#define COL_ORIG_GRP_ID 13 -#define COL_GRP_SERV_STRING 14 -#define COL_GRP_SIGN_FLAGS 15 -#define COL_GRP_CIRCLE_ID 16 -#define COL_GRP_CIRCL_TYPE 17 -#define COL_GRP_INTERN_CIRCLE 18 -#define COL_GRP_ORIGINATOR 19 -#define COL_GRP_AUTHEN_FLAGS 20 -#define COL_PARENT_GRP_ID 21 -#define COL_GRP_RECV_TS 22 -#define COL_GRP_REP_CUTOFF 23 - - -// msg col numbers -#define COL_MSG_ID 6 -#define COL_ORIG_MSG_ID 7 -#define COL_MSG_STATUS 8 -#define COL_CHILD_TS 9 -#define COL_PARENT_ID 10 -#define COL_THREAD_ID 11 -#define COL_MSG_NAME 12 -#define COL_MSG_SERV_STRING 13 -#define COL_MSG_RECV_TS 14 - -// generic meta shared col numbers -#define COL_GRP_ID 0 -#define COL_TIME_STAMP 1 -#define COL_NXS_FLAGS 2 -#define COL_SIGN_SET 3 -#define COL_IDENTITY 4 -#define COL_HASH 5 - -/***** - * #define RS_DATA_SERVICE_DEBUG 1 - ****/ +// database release columns +#define KEY_DATABASE_RELEASE_ID std::string("id") +#define KEY_DATABASE_RELEASE_ID_VALUE 1 +#define KEY_DATABASE_RELEASE std::string("release") const std::string RsGeneralDataService::GRP_META_SERV_STRING = KEY_NXS_SERV_STRING; const std::string RsGeneralDataService::GRP_META_STATUS = KEY_GRP_STATUS; @@ -154,47 +112,83 @@ const std::string RsGeneralDataService::MSG_META_STATUS = KEY_MSG_STATUS; const uint32_t RsGeneralDataService::GXS_MAX_ITEM_SIZE = 1572864; // 1.5 Mbytes +static int addColumn(std::list &list, const std::string &attribute) +{ + list.push_back(attribute); + return list.size() - 1; +} + RsDataService::RsDataService(const std::string &serviceDir, const std::string &dbName, uint16_t serviceType, RsGxsSearchModule * /* mod */, const std::string& key) - : RsGeneralDataService(), mDbMutex("RsDataService"), mServiceDir(serviceDir), mDbName(mServiceDir + "/" + dbName), mServType(serviceType), - mDb( new RetroDb(mDbName, RetroDb::OPEN_READWRITE_CREATE, key)) { + : RsGeneralDataService(), mDbMutex("RsDataService"), mServiceDir(serviceDir), mDbName(dbName), mDbPath(mServiceDir + "/" + dbName), mServType(serviceType), mDb(NULL) +{ + bool isNewDatabase = !RsDirUtil::fileExists(mDbPath); - initialise(); + mDb = new RetroDb(mDbPath, RetroDb::OPEN_READWRITE_CREATE, key); + + initialise(isNewDatabase); // for retrieving msg meta - msgMetaColumns.push_back(KEY_GRP_ID); msgMetaColumns.push_back(KEY_TIME_STAMP); msgMetaColumns.push_back(KEY_NXS_FLAGS); - msgMetaColumns.push_back(KEY_SIGN_SET); msgMetaColumns.push_back(KEY_NXS_IDENTITY); msgMetaColumns.push_back(KEY_NXS_HASH); - msgMetaColumns.push_back(KEY_MSG_ID); msgMetaColumns.push_back(KEY_ORIG_MSG_ID); msgMetaColumns.push_back(KEY_MSG_STATUS); - msgMetaColumns.push_back(KEY_CHILD_TS); msgMetaColumns.push_back(KEY_MSG_PARENT_ID); msgMetaColumns.push_back(KEY_MSG_THREAD_ID); - msgMetaColumns.push_back(KEY_MSG_NAME); msgMetaColumns.push_back(KEY_NXS_SERV_STRING); msgMetaColumns.push_back(KEY_RECV_TS); + mColMsgMeta_GrpId = addColumn(mMsgMetaColumns, KEY_GRP_ID); + mColMsgMeta_TimeStamp = addColumn(mMsgMetaColumns, KEY_TIME_STAMP); + mColMsgMeta_NxsFlags = addColumn(mMsgMetaColumns, KEY_NXS_FLAGS); + mColMsgMeta_SignSet = addColumn(mMsgMetaColumns, KEY_SIGN_SET); + mColMsgMeta_NxsIdentity = addColumn(mMsgMetaColumns, KEY_NXS_IDENTITY); + mColMsgMeta_NxsHash = addColumn(mMsgMetaColumns, KEY_NXS_HASH); + mColMsgMeta_MsgId = addColumn(mMsgMetaColumns, KEY_MSG_ID); + mColMsgMeta_OrigMsgId = addColumn(mMsgMetaColumns, KEY_ORIG_MSG_ID); + mColMsgMeta_MsgStatus = addColumn(mMsgMetaColumns, KEY_MSG_STATUS); + mColMsgMeta_ChildTs = addColumn(mMsgMetaColumns, KEY_CHILD_TS); + mColMsgMeta_MsgParentId = addColumn(mMsgMetaColumns, KEY_MSG_PARENT_ID); + mColMsgMeta_MsgThreadId = addColumn(mMsgMetaColumns, KEY_MSG_THREAD_ID); + mColMsgMeta_Name = addColumn(mMsgMetaColumns, KEY_MSG_NAME); + mColMsgMeta_NxsServString = addColumn(mMsgMetaColumns, KEY_NXS_SERV_STRING); + mColMsgMeta_RecvTs = addColumn(mMsgMetaColumns, KEY_RECV_TS); + mColMsgMeta_NxsDataLen = addColumn(mMsgMetaColumns, KEY_NXS_DATA_LEN); // for retrieving actual data - msgColumns.push_back(KEY_GRP_ID); msgColumns.push_back(KEY_NXS_FILE); msgColumns.push_back(KEY_NXS_FILE_OFFSET); - msgColumns.push_back(KEY_NXS_FILE_LEN); msgColumns.push_back(KEY_NXS_META); msgColumns.push_back(KEY_MSG_ID); + mColMsg_GrpId = addColumn(mMsgColumns, KEY_GRP_ID); + mColMsg_NxsData = addColumn(mMsgColumns, KEY_NXS_DATA); + mColMsg_MetaData = addColumn(mMsgColumns, KEY_NXS_META); + mColMsg_MsgId = addColumn(mMsgColumns, KEY_MSG_ID); // for retrieving grp meta data - grpMetaColumns.push_back(KEY_GRP_ID); grpMetaColumns.push_back(KEY_TIME_STAMP); grpMetaColumns.push_back(KEY_NXS_FLAGS); - grpMetaColumns.push_back(KEY_SIGN_SET); grpMetaColumns.push_back(KEY_NXS_IDENTITY); grpMetaColumns.push_back(KEY_NXS_HASH); - grpMetaColumns.push_back(KEY_KEY_SET); grpMetaColumns.push_back(KEY_GRP_SUBCR_FLAG); grpMetaColumns.push_back(KEY_GRP_POP); - grpMetaColumns.push_back(KEY_MSG_COUNT); grpMetaColumns.push_back(KEY_GRP_STATUS); grpMetaColumns.push_back(KEY_GRP_NAME); - grpMetaColumns.push_back(KEY_GRP_LAST_POST); grpMetaColumns.push_back(KEY_ORIG_GRP_ID); grpMetaColumns.push_back(KEY_NXS_SERV_STRING); - grpMetaColumns.push_back(KEY_GRP_SIGN_FLAGS); grpMetaColumns.push_back(KEY_GRP_CIRCLE_ID); grpMetaColumns.push_back(KEY_GRP_CIRCLE_TYPE); - grpMetaColumns.push_back(KEY_GRP_INTERNAL_CIRCLE); grpMetaColumns.push_back(KEY_GRP_ORIGINATOR); - grpMetaColumns.push_back(KEY_GRP_AUTHEN_FLAGS); grpMetaColumns.push_back(KEY_PARENT_GRP_ID); grpMetaColumns.push_back(KEY_RECV_TS); - grpMetaColumns.push_back(KEY_GRP_REP_CUTOFF); - + mColGrpMeta_GrpId = addColumn(mGrpMetaColumns, KEY_GRP_ID); + mColGrpMeta_TimeStamp = addColumn(mGrpMetaColumns, KEY_TIME_STAMP); + mColGrpMeta_NxsFlags = addColumn(mGrpMetaColumns, KEY_NXS_FLAGS); +// mColGrpMeta_SignSet = addColumn(mGrpMetaColumns, KEY_SIGN_SET); + mColGrpMeta_NxsIdentity = addColumn(mGrpMetaColumns, KEY_NXS_IDENTITY); + mColGrpMeta_NxsHash = addColumn(mGrpMetaColumns, KEY_NXS_HASH); + mColGrpMeta_KeySet = addColumn(mGrpMetaColumns, KEY_KEY_SET); + mColGrpMeta_SubscrFlag = addColumn(mGrpMetaColumns, KEY_GRP_SUBCR_FLAG); + mColGrpMeta_Pop = addColumn(mGrpMetaColumns, KEY_GRP_POP); + mColGrpMeta_MsgCount = addColumn(mGrpMetaColumns, KEY_MSG_COUNT); + mColGrpMeta_Status = addColumn(mGrpMetaColumns, KEY_GRP_STATUS); + mColGrpMeta_Name = addColumn(mGrpMetaColumns, KEY_GRP_NAME); + mColGrpMeta_LastPost = addColumn(mGrpMetaColumns, KEY_GRP_LAST_POST); + mColGrpMeta_OrigGrpId = addColumn(mGrpMetaColumns, KEY_ORIG_GRP_ID); + mColGrpMeta_ServString = addColumn(mGrpMetaColumns, KEY_NXS_SERV_STRING); + mColGrpMeta_SignFlags = addColumn(mGrpMetaColumns, KEY_GRP_SIGN_FLAGS); + mColGrpMeta_CircleId = addColumn(mGrpMetaColumns, KEY_GRP_CIRCLE_ID); + mColGrpMeta_CircleType = addColumn(mGrpMetaColumns, KEY_GRP_CIRCLE_TYPE); + mColGrpMeta_InternCircle = addColumn(mGrpMetaColumns, KEY_GRP_INTERNAL_CIRCLE); + mColGrpMeta_Originator = addColumn(mGrpMetaColumns, KEY_GRP_ORIGINATOR); + mColGrpMeta_AuthenFlags = addColumn(mGrpMetaColumns, KEY_GRP_AUTHEN_FLAGS); + mColGrpMeta_ParentGrpId = addColumn(mGrpMetaColumns, KEY_PARENT_GRP_ID); + mColGrpMeta_RecvTs = addColumn(mGrpMetaColumns, KEY_RECV_TS); + mColGrpMeta_RepCutoff = addColumn(mGrpMetaColumns, KEY_GRP_REP_CUTOFF); + mColGrpMeta_NxsDataLen = addColumn(mGrpMetaColumns, KEY_NXS_DATA_LEN); // for retrieving actual grp data - grpColumns.push_back(KEY_GRP_ID); grpColumns.push_back(KEY_NXS_FILE); grpColumns.push_back(KEY_NXS_FILE_OFFSET); - grpColumns.push_back(KEY_NXS_FILE_LEN); grpColumns.push_back(KEY_NXS_META); + mColGrp_GrpId = addColumn(mGrpColumns, KEY_GRP_ID); + mColGrp_NxsData = addColumn(mGrpColumns, KEY_NXS_DATA); + mColGrp_MetaData = addColumn(mGrpColumns, KEY_NXS_META); - // for retrieving msg offsets - mMsgOffSetColumns.push_back(KEY_MSG_ID); mMsgOffSetColumns.push_back(KEY_NXS_FILE_OFFSET); - mMsgOffSetColumns.push_back(KEY_NXS_FILE_LEN); + // Group id columns + mColGrpId_GrpId = addColumn(mGrpIdColumn, KEY_GRP_ID); - grpIdColumn.push_back(KEY_GRP_ID); - - mMsgIdColumn.push_back(KEY_MSG_ID); + // Msg id columns + mColMsgId_MsgId = addColumn(mMsgIdColumn, KEY_MSG_ID); } RsDataService::~RsDataService(){ @@ -208,72 +202,276 @@ RsDataService::~RsDataService(){ delete mDb; } -void RsDataService::initialise(){ +static bool moveDataFromFileToDatabase(RetroDb *db, const std::string serviceDir, const std::string &tableName, const std::string &keyId, std::list &files) +{ + bool ok = true; + + // Move message data + std::list columns; + columns.push_back(keyId); + columns.push_back(KEY_NXS_FILE_OLD); + columns.push_back(KEY_NXS_FILE_OFFSET_OLD); + columns.push_back(KEY_NXS_FILE_LEN_OLD); + + RetroCursor* c = db->sqlQuery(tableName, columns, "", ""); + + if (c) + { + bool valid = c->moveToFirst(); + + while (ok && valid){ + std::string dataFile; + c->getString(1, dataFile); + + if (!dataFile.empty()) { + bool fileOk = true; + + // first try to find the file in the service dir + if (RsDirUtil::fileExists(serviceDir + "/" + dataFile)) { + dataFile.insert(0, serviceDir + "/"); + } else if (RsDirUtil::fileExists(dataFile)) { + // use old way for backward compatibility + //TODO: can be removed later + } else { + fileOk = false; + + std::cerr << "moveDataFromFileToDatabase() cannot find file " << dataFile; + std::cerr << std::endl; + } + + if (fileOk) { + std::string id; + c->getString(0, id); + + uint32_t offset = c->getInt32(2); + uint32_t data_len = c->getInt32(3); + + char* data = new char[data_len]; + std::ifstream istrm(dataFile.c_str(), std::ios::binary); + istrm.seekg(offset, std::ios::beg); + istrm.read(data, data_len); + istrm.close(); + + ContentValue cv; + // insert new columns + cv.put(KEY_NXS_DATA, data_len, data); + cv.put(KEY_NXS_DATA_LEN, (int32_t) data_len); + // clear old columns + cv.put(KEY_NXS_FILE_OLD, ""); + cv.put(KEY_NXS_FILE_OFFSET_OLD, 0); + cv.put(KEY_NXS_FILE_LEN_OLD, 0); + + ok = db->sqlUpdate(tableName, keyId + "='" + id + "'", cv); + delete[] data; + + if (std::find(files.begin(), files.end(), dataFile) == files.end()) { + files.push_back(dataFile); + } + } + } + + valid = c->moveToNext(); + } + + delete c; + } + + return ok; +} + +void RsDataService::initialise(bool isNewDatabase) +{ + const int databaseRelease = 1; + int currentDatabaseRelease = 0; + bool ok = true; RsStackMutex stack(mDbMutex); // initialise database + if (isNewDatabase || !mDb->tableExists(DATABASE_RELEASE_TABLE_NAME)) { + // create table for database release + mDb->execSQL("CREATE TABLE " + DATABASE_RELEASE_TABLE_NAME + "(" + + KEY_DATABASE_RELEASE_ID + " INT PRIMARY KEY," + + KEY_DATABASE_RELEASE + " INT);"); + } - // create table for msg data - mDb->execSQL("CREATE TABLE " + MSG_TABLE_NAME + "(" + - KEY_MSG_ID + " TEXT PRIMARY KEY," + - KEY_GRP_ID + " TEXT," + - KEY_NXS_FLAGS + " INT," + - KEY_ORIG_MSG_ID + " TEXT," + - KEY_TIME_STAMP + " INT," + - KEY_NXS_IDENTITY + " TEXT," + - KEY_SIGN_SET + " BLOB," + - KEY_NXS_FILE + " TEXT,"+ - KEY_NXS_FILE_OFFSET + " INT," + - KEY_MSG_STATUS + " INT," + - KEY_CHILD_TS + " INT," + - KEY_NXS_META + " BLOB," + - KEY_MSG_THREAD_ID + " TEXT," + - KEY_MSG_PARENT_ID + " TEXT,"+ - KEY_MSG_NAME + " TEXT," + - KEY_NXS_SERV_STRING + " TEXT," + - KEY_NXS_HASH + " TEXT," + - KEY_RECV_TS + " INT," + - KEY_NXS_FILE_LEN + " INT);"); + if (isNewDatabase) { + // create table for msg data + mDb->execSQL("CREATE TABLE " + MSG_TABLE_NAME + "(" + + KEY_MSG_ID + " TEXT PRIMARY KEY," + + KEY_GRP_ID + " TEXT," + + KEY_NXS_FLAGS + " INT," + + KEY_ORIG_MSG_ID + " TEXT," + + KEY_TIME_STAMP + " INT," + + KEY_NXS_IDENTITY + " TEXT," + + KEY_SIGN_SET + " BLOB," + + KEY_NXS_DATA + " BLOB,"+ + KEY_NXS_DATA_LEN + " INT," + + KEY_MSG_STATUS + " INT," + + KEY_CHILD_TS + " INT," + + KEY_NXS_META + " BLOB," + + KEY_MSG_THREAD_ID + " TEXT," + + KEY_MSG_PARENT_ID + " TEXT,"+ + KEY_MSG_NAME + " TEXT," + + KEY_NXS_SERV_STRING + " TEXT," + + KEY_NXS_HASH + " TEXT," + + KEY_RECV_TS + " INT);"); - // create table for grp data - mDb->execSQL("CREATE TABLE " + GRP_TABLE_NAME + "(" + - KEY_GRP_ID + " TEXT PRIMARY KEY," + - KEY_TIME_STAMP + " INT," + - KEY_NXS_FILE + " TEXT," + - KEY_NXS_FILE_OFFSET + " INT," + - KEY_KEY_SET + " BLOB," + - KEY_NXS_FILE_LEN + " INT," + - KEY_NXS_META + " BLOB," + - KEY_GRP_NAME + " TEXT," + - KEY_GRP_LAST_POST + " INT," + - KEY_GRP_POP + " INT," + - KEY_MSG_COUNT + " INT," + - KEY_GRP_SUBCR_FLAG + " INT," + - KEY_GRP_STATUS + " INT," + - KEY_NXS_IDENTITY + " TEXT," + - KEY_ORIG_GRP_ID + " TEXT," + - KEY_NXS_SERV_STRING + " TEXT," + - KEY_NXS_FLAGS + " INT," + - KEY_GRP_AUTHEN_FLAGS + " INT," + - KEY_GRP_SIGN_FLAGS + " INT," + - KEY_GRP_CIRCLE_ID + " TEXT," + - KEY_GRP_CIRCLE_TYPE + " INT," + - KEY_GRP_INTERNAL_CIRCLE + " TEXT," + - KEY_GRP_ORIGINATOR + " TEXT," + - KEY_NXS_HASH + " TEXT," + - KEY_RECV_TS + " INT," + - KEY_PARENT_GRP_ID + " TEXT," + - KEY_GRP_REP_CUTOFF + " INT," + - KEY_SIGN_SET + " BLOB);"); + // create table for grp data + mDb->execSQL("CREATE TABLE " + GRP_TABLE_NAME + "(" + + KEY_GRP_ID + " TEXT PRIMARY KEY," + + KEY_TIME_STAMP + " INT," + + KEY_NXS_DATA + " BLOB," + + KEY_NXS_DATA_LEN + " INT," + + KEY_KEY_SET + " BLOB," + + KEY_NXS_META + " BLOB," + + KEY_GRP_NAME + " TEXT," + + KEY_GRP_LAST_POST + " INT," + + KEY_GRP_POP + " INT," + + KEY_MSG_COUNT + " INT," + + KEY_GRP_SUBCR_FLAG + " INT," + + KEY_GRP_STATUS + " INT," + + KEY_NXS_IDENTITY + " TEXT," + + KEY_ORIG_GRP_ID + " TEXT," + + KEY_NXS_SERV_STRING + " TEXT," + + KEY_NXS_FLAGS + " INT," + + KEY_GRP_AUTHEN_FLAGS + " INT," + + KEY_GRP_SIGN_FLAGS + " INT," + + KEY_GRP_CIRCLE_ID + " TEXT," + + KEY_GRP_CIRCLE_TYPE + " INT," + + KEY_GRP_INTERNAL_CIRCLE + " TEXT," + + KEY_GRP_ORIGINATOR + " TEXT," + + KEY_NXS_HASH + " TEXT," + + KEY_RECV_TS + " INT," + + KEY_PARENT_GRP_ID + " TEXT," + + KEY_GRP_REP_CUTOFF + " INT," + + KEY_SIGN_SET + " BLOB);"); - mDb->execSQL("CREATE TRIGGER " + GRP_LAST_POST_UPDATE_TRIGGER + - " INSERT ON " + MSG_TABLE_NAME + - std::string(" BEGIN ") + - " UPDATE " + GRP_TABLE_NAME + " SET " + KEY_GRP_LAST_POST + "= new." - + KEY_RECV_TS + " WHERE " + KEY_GRP_ID + "=new." + KEY_GRP_ID + ";" - + std::string("END;")); + mDb->execSQL("CREATE TRIGGER " + GRP_LAST_POST_UPDATE_TRIGGER + + " INSERT ON " + MSG_TABLE_NAME + + std::string(" BEGIN ") + + " UPDATE " + GRP_TABLE_NAME + " SET " + KEY_GRP_LAST_POST + "= new." + + KEY_RECV_TS + " WHERE " + KEY_GRP_ID + "=new." + KEY_GRP_ID + ";" + + std::string("END;")); + + mDb->execSQL("CREATE INDEX " + MSG_INDEX_GRPID + " ON " + MSG_TABLE_NAME + "(" + KEY_GRP_ID + ");"); + + // Insert release, no need to upgrade + ContentValue cv; + cv.put(KEY_DATABASE_RELEASE_ID, KEY_DATABASE_RELEASE_ID_VALUE); + cv.put(KEY_DATABASE_RELEASE, databaseRelease); + mDb->sqlInsert(DATABASE_RELEASE_TABLE_NAME, "", cv); + + currentDatabaseRelease = databaseRelease; + } else { + // check release + + { + // try to select the release + std::list columns; + columns.push_back(KEY_DATABASE_RELEASE); + + std::string where; + rs_sprintf(where, "%s=%d", KEY_DATABASE_RELEASE_ID.c_str(), KEY_DATABASE_RELEASE_ID_VALUE); + + RetroCursor* c = mDb->sqlQuery(DATABASE_RELEASE_TABLE_NAME, columns, where, ""); + if (c) { + ok = c->moveToFirst(); + + if (ok) { + currentDatabaseRelease = c->getInt32(0); + } + delete c; + + if (!ok) { + // No record found ... insert the record + ContentValue cv; + cv.put(KEY_DATABASE_RELEASE_ID, KEY_DATABASE_RELEASE_ID_VALUE); + cv.put(KEY_DATABASE_RELEASE, currentDatabaseRelease); + ok = mDb->sqlInsert(DATABASE_RELEASE_TABLE_NAME, "", cv); + } + } else { + ok = false; + } + } + + // Release 1 + int newRelease = 1; + if (ok && currentDatabaseRelease < newRelease) { + // Update database + std::list files; + + ok = startReleaseUpdate(newRelease); + + // Move data in files into database + ok = ok && mDb->execSQL("ALTER TABLE " + GRP_TABLE_NAME + " ADD COLUMN " + KEY_NXS_DATA + " BLOB;"); + ok = ok && mDb->execSQL("ALTER TABLE " + GRP_TABLE_NAME + " ADD COLUMN " + KEY_NXS_DATA_LEN + " INT;"); + ok = ok && mDb->execSQL("ALTER TABLE " + MSG_TABLE_NAME + " ADD COLUMN " + KEY_NXS_DATA + " BLOB;"); + ok = ok && mDb->execSQL("ALTER TABLE " + MSG_TABLE_NAME + " ADD COLUMN " + KEY_NXS_DATA_LEN + " INT;"); + + ok = ok && moveDataFromFileToDatabase(mDb, mServiceDir, GRP_TABLE_NAME, KEY_GRP_ID, files); + ok = ok && moveDataFromFileToDatabase(mDb, mServiceDir, MSG_TABLE_NAME, KEY_MSG_ID, files); + +// SQLite doesn't support DROP COLUMN +// ok = ok && mDb->execSQL("ALTER TABLE " + GRP_TABLE_NAME + " DROP COLUMN " + KEY_NXS_FILE_OLD + ";"); +// ok = ok && mDb->execSQL("ALTER TABLE " + GRP_TABLE_NAME + " DROP COLUMN " + KEY_NXS_FILE_OFFSET_OLD + ";"); +// ok = ok && mDb->execSQL("ALTER TABLE " + GRP_TABLE_NAME + " DROP COLUMN " + KEY_NXS_FILE_LEN_OLD + ";"); +// ok = ok && mDb->execSQL("ALTER TABLE " + MSG_TABLE_NAME + " DROP COLUMN " + KEY_NXS_FILE_OLD + ";"); +// ok = ok && mDb->execSQL("ALTER TABLE " + MSG_TABLE_NAME + " DROP COLUMN " + KEY_NXS_FILE_OFFSET_OLD + ";"); +// ok = ok && mDb->execSQL("ALTER TABLE " + MSG_TABLE_NAME + " DROP COLUMN " + KEY_NXS_FILE_LEN_OLD + ";"); + + ok = finishReleaseUpdate(newRelease, ok); + if (ok) { + // Remove transfered files + std::list::const_iterator file; + for (file = files.begin(); file != files.end(); ++file) { + remove(file->c_str()); + } + currentDatabaseRelease = newRelease; + } + } + } + + if (ok) { + std::cerr << "Database " << mDbName << " release " << currentDatabaseRelease << " successfully initialised." << std::endl; + } else { + std::cerr << "Database " << mDbName << " initialisation failed." << std::endl; + } +} + +bool RsDataService::startReleaseUpdate(int release) +{ + // Update database + std::cerr << "Database " << mDbName << " update to release " << release << "." << std::endl; + + return mDb->beginTransaction(); +} + +bool RsDataService::finishReleaseUpdate(int release, bool result) +{ + if (result) { + std::string where; + rs_sprintf(where, "%s=%d", KEY_DATABASE_RELEASE_ID.c_str(), KEY_DATABASE_RELEASE_ID_VALUE); + + ContentValue cv; + cv.put(KEY_DATABASE_RELEASE, release); + result = mDb->sqlUpdate(DATABASE_RELEASE_TABLE_NAME, where, cv); + } + + if (result) { + result = mDb->commitTransaction(); + } else { + result = mDb->rollbackTransaction(); + } + + if (result) { + std::cerr << "Database " << mDbName << " successfully updated to release " << release << "." << std::endl; + } else { + std::cerr << "Database " << mDbName << " update to release " << release << "failed." << std::endl; + } + + return result; } RsGxsGrpMetaData* RsDataService::locked_getGrpMeta(RetroCursor &c) @@ -294,30 +492,27 @@ RsGxsGrpMetaData* RsDataService::locked_getGrpMeta(RetroCursor &c) // grpId std::string tempId; - c.getString(COL_GRP_ID, tempId); + c.getString(mColGrpMeta_GrpId, tempId); grpMeta->mGroupId = RsGxsGroupId(tempId); - c.getString(COL_IDENTITY, tempId); + c.getString(mColGrpMeta_NxsIdentity, tempId); grpMeta->mAuthorId = RsGxsId(tempId); - c.getString(COL_GRP_NAME, grpMeta->mGroupName); - c.getString(COL_ORIG_GRP_ID, tempId); + c.getString(mColGrpMeta_Name, grpMeta->mGroupName); + c.getString(mColGrpMeta_OrigGrpId, tempId); grpMeta->mOrigGrpId = RsGxsGroupId(tempId); - c.getString(COL_GRP_SERV_STRING, grpMeta->mServiceString); + c.getString(mColGrpMeta_ServString, grpMeta->mServiceString); std::string temp; - c.getString(COL_HASH, temp); + c.getString(mColGrpMeta_NxsHash, temp); grpMeta->mHash = RsFileHash(temp); - grpMeta->mReputationCutOff = c.getInt32(COL_GRP_REP_CUTOFF); - grpMeta->mSignFlags = c.getInt32(COL_GRP_SIGN_FLAGS); - - grpMeta->mPublishTs = c.getInt32(COL_TIME_STAMP); - grpMeta->mGroupFlags = c.getInt32(COL_NXS_FLAGS); - grpMeta->mGrpSize = c.getInt32(COL_NXS_FILE_LEN); - - offset = 0; + grpMeta->mReputationCutOff = c.getInt32(mColGrpMeta_RepCutoff); + grpMeta->mSignFlags = c.getInt32(mColGrpMeta_SignFlags); + grpMeta->mPublishTs = c.getInt32(mColGrpMeta_TimeStamp); + grpMeta->mGroupFlags = c.getInt32(mColGrpMeta_NxsFlags); + grpMeta->mGrpSize = c.getInt32(mColGrpMeta_NxsDataLen); offset = 0; data = NULL; data_len = 0; - data = (char*)c.getData(COL_KEY_SET, data_len); + data = (char*)c.getData(mColGrpMeta_KeySet, data_len); if(data) ok &= grpMeta->keys.GetTlv(data, data_len, &offset); @@ -325,25 +520,25 @@ RsGxsGrpMetaData* RsDataService::locked_getGrpMeta(RetroCursor &c) grpMeta->keys.TlvClear() ; // local meta - grpMeta->mSubscribeFlags = c.getInt32(COL_GRP_SUBCR_FLAG); - grpMeta->mPop = c.getInt32(COL_GRP_POP); - grpMeta->mVisibleMsgCount = c.getInt32(COL_MSG_COUNT); - grpMeta->mLastPost = c.getInt32(COL_GRP_LAST_POST); - grpMeta->mGroupStatus = c.getInt32(COL_GRP_STATUS); + grpMeta->mSubscribeFlags = c.getInt32(mColGrpMeta_SubscrFlag); + grpMeta->mPop = c.getInt32(mColGrpMeta_Pop); + grpMeta->mVisibleMsgCount = c.getInt32(mColGrpMeta_MsgCount); + grpMeta->mLastPost = c.getInt32(mColGrpMeta_LastPost); + grpMeta->mGroupStatus = c.getInt32(mColGrpMeta_Status); - c.getString(COL_GRP_CIRCLE_ID, tempId); + c.getString(mColGrpMeta_CircleId, tempId); grpMeta->mCircleId = RsGxsCircleId(tempId); - grpMeta->mCircleType = c.getInt32(COL_GRP_CIRCL_TYPE); - c.getString(COL_GRP_INTERN_CIRCLE, tempId); + grpMeta->mCircleType = c.getInt32(mColGrpMeta_CircleType); + c.getString(mColGrpMeta_InternCircle, tempId); grpMeta->mInternalCircle = RsGxsCircleId(tempId); - std::string s ; c.getString(COL_GRP_ORIGINATOR, s) ; + std::string s ; c.getString(mColGrpMeta_Originator, s) ; grpMeta->mOriginator = RsPeerId(s); - grpMeta->mAuthenFlags = c.getInt32(COL_GRP_AUTHEN_FLAGS); - grpMeta->mRecvTS = c.getInt32(COL_GRP_RECV_TS); + grpMeta->mAuthenFlags = c.getInt32(mColGrpMeta_AuthenFlags); + grpMeta->mRecvTS = c.getInt32(mColGrpMeta_RecvTs); - c.getString(COL_PARENT_GRP_ID, tempId); + c.getString(mColGrpMeta_ParentGrpId, tempId); grpMeta->mParentGrpId = RsGxsGroupId(tempId); if(ok) @@ -369,52 +564,23 @@ RsNxsGrp* RsDataService::locked_getGroup(RetroCursor &c) uint32_t data_len = 0; // grpId - c.getStringT(COL_ACT_GROUP_ID, grp->grpId); + c.getStringT(mColGrp_GrpId, grp->grpId); ok &= !grp->grpId.isNull(); offset = 0; data_len = 0; if(ok){ - data = (char*)c.getData(COL_META_DATA, data_len); + data = (char*)c.getData(mColGrp_MetaData, data_len); if(data) grp->meta.GetTlv(data, data_len, &offset); } - /* now retrieve grp data from file */ - std::string grpFile; - c.getString(COL_NXS_FILE, grpFile); - ok &= !grpFile.empty(); - + /* now retrieve grp data */ + offset = 0; data_len = 0; if(ok){ - - data_len = c.getInt32(COL_NXS_FILE_LEN); - offset = c.getInt32(COL_NXS_FILE_OFFSET); - - // first try to find the file in the service dir - if (RsDirUtil::fileExists(mServiceDir + "/" + grpFile)) { - grpFile.insert(0, mServiceDir + "/"); - } else if (RsDirUtil::fileExists(grpFile)) { - // use old way for backward compatibility - //TODO: can be removed later - } else { - ok = false; - -//#ifdef RS_DATA_SERVICE_DEBUG - std::cerr << "RsDataService::locked_getGroup() cannot find group file " << grpFile; - std::cerr << std::endl; -//#endif - } - - if (ok) { - char grp_data[data_len]; - std::ifstream istrm(grpFile.c_str(), std::ios::binary); - istrm.seekg(offset, std::ios::beg); - istrm.read(grp_data, data_len); - - istrm.close(); - offset = 0; - ok &= grp->grp.GetTlv(grp_data, data_len, &offset); - } + data = (char*)c.getData(mColGrp_NxsData, data_len); + if(data) + ok &= grp->grp.GetTlv(data, data_len, &offset); } if(ok) @@ -435,46 +601,45 @@ RsGxsMsgMetaData* RsDataService::locked_getMsgMeta(RetroCursor &c) offset = 0; char* data = NULL; - std::string gId; - c.getString(COL_GRP_ID, gId); + c.getString(mColMsgMeta_GrpId, gId); msgMeta->mGroupId = RsGxsGroupId(gId); std::string temp; - c.getString(COL_MSG_ID, temp); + c.getString(mColMsgMeta_MsgId, temp); msgMeta->mMsgId = RsGxsMessageId(temp); // without these, a msg is meaningless ok &= (!msgMeta->mGroupId.isNull()) && (!msgMeta->mMsgId.isNull()); - c.getString(COL_ORIG_MSG_ID, temp); + c.getString(mColMsgMeta_OrigMsgId, temp); msgMeta->mOrigMsgId = RsGxsMessageId(temp); - c.getString(COL_IDENTITY, temp); + c.getString(mColMsgMeta_NxsIdentity, temp); msgMeta->mAuthorId = RsGxsId(temp); - c.getString(COL_MSG_NAME, msgMeta->mMsgName); - c.getString(COL_MSG_SERV_STRING, msgMeta->mServiceString); + c.getString(mColMsgMeta_Name, msgMeta->mMsgName); + c.getString(mColMsgMeta_NxsServString, msgMeta->mServiceString); - c.getString(COL_HASH, temp); + c.getString(mColMsgMeta_NxsHash, temp); msgMeta->mHash = RsFileHash(temp); - msgMeta->recvTS = c.getInt32(COL_MSG_RECV_TS); + msgMeta->recvTS = c.getInt32(mColMsgMeta_RecvTs); offset = 0; - data = (char*)c.getData(COL_SIGN_SET, data_len); + data = (char*)c.getData(mColMsgMeta_SignSet, data_len); msgMeta->signSet.GetTlv(data, data_len, &offset); - msgMeta->mMsgSize = c.getInt32(COL_NXS_FILE_LEN); + msgMeta->mMsgSize = c.getInt32(mColMsgMeta_NxsDataLen); - msgMeta->mMsgFlags = c.getInt32(COL_NXS_FLAGS); - msgMeta->mPublishTs = c.getInt32(COL_TIME_STAMP); + msgMeta->mMsgFlags = c.getInt32(mColMsgMeta_NxsFlags); + msgMeta->mPublishTs = c.getInt32(mColMsgMeta_TimeStamp); offset = 0; data_len = 0; // thread and parent id - c.getString(COL_THREAD_ID, temp); + c.getString(mColMsgMeta_MsgThreadId, temp); msgMeta->mThreadId = RsGxsMessageId(temp); - c.getString(COL_PARENT_ID, temp); + c.getString(mColMsgMeta_MsgParentId, temp); msgMeta->mParentId = RsGxsMessageId(temp); // local meta - msgMeta->mMsgStatus = c.getInt32(COL_MSG_STATUS); - msgMeta->mChildTs = c.getInt32(COL_CHILD_TS); + msgMeta->mMsgStatus = c.getInt32(mColMsgMeta_MsgStatus); + msgMeta->mChildTs = c.getInt32(mColMsgMeta_ChildTs); if(ok) return msgMeta; @@ -495,9 +660,9 @@ RsNxsMsg* RsDataService::locked_getMessage(RetroCursor &c) uint32_t data_len = 0, offset = 0; char* data = NULL; - c.getStringT(COL_ACT_GROUP_ID, msg->grpId); + c.getStringT(mColMsg_GrpId, msg->grpId); std::string temp; - c.getString(COL_ACT_MSG_ID, temp); + c.getString(mColMsg_MsgId, temp); msg->msgId = RsGxsMessageId(temp); ok &= (!msg->grpId.isNull()) && (!msg->msgId.isNull()); @@ -505,46 +670,17 @@ RsNxsMsg* RsDataService::locked_getMessage(RetroCursor &c) offset = 0; data_len = 0; if(ok){ - data = (char*)c.getData(COL_META_DATA, data_len); + data = (char*)c.getData(mColMsg_MetaData, data_len); if(data) msg->meta.GetTlv(data, data_len, &offset); } - /* now retrieve grp data from file */ - std::string msgFile; - c.getString(COL_NXS_FILE, msgFile); - offset = c.getInt32(COL_NXS_FILE_OFFSET); - data_len = c.getInt32(COL_NXS_FILE_LEN); - ok &= !msgFile.empty(); - + /* now retrieve msg data */ + offset = 0; data_len = 0; if(ok){ - - // first try to find the file in the service dir - if (RsDirUtil::fileExists(mServiceDir + "/" + msgFile)) { - msgFile.insert(0, mServiceDir + "/"); - } else if (RsDirUtil::fileExists(msgFile)) { - // use old way for backward compatibility - //TODO: can be removed later - } else { - ok = false; - -//#ifdef RS_DATA_SERVICE_DEBUG - std::cerr << "RsDataService::locked_getMessage() cannot find message file " << msgFile; - std::cerr << std::endl; -//#endif - } - - if (ok) { - char* msg_data = new char[data_len]; - std::ifstream istrm(msgFile.c_str(), std::ios::binary); - istrm.seekg(offset, std::ios::beg); - istrm.read(msg_data, data_len); - - istrm.close(); - offset = 0; - ok &= msg->msg.GetTlv(msg_data, data_len, &offset); - delete[] msg_data; - } + data = (char*)c.getData(mColMsg_NxsData, data_len); + if(data) + ok &= msg->msg.GetTlv(data, data_len, &offset); } if(ok) @@ -563,7 +699,7 @@ int RsDataService::storeMessage(std::map &msg) std::map::iterator mit = msg.begin(); // start a transaction - mDb->execSQL("BEGIN;"); + mDb->beginTransaction(); for(; mit != msg.end(); ++mit){ @@ -585,18 +721,15 @@ int RsDataService::storeMessage(std::map &msg) continue; } - // create or access file in binary - std::string filename = msgPtr->grpId.toStdString() + "-msgs"; - std::string msgFile = mServiceDir + "/" + filename; - std::fstream ostrm(msgFile.c_str(), std::ios::binary | std::ios::app | std::ios::out); - ostrm.seekg(0, std::ios::end); // go to end to append - uint32_t offset = ostrm.tellg(); // get fill offset - ContentValue cv; - cv.put(KEY_NXS_FILE_OFFSET, (int32_t)offset); - cv.put(KEY_NXS_FILE, filename); - cv.put(KEY_NXS_FILE_LEN, (int32_t)msgPtr->msg.TlvSize()); + uint32_t dataLen = msgPtr->msg.TlvSize(); + char msgData[dataLen]; + uint32_t offset = 0; + msgPtr->msg.SetTlv(msgData, dataLen, &offset); + cv.put(KEY_NXS_DATA, dataLen, msgData); + + cv.put(KEY_NXS_DATA_LEN, (int32_t)dataLen); cv.put(KEY_MSG_ID, msgMetaPtr->mMsgId.toStdString()); cv.put(KEY_GRP_ID, msgMetaPtr->mGroupId.toStdString()); cv.put(KEY_NXS_SERV_STRING, msgMetaPtr->mServiceString); @@ -628,13 +761,6 @@ int RsDataService::storeMessage(std::map &msg) cv.put(KEY_MSG_STATUS, (int32_t)msgMetaPtr->mMsgStatus); cv.put(KEY_CHILD_TS, (int32_t)msgMetaPtr->mChildTs); - offset = 0; - char* msgData = new char[msgPtr->msg.TlvSize()]; - msgPtr->msg.SetTlv(msgData, msgPtr->msg.TlvSize(), &offset); - ostrm.write(msgData, msgPtr->msg.TlvSize()); - ostrm.close(); - delete[] msgData; - if (!mDb->sqlInsert(MSG_TABLE_NAME, "", cv)) { std::cerr << "RsDataService::storeMessage() sqlInsert Failed"; @@ -647,7 +773,7 @@ int RsDataService::storeMessage(std::map &msg) } // finish transaction - bool ret = mDb->execSQL("COMMIT;"); + bool ret = mDb->commitTransaction(); for(mit = msg.begin(); mit != msg.end(); ++mit) { @@ -678,7 +804,7 @@ int RsDataService::storeGroup(std::map &grp) std::map::iterator sit = grp.begin(); // begin transaction - mDb->execSQL("BEGIN;"); + mDb->beginTransaction(); for(; sit != grp.end(); ++sit) { @@ -696,22 +822,21 @@ int RsDataService::storeGroup(std::map &grp) std::cerr << std::endl; #endif - std::string filename = grpPtr->grpId.toStdString(); - std::string grpFile = mServiceDir + "/" + filename; - std::fstream ostrm(grpFile.c_str(), std::ios::binary | std::ios::app | std::ios::out); - ostrm.seekg(0, std::ios::end); // go to end to append - uint32_t offset = ostrm.tellg(); // get fill offset - /*! - * STORE file offset, file length, file name, + * STORE data, data len, * grpId, flags, publish time stamp, identity, * id signature, admin signatue, key set, last posting ts * and meta data **/ ContentValue cv; - cv.put(KEY_NXS_FILE_OFFSET, (int32_t)offset); - cv.put(KEY_NXS_FILE_LEN, (int32_t)grpPtr->grp.TlvSize()); - cv.put(KEY_NXS_FILE, filename); + + uint32_t dataLen = grpPtr->grp.TlvSize(); + char grpData[dataLen]; + uint32_t offset = 0; + grpPtr->grp.SetTlv(grpData, dataLen, &offset); + cv.put(KEY_NXS_DATA, dataLen, grpData); + + cv.put(KEY_NXS_DATA_LEN, (int32_t) dataLen); cv.put(KEY_GRP_ID, grpPtr->grpId.toStdString()); cv.put(KEY_GRP_NAME, grpMetaPtr->mGroupName); cv.put(KEY_ORIG_GRP_ID, grpMetaPtr->mOrigGrpId.toStdString()); @@ -747,12 +872,6 @@ int RsDataService::storeGroup(std::map &grp) cv.put(KEY_GRP_STATUS, (int32_t)grpMetaPtr->mGroupStatus); cv.put(KEY_GRP_LAST_POST, (int32_t)grpMetaPtr->mLastPost); - offset = 0; - char grpData[grpPtr->grp.TlvSize()]; - grpPtr->grp.SetTlv(grpData, grpPtr->grp.TlvSize(), &offset); - ostrm.write(grpData, grpPtr->grp.TlvSize()); - ostrm.close(); - if (!mDb->sqlInsert(GRP_TABLE_NAME, "", cv)) { std::cerr << "RsDataService::storeGroup() sqlInsert Failed"; @@ -762,7 +881,7 @@ int RsDataService::storeGroup(std::map &grp) } } // finish transaction - bool ret = mDb->execSQL("COMMIT;"); + bool ret = mDb->commitTransaction(); for(sit = grp.begin(); sit != grp.end(); ++sit) { @@ -784,7 +903,7 @@ int RsDataService::updateGroup(std::map &grp) std::map::iterator sit = grp.begin(); // begin transaction - mDb->execSQL("BEGIN;"); + mDb->beginTransaction(); for(; sit != grp.end(); ++sit) { @@ -795,21 +914,20 @@ int RsDataService::updateGroup(std::map &grp) // if data is larger than max item size do not add if(!validSize(grpPtr)) continue; - std::string filename = grpPtr->grpId.toStdString(); - std::string grpFile = mServiceDir + "/" + filename; - std::ofstream ostrm(grpFile.c_str(), std::ios::binary | std::ios::trunc); - uint32_t offset = 0; // get file offset - /*! - * STORE file offset, file length, file name, + * STORE data, data len, * grpId, flags, publish time stamp, identity, * id signature, admin signatue, key set, last posting ts * and meta data **/ ContentValue cv; - cv.put(KEY_NXS_FILE_OFFSET, (int32_t)offset); - cv.put(KEY_NXS_FILE_LEN, (int32_t)grpPtr->grp.TlvSize()); - cv.put(KEY_NXS_FILE, filename); + uint32_t dataLen = grpPtr->grp.TlvSize(); + char grpData[dataLen]; + uint32_t offset = 0; + grpPtr->grp.SetTlv(grpData, dataLen, &offset); + cv.put(KEY_NXS_DATA, dataLen, grpData); + + cv.put(KEY_NXS_DATA_LEN, (int32_t) dataLen); cv.put(KEY_GRP_ID, grpPtr->grpId.toStdString()); cv.put(KEY_GRP_NAME, grpMetaPtr->mGroupName); cv.put(KEY_ORIG_GRP_ID, grpMetaPtr->mOrigGrpId.toStdString()); @@ -842,16 +960,10 @@ int RsDataService::updateGroup(std::map &grp) cv.put(KEY_GRP_STATUS, (int32_t)grpMetaPtr->mGroupStatus); cv.put(KEY_GRP_LAST_POST, (int32_t)grpMetaPtr->mLastPost); - offset = 0; - char grpData[grpPtr->grp.TlvSize()]; - grpPtr->grp.SetTlv(grpData, grpPtr->grp.TlvSize(), &offset); - ostrm.write(grpData, grpPtr->grp.TlvSize()); - ostrm.close(); - mDb->sqlUpdate(GRP_TABLE_NAME, "grpId='" + grpPtr->grpId.toStdString() + "'", cv); } // finish transaction - bool ret = mDb->execSQL("COMMIT;"); + bool ret = mDb->commitTransaction(); for(sit = grp.begin(); sit != grp.end(); ++sit) { @@ -870,7 +982,7 @@ int RsDataService::updateGroupKeys(const RsGxsGroupId& grpId,const RsTlvSecurity RsStackMutex stack(mDbMutex); // begin transaction - mDb->execSQL("BEGIN;"); + mDb->beginTransaction(); /*! * STORE key set @@ -888,7 +1000,7 @@ int RsDataService::updateGroupKeys(const RsGxsGroupId& grpId,const RsTlvSecurity mDb->sqlUpdate(GRP_TABLE_NAME, "grpId='" + grpId.toStdString() + "'", cv); // finish transaction - return mDb->execSQL("COMMIT;"); + return mDb->commitTransaction(); } bool RsDataService::validSize(RsNxsGrp* grp) const @@ -897,12 +1009,18 @@ bool RsDataService::validSize(RsNxsGrp* grp) const return false; } -int RsDataService::retrieveNxsGrps(std::map &grp, bool withMeta, bool /* cache */){ +int RsDataService::retrieveNxsGrps(std::map &grp, bool withMeta, bool /* cache */) +{ +#ifdef RS_DATA_SERVICE_DEBUG_TIME + RsScopeTimer timer(""); + int resultCount = 0; + int requestedGroups = grp.size(); +#endif if(grp.empty()){ RsStackMutex stack(mDbMutex); - RetroCursor* c = mDb->sqlQuery(GRP_TABLE_NAME, grpColumns, "", ""); + RetroCursor* c = mDb->sqlQuery(GRP_TABLE_NAME, mGrpColumns, "", ""); if(c) { @@ -911,6 +1029,10 @@ int RsDataService::retrieveNxsGrps(std::map &grp, bool locked_retrieveGroups(c, grps); std::vector::iterator vit = grps.begin(); +#ifdef RS_DATA_SERVICE_DEBUG_TIME + resultCount = grps.size(); +#endif + for(; vit != grps.end(); ++vit) { grp[(*vit)->grpId] = *vit; @@ -929,7 +1051,7 @@ int RsDataService::retrieveNxsGrps(std::map &grp, bool for(; mit != grp.end(); ++mit) { const RsGxsGroupId& grpId = mit->first; - RetroCursor* c = mDb->sqlQuery(GRP_TABLE_NAME, grpColumns, "grpId='" + grpId.toStdString() + "'", ""); + RetroCursor* c = mDb->sqlQuery(GRP_TABLE_NAME, mGrpColumns, "grpId='" + grpId.toStdString() + "'", ""); if(c) { @@ -940,6 +1062,10 @@ int RsDataService::retrieveNxsGrps(std::map &grp, bool { RsNxsGrp* ng = grps.front(); grp[ng->grpId] = ng; + +#ifdef RS_DATA_SERVICE_DEBUG_TIME + ++resultCount; +#endif }else{ toRemove.push_back(grpId); } @@ -955,6 +1081,10 @@ int RsDataService::retrieveNxsGrps(std::map &grp, bool } } +#ifdef RS_DATA_SERVICE_DEBUG_TIME + std::cerr << "RsDataService::retrieveNxsGrps() " << mDbName << ", Requests: " << requestedGroups << ", Results: " << resultCount << ", Time: " << timer.duration() << std::endl; +#endif + if(withMeta && !grp.empty()) { std::map metaMap; @@ -977,6 +1107,10 @@ int RsDataService::retrieveNxsGrps(std::map &grp, bool std::cerr << std::endl; #endif } + +#ifdef RS_DATA_SERVICE_DEBUG_TIME + std::cerr << "RsDataService::retrieveNxsGrps() " << mDbName << ", Time with meta: " << timer.duration() << std::endl; +#endif } return 1; @@ -1002,6 +1136,10 @@ void RsDataService::locked_retrieveGroups(RetroCursor* c, std::vector int RsDataService::retrieveNxsMsgs(const GxsMsgReq &reqIds, GxsMsgResult &msg, bool /* cache */, bool withMeta) { +#ifdef RS_DATA_SERVICE_DEBUG_TIME + RsScopeTimer timer(""); + int resultCount = 0; +#endif GxsMsgReq::const_iterator mit = reqIds.begin(); @@ -1020,11 +1158,17 @@ int RsDataService::retrieveNxsMsgs(const GxsMsgReq &reqIds, GxsMsgResult &msg, b RsStackMutex stack(mDbMutex); - RetroCursor* c = mDb->sqlQuery(MSG_TABLE_NAME, msgColumns, KEY_GRP_ID+ "='" + grpId.toStdString() + "'", ""); + RetroCursor* c = mDb->sqlQuery(MSG_TABLE_NAME, mMsgColumns, KEY_GRP_ID+ "='" + grpId.toStdString() + "'", ""); if(c) + { locked_retrieveMessages(c, msgSet); +#ifdef RS_DATA_SERVICE_DEBUG_TIME + resultCount += msgSet.size(); +#endif + } + delete c; }else{ @@ -1036,12 +1180,18 @@ int RsDataService::retrieveNxsMsgs(const GxsMsgReq &reqIds, GxsMsgResult &msg, b RsStackMutex stack(mDbMutex); - RetroCursor* c = mDb->sqlQuery(MSG_TABLE_NAME, msgColumns, KEY_GRP_ID+ "='" + grpId.toStdString() + RetroCursor* c = mDb->sqlQuery(MSG_TABLE_NAME, mMsgColumns, KEY_GRP_ID+ "='" + grpId.toStdString() + "' AND " + KEY_MSG_ID + "='" + msgId.toStdString() + "'", ""); if(c) + { locked_retrieveMessages(c, msgSet); +#ifdef RS_DATA_SERVICE_DEBUG_TIME + resultCount += c->getResultCount(); +#endif + } + delete c; } } @@ -1063,6 +1213,10 @@ int RsDataService::retrieveNxsMsgs(const GxsMsgReq &reqIds, GxsMsgResult &msg, b msgSet.clear(); } +#ifdef RS_DATA_SERVICE_DEBUG_TIME + std::cerr << "RsDataService::retrieveNxsMsgs() " << mDbName << ", Requests: " << reqIds.size() << ", Results: " << resultCount << ", Time: " << timer.duration() << std::endl; +#endif + // tres expensive !? if(withMeta) { @@ -1114,6 +1268,10 @@ int RsDataService::retrieveNxsMsgs(const GxsMsgReq &reqIds, GxsMsgResult &msg, b meta_lit = msgMetaV.erase(meta_lit); } } + +#ifdef RS_DATA_SERVICE_DEBUG_TIME + std::cerr << "RsDataService::retrieveNxsMsgs() " << mDbName << ", Time with meta: " << timer.duration() << std::endl; +#endif } return 1; @@ -1126,7 +1284,7 @@ void RsDataService::locked_retrieveMessages(RetroCursor *c, std::vectormoveToNext(); @@ -1136,9 +1294,13 @@ void RsDataService::locked_retrieveMessages(RetroCursor *c, std::vector metaSet; if(msgIdV.empty()){ - RetroCursor* c = mDb->sqlQuery(MSG_TABLE_NAME, msgMetaColumns, KEY_GRP_ID+ "='" + grpId.toStdString() + "'", ""); + RetroCursor* c = mDb->sqlQuery(MSG_TABLE_NAME, mMsgMetaColumns, KEY_GRP_ID+ "='" + grpId.toStdString() + "'", ""); - locked_retrieveMsgMeta(c, metaSet); + if (c) + { + locked_retrieveMsgMeta(c, metaSet); +#ifdef RS_DATA_SERVICE_DEBUG_TIME + resultCount += metaSet.size(); +#endif + } }else{ // request each grp @@ -1162,16 +1330,27 @@ int RsDataService::retrieveGxsMsgMetaData(const GxsMsgReq& reqIds, GxsMsgMetaRes for(; sit!=msgIdV.end(); ++sit){ const RsGxsMessageId& msgId = *sit; - RetroCursor* c = mDb->sqlQuery(MSG_TABLE_NAME, msgMetaColumns, KEY_GRP_ID+ "='" + grpId.toStdString() + RetroCursor* c = mDb->sqlQuery(MSG_TABLE_NAME, mMsgMetaColumns, KEY_GRP_ID+ "='" + grpId.toStdString() + "' AND " + KEY_MSG_ID + "='" + msgId.toStdString() + "'", ""); - locked_retrieveMsgMeta(c, metaSet); + if (c) + { + locked_retrieveMsgMeta(c, metaSet); + +#ifdef RS_DATA_SERVICE_DEBUG_TIME + resultCount += c->getResultCount(); +#endif + } } } msgMeta[grpId] = metaSet; } +#ifdef RS_DATA_SERVICE_DEBUG_TIME + std::cerr << "RsDataService::retrieveGxsMsgMetaData() " << mDbName << ", Requests: " << reqIds.size() << ", Results: " << resultCount << ", Time: " << timer.duration() << std::endl; +#endif + return 1; } @@ -1202,6 +1381,12 @@ int RsDataService::retrieveGxsGrpMetaData(std::mapsqlQuery(GRP_TABLE_NAME, grpMetaColumns, "", ""); + RetroCursor* c = mDb->sqlQuery(GRP_TABLE_NAME, mGrpMetaColumns, "", ""); if(c) { @@ -1223,6 +1408,10 @@ int RsDataService::retrieveGxsGrpMetaData(std::mapmGroupId] = g; } valid = c->moveToNext(); + +#ifdef RS_DATA_SERVICE_DEBUG_TIME + ++resultCount; +#endif } delete c; } @@ -1234,7 +1423,7 @@ int RsDataService::retrieveGxsGrpMetaData(std::mapfirst; - RetroCursor* c = mDb->sqlQuery(GRP_TABLE_NAME, grpMetaColumns, "grpId='" + grpId.toStdString() + "'", ""); + RetroCursor* c = mDb->sqlQuery(GRP_TABLE_NAME, mGrpMetaColumns, "grpId='" + grpId.toStdString() + "'", ""); if(c) { @@ -1249,6 +1438,10 @@ int RsDataService::retrieveGxsGrpMetaData(std::mapmGroupId] = g; } valid = c->moveToNext(); + +#ifdef RS_DATA_SERVICE_DEBUG_TIME + ++resultCount; +#endif } delete c; } @@ -1257,6 +1450,9 @@ int RsDataService::retrieveGxsGrpMetaData(std::map grps; - - retrieveNxsGrps(grps, false, false); - std::map::iterator mit - = grps.begin(); - { RsStackMutex stack(mDbMutex); - // remove all grp msgs files from service dir - for(; mit != grps.end(); ++mit){ - std::string file = mServiceDir + "/" + mit->first.toStdString(); - std::string msgFile = file + "-msgs"; - remove(file.c_str()); // remove group file - remove(msgFile.c_str()); // and remove messages file - delete mit->second; - } - + mDb->execSQL("DROP INDEX " + MSG_INDEX_GRPID); + mDb->execSQL("DROP TABLE " + DATABASE_RELEASE_TABLE_NAME); mDb->execSQL("DROP TABLE " + MSG_TABLE_NAME); mDb->execSQL("DROP TABLE " + GRP_TABLE_NAME); mDb->execSQL("DROP TRIGGER " + GRP_LAST_POST_UPDATE_TRIGGER); } // recreate database - initialise(); + initialise(true); return 1; } @@ -1313,109 +1496,21 @@ int RsDataService::updateMessageMetaData(MsgLocMetaData &metaData) + "' AND " + KEY_MSG_ID + "='" + msgId.toStdString() + "'", metaData.val) ? 1 : 0; } -MsgOffset offSetAccum(const MsgOffset& x, const MsgOffset& y) -{ - MsgOffset m; - m.msgLen = y.msgLen + x.msgLen; - return m; -} - int RsDataService::removeMsgs(const GxsMsgReq& msgIds) { RsStackMutex stack(mDbMutex); - // for each group - // get for all msgs their offsets and lengths - // for message not contained in msg id vector - // store their data file segments in buffer - // then recalculate the retained messages' - // new offsets, update db with new offsets - // replace old msg file with new file - // remove messages that were not retained from - // db - GxsMsgReq::const_iterator mit = msgIds.begin(); - for(; mit != msgIds.end(); ++mit) { - MsgUpdates updates; const std::vector& msgIdV = mit->second; const RsGxsGroupId& grpId = mit->first; - GxsMsgReq reqIds; - reqIds.insert(std::make_pair(grpId, std::vector() )); - - // can get offsets for each file - std::vector msgOffsets; - locked_getMessageOffsets(grpId, msgOffsets); - - std::string oldFileName = mServiceDir + "/" + grpId.toStdString() + "-msgs"; - std::string newFileName = mServiceDir + "/" + grpId.toStdString() + "-msgs-temp"; - std::ifstream in(oldFileName.c_str(), std::ios::binary); - std::vector dataBuff, newBuffer; - - std::vector::iterator vit = msgOffsets.begin(); - - uint32_t maxSize = 0;// größe aller msgs, newbuf könnte aber kleiner sein, weil msgs weggehen - for(; vit != msgOffsets.end(); ++vit) - maxSize += vit->msgLen; - - // may be preferable to determine file len reality - // from file? corrupt db? - dataBuff.reserve(maxSize);// dataBuff.resize(maxSize); - newBuffer.reserve(maxSize);// newBuffer.resize(maxSize); - - dataBuff.insert(dataBuff.end(), - std::istreambuf_iterator(in), - std::istreambuf_iterator()); - - in.close(); - uint32_t newOffset = 0;// am anfang der liste ist offset=0, jetzt gehen wir die msgs liste durch - for(std::vector::size_type i = 0; i < msgOffsets.size(); ++i) - { - const MsgOffset& m = msgOffsets[i]; - - //uint32_t newOffset = 0;//hier ist es zu spät, offset muss hochgezählt werden - if(std::find(msgIdV.begin(), msgIdV.end(), m.msgId) == msgIdV.end()) - { - MsgUpdate up; - - uint32_t msgLen = m.msgLen; - - up.msgId = m.msgId; - up.cv.put(KEY_NXS_FILE_OFFSET, (int32_t)newOffset); - - newBuffer.insert(newBuffer.end(), dataBuff.begin()+m.msgOffset, - dataBuff.begin()+m.msgOffset+m.msgLen); - - newOffset += msgLen; - - up.cv.put(KEY_NXS_FILE_LEN, (int32_t)msgLen); - - // add msg update - updates[grpId].push_back(up); - } - } - - std::ofstream out(newFileName.c_str(), std::ios::binary); - - std::copy(newBuffer.begin(), newBuffer.end(), - std::ostreambuf_iterator(out)); - - out.close(); - - // now update the new positions in db - locked_updateMessageEntries(updates); - - // then delete removed messages + // delete messages GxsMsgReq msgsToDelete; msgsToDelete[grpId] = msgIdV; locked_removeMessageEntries(msgsToDelete); - - // now replace old file location with new file - remove(oldFileName.c_str()); - RsDirUtil::renameFile(newFileName, oldFileName); } return 1; @@ -1426,17 +1521,6 @@ int RsDataService::removeGroups(const std::vector &grpIds) RsStackMutex stack(mDbMutex); - // the grp id is the group file name - // first remove file then remove group - // from db - - std::vector::const_iterator vit = grpIds.begin(); - for(; vit != grpIds.end(); ++vit) - { - const std::string grpFileName = mServiceDir + "/" + (*vit).toStdString(); - remove(grpFileName.c_str()); - } - locked_removeGroupEntries(grpIds); return 1; @@ -1446,7 +1530,12 @@ int RsDataService::retrieveGroupIds(std::vector &grpIds) { RsStackMutex stack(mDbMutex); - RetroCursor* c = mDb->sqlQuery(GRP_TABLE_NAME, grpIdColumn, "", ""); +#ifdef RS_DATA_SERVICE_DEBUG_TIME + RsScopeTimer timer(""); + int resultCount = 0; +#endif + + RetroCursor* c = mDb->sqlQuery(GRP_TABLE_NAME, mGrpIdColumn, "", ""); if(c) { @@ -1455,9 +1544,13 @@ int RsDataService::retrieveGroupIds(std::vector &grpIds) while(valid) { std::string grpId; - c->getString(0, grpId); + c->getString(mColGrpId_GrpId, grpId); grpIds.push_back(RsGxsGroupId(grpId)); valid = c->moveToNext(); + +#ifdef RS_DATA_SERVICE_DEBUG_TIME + ++resultCount; +#endif } delete c; }else @@ -1465,11 +1558,19 @@ int RsDataService::retrieveGroupIds(std::vector &grpIds) return 0; } +#ifdef RS_DATA_SERVICE_DEBUG_TIME + std::cerr << "RsDataService::retrieveGroupIds() " << mDbName << ", Results: " << resultCount << ", Time: " << timer.duration() << std::endl; +#endif + return 1; } -int RsDataService::retrieveMsgIds(const RsGxsGroupId& grpId, - RsGxsMessageId::std_vector& msgIds) { +int RsDataService::retrieveMsgIds(const RsGxsGroupId& grpId, RsGxsMessageId::std_vector& msgIds) +{ +#ifdef RS_DATA_SERVICE_DEBUG_TIME + RsScopeTimer timer(""); + int resultCount = 0; +#endif RetroCursor* c = mDb->sqlQuery(MSG_TABLE_NAME, mMsgIdColumn, KEY_GRP_ID+ "='" + grpId.toStdString() + "'", ""); @@ -1480,13 +1581,17 @@ int RsDataService::retrieveMsgIds(const RsGxsGroupId& grpId, while(valid) { std::string msgId; - c->getString(0, msgId); + c->getString(mColMsgId_MsgId, msgId); if(c->columnCount() != 1) std::cerr << "(EE) ********* not retrieving all columns!!" << std::endl; msgIds.push_back(RsGxsMessageId(msgId)); valid = c->moveToNext(); + +#ifdef RS_DATA_SERVICE_DEBUG_TIME + ++resultCount; +#endif } delete c; }else @@ -1494,41 +1599,18 @@ int RsDataService::retrieveMsgIds(const RsGxsGroupId& grpId, return 0; } +#ifdef RS_DATA_SERVICE_DEBUG_TIME + std::cerr << "RsDataService::retrieveNxsGrps() " << mDbName << ", Results: " << resultCount << ", Time: " << timer.duration() << std::endl; +#endif + return 1; } -bool RsDataService::locked_updateMessageEntries(const MsgUpdates& updates) -{ - // start a transaction - bool ret = mDb->execSQL("BEGIN;"); - - MsgUpdates::const_iterator mit = updates.begin(); - - for(; mit != updates.end(); ++mit) - { - - const RsGxsGroupId& grpId = mit->first; - const std::vector& updateV = mit->second; - std::vector::const_iterator vit = updateV.begin(); - - for(; vit != updateV.end(); ++vit) - { - const MsgUpdate& update = *vit; - mDb->sqlUpdate(MSG_TABLE_NAME, KEY_GRP_ID+ "='" + grpId.toStdString() - + "' AND " + KEY_MSG_ID + "='" + update.msgId.toStdString() + "'", update.cv); - } - } - - ret &= mDb->execSQL("COMMIT;"); - - return ret; -} - bool RsDataService::locked_removeMessageEntries(const GxsMsgReq& msgIds) { // start a transaction - bool ret = mDb->execSQL("BEGIN;"); + bool ret = mDb->beginTransaction(); GxsMsgReq::const_iterator mit = msgIds.begin(); @@ -1546,7 +1628,7 @@ bool RsDataService::locked_removeMessageEntries(const GxsMsgReq& msgIds) } } - ret &= mDb->execSQL("COMMIT;"); + ret &= mDb->commitTransaction(); return ret; } @@ -1554,7 +1636,7 @@ bool RsDataService::locked_removeMessageEntries(const GxsMsgReq& msgIds) bool RsDataService::locked_removeGroupEntries(const std::vector& grpIds) { // start a transaction - bool ret = mDb->execSQL("BEGIN;"); + bool ret = mDb->beginTransaction(); std::vector::const_iterator vit = grpIds.begin(); @@ -1565,42 +1647,10 @@ bool RsDataService::locked_removeGroupEntries(const std::vector& g mDb->sqlDelete(GRP_TABLE_NAME, KEY_GRP_ID+ "='" + grpId.toStdString() + "'", ""); } - ret &= mDb->execSQL("COMMIT;"); + ret &= mDb->commitTransaction(); return ret; } -void RsDataService::locked_getMessageOffsets(const RsGxsGroupId& grpId, std::vector& offsets) -{ - - RetroCursor* c = mDb->sqlQuery(MSG_TABLE_NAME, mMsgOffSetColumns, KEY_GRP_ID+ "='" + grpId.toStdString() + "'", ""); - - if(c) - { - bool valid = c->moveToFirst(); - - while(valid) - { - RsGxsMessageId msgId; - int32_t msgLen; - int32_t msgOffSet; - std::string temp; - c->getString(0, temp); - msgId = RsGxsMessageId(temp); - msgOffSet = c->getInt32(1); - msgLen = c->getInt32(2); - - MsgOffset offset; - offset.msgId = msgId; - offset.msgLen = msgLen; - offset.msgOffset = msgOffSet; - offsets.push_back(offset); - - valid = c->moveToNext(); - } - delete c; - } -} - uint32_t RsDataService::cacheSize() const { return 0; } diff --git a/libretroshare/src/gxs/rsdataservice.h b/libretroshare/src/gxs/rsdataservice.h index ea74bc831..e9f54b39d 100644 --- a/libretroshare/src/gxs/rsdataservice.h +++ b/libretroshare/src/gxs/rsdataservice.h @@ -29,15 +29,6 @@ #include "gxs/rsgds.h" #include "util/retrodb.h" -class MsgOffset -{ -public: - - MsgOffset() : msgOffset(0), msgLen(0) {} - RsGxsMessageId msgId; - uint32_t msgOffset, msgLen; -}; - class MsgUpdate { public: @@ -233,8 +224,9 @@ private: /*! * Creates an sql database and its associated file * also creates the message and groups table + * @param isNewDatabase is new database */ - void initialise(); + void initialise(bool isNewDatabase); /*! * Remove entries for data base @@ -243,34 +235,99 @@ private: bool locked_removeMessageEntries(const GxsMsgReq& msgIds); bool locked_removeGroupEntries(const std::vector& grpIds); - typedef std::map > MsgUpdates; +private: + /*! + * Start release update + * @param release + * @return true/false + */ + bool startReleaseUpdate(int release); /*! - * Update messages entries with new values - * @param msgIds - * @param cv contains values to update message entries with + * Finish release update + * @param release + * @param result + * @return true/false */ - bool locked_updateMessageEntries(const MsgUpdates& updates); - - -private: - - void locked_getMessageOffsets(const RsGxsGroupId& grpId, std::vector& msgOffsets); + bool finishReleaseUpdate(int release, bool result); private: RsMutex mDbMutex; - std::list msgColumns; - std::list msgMetaColumns; - std::list mMsgOffSetColumns; + std::list mMsgColumns; + std::list mMsgMetaColumns; std::list mMsgIdColumn; - std::list grpColumns; - std::list grpMetaColumns; - std::list grpIdColumn; + std::list mGrpColumns; + std::list mGrpMetaColumns; + std::list mGrpIdColumn; - std::string mServiceDir, mDbName; + // Message meta column + int mColMsgMeta_GrpId; + int mColMsgMeta_TimeStamp; + int mColMsgMeta_NxsFlags; + int mColMsgMeta_SignSet; + int mColMsgMeta_NxsIdentity; + int mColMsgMeta_NxsHash; + int mColMsgMeta_MsgId; + int mColMsgMeta_OrigMsgId; + int mColMsgMeta_MsgStatus; + int mColMsgMeta_ChildTs; + int mColMsgMeta_MsgParentId; + int mColMsgMeta_MsgThreadId; + int mColMsgMeta_Name; + int mColMsgMeta_NxsServString; + int mColMsgMeta_RecvTs; + int mColMsgMeta_NxsDataLen; + + // Message columns + int mColMsg_GrpId; + int mColMsg_NxsData; + int mColMsg_MetaData; + int mColMsg_MsgId; + + // Group meta columns + int mColGrpMeta_GrpId; + int mColGrpMeta_TimeStamp; + int mColGrpMeta_NxsFlags; +// int mColGrpMeta_SignSet; + int mColGrpMeta_NxsIdentity; + int mColGrpMeta_NxsHash; + int mColGrpMeta_KeySet; + int mColGrpMeta_SubscrFlag; + int mColGrpMeta_Pop; + int mColGrpMeta_MsgCount; + int mColGrpMeta_Status; + int mColGrpMeta_Name; + int mColGrpMeta_LastPost; + int mColGrpMeta_OrigGrpId; + int mColGrpMeta_ServString; + int mColGrpMeta_SignFlags; + int mColGrpMeta_CircleId; + int mColGrpMeta_CircleType; + int mColGrpMeta_InternCircle; + int mColGrpMeta_Originator; + int mColGrpMeta_AuthenFlags; + int mColGrpMeta_ParentGrpId; + int mColGrpMeta_RecvTs; + int mColGrpMeta_RepCutoff; + int mColGrpMeta_NxsDataLen; + + // Group columns + int mColGrp_GrpId; + int mColGrp_NxsData; + int mColGrp_MetaData; + + // Group id columns + int mColGrpId_GrpId; + + // Msg id columns + int mColMsgId_MsgId; + + std::string mServiceDir; + std::string mDbName; + std::string mDbPath; uint16_t mServType; RetroDb* mDb; diff --git a/libretroshare/src/gxs/rsgenexchange.cc b/libretroshare/src/gxs/rsgenexchange.cc index 54828dc4e..accba84fc 100644 --- a/libretroshare/src/gxs/rsgenexchange.cc +++ b/libretroshare/src/gxs/rsgenexchange.cc @@ -908,7 +908,7 @@ int RsGenExchange::validateGrp(RsNxsGrp* grp) PrivacyBitPos pos = GRP_OPTION_BITS; // Check required permissions, and allow them to sign it - if they want too - as well! - if (!(metaData.mAuthorId.isNull()) || checkAuthenFlag(pos, author_flag)) + if ((!metaData.mAuthorId.isNull()) || checkAuthenFlag(pos, author_flag)) { needIdentitySign = true; std::cerr << "Needs Identity sign! (Service Flags)"; @@ -1718,7 +1718,7 @@ void RsGenExchange::processGrpMetaChanges() // process mask bool ok = processGrpMask(g.grpId, g.val); - ok &= mDataStore->updateGroupMetaData(g) == 1; + ok = ok && (mDataStore->updateGroupMetaData(g) == 1); if(ok) { @@ -1761,6 +1761,12 @@ bool RsGenExchange::processGrpMask(const RsGxsGroupId& grpId, ContentValue &grpC if((mit = grpMetaMap.find(grpId)) != grpMetaMap.end()) { grpMeta = mit->second; + if (!grpMeta) + { + std::cerr << "RsGenExchange::processGrpMask() Ignore update for not existing grp id " << grpId.toStdString(); + std::cerr << std::endl; + return false; + } ok = true; } @@ -2090,7 +2096,7 @@ void RsGenExchange::processGroupDelete() gprIds.push_back(groupId); mDataStore->removeGroups(gprIds); toNotify.insert(std::make_pair( - token, GrpNote(true, RsGxsGroupId()))); + token, GrpNote(true, groupId))); } diff --git a/libretroshare/src/gxs/rsgxsdataaccess.cc b/libretroshare/src/gxs/rsgxsdataaccess.cc index 55c4de7d6..e1c922d61 100644 --- a/libretroshare/src/gxs/rsgxsdataaccess.cc +++ b/libretroshare/src/gxs/rsgxsdataaccess.cc @@ -59,7 +59,7 @@ const uint8_t RsTokenService::GXS_REQUEST_V2_STATUS_FINISHED_INCOMPLETE = 3; const uint8_t RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE = 4; const uint8_t RsTokenService::GXS_REQUEST_V2_STATUS_DONE = 5; // ONCE ALL DATA RETRIEVED. - + const uint8_t RsTokenService::GXS_REQUEST_V2_STATUS_CANCELLED = 6; /*********** * #define DATA_DEBUG 1 @@ -367,13 +367,19 @@ uint32_t RsGxsDataAccess::requestStatus(uint32_t token) return status; } - - - - bool RsGxsDataAccess::cancelRequest(const uint32_t& token) { - return clearRequest(token); + RsStackMutex stack(mDataMutex); /****** LOCKED *****/ + + GxsRequest* req = locked_retrieveRequest(token); + if (!req) + { + return false; + } + + req->status = GXS_REQUEST_V2_STATUS_CANCELLED; + + return true; } bool RsGxsDataAccess::clearRequest(const uint32_t& token) @@ -389,7 +395,7 @@ bool RsGxsDataAccess::clearRequest(const uint32_t& token) } delete it->second; - mRequests.erase(it->first); + mRequests.erase(it); return true; } @@ -707,7 +713,6 @@ bool RsGxsDataAccess::getGroupList(const uint32_t& token, std::list toClear; - std::list::iterator cit; time_t now = time(NULL); + std::map::iterator it; { RsStackMutex stack(mDataMutex); /******* LOCKED *******/ - std::map::iterator it; + // process status of the requests + for (it = mRequests.begin(); it != mRequests.end(); ++it) + { + GxsRequest* req = it->second; + + switch (req->status) + { + case GXS_REQUEST_V2_STATUS_PENDING: + // process request later + break; + case GXS_REQUEST_V2_STATUS_PARTIAL: + // should not happen + req->status = GXS_REQUEST_V2_STATUS_COMPLETE; + break; + case GXS_REQUEST_V2_STATUS_DONE: +#ifdef DATA_DEBUG + std::cerr << "RsGxsDataAccess::processrequests() Clearing Done Request Token: " << req->token; + std::cerr << std::endl; +#endif + toClear.push_back(req->token); + break; + case GXS_REQUEST_V2_STATUS_CANCELLED: +#ifdef DATA_DEBUG + std::cerr << "RsGxsDataAccess::processrequests() Clearing Cancelled Request Token: " << req->token; + std::cerr << std::endl; +#endif + toClear.push_back(req->token); + break; + default: + if (now - req->reqTime > MAX_REQUEST_AGE) + { +#ifdef DATA_DEBUG + std::cerr << "RsGxsDataAccess::processrequests() Clearing Old Request Token: " << req->token; + std::cerr << std::endl; +#endif + toClear.push_back(req->token); + } + } + } + } // END OF MUTEX. + + // clear requests + std::list::iterator cit; + for (cit = toClear.begin(); cit != toClear.end(); ++cit) + { + clearRequest(*cit); + } + + // process requests + while (true) + { + GxsRequest* req = NULL; + { + RsStackMutex stack(mDataMutex); /******* LOCKED *******/ + + // get the first pending request + for (it = mRequests.begin(); it != mRequests.end(); ++it) + { + GxsRequest* reqCheck = it->second; + if (reqCheck->status == GXS_REQUEST_V2_STATUS_PENDING) + { + req = reqCheck; + req->status = GXS_REQUEST_V2_STATUS_PARTIAL; + break; + } + } + } // END OF MUTEX. + + if (!req) { + break; + } GroupMetaReq* gmr; GroupDataReq* gdr; @@ -739,101 +813,69 @@ void RsGxsDataAccess::processRequests() MsgMetaReq* mmr; MsgDataReq* mdr; MsgIdReq* mir; - MsgRelatedInfoReq* mri; - GroupStatisticRequest* gsr; - ServiceStatisticRequest* ssr; + MsgRelatedInfoReq* mri; + GroupStatisticRequest* gsr; + ServiceStatisticRequest* ssr; - for(it = mRequests.begin(); it != mRequests.end(); ++it) +#ifdef DATA_DEBUG + std::cerr << "RsGxsDataAccess::processRequests() Processing Token: " << req->token << " Status: " + << req->status << " ReqType: " << req->reqType << " Age: " + << now - req->reqTime << std::endl; +#endif + + /* PROCESS REQUEST! */ + bool ok = false; + + if((gmr = dynamic_cast(req)) != NULL) { - - GxsRequest* req = it->second; - if (req->status == GXS_REQUEST_V2_STATUS_PENDING) - { -#ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::processRequests() Processing Token: " << req->token << " Status: " - << req->status << " ReqType: " << req->reqType << " Age: " - << now - req->reqTime << std::endl; -#endif - - req->status = GXS_REQUEST_V2_STATUS_PARTIAL; - - /* PROCESS REQUEST! */ - - if((gmr = dynamic_cast(req)) != NULL) - { - getGroupSummary(gmr); - } - else if((gdr = dynamic_cast(req)) != NULL) - { - getGroupData(gdr); - } - else if((gir = dynamic_cast(req)) != NULL) - { - getGroupList(gir); - } - else if((mmr = dynamic_cast(req)) != NULL) - { - getMsgSummary(mmr); - } - else if((mdr = dynamic_cast(req)) != NULL) - { - getMsgData(mdr); - } - else if((mir = dynamic_cast(req)) != NULL) - { - getMsgList(mir); - } - else if((mri = dynamic_cast(req)) != NULL) - { - getMsgRelatedInfo(mri); - } - else if((gsr = dynamic_cast(req)) != NULL) - { - getGroupStatistic(gsr); - } - else if((ssr = dynamic_cast(req)) != NULL) - { - getServiceStatistic(ssr); - } - else - { - std::cerr << "RsGxsDataAccess::processRequests() Failed to process request, token: " - << req->token << std::endl; - - req->status = GXS_REQUEST_V2_STATUS_FAILED; - } - } - else if (req->status == GXS_REQUEST_V2_STATUS_PARTIAL) - { - req->status = GXS_REQUEST_V2_STATUS_COMPLETE; - } - else if (req->status == GXS_REQUEST_V2_STATUS_DONE) - { -#ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::processrequests() Clearing Done Request Token: " - << req->token; - std::cerr << std::endl; -#endif - toClear.push_back(req->token); - } - else if (now - req->reqTime > MAX_REQUEST_AGE) - { -#ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::processrequests() Clearing Old Request Token: " << req->token; - std::cerr << std::endl; -#endif - toClear.push_back(req->token); - } + ok = getGroupSummary(gmr); + } + else if((gdr = dynamic_cast(req)) != NULL) + { + ok = getGroupData(gdr); + } + else if((gir = dynamic_cast(req)) != NULL) + { + ok = getGroupList(gir); + } + else if((mmr = dynamic_cast(req)) != NULL) + { + ok = getMsgSummary(mmr); + } + else if((mdr = dynamic_cast(req)) != NULL) + { + ok = getMsgData(mdr); + } + else if((mir = dynamic_cast(req)) != NULL) + { + ok = getMsgList(mir); + } + else if((mri = dynamic_cast(req)) != NULL) + { + ok = getMsgRelatedInfo(mri); + } + else if((gsr = dynamic_cast(req)) != NULL) + { + ok = getGroupStatistic(gsr); + } + else if((ssr = dynamic_cast(req)) != NULL) + { + ok = getServiceStatistic(ssr); + } + else + { + std::cerr << "RsGxsDataAccess::processRequests() Failed to process request, token: " + << req->token << std::endl; } - } // END OF MUTEX. - - for(cit = toClear.begin(); cit != toClear.end(); ++cit) - { - clearRequest(*cit); + { + RsStackMutex stack(mDataMutex); /******* LOCKED *******/ + if (req->status == GXS_REQUEST_V2_STATUS_PARTIAL) + { + req->status = ok ? GXS_REQUEST_V2_STATUS_COMPLETE : GXS_REQUEST_V2_STATUS_FAILED; + } + } // END OF MUTEX. } - - return; } bool RsGxsDataAccess::getGroupStatistic(const uint32_t &token, GxsGroupStatistic &grpStatistic) @@ -1719,7 +1761,7 @@ bool RsGxsDataAccess::checkRequestStatus(const uint32_t& token, GxsRequest* req = locked_retrieveRequest(token); - if(req == NULL) + if (req == NULL || req->status == GXS_REQUEST_V2_STATUS_CANCELLED) return false; anstype = req->ansType; diff --git a/libretroshare/src/gxs/rsgxsnetservice.cc b/libretroshare/src/gxs/rsgxsnetservice.cc index ccd7bf6eb..4d0c88399 100644 --- a/libretroshare/src/gxs/rsgxsnetservice.cc +++ b/libretroshare/src/gxs/rsgxsnetservice.cc @@ -235,6 +235,10 @@ void RsGxsNetService::syncWithPeers() std::set peers; mNetMgr->getOnlineList(mServiceInfo.mServiceType, peers); + if (peers.empty()) { + // nothing to do + return; + } std::set::iterator sit = peers.begin(); @@ -1160,7 +1164,7 @@ void RsGxsNetService::data_tick() //Start waiting as nothing to do in runup usleep((int) (timeDelta * 1000 * 1000)); // timeDelta sec - if(mUpdateCounter >= 20) + if(mUpdateCounter >= 120) // 60 seconds { updateServerSyncTS(); mUpdateCounter = 0; @@ -2156,6 +2160,9 @@ void RsGxsNetService::locked_genReqGrpTransaction(NxsTransaction* tr) std::cerr << "locked_genReqGrpTransaction(): " << std::endl; #endif + std::map grpMetaMap; + std::map::const_iterator metaIter; + std::list grpItemL; std::list::iterator lit = tr->mItems.begin(); @@ -2165,6 +2172,7 @@ void RsGxsNetService::locked_genReqGrpTransaction(NxsTransaction* tr) if(item) { grpItemL.push_back(item); + grpMetaMap[item->grpId] = NULL; }else { #ifdef NXS_NET_DEBUG @@ -2174,8 +2182,11 @@ void RsGxsNetService::locked_genReqGrpTransaction(NxsTransaction* tr) } } - std::map grpMetaMap; - std::map::const_iterator metaIter; + if (grpItemL.empty()) + { + return; + } + mDataStore->retrieveGxsGrpMetaData(grpMetaMap); // now do compare and add loop @@ -2195,7 +2206,7 @@ void RsGxsNetService::locked_genReqGrpTransaction(NxsTransaction* tr) metaIter = grpMetaMap.find(grpId); bool haveItem = false; bool latestVersion = false; - if (metaIter != grpMetaMap.end()) + if (metaIter != grpMetaMap.end() && metaIter->second) { haveItem = true; latestVersion = grpSyncItem->publishTs > metaIter->second->mPublishTs; diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index a103392eb..18ded24a5 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -1,12 +1,16 @@ +!include("../../retroshare.pri"): error("Could not include file ../../retroshare.pri") + TEMPLATE = lib CONFIG += staticlib bitdht +CONFIG += create_prl CONFIG -= qt TARGET = retroshare +TARGET_PRL = libretroshare #GXS Stuff. # This should be disabled for releases until further notice. -CONFIG += gxs debug +CONFIG += gxs #CONFIG += dsdv @@ -19,7 +23,6 @@ profiling { #QMAKE_CFLAGS += -Werror #QMAKE_CXXFLAGS += -Werror -CONFIG += debug debug { # DEFINES *= DEBUG # DEFINES *= OPENDHT_DEBUG DHT_DEBUG CONN_DEBUG DEBUG_UDP_SORTER P3DISC_DEBUG DEBUG_UDP_LAYER FT_DEBUG EXTADDRSEARCH_DEBUG @@ -81,6 +84,8 @@ SOURCES += tcponudp/udppeer.cc \ # The next line is for compliance with debian packages. Keep it! INCLUDEPATH += ../libbitdht DEFINES *= RS_USE_BITDHT + PRE_TARGETDEPS *= ../../libbitdht/src/lib/libbitdht.a + LIBS += ../../libbitdht/src/lib/libbitdht.a } @@ -120,10 +125,6 @@ HEADERS += $$PUBLIC_HEADERS ################################# Linux ########################################## linux-* { - isEmpty(PREFIX) { PREFIX = /usr } - isEmpty(INC_DIR) { INC_DIR = $${PREFIX}/include/retroshare/ } - isEmpty(LIB_DIR) { LIB_DIR = $${PREFIX}/lib/ } - # These two lines fixe compilation on ubuntu natty. Probably a ubuntu packaging error. INCLUDEPATH += $$system(pkg-config --cflags glib-2.0 | sed -e "s/-I//g") @@ -140,27 +141,25 @@ linux-* { DEPENDPATH += . $${SSL_DIR} $${UPNP_DIR} INCLUDEPATH += . $${SSL_DIR} $${UPNP_DIR} - # where to put the shared library itself - target.path = $$LIB_DIR - INSTALLS *= target - - SQLCIPHER_OK = $$system(pkg-config --exists sqlcipher && echo yes) - isEmpty(SQLCIPHER_OK) { -# We need a explicit path here, to force using the home version of sqlite3 that really encrypts the database. - !exists(../../../lib/sqlcipher/.libs/libsqlcipher.a) { - message(libsqlcipher.a not found. Compilation will not use SQLCIPER. Database will be unencrypted.) - DEFINES *= NO_SQLCIPHER + contains(CONFIG, NO_SQLCIPHER) { + DEFINES *= NO_SQLCIPHER + LIBS *= -lsqlite3 + } else { + SQLCIPHER_OK = $$system(pkg-config --exists sqlcipher && echo yes) + isEmpty(SQLCIPHER_OK) { + # We need a explicit path here, to force using the home version of sqlite3 that really encrypts the database. + exists(../../../lib/sqlcipher/.libs/libsqlcipher.a) { + LIBS += ../../../lib/sqlcipher/.libs/libsqlcipher.a + DEPENDPATH += ../../../lib/ + INCLUDEPATH += ../../../lib/ + } else { + error("libsqlcipher is not installed and libsqlcipher.a not found. SQLCIPHER is necessary for encrypted database, to build with unencrypted database, run: qmake CONFIG+=NO_SQLCIPHER") + } } else { - DEPENDPATH += ../../../lib/ - INCLUDEPATH += ../../../lib/ + LIBS *= -lsqlcipher } } - # where to put the librarys interface - include_rsiface.path = $${INC_DIR} - include_rsiface.files = $$PUBLIC_HEADERS - INSTALLS += include_rsiface - #CONFIG += version_detail_bash_script @@ -179,6 +178,22 @@ linux-* { DEFINES *= UBUNTU INCLUDEPATH += /usr/include/glib-2.0/ /usr/lib/glib-2.0/include LIBS *= -lgnome-keyring + LIBS *= -lssl -lupnp -lixml + LIBS *= -lcrypto -lz -lpthread +} + +unix { + DEFINES *= LIB_DIR=\"\\\"$${LIB_DIR}\\\"\" + DEFINES *= DATA_DIR=\"\\\"$${DATA_DIR}\\\"\" + + ## where to put the librarys interface + #include_rsiface.path = "$${INC_DIR}" + #include_rsiface.files = $$PUBLIC_HEADERS + #INSTALLS += include_rsiface + + ## where to put the shared library itself + #target.path = "$$LIB_DIR" + #INSTALLS *= target } linux-g++ { @@ -190,9 +205,16 @@ linux-g++-64 { } version_detail_bash_script { - QMAKE_EXTRA_TARGETS += write_version_detail - PRE_TARGETDEPS = write_version_detail - write_version_detail.commands = ./version_detail.sh + linux-* { + QMAKE_EXTRA_TARGETS += write_version_detail + PRE_TARGETDEPS = write_version_detail + write_version_detail.commands = ./version_detail.sh + } + win32 { + QMAKE_EXTRA_TARGETS += write_version_detail + PRE_TARGETDEPS = write_version_detail + write_version_detail.commands = $$PWD/version_detail.bat + } } #################### Cross compilation for windows under Linux #################### @@ -318,6 +340,10 @@ openbsd-* { ################################### COMMON stuff ################################## +# openpgpsdk +PRE_TARGETDEPS *= ../../openpgpsdk/src/lib/libops.a +LIBS *= ../../openpgpsdk/src/lib/libops.a -lbz2 + HEADERS += dbase/cachestrapper.h \ dbase/fimonitor.h \ dbase/findex.h \ @@ -477,6 +503,7 @@ HEADERS += util/folderiterator.h \ util/rsmemcache.h \ util/rstickevent.h \ util/rsrecogn.h \ + util/rsscopetimer.h SOURCES += dbase/cachestrapper.cc \ dbase/fimonitor.cc \ @@ -626,6 +653,7 @@ SOURCES += util/folderiterator.cc \ util/rsrandom.cc \ util/rstickevent.cc \ util/rsrecogn.cc \ + util/rsscopetimer.cc upnp_miniupnpc { diff --git a/libretroshare/src/mingw32make.bat b/libretroshare/src/mingw32make.bat index f5b493923..3a58fe173 100644 --- a/libretroshare/src/mingw32make.bat +++ b/libretroshare/src/mingw32make.bat @@ -1,13 +1,12 @@ set QTDIR=C:\Qt\4.8.6 set MINGW=C:\MinGW +set GIT=C:\Program Files\Git -set PATH=%QTDIR%\bin;%MINGW%\bin;%PATH% +set PATH=%QTDIR%\bin;%MINGW%\bin;;%GIT%\bin;%PATH% -"c:\Program Files\TortoiseSVN\bin\SubWCRev" . retroshare\rsversion.in retroshare\rsversion.h +mingw32-make clean -mingw32-make clean - -qmake libretroshare.pro +qmake libretroshare.pro "CONFIG+=version_detail_bash_script" mingw32-make diff --git a/libretroshare/src/pqi/p3historymgr.cc b/libretroshare/src/pqi/p3historymgr.cc index 69bfe6402..60f279bd2 100644 --- a/libretroshare/src/pqi/p3historymgr.cc +++ b/libretroshare/src/pqi/p3historymgr.cc @@ -99,7 +99,17 @@ void p3HistoryMgr::addMessage(const ChatMessage& cm) enabled = true; } - // not handled: private distant chat + if (cm.chat_id.isGxsId() && mPrivateEnable == true) { + if (cm.incoming) { + peerName = cm.chat_id.toGxsId().toStdString(); + } else { + uint32_t status; + RsGxsId from_gxs_id; + if (rsMsgs->getDistantChatStatus(cm.chat_id.toGxsId(), status, &from_gxs_id)) + peerName = from_gxs_id.toStdString(); + } + enabled = true; + } if(enabled == false) return; @@ -115,11 +125,6 @@ void p3HistoryMgr::addMessage(const ChatMessage& cm) item->sendTime = cm.sendTime; item->recvTime = cm.recvTime; - if (cm.chat_id.isLobbyId()) { - // disable save to disc for chat lobbies until they are saved - item->saveToDisc = false; - } - item->message = cm.msg ; //librs::util::ConvertUtf16ToUtf8(chatItem->message, item->message); @@ -392,7 +397,10 @@ bool p3HistoryMgr::chatIdToVirtualPeerId(ChatId chat_id, RsPeerId &peer_id) return true; } - // not handled: private distant chat + if (chat_id.isGxsId()) { + peer_id = RsPeerId(chat_id.toGxsId()); + return true; + } return false; } @@ -428,6 +436,9 @@ bool p3HistoryMgr::getMessages(const ChatId &chatId, std::list &msgs if (chatId.isLobbyId() && mLobbyEnable == true) { enabled = true; } + if (chatId.isGxsId() && mPrivateEnable == true) { + enabled = true; + } if(enabled == false) return false; diff --git a/libretroshare/src/pqi/pqissl.cc b/libretroshare/src/pqi/pqissl.cc index 083e4a047..35007db99 100644 --- a/libretroshare/src/pqi/pqissl.cc +++ b/libretroshare/src/pqi/pqissl.cc @@ -1322,7 +1322,9 @@ int pqissl::Authorise_SSL_Connection() if(!rsBanList->isAddressAccepted(remote_addr,checking_flags,&check_result)) { - std::cerr << "(SS) connection attempt from banned IP address " << sockaddr_storage_iptostring(remote_addr) << ". Refusing it. Reason: " << check_result << ". Attack??" << std::endl; + std::cerr << "(SS) refusing connection attempt from IP address " << sockaddr_storage_iptostring(remote_addr) << ". Reason: " << + ((check_result == RSBANLIST_CHECK_RESULT_NOT_WHITELISTED)?"not whitelisted (peer requires whitelist)":"blacklisted") << std::endl; + RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_IP_BLACKLISTED, PeerId().toStdString(), sockaddr_storage_iptostring(remote_addr), "", "", check_result); reset_locked(); return 0 ; @@ -1825,6 +1827,12 @@ bool pqissl::moretoread(uint32_t usec) } #endif + if(sockfd == -1) + { + std::cerr << "pqissl::moretoread(): socket is invalid or closed." << std::endl; + return 0 ; + } + fd_set ReadFDs, WriteFDs, ExceptFDs; FD_ZERO(&ReadFDs); FD_ZERO(&WriteFDs); @@ -1887,6 +1895,12 @@ bool pqissl::cansend(uint32_t usec) "pqissl::cansend() polling socket!"); #endif + if(sockfd == -1) + { + std::cerr << "pqissl::cansend(): socket is invalid or closed." << std::endl; + return 0 ; + } + // Interestingly - This code might be portable.... fd_set ReadFDs, WriteFDs, ExceptFDs; diff --git a/libretroshare/src/retroshare/rsexpr.h b/libretroshare/src/retroshare/rsexpr.h old mode 100755 new mode 100644 diff --git a/libretroshare/src/retroshare/rsflags.h b/libretroshare/src/retroshare/rsflags.h index ec3d2b51f..de146273f 100644 --- a/libretroshare/src/retroshare/rsflags.h +++ b/libretroshare/src/retroshare/rsflags.h @@ -28,6 +28,7 @@ template class t_RsFlags32 inline t_RsFlags32 operator| (const t_RsFlags32& f) const { return t_RsFlags32(_bits | f._bits) ; } inline t_RsFlags32 operator^ (const t_RsFlags32& f) const { return t_RsFlags32(_bits ^ f._bits) ; } + inline t_RsFlags32 operator* (const t_RsFlags32& f) const { return t_RsFlags32(_bits & f._bits) ; } inline bool operator!=(const t_RsFlags32& f) const { return _bits != f._bits ; } inline bool operator==(const t_RsFlags32& f) const { return _bits == f._bits ; } diff --git a/libretroshare/src/retroshare/rsmsgs.h b/libretroshare/src/retroshare/rsmsgs.h index a92b9c1e0..d71544d15 100644 --- a/libretroshare/src/retroshare/rsmsgs.h +++ b/libretroshare/src/retroshare/rsmsgs.h @@ -90,9 +90,10 @@ #define RS_CHAT_TYPE_DISTANT 4 const ChatLobbyFlags RS_CHAT_LOBBY_FLAGS_AUTO_SUBSCRIBE( 0x00000001 ) ; -const ChatLobbyFlags RS_CHAT_LOBBY_FLAGS_ANONYMOUS ( 0x00000002 ) ; +const ChatLobbyFlags RS_CHAT_LOBBY_FLAGS_deprecated ( 0x00000002 ) ; const ChatLobbyFlags RS_CHAT_LOBBY_FLAGS_PUBLIC ( 0x00000004 ) ; const ChatLobbyFlags RS_CHAT_LOBBY_FLAGS_CHALLENGE ( 0x00000008 ) ; +const ChatLobbyFlags RS_CHAT_LOBBY_FLAGS_PGP_SIGNED ( 0x00000010 ) ; // requires the signing ID to be PGP-linked. Avoids anonymous crap. typedef uint64_t ChatLobbyId ; typedef uint64_t ChatLobbyMsgId ; diff --git a/libretroshare/src/retroshare/rstokenservice.h b/libretroshare/src/retroshare/rstokenservice.h index 97f406222..954148359 100644 --- a/libretroshare/src/retroshare/rstokenservice.h +++ b/libretroshare/src/retroshare/rstokenservice.h @@ -121,6 +121,7 @@ public: static const uint8_t GXS_REQUEST_V2_STATUS_FINISHED_INCOMPLETE; static const uint8_t GXS_REQUEST_V2_STATUS_COMPLETE; static const uint8_t GXS_REQUEST_V2_STATUS_DONE; // ONCE ALL DATA RETRIEVED. + static const uint8_t GXS_REQUEST_V2_STATUS_CANCELLED; public: diff --git a/libretroshare/src/retroshare/rsversion.h b/libretroshare/src/retroshare/rsversion.h index f0707c1e9..26cf284a6 100644 --- a/libretroshare/src/retroshare/rsversion.h +++ b/libretroshare/src/retroshare/rsversion.h @@ -2,4 +2,11 @@ #define RS_MINOR_VERSION 6 #define RS_BUILD_NUMBER 0 #define RS_BUILD_NUMBER_ADD "x" // <-- do we need this? -#define RS_REVISION_NUMBER 0001 + +// The revision number should be the 4 first bytes of the git revision hash, which is obtained using: +// git log --pretty="%H" | head -1 | cut -c1-8 +// +// Do not forget the 0x, since the RS_REVISION_NUMBER should be an integer. +// +#define RS_REVISION_STRING "01234567" +#define RS_REVISION_NUMBER 0x01234567 diff --git a/libretroshare/src/retroshare/rsversion.in b/libretroshare/src/retroshare/rsversion.in index d405810f7..cf3521ed2 100644 --- a/libretroshare/src/retroshare/rsversion.in +++ b/libretroshare/src/retroshare/rsversion.in @@ -2,4 +2,11 @@ #define RS_MINOR_VERSION 6 #define RS_BUILD_NUMBER 0 #define RS_BUILD_NUMBER_ADD "x" // <-- do we need this? -#define RS_REVISION_NUMBER $WCREV$ + +// The revision number should be the 4 first bytes of the git revision hash, which is obtained using: +// git log --pretty="%H" | head -1 | cut -c1-8 +// +// Do not forget the 0x, since the RS_REVISION_NUMBER should be an integer. +// +#define RS_REVISION_STRING "$REV$" +#define RS_REVISION_NUMBER 0x$REV$ diff --git a/libretroshare/src/rsserver/rsaccounts.cc b/libretroshare/src/rsserver/rsaccounts.cc index efbc33a87..f63dfce2e 100644 --- a/libretroshare/src/rsserver/rsaccounts.cc +++ b/libretroshare/src/rsserver/rsaccounts.cc @@ -781,9 +781,12 @@ static bool checkAccount(std::string accountdir, AccountDetails &account,std::ma std::cerr << "getRetroshareDataDirectory() BSD: " << dataDirectory; #else - /* For Linux, we have a fixed standard data directory */ - dataDirectory = "/usr/share/RetroShare06"; - std::cerr << "getRetroshareDataDirectory() Linux: " << dataDirectory; + /* For Linux, the data directory is set in libretroshare.pro */ + #ifndef DATA_DIR + #error DATA_DIR variable not set. Cannot compile. + #endif + dataDirectory = DATA_DIR; + std::cerr << "getRetroshareDataDirectory() Linux: " << dataDirectory << std::endl; #endif #else diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index 23f9ab317..c0e7697fa 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -1251,7 +1251,7 @@ int RsServer::StartupRetroShare() std::vector plugins_directories ; #ifndef WINDOWS_SYS - plugins_directories.push_back(std::string("/usr/lib/retroshare/extensions6/")) ; + plugins_directories.push_back(std::string(LIB_DIR) + "/retroshare/extensions6/") ; #endif std::string extensions_dir = rsAccounts->PathBaseDirectory() + "/extensions6/" ; plugins_directories.push_back(extensions_dir) ; diff --git a/libretroshare/src/serialiser/rstlvbase.cc b/libretroshare/src/serialiser/rstlvbase.cc index 21b99e96a..5bd704fe4 100644 --- a/libretroshare/src/serialiser/rstlvbase.cc +++ b/libretroshare/src/serialiser/rstlvbase.cc @@ -602,6 +602,11 @@ bool GetTlvString(void *data, uint32_t size, uint32_t *offset, in = std::string(strdata, strsize); } +#ifdef TLV_BASE_DEBUG + if(type == TLV_TYPE_STR_MSG) + std::cerr << "Checking string \"" << in << "\"" << std::endl; +#endif + // Check for string content. We want to avoid possible lol bombs as soon as possible. static const int number_of_suspiscious_strings = 4 ; diff --git a/libretroshare/src/serialiser/rstlvkeys.cc b/libretroshare/src/serialiser/rstlvkeys.cc index eb90fff52..968b09d83 100644 --- a/libretroshare/src/serialiser/rstlvkeys.cc +++ b/libretroshare/src/serialiser/rstlvkeys.cc @@ -649,7 +649,6 @@ bool RsTlvKeySignatureSet::GetTlv(void *data, uint32_t size, uint32_t *offset) /* get the next type */ uint16_t tlvsubtype = GetTlvType( &(((uint8_t *) data)[*offset]) ); - SignType currType; switch(tlvsubtype) { @@ -659,16 +658,13 @@ bool RsTlvKeySignatureSet::GetTlv(void *data, uint32_t size, uint32_t *offset) ok &= sign.GetTlv(data, size, offset); if (ok) { - keySignSet[currType] = sign; + keySignSet[sign_type] = sign; } } break; case TLV_TYPE_KEYSIGNATURETYPE: { ok = GetTlvUInt32(data, size, offset, TLV_TYPE_KEYSIGNATURETYPE, &sign_type); - - if(ok) - currType = sign_type; } break; default: diff --git a/libretroshare/src/services/p3idservice.cc b/libretroshare/src/services/p3idservice.cc index 6e8105770..8eaa08928 100644 --- a/libretroshare/src/services/p3idservice.cc +++ b/libretroshare/src/services/p3idservice.cc @@ -718,7 +718,9 @@ bool p3IdService::validateData(const uint8_t *data,uint32_t data_size,const RsTl if(signature_key.keyData.bin_data == NULL) { +#ifdef DEBUG_IDS std::cerr << "(EE) Cannot validate signature for unknown key " << signature.keyId << std::endl; +#endif signing_error = RS_GIXS_ERROR_KEY_NOT_AVAILABLE ; return false; } diff --git a/libretroshare/src/svn_revision.bat b/libretroshare/src/svn_revision.bat deleted file mode 100644 index d828ece90..000000000 --- a/libretroshare/src/svn_revision.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -"D:\Programme\TortoiseSVN\bin\SubWCRev" . util\rsversion.in util\rsversion.h \ No newline at end of file diff --git a/libretroshare/src/util/retrodb.cc b/libretroshare/src/util/retrodb.cc index 8438ab831..b6633c3a5 100644 --- a/libretroshare/src/util/retrodb.cc +++ b/libretroshare/src/util/retrodb.cc @@ -183,12 +183,11 @@ RetroCursor* RetroDb::sqlQuery(const std::string& tableName, const std::list::const_iterator it = columns.begin(); for(; it != columns.end(); ++it){ - columnSelection += *it; - - ++it; - if(it != columns.end()) + if (it != columns.begin()) { columnSelection += ","; - --it; + } + + columnSelection += *it; } // construct query @@ -265,6 +264,32 @@ std::string RetroDb::getKey() const return mKey; } +bool RetroDb::beginTransaction() +{ + if (!isOpen()) { + return false; + } + + return execSQL("BEGIN;"); +} + +bool RetroDb::commitTransaction() +{ + if (!isOpen()) { + return false; + } + + return execSQL("COMMIT;"); +} +bool RetroDb::rollbackTransaction() +{ + if (!isOpen()) { + return false; + } + + return execSQL("ROLLBACK;"); +} + bool RetroDb::execSQL_bind(const std::string &query, std::list ¶mBindings){ // prepare statement @@ -532,6 +557,43 @@ bool RetroDb::sqlUpdate(const std::string &tableName, std::string whereClause, c return execSQL_bind(sqlQuery, paramBindings); } +bool RetroDb::tableExists(const std::string &tableName) +{ + if (!isOpen()) { + return false; + } + + std::string sqlQuery = "PRAGMA table_info(" + tableName + ");"; + + bool result = false; + sqlite3_stmt* stmt = NULL; + + int rc = sqlite3_prepare_v2(mDb, sqlQuery.c_str(), sqlQuery.length(), &stmt, NULL); + if (rc == SQLITE_OK) { + rc = sqlite3_step(stmt); + switch (rc) { + case SQLITE_ROW: + result = true; + break; + case SQLITE_DONE: + break; + default: + std::cerr << "RetroDb::tableExists(): Error executing statement (code: " << rc << ")" + << std::endl; + return false; + } + } else { + std::cerr << "RetroDb::tableExists(): Error preparing statement\n"; + std::cerr << "Error code: " << sqlite3_errmsg(mDb) + << std::endl; + } + + if (stmt) { + sqlite3_finalize(stmt); + } + + return result; +} /********************** RetroCursor ************************/ diff --git a/libretroshare/src/util/retrodb.h b/libretroshare/src/util/retrodb.h index c0e2f8db6..8b79c0017 100644 --- a/libretroshare/src/util/retrodb.h +++ b/libretroshare/src/util/retrodb.h @@ -38,8 +38,6 @@ #include "contentvalue.h" - - class RetroCursor; /*! @@ -90,7 +88,23 @@ public: /* modifying db */ public: + /*! + * Start transaction + * @return true/false + */ + bool beginTransaction(); + /*! + * Commit transaction + * @return true/false + */ + bool commitTransaction(); + + /*! + * Rollback transaction + * @return true/false + */ + bool rollbackTransaction(); /*! * To a make query which do not return a result \n @@ -153,22 +167,13 @@ public: */ void vacuum(); - /*! - * Build the "VALUE" part of an insertiong sql query - * @param parameter contains place holder query - * @param paramBindings + * Check if table exist in database + * @param tableName table to check + * @return true/false */ - void buildInsertQueryValue(const std::map keyMap, const ContentValue& cv, - std::string& parameter, std::list& paramBindings); + bool tableExists(const std::string& tableName); - /*! - * Build the "VALUE" part of an insertiong sql query - * @param parameter contains place holder query - * @param paramBindings - */ - void buildUpdateQueryValue(const std::map keyMap, const ContentValue& cv, - std::string& parameter, std::list& paramBindings); public: static const int OPEN_READONLY; @@ -179,6 +184,22 @@ private: bool execSQL_bind(const std::string &query, std::list& blobs); + /*! + * Build the "VALUE" part of an insertiong sql query + * @param parameter contains place holder query + * @param paramBindings + */ + void buildInsertQueryValue(const std::map keyMap, const ContentValue& cv, + std::string& parameter, std::list& paramBindings); + + /*! + * Build the "VALUE" part of an insertiong sql query + * @param parameter contains place holder query + * @param paramBindings + */ + void buildUpdateQueryValue(const std::map keyMap, const ContentValue& cv, + std::string& parameter, std::list& paramBindings); + private: sqlite3* mDb; diff --git a/libretroshare/src/util/rsscopetimer.cc b/libretroshare/src/util/rsscopetimer.cc new file mode 100644 index 000000000..b3ce8fbc3 --- /dev/null +++ b/libretroshare/src/util/rsscopetimer.cc @@ -0,0 +1,59 @@ +/* + * libretroshare/src/util: rsscopetimer.cc + * + * 3P/PQI network interface for RetroShare. + * + * Copyright 2013- by Cyril Soler + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License Version 2 as published by the Free Software Foundation. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems to "retroshare@lunamutt.com". + * + */ + +#include +#include +#include "rsscopetimer.h" + +RsScopeTimer::RsScopeTimer(const std::string& name) +{ + _name = name ; + start(); +} + +RsScopeTimer::~RsScopeTimer() +{ + if (!_name.empty()) + { + std::cerr << "Time for \"" << _name << "\": " << duration() << std::endl; + } +} + +double RsScopeTimer::currentTime() +{ + timeval tv ; + gettimeofday(&tv,NULL) ; + return (tv.tv_sec % 10000) + tv.tv_usec/1000000.0f ; // the %1000 is here to allow double precision to cover the decimals. +} + +void RsScopeTimer::start() +{ + _seconds = currentTime(); +} + +double RsScopeTimer::duration() +{ + return currentTime() - _seconds; +} diff --git a/libretroshare/src/util/rsscopetimer.h b/libretroshare/src/util/rsscopetimer.h index d4b7553d9..b76ae4f96 100644 --- a/libretroshare/src/util/rsscopetimer.h +++ b/libretroshare/src/util/rsscopetimer.h @@ -31,29 +31,22 @@ // callToMeasure() ; // } // -#include + +#include class RsScopeTimer { - public: - RsScopeTimer(const std::string& name) - { - timeval tv ; - gettimeofday(&tv,NULL) ; - _seconds = (tv.tv_sec % 10000) + tv.tv_usec/1000000.0f ; // the %1000 is here to allow double precision to cover the decimals. - _name = name ; - } +public: + RsScopeTimer(const std::string& name); + ~RsScopeTimer(); - ~RsScopeTimer() - { - timeval tv ; - gettimeofday(&tv,NULL) ; - double ss = (tv.tv_sec % 10000) + tv.tv_usec/1000000.0f ; + void start(); + double duration(); - std::cerr << "Time for \"" << _name << "\": " << ss - _seconds << std::endl; - } +private: + double currentTime(); - private: - std::string _name ; - double _seconds ; +private: + std::string _name ; + double _seconds ; }; diff --git a/libretroshare/src/util/rsversioninfo.cc b/libretroshare/src/util/rsversioninfo.cc index 96520af62..04f03322f 100644 --- a/libretroshare/src/util/rsversioninfo.cc +++ b/libretroshare/src/util/rsversioninfo.cc @@ -12,7 +12,7 @@ std::string RsUtil::retroshareVersion() { std::string version; - rs_sprintf(version, "%d.%d.%d%s Revision %d", RS_MAJOR_VERSION, RS_MINOR_VERSION, RS_BUILD_NUMBER, RS_BUILD_NUMBER_ADD, RS_REVISION_NUMBER); + rs_sprintf(version, "%d.%d.%d%s Revision %08x", RS_MAJOR_VERSION, RS_MINOR_VERSION, RS_BUILD_NUMBER, RS_BUILD_NUMBER_ADD, RS_REVISION_NUMBER); return version; } diff --git a/libretroshare/src/version_detail.bat b/libretroshare/src/version_detail.bat new file mode 100644 index 000000000..ffb523a96 --- /dev/null +++ b/libretroshare/src/version_detail.bat @@ -0,0 +1,48 @@ +@echo off + +setlocal enabledelayedexpansion + +:: Search git in PATH +set GitPath= +for %%P in ("%PATH:;=" "%") do ( + if exist "%%~P.\git.exe" ( + set GitPath=%%~P + goto found_git + ) +) + +:found_git +if "%GitPath%"=="" ( + echo git not found in PATH. Version update cancelled. + endlocal + exit /B 0 +) + +echo Update version + +:: Retrieve git information +set RsHash= + +pushd "%~dp0" +for /f "tokens=1*" %%A in ('"git log --pretty=format:"%%H" --max-count=1"') do set RsHash=%%A +popd + +if "%RsHash%"=="" ( + echo Git hash not found. + endlocal + exit /B 1 +) + +:: Create file +set InFile=%~dp0retroshare\rsversion.in +set OutFile=%~dp0retroshare\rsversion.h +if exist "%OutFile%" del /Q "%OutFile%" + +for /f "tokens=* delims= " %%a in (%InFile%) do ( + set line=%%a + set line=!line:$REV$=%RsHash:~0,8%! + echo !line!>>"%OutFile%" +) + +endlocal +exit /B 0 diff --git a/libretroshare/src/version_detail.sh b/libretroshare/src/version_detail.sh index b9fbead07..d13a30978 100755 --- a/libretroshare/src/version_detail.sh +++ b/libretroshare/src/version_detail.sh @@ -5,24 +5,24 @@ set +e if ( git log -n 1 &> /dev/null); then #retrieve git information - version="git : $(git status | grep branch | cut -c 13-) $(git log -n 1 | grep commit | cut -c 8-)" + version="$(git log --pretty=format:"%H" | head -1 | cut -c1-8)" fi -if ( git log -n 1 | grep svn &> /dev/null); then - #retrieve git svn information - version="${version} svn : $(git log -n 1 | awk '/svn/ {print $2}' | head -1 | sed 's/.*@//')" -elif ( git log -n 10 | grep svn &> /dev/null); then - #retrieve git svn information - version="${version} svn closest version : $(git log -n 10 | awk '/svn/ {print $2}' | head -1 | sed 's/.*@//')" -fi +# if ( git log -n 1 | grep svn &> /dev/null); then +# #retrieve git svn information +# version="${version} svn : $(git log -n 1 | awk '/svn/ {print $2}' | head -1 | sed 's/.*@//')" +# elif ( git log -n 10 | grep svn &> /dev/null); then +# #retrieve git svn information +# version="${version} svn closest version : $(git log -n 10 | awk '/svn/ {print $2}' | head -1 | sed 's/.*@//')" +# fi -if ( svn info &> /dev/null); then - version=$(svn info | awk '/^Revision:/ {print $NF}') -fi +# if ( svn info &> /dev/null); then +# version=$(svn info | awk '/^Revision:/ {print $NF}') +# fi if [[ ${version} != '' ]]; then echo "Writing version to retroshare/rsversion.h : ${version}" - sed -e "s%RS_REVISION_NUMBER.*%RS_REVISION_NUMBER ${version}%" retroshare/rsversion.in >retroshare/rsversion.h + sed -e "s%RS_REVISION_NUMBER.*%RS_REVISION_NUMBER 0x${version}%" retroshare/rsversion.in >retroshare/rsversion.h fi echo "script version_detail.sh finished normally" exit 0 diff --git a/openpgpsdk/src/openpgpsdk.pro b/openpgpsdk/src/openpgpsdk.pro index dced8d172..f54f5d7f8 100644 --- a/openpgpsdk/src/openpgpsdk.pro +++ b/openpgpsdk/src/openpgpsdk.pro @@ -1,8 +1,10 @@ +!include("../../retroshare.pri"): error("Could not include file ../../retroshare.pri") + TEMPLATE = lib -win32 { - CONFIG += staticlib +macx { + CONFIG = staticlib } else { - CONFIG = staticlib debug + CONFIG += staticlib } DEFINES *= OPENSSL_NO_IDEA diff --git a/plugins/Common/retroshare_plugin.pri b/plugins/Common/retroshare_plugin.pri index 3165b14cf..3c9644c55 100644 --- a/plugins/Common/retroshare_plugin.pri +++ b/plugins/Common/retroshare_plugin.pri @@ -1,8 +1,16 @@ +!include("../../retroshare.pri"): error("Could not include file ../../retroshare.pri") + TEMPLATE = lib +CONFIG *= plugin DEPENDPATH += ../../libretroshare/src/ ../../retroshare-gui/src/ INCLUDEPATH += ../../libretroshare/src/ ../../retroshare-gui/src/ +unix { + target.path = "$${LIB_DIR}/retroshare/extensions6" + INSTALLS += target +} + linux-g++ { LIBS *= -ldl } @@ -20,6 +28,9 @@ win32 { QMAKE_CFLAGS += -Wextra QMAKE_CXXFLAGS += -Wextra + # solve linker warnings because of the order of the libraries + QMAKE_LFLAGS += -Wl,--start-group + OBJECTS_DIR = temp/obj MOC_DIR = temp/moc RCC_DIR = temp/qrc diff --git a/plugins/FeedReader/FeedReader.pro b/plugins/FeedReader/FeedReader.pro index acc3b4e4c..4cebc5f48 100644 --- a/plugins/FeedReader/FeedReader.pro +++ b/plugins/FeedReader/FeedReader.pro @@ -92,8 +92,7 @@ linux-* { win32 { DEFINES += CURL_STATICLIB LIBXML_STATIC LIBXSLT_STATIC LIBEXSLT_STATIC - # Change order of the libraries - LIBS = -lcurl -lxml2 -lz -lxslt -lws2_32 -lwldap32 -lssl -lcrypto -lgdi32 -lwsock32 $${LIBS} + LIBS += -lcurl -lxml2 -lz -lxslt -lws2_32 -lwldap32 -lssl -lcrypto } openbsd-* { diff --git a/plugins/LinksCloud/AddLinksDialog.cpp b/plugins/LinksCloud/AddLinksDialog.cpp deleted file mode 100644 index 366e2ccff..000000000 --- a/plugins/LinksCloud/AddLinksDialog.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/**************************************************************** - * RetroShare is distributed under the following license: - * - * Copyright (C) 2008 Robert Fernie - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - ****************************************************************/ - -#include - -#include "AddLinksDialog.h" -//#include -#include "rsrank.h" - -/* Images for context menu icons */ -#define IMAGE_EXPORTFRIEND ":/images/exportpeers_16x16.png" -#define IMAGE_GREAT ":/images/filerating5.png" -#define IMAGE_GOOD ":/images/filerating4.png" -#define IMAGE_OK ":/images/filerating3.png" -#define IMAGE_SUX ":/images/filerating2.png" -#define IMAGE_BADLINK ":/images/filerating1.png" - -/** Constructor */ -AddLinksDialog::AddLinksDialog(QString url, QWidget *parent) -: QDialog(parent) -{ - /* Invoke the Qt Designer generated object setup routine */ - ui.setupUi(this); - - ui.headerFrame->setHeaderImage(QPixmap(":/images/irkick.png")); - ui.headerFrame->setHeaderText(tr("Add Link to Cloud")); - - setAttribute ( Qt::WA_DeleteOnClose, true ); - - /* add button */ - connect(ui.addLinkButton, SIGNAL(clicked()), this, SLOT(addLinkComment())); - connect(ui.closepushButton, SIGNAL(clicked()), this, SLOT(close())); - - connect( ui.anonBox, SIGNAL( stateChanged ( int ) ), this, SLOT( load ( void ) ) ); - - ui.linkLineEdit->setText(url); - - // RetroShareLink link(url); - -// if(link.valid() && link.type() == RetroShareLink::TYPE_FILE) -// ui.titleLineEdit->setText(link.name()); -// else - ui.titleLineEdit->setText(tr("New Link")); - - load(); -} - -int AddLinksDialog::IndexToScore(int index) -{ - if ((index == -1) || (index > 4)) - return 0; - int score = 2 - index; - return score; -} - -void AddLinksDialog::addLinkComment() -{ - /* get the title / link / comment */ - QString title = ui.titleLineEdit->text(); - QString link = ui.linkLineEdit->text(); - QString comment = ui.linkTextEdit->toPlainText(); - int32_t score = AddLinksDialog::IndexToScore(ui.scoreBox->currentIndex()); - - if ((link == "") || (title == "")) - { - QMessageBox::warning(NULL, tr("Add Link Failure"), tr("Missing Link and/or Title"), QMessageBox::Ok); - /* can't do anything */ - return; - } - - /* add it either way */ - if (ui.anonBox->isChecked()) - { - rsRanks->anonRankMsg("", link.toStdWString(), title.toStdWString()); - } - else - { - rsRanks->newRankMsg(link.toStdWString(), - title.toStdWString(), - comment.toStdWString(), score); - } - - close(); -} - -void AddLinksDialog::load() -{ - if (ui.anonBox->isChecked()) - { - - /* disable comment + score */ - ui.scoreBox->setEnabled(false); - ui.linkTextEdit->setEnabled(false); - - /* done! */ - return; - } - else - { - /* enable comment + score */ - ui.scoreBox->setEnabled(true); - ui.linkTextEdit->setEnabled(true); - } -} diff --git a/plugins/LinksCloud/AddLinksDialog.h b/plugins/LinksCloud/AddLinksDialog.h deleted file mode 100644 index 9e4451117..000000000 --- a/plugins/LinksCloud/AddLinksDialog.h +++ /dev/null @@ -1,48 +0,0 @@ -/**************************************************************** - * RetroShare GUI is distributed under the following license: - * - * Copyright (C) 2008 Robert Fernie - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - ****************************************************************/ - -#ifndef _ADDLINKS_DIALOG_H -#define _ADDLINKS_DIALOG_H - -#include "ui_AddLinksDialog.h" - -class AddLinksDialog : public QDialog -{ - Q_OBJECT - -public: - /** Default Constructor */ - AddLinksDialog(QString url, QWidget *parent = 0); - /** Default Destructor */ - - static int IndexToScore(int index); - -public slots: - void addLinkComment(); - - void load(); - -private: - /** Qt Designer generated object */ - Ui::AddLinksDialog ui; -}; - -#endif diff --git a/plugins/LinksCloud/AddLinksDialog.ui b/plugins/LinksCloud/AddLinksDialog.ui deleted file mode 100644 index 26018091d..000000000 --- a/plugins/LinksCloud/AddLinksDialog.ui +++ /dev/null @@ -1,244 +0,0 @@ - - - AddLinksDialog - - - - 0 - 0 - 614 - 415 - - - - Add Link - - - - :/images/rstray3.png:/images/rstray3.png - - - - 0 - - - 0 - - - - - QFrame::NoFrame - - - QFrame::Raised - - - - - - - QFrame::NoFrame - - - QFrame::Raised - - - - - - Cancel - - - - - - - Add Link - - - false - - - true - - - - - - - Qt::Horizontal - - - - 375 - 20 - - - - - - - - Add a new Link - - - - 1 - - - - - - - - - Title: - - - - - - - Url: - - - - - - - - - - - - - - - 0 - 0 - - - - - - - - - - - - - 16777215 - 40 - - - - - - - Add Anonymous Link - - - - - - - - +2 Great! - - - - :/images/filerating5.png:/images/filerating5.png - - - - - +1 Good - - - - :/images/filerating4.png:/images/filerating4.png - - - - - 0 Okay - - - - :/images/filerating3.png:/images/filerating3.png - - - - - -1 Sux - - - - :/images/filerating2.png:/images/filerating2.png - - - - - -2 Bad Link - - - - :/images/filerating1.png:/images/filerating1.png - - - - - - - - Qt::Horizontal - - - - 299 - 20 - - - - - - - - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - - - - - - - - - - - - HeaderFrame - QFrame -
gui/common/HeaderFrame.h
- 1 -
-
- - - - -
diff --git a/plugins/LinksCloud/LinksCloud.pro b/plugins/LinksCloud/LinksCloud.pro deleted file mode 100644 index fe904d930..000000000 --- a/plugins/LinksCloud/LinksCloud.pro +++ /dev/null @@ -1,37 +0,0 @@ -!include("../Common/retroshare_plugin.pri"): error("Could not include file ../Common/retroshare_plugin.pri") - -CONFIG += qt uic qrc resources - -greaterThan(QT_MAJOR_VERSION, 4) { - # Qt 5 - QT += widgets -} - -SOURCES = p3ranking.cc LinksDialog.cpp rsrankitems.cc AddLinksDialog.cpp LinksCloudPlugin.cpp -HEADERS = rsrank.h p3ranking.h LinksDialog.h rsrankitems.h AddLinksDialog.h LinksCloudPlugin.h -FORMS = LinksDialog.ui AddLinksDialog.ui - -TARGET = LinksCloud - -RESOURCES = LinksCloud_images.qrc lang/LinksCloud_lang.qrc - -TRANSLATIONS += \ - lang/LinksCloud_ca_ES.ts \ - lang/LinksCloud_cs.ts \ - lang/LinksCloud_da.ts \ - lang/LinksCloud_de.ts \ - lang/LinksCloud_el.ts \ - lang/LinksCloud_en.ts \ - lang/LinksCloud_es.ts \ - lang/LinksCloud_fi.ts \ - lang/LinksCloud_fr.ts \ - lang/LinksCloud_hu.ts \ - lang/LinksCloud_it.ts \ - lang/LinksCloud_ja_JP.ts \ - lang/LinksCloud_ko.ts \ - lang/LinksCloud_nl.ts \ - lang/LinksCloud_pl.ts \ - lang/LinksCloud_ru.ts \ - lang/LinksCloud_sv.ts \ - lang/LinksCloud_tr.ts \ - lang/LinksCloud_zh_CN.ts \ No newline at end of file diff --git a/plugins/LinksCloud/LinksCloudPlugin.cpp b/plugins/LinksCloud/LinksCloudPlugin.cpp deleted file mode 100644 index f1993988b..000000000 --- a/plugins/LinksCloud/LinksCloudPlugin.cpp +++ /dev/null @@ -1,117 +0,0 @@ -#include -#include -#include - -#include "LinksCloudPlugin.h" -#include "LinksDialog.h" - -static void *inited = new LinksCloudPlugin() ; - -extern "C" { - void *RETROSHARE_PLUGIN_provide() - { - static LinksCloudPlugin *p = new LinksCloudPlugin() ; - - return (void*)p ; - } - // This symbol contains the svn revision number grabbed from the executable. - // It will be tested by RS to load the plugin automatically, since it is safe to load plugins - // with same revision numbers, assuming that the revision numbers are up-to-date. - // - uint32_t RETROSHARE_PLUGIN_revision = SVN_REVISION_NUMBER ; - - // This symbol contains the svn revision number grabbed from the executable. - // It will be tested by RS to load the plugin automatically, since it is safe to load plugins - // with same revision numbers, assuming that the revision numbers are up-to-date. - // - uint32_t RETROSHARE_PLUGIN_api = RS_PLUGIN_API_VERSION ; -} - -#define IMAGE_LINKS ":/images/irkick.png" - -void LinksCloudPlugin::getPluginVersion(int& major,int& minor,int& svn_rev) const -{ - major = 5 ; - minor = 4 ; - svn_rev = SVN_REVISION_NUMBER ; -} - -LinksCloudPlugin::LinksCloudPlugin() -{ - mRanking = NULL ; - mainpage = NULL ; - mIcon = NULL ; - mPlugInHandler = NULL; - mPeers = NULL; - mFiles = NULL; -} - -void LinksCloudPlugin::setInterfaces(RsPlugInInterfaces &interfaces){ - - mPeers = interfaces.mPeers; - mFiles = interfaces.mFiles; -} - -MainPage *LinksCloudPlugin::qt_page() const -{ - if(mainpage == NULL) - mainpage = new LinksDialog(mPeers, mFiles) ; - - return mainpage ; -} - -RsCacheService *LinksCloudPlugin::rs_cache_service() const -{ - if(mRanking == NULL) - { - mRanking = new p3Ranking(mPlugInHandler) ; // , 3600 * 24 * 30 * 6); // 6 Months - rsRanks = mRanking ; - } - - return mRanking ; -} - -void LinksCloudPlugin::setPlugInHandler(RsPluginHandler *pgHandler){ - mPlugInHandler = pgHandler; - -} - -QIcon *LinksCloudPlugin::qt_icon() const -{ - if(mIcon == NULL) - { - Q_INIT_RESOURCE(LinksCloud_images) ; - - mIcon = new QIcon(IMAGE_LINKS) ; - } - - return mIcon ; -} - -std::string LinksCloudPlugin::getShortPluginDescription() const -{ - return QApplication::translate("LinksCloudPlugin", "This plugin provides a set of cached links, and a voting system to promote them.").toUtf8().constData(); -} - -std::string LinksCloudPlugin::getPluginName() const -{ - return QApplication::translate("LinksCloudPlugin", "LinksCloud").toUtf8().constData(); -} - -QTranslator* LinksCloudPlugin::qt_translator(QApplication */*app*/, const QString& languageCode, const QString& externalDir) const -{ - if (languageCode == "en") { - return NULL; - } - - QTranslator* translator = new QTranslator(); - - if (translator->load(externalDir + "/LinksCloud_" + languageCode + ".qm")) { - return translator; - } else if (translator->load(":/lang/LinksCloud_" + languageCode + ".qm")) { - return translator; - } - - delete(translator); - return NULL; -} diff --git a/plugins/LinksCloud/LinksCloudPlugin.h b/plugins/LinksCloud/LinksCloudPlugin.h deleted file mode 100644 index e1c590ca5..000000000 --- a/plugins/LinksCloud/LinksCloudPlugin.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include -#include -#include "p3ranking.h" - -class LinksCloudPlugin: public RsPlugin -{ - public: - LinksCloudPlugin() ; - virtual ~LinksCloudPlugin() {} - - virtual RsCacheService *rs_cache_service() const ; - virtual MainPage *qt_page() const ; - virtual QIcon *qt_icon() const ; - virtual uint16_t rs_service_id() const { return RS_SERVICE_TYPE_RANK ; } - virtual QTranslator *qt_translator(QApplication *app, const QString& languageCode, const QString& externalDir) const; - - virtual void getPluginVersion(int& major,int& minor,int& svn_rev) const ; - virtual void setPlugInHandler(RsPluginHandler *pgHandler); - - virtual std::string configurationFileName() const { return std::string() ; } - - virtual std::string getShortPluginDescription() const ; - virtual std::string getPluginName() const; - virtual void setInterfaces(RsPlugInInterfaces& interfaces); - private: - mutable p3Ranking *mRanking ; - mutable RsPluginHandler *mPlugInHandler; - mutable RsFiles* mFiles; - mutable RsPeers* mPeers; - mutable MainPage* mainpage ; - mutable QIcon* mIcon ; -}; - diff --git a/plugins/LinksCloud/LinksCloud_images.qrc b/plugins/LinksCloud/LinksCloud_images.qrc deleted file mode 100644 index 8b2550249..000000000 --- a/plugins/LinksCloud/LinksCloud_images.qrc +++ /dev/null @@ -1,5 +0,0 @@ - - - images/irkick.png - - diff --git a/plugins/LinksCloud/LinksDialog.cpp b/plugins/LinksCloud/LinksDialog.cpp deleted file mode 100644 index 08ee39609..000000000 --- a/plugins/LinksCloud/LinksDialog.cpp +++ /dev/null @@ -1,994 +0,0 @@ -/**************************************************************** - * RetroShare is distributed under the following license: - * - * Copyright (C) 2008 Robert Fernie - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - ****************************************************************/ - -#include -#include -#include -#include -#include -#include "LinksDialog.h" -#include -#include "AddLinksDialog.h" -#include "rsrank.h" -#include "util/QtVersion.h" - -#include - - -/* Images for context menu icons */ -#define IMAGE_EXPORTFRIEND ":/images/exportpeers_16x16.png" -#define IMAGE_GREAT ":/images/filerating5.png" -#define IMAGE_GOOD ":/images/filerating4.png" -#define IMAGE_OK ":/images/filerating3.png" -#define IMAGE_SUX ":/images/filerating2.png" -#define IMAGE_BADLINK ":/images/filerating1.png" -#define IMAGE_NOCOMMENTRATING ":/images/filerating0.png" -#define IMAGE_DOWNLOAD ":/images/download16.png" - -/****** - * #define LINKS_DEBUG 1 - *****/ - -/** Constructor */ -LinksDialog::LinksDialog(RsPeers *peers, RsFiles *files, QWidget *parent) -: MainPage(parent), mPeers(peers), mFiles(files) -{ - /* Invoke the Qt Designer generated object setup routine */ - ui.setupUi(this); - - connect( ui.linkTreeWidget, SIGNAL( customContextMenuRequested( QPoint ) ), this, SLOT( linkTreeWidgetCostumPopupMenu( QPoint ) ) ); - - - /* link combos */ - connect( ui.rankComboBox, SIGNAL( currentIndexChanged( int ) ), this, SLOT( changedSortRank( int ) ) ); - connect( ui.periodComboBox, SIGNAL( currentIndexChanged( int ) ), this, SLOT( changedSortPeriod( int ) ) ); - connect( ui.fromComboBox, SIGNAL( currentIndexChanged( int ) ), this, SLOT( changedSortFrom( int ) ) ); - connect( ui.topComboBox, SIGNAL( currentIndexChanged( int ) ), this, SLOT( changedSortTop( int ) ) ); - - /* add button */ - connect( ui.addButton, SIGNAL( clicked( void ) ), this, SLOT( addLinkComment( void ) ) ); - connect( ui.expandButton, SIGNAL( clicked( void ) ), this, SLOT( toggleWindows( void ) ) ); - - connect( ui.addToolButton, SIGNAL( clicked( ) ), this, SLOT( addNewLink( ) ) ); - - connect( ui.linkTreeWidget, SIGNAL( currentItemChanged ( QTreeWidgetItem *, QTreeWidgetItem * ) ), - this, SLOT( changedItem ( QTreeWidgetItem *, QTreeWidgetItem * ) ) ); - - connect( ui.linkTreeWidget, SIGNAL( itemDoubleClicked ( QTreeWidgetItem *, int ) ), - this, SLOT( openLink ( QTreeWidgetItem *, int ) ) ); - - connect( ui.anonBox, SIGNAL( stateChanged ( int ) ), this, SLOT( checkAnon ( void ) ) ); - - mStart = 0; - - - /* Set header resize modes and initial section sizes */ - QHeaderView * _header = ui.linkTreeWidget->header () ; - QHeaderView_setSectionResizeMode(_header, 0, QHeaderView::Interactive); - QHeaderView_setSectionResizeMode(_header, 1, QHeaderView::Interactive); - QHeaderView_setSectionResizeMode(_header, 2, QHeaderView::Interactive); - - _header->resizeSection ( 0, 400 ); - _header->resizeSection ( 1, 60 ); - _header->resizeSection ( 2, 150 ); - - ui.linkTreeWidget->setSortingEnabled(true); - - ui.linklabel->setMinimumWidth(20); - - - /* Set a GUI update timer - much cleaner than - * doing everything through the notify agent - */ - - QTimer *timer = new QTimer(this); - timer->connect(timer, SIGNAL(timeout()), this, SLOT(checkUpdate())); - timer->start(1000); -} - -void LinksDialog::checkUpdate() -{ - /* update */ - if (!rsRanks) - { - std::cerr << " rsRanks = 0 !!!!" << std::endl; - return; - } - - if (rsRanks->updated()) - { -#ifdef LINKS_DEBUG - std::cerr << " rsRanks was updated -> redraw()" << std::endl; -#endif - updateLinks(); - } - - return; -} - -void LinksDialog::linkTreeWidgetCostumPopupMenu( QPoint point ) -{ - - QMenu contextMnu( this ); - - QAction *voteupAct = new QAction(QIcon(IMAGE_EXPORTFRIEND), tr( "Share Link Anonymously" ), &contextMnu ); - connect( voteupAct , SIGNAL( triggered() ), this, SLOT( voteup_anon() ) ); - - - QMenu *voteMenu = new QMenu( tr("Vote on Link"), &contextMnu ); - voteMenu->setIcon(QIcon(IMAGE_EXPORTFRIEND)); - - QAction *vote_p2 = new QAction( QIcon(IMAGE_GREAT), tr("+2 Great!"), &contextMnu ); - connect( vote_p2 , SIGNAL( triggered() ), this, SLOT( voteup_p2() ) ); - voteMenu->addAction(vote_p2); - QAction *vote_p1 = new QAction( QIcon(IMAGE_GOOD), tr("+1 Good"), &contextMnu ); - connect( vote_p1 , SIGNAL( triggered() ), this, SLOT( voteup_p1() ) ); - voteMenu->addAction(vote_p1); - QAction *vote_p0 = new QAction( QIcon(IMAGE_OK), tr("0 Okay"), &contextMnu ); - connect( vote_p0 , SIGNAL( triggered() ), this, SLOT( voteup_p0() ) ); - voteMenu->addAction(vote_p0); - QAction *vote_m1 = new QAction( QIcon(IMAGE_SUX), tr("-1 Sux"), &contextMnu ); - connect( vote_m1 , SIGNAL( triggered() ), this, SLOT( voteup_m1() ) ); - voteMenu->addAction(vote_m1); - QAction *vote_m2 = new QAction( QIcon(IMAGE_BADLINK), tr("-2 Bad Link"), &contextMnu ); - connect( vote_m2 , SIGNAL( triggered() ), this, SLOT( voteup_m2() ) ); - voteMenu->addAction(vote_m2); - - QAction *downloadAct = new QAction(QIcon(IMAGE_DOWNLOAD), tr("Download"), &contextMnu); - connect(downloadAct, SIGNAL(triggered()), this, SLOT(downloadSelected())); - - contextMnu.addAction(voteupAct); - contextMnu.addSeparator(); - contextMnu.addMenu(voteMenu); - contextMnu.addSeparator(); - contextMnu.addAction(downloadAct); - - contextMnu.exec(ui.linkTreeWidget->viewport()->mapToGlobal(point)); -} - -void LinksDialog::changedSortRank( int index ) -{ - /* update */ - if (!rsRanks) - return; - - /* translate */ - uint32_t type = 0; - switch (index) - { - case 1: - type = RS_RANK_TIME; - break; - case 2: - type = RS_RANK_SCORE; - break; - default: - case 0: - type = RS_RANK_ALG; - break; - } - - if (type) - { - rsRanks->setSortMethod(type); - } - updateLinks(); -} - -void LinksDialog::changedSortPeriod( int index ) -{ - /* update */ - if (!rsRanks) - return; - - /* translate */ - uint32_t period = 0; - switch (index) - { - case 1: - period = 60 * 60 * 24 * 7; /* WEEK */ - break; - case 2: - period = 60 * 60 * 24; /* DAY */ - break; - default: - case 0: - period = 60 * 60 * 24 * 30; /* MONTH */ - break; - } - - if (period) - { - rsRanks->setSortPeriod(period); - } - updateLinks(); -} - -void LinksDialog::changedSortFrom( int index ) -{ - /* update */ - if (!rsRanks) - return; - - std::list peers; - - /* translate */ - switch (index) - { - default: - case 0: - break; - case 1: - peers.push_back(mPeers->getOwnId()); - break; - } - - if (peers.size() < 1) - { - rsRanks->clearPeerFilter(); - } - else - { - rsRanks->setPeerFilter(peers); - } - updateLinks(); -} - -#define ENTRIES_PER_BLOCK 100 - -void LinksDialog::changedSortTop( int index ) -{ - /* update */ - if (!rsRanks) - return; - - std::list peers; - - /* translate */ - switch (index) - { - default: - case 0: - mStart = 0; - break; - case 1: - mStart = 1 * ENTRIES_PER_BLOCK; - break; - case 2: - mStart = 2 * ENTRIES_PER_BLOCK; - break; - case 3: - mStart = 3 * ENTRIES_PER_BLOCK; - break; - case 4: - mStart = 4 * ENTRIES_PER_BLOCK; - break; - case 5: - mStart = -1; - break; - } - updateLinks(); -} - - -/* get the list of Links from the RsRanks. */ -void LinksDialog::updateLinks() -{ - - std::list rids; - std::list::iterator rit; - std::list::iterator cit; - -#ifdef LINKS_DEBUG - std::cerr << "LinksDialog::updateLinks()" << std::endl; -#endif - - /* Work out the number/entries to show */ - uint32_t count = rsRanks->getRankingsCount(); - uint32_t start; - - uint32_t entries = ENTRIES_PER_BLOCK; - if (count < entries) - { - entries = count; - } - - if (mStart == -1) - { - /* backwards */ - start = count-entries; - } - else - { - start = mStart; - if (start + entries > count) - { - start = count - entries; - } - } - - /* get a link to the table */ - QTreeWidget *linkWidget = ui.linkTreeWidget; - QList items; - - rsRanks->getRankings(start, entries, rids); - float maxRank = rsRanks->getMaxRank(); - - for(rit = rids.begin(); rit != rids.end(); rit++) - { - RsRankDetails detail; - if (!rsRanks->getRankDetails(*rit, detail)) - { - continue; - } - - /* create items */ - QTreeWidgetItem *item = new QTreeWidgetItem((QTreeWidget*)0); - - /* (0) Title */ - { - item -> setText(0, QString::fromStdWString(detail.title)); - item -> setSizeHint(0, QSize( 20,20 ) ); - - /* Bold and bigger */ - /*QFont font = item->font(0); - font.setBold(true); - font.setPointSize(font.pointSize() + 2); - item->setFont(0, font);*/ - } - - /* (1) Rank */ - { - std::ostringstream out; - out << 100 * (detail.rank / (maxRank + 0.01)); - item -> setText(1, QString::fromStdString(out.str())); - item -> setSizeHint(1, QSize( 20,20 ) ); - - /* Bold and bigger */ - /*QFont font = item->font(1); - font.setBold(true); - font.setPointSize(font.pointSize() + 2); - item->setFont(1, font);*/ - } - - /* (2) Link */ - { - item -> setText(2, QString::fromStdWString(detail.link)); - item -> setSizeHint(2, QSize( 20,20 ) ); - - /* Bold and bigger */ - /*QFont font = item->font(2); - font.setBold(true); - font.setPointSize(font.pointSize() + 2); - item->setFont(2, font);*/ - } - - /* (3) Date */ - /*{ - QDateTime qtime; - qtime.setTime_t(it->lastPost); - QString timestamp = qtime.toString("yyyy-MM-dd hh:mm:ss"); - item -> setText(3, timestamp); - }*/ - - - /* (4) rid */ - item -> setText(4, QString::fromStdString(detail.rid)); - - - /* add children */ - int i = 0; - for(cit = detail.comments.begin(); - cit != detail.comments.end(); cit++, i++) - { - /* create items */ - QTreeWidgetItem *child = new QTreeWidgetItem((QTreeWidget*)0); - - QString commentText; - QString peerScore; - if (cit->score > 1) - { - peerScore = "[+2] "; - child -> setIcon(0,(QIcon(IMAGE_GREAT))); - item -> setIcon(0,(QIcon(IMAGE_GREAT))); - //peerScore = "[+2 Great Link] "; - } - else if (cit->score == 1) - { - peerScore = "[+1] "; - child -> setIcon(0,(QIcon(IMAGE_GOOD))); - item -> setIcon(0,(QIcon(IMAGE_GOOD))); - //peerScore = "[+1 Good] "; - } - else if (cit->score == 0) - { - peerScore = "[+0] "; - child -> setIcon(0,(QIcon(IMAGE_OK))); - item -> setIcon(0,(QIcon(IMAGE_OK))); - //peerScore = "[+0 Okay] "; - } - else if (cit->score == -1) - { - peerScore = "[-1] "; - child -> setIcon(0,(QIcon(IMAGE_SUX))); - item -> setIcon(0,(QIcon(IMAGE_SUX))); - //peerScore = "[-1 Not Worth It] "; - } - else //if (cit->score < -1) - { - peerScore = "[-2 BAD] "; - child -> setIcon(0,(QIcon(IMAGE_BADLINK))); - item -> setIcon(0,(QIcon(IMAGE_BADLINK))); - //peerScore = "[-2 BAD Link] "; - } - - /* (0) Comment */ - if (cit->comment != L"") - { - commentText = peerScore + QString::fromStdWString(cit->comment); - } - else - { - commentText = peerScore + "No Comment"; - } - child -> setText(0, commentText); - - /* (2) Peer / Date */ - { - QDateTime qtime; - qtime.setTime_t(cit->timestamp); - QString timestamp = qtime.toString("yyyy-MM-dd hh:mm:ss"); - - QString peerLabel = QString::fromStdString(mPeers->getPeerName(cit->id)); - if (peerLabel == "") - { - peerLabel = "<"; - peerLabel += QString::fromStdString(cit->id); - peerLabel += ">"; - } - peerLabel += " "; - - peerLabel += timestamp; - child -> setText(2, peerLabel); - - } - - /* (4) Id */ - child -> setText(4, QString::fromStdString(cit->id)); - - if (i % 2 == 1) - { - /* set to light gray background */ - child->setBackground(0,QBrush(Qt::lightGray)); - child->setBackground(1,QBrush(Qt::lightGray)); - child->setBackground(2,QBrush(Qt::lightGray)); - } - - /* push to items */ - item->addChild(child); - } - - /* add to the list */ - items.append(item); - } - - /* remove old items */ - linkWidget->clear(); - linkWidget->setColumnCount(3); - - /* add the items in! */ - linkWidget->insertTopLevelItems(0, items); - - linkWidget->update(); /* update display */ - - -} - -void LinksDialog::openLink ( QTreeWidgetItem * item, int ) -{ -#ifdef LINKS_DEBUG - std::cerr << "LinksDialog::openLink()" << std::endl; -#endif - - /* work out the ids */ - if (!item) - { - -#ifdef LINKS_DEBUG - std::cerr << "LinksDialog::openLink() Failed Item" << std::endl; -#endif - return; - } - - std::string rid; - std::string pid; - - QTreeWidgetItem *parent = item->parent(); - if (parent) - { - /* a child comment -> ignore double click */ -#ifdef LINKS_DEBUG - std::cerr << "LinksDialog::openLink() Failed Child" << std::endl; -#endif - return; - } - -#ifdef LINKS_DEBUG - std::cerr << "LinksDialog::openLink() " << (item->text(2)).toStdString() << std::endl; -#endif - /* open a browser */ - QUrl url(item->text(2)); - QDesktopServices::openUrl ( url ); - - /* close expansion */ - bool state = item->isExpanded(); - item->setExpanded(!state); -} - -void LinksDialog::changedItem(QTreeWidgetItem *curr, QTreeWidgetItem *) -{ - /* work out the ids */ - if (!curr) - { - updateComments("", ""); - return; - } - - std::string rid; - std::string pid; - - QTreeWidgetItem *parent = curr->parent(); - if (parent) - { - rid = (parent->text(4)).toStdString(); - pid = (curr->text(4)).toStdString(); - -#ifdef LINKS_DEBUG - std::cerr << "LinksDialog::changedItem() Rid: " << rid << " Pid: " << pid; - std::cerr << std::endl; -#endif - - updateComments(rid, pid); - } - else - { - rid = (curr->text(4)).toStdString(); - -#ifdef LINKS_DEBUG - std::cerr << "LinksDialog::changedItem() Rid: " << rid << " Pid: NULL"; - std::cerr << std::endl; -#endif - - updateComments(rid, ""); - } -} - -void LinksDialog::checkAnon() -{ - changedItem(ui.linkTreeWidget->currentItem(), NULL); -} - - -int IndexToScore(int index) -{ - if ((index == -1) || (index > 4)) - return 0; - int score = 2 - index; - return score; -} - -int ScoreToIndex(int score) -{ - if ((score < -2) || (score > 2)) - return 2; - int index = 2 - score; - return index; -} - - -/* get the list of Links from the RsRanks. */ -void LinksDialog::updateComments(std::string rid, std::string ) -{ - std::list::iterator cit; - - - if (ui.anonBox->isChecked()) - { - /* empty everything */ - ui.titleLineEdit->setText(""); - ui.linkLineEdit->setText(""); - ui.linkTextEdit->setText(""); - ui.scoreBox->setCurrentIndex(ScoreToIndex(0)); - mLinkId = rid; /* must be set for Context Menu */ - - /* disable comment + score */ - ui.scoreBox->setEnabled(false); - ui.linkTextEdit->setEnabled(false); - - /* done! */ - return; - } - else - { - /* enable comment + score */ - ui.scoreBox->setEnabled(true); - ui.linkTextEdit->setEnabled(true); - } - - - RsRankDetails detail; - if ((rid == "") || (!rsRanks->getRankDetails(rid, detail))) - { - /* clear it up */ - ui.titleLineEdit->setText(""); - ui.linkLineEdit->setText(""); - ui.linkTextEdit->setText(""); - ui.scoreBox->setCurrentIndex(ScoreToIndex(0)); - mLinkId = rid; - return; - } - - - /* set Link details */ - ui.titleLineEdit->setText(QString::fromStdWString(detail.title)); - ui.linkLineEdit->setText(QString::fromStdWString(detail.link)); - ui.linklabel->setText(" " + QString::fromStdWString(detail.link) +""); - - - if (mLinkId == rid) - { - /* leave comments */ - //ui.linkTextEdit->setText(""); - return; - } - - mLinkId = rid; - - /* Add your text to the comment */ - std::string ownId = mPeers->getOwnId(); - - for(cit = detail.comments.begin(); cit != detail.comments.end(); cit++) - { - if (cit->id == ownId) - break; - } - - if (cit != detail.comments.end()) - { - QString comment = QString::fromStdWString(cit->comment); - ui.linkTextEdit->setText(comment); - ui.scoreBox->setCurrentIndex(ScoreToIndex(cit->score)); - } - else - { - ui.linkTextEdit->setText(""); - ui.scoreBox->setCurrentIndex(ScoreToIndex(0)); - - } - - return; -} - -void LinksDialog::addLinkComment( void ) -{ - /* get the title / link / comment */ - QString title = ui.titleLineEdit->text(); - QString link = ui.linkLineEdit->text(); - QString comment = ui.linkTextEdit->toPlainText(); - int32_t score = IndexToScore(ui.scoreBox->currentIndex()); - - if ((mLinkId == "") || (ui.anonBox->isChecked())) - { - if ((link == "") || (title == "")) - { - QMessageBox::warning ( NULL, tr("Add Link Failure"), tr("Missing Link and/or Title"), QMessageBox::Ok); - /* can't do anything */ - return; - } - - /* add it either way */ - if (ui.anonBox->isChecked()) - { - rsRanks->anonRankMsg("", link.toStdWString(), title.toStdWString()); - } - else - { - rsRanks->newRankMsg( - link.toStdWString(), - title.toStdWString(), - comment.toStdWString(), score); - } - - updateLinks(); - return; - } - - /* get existing details */ - - RsRankDetails detail; - if (!rsRanks->getRankDetails(mLinkId, detail)) - { - /* strange error! */ - QMessageBox::warning ( NULL, tr("Add Link Failure"), tr("Missing Link Data"), QMessageBox::Ok); - return; - } - - if (link.toStdWString() == detail.link) /* same link! - we can add a comment */ - { - if (comment == "") /* no comment! */ - { - QMessageBox::warning ( NULL, tr("Add Link Failure"), tr("Missing Comment"), QMessageBox::Ok); - return; - } - - rsRanks->updateComment(mLinkId, - comment.toStdWString(), - score); - } - else - { - QMessageBox::StandardButton sb = QMessageBox::Yes; - - if ((title.toStdWString() == detail.title) /* same title! - wrong */ - || (title == "")) - { - sb = QMessageBox::question ( NULL, tr("Link Title Not Changed"), tr("Do you want to continue?"), (QMessageBox::Yes | QMessageBox::No)); - } - - /* add Link! */ - if (sb == QMessageBox::Yes) - { - rsRanks->newRankMsg( - link.toStdWString(), - title.toStdWString(), - comment.toStdWString(), - score); - } - } - updateLinks(); - return; -} - -void LinksDialog::toggleWindows( void ) -{ - /* if msg header visible -> hide by changing splitter - */ - - QList sizeList = ui.msgSplitter->sizes(); - QList::iterator it; - - int listSize = 0; - int msgSize = 0; - int i = 0; - - for(it = sizeList.begin(); it != sizeList.end(); it++, i++) - { - if (i == 0) - { - listSize = (*it); - } - else if (i == 1) - { - msgSize = (*it); - } - } - - int totalSize = listSize + msgSize; - - bool toShrink = true; - if (msgSize < (int) totalSize / 10) - { - toShrink = false; - } - - QList newSizeList; - if (toShrink) - { - newSizeList.push_back(totalSize); - newSizeList.push_back(0); - ui.expandButton->setIcon(QIcon(QString(":/images/edit_add24.png"))); - ui.expandButton->setToolTip(tr("Expand")); - } - else - { - newSizeList.push_back(totalSize * 3/4); - newSizeList.push_back(totalSize * 1/4); - ui.expandButton->setIcon(QIcon(QString(":/images/edit_remove24.png"))); - ui.expandButton->setToolTip(tr("Hide")); - } - - ui.msgSplitter->setSizes(newSizeList); - return; -} - - -QTreeWidgetItem *LinksDialog::getCurrentLine() -{ - /* get the current, and extract the Id */ - - /* get a link to the table */ - QTreeWidget *peerWidget = ui.linkTreeWidget; - QTreeWidgetItem *item = peerWidget -> currentItem(); - if (!item) - { -#ifdef LINKS_DEBUG - std::cerr << "Invalid Current Item" << std::endl; -#endif - return NULL; - } - -#ifdef LINKS_DEBUG - /* Display the columns of this item. */ - std::ostringstream out; - out << "CurrentPeerItem: " << std::endl; - - for(int i = 1; i < 6; i++) - { - QString txt = item -> text(i); - out << "\t" << i << ":" << txt.toStdString() << std::endl; - } - std::cerr << out.str(); -#endif - - return item; -} - -void LinksDialog::voteup_anon() -{ - //QTreeWidgetItem *c = getCurrentLine(); - - if (mLinkId == "") - { - return; - } - - RsRankDetails detail; - if (!rsRanks->getRankDetails(mLinkId, detail)) - { - /* not there! */ - return; - } - - QString link = QString::fromStdWString(detail.link); -#ifdef LINKS_DEBUG - std::cerr << "LinksDialog::voteup_anon() : " << link.toStdString() << std::endl; -#endif - // need a proper anon sharing option. - rsRanks->anonRankMsg(mLinkId, detail.link, detail.title); -} - - - - -void LinksDialog::voteup_score(int score) -{ - if (mLinkId == "") - { - return; - } - - RsRankDetails detail; - if (!rsRanks->getRankDetails(mLinkId, detail)) - { - /* not there! */ - return; - } - - QString link = QString::fromStdWString(detail.link); - std::wstring comment; -#ifdef LINKS_DEBUG - std::cerr << "LinksDialog::voteup_score() : " << link.toStdString() << std::endl; -#endif - - - std::list::iterator cit; - /* Add your text to the comment */ - std::string ownId = mPeers->getOwnId(); - - for(cit = detail.comments.begin(); cit != detail.comments.end(); cit++) - { - if (cit->id == ownId) - break; - } - - if (cit != detail.comments.end()) - { - comment = cit->comment; - } - - rsRanks->updateComment(mLinkId, comment, score); -} - - -void LinksDialog::voteup_p2() -{ - voteup_score(2); -} - -void LinksDialog::voteup_p1() -{ - voteup_score(1); -} - -void LinksDialog::voteup_p0() -{ - voteup_score(0); -} - -void LinksDialog::voteup_m1() -{ - voteup_score(-1); -} - -void LinksDialog::voteup_m2() -{ - voteup_score(-2); -} - -void LinksDialog::downloadSelected() -{ - if (mLinkId == "") - { - return; - } - - RsRankDetails detail; - if (!rsRanks->getRankDetails(mLinkId, detail)) - { - /* not there! */ - return; - } - - QString link = QString::fromStdWString(detail.link); - std::wstring comment; -#ifdef LINKS_DEBUG - std::cerr << "LinksDialog::downloadSelected() : " << link.toStdString() << std::endl; -#endif - - //RetroShareLink rslink(QString::fromStdWString(detail.link)); - - //if(!rslink.valid() || rslink.type() != RetroShareLink::TYPE_FILE) - //{ -// QMessageBox::critical(NULL,"Badly formed link","This link is badly formed. Can't parse/use it. This is a bug. Please contact the developers.") ; -// return ; -// } - - /* retrieve all peers id for this file */ -// FileInfo info; -// rsFiles->FileDetails(rslink.hash().toStdString(), 0, info); - -// std::list srcIds; -// std::list::iterator pit; -// for (pit = info.peers.begin(); pit != info.peers.end(); pit ++) -// srcIds.push_back(pit->peerId); - -// rsFiles->FileRequest(rslink.name().toStdString(), rslink.hash().toStdString(), rslink.size(), "", 0, srcIds); -} - -void LinksDialog::addNewLink() -{ - - AddLinksDialog *nAddLinksDialog = new AddLinksDialog(""); - - nAddLinksDialog->show(); - - /* window will destroy itself! */ -} diff --git a/plugins/LinksCloud/LinksDialog.h b/plugins/LinksCloud/LinksDialog.h deleted file mode 100644 index 58c763449..000000000 --- a/plugins/LinksCloud/LinksDialog.h +++ /dev/null @@ -1,97 +0,0 @@ -/**************************************************************** - * RetroShare GUI is distributed under the following license: - * - * Copyright (C) 2008 Robert Fernie - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - ****************************************************************/ - -#ifndef _LINKS_DIALOG_H -#define _LINKS_DIALOG_H - -#include -#include -#include -#include "ui_LinksDialog.h" - - -class LinksDialog : public MainPage -{ - Q_OBJECT - -public: - /** Default Constructor */ - LinksDialog(RsPeers* peers, RsFiles* files, QWidget *parent = 0); - /** Default Destructor */ - - void insertExample(); - -private slots: - /** Create the context popup menu and it's submenus */ - void linkTreeWidgetCostumPopupMenu( QPoint point ); - - void voteup_anon(); - void voteup_score(int score); - void voteup_p2(); - void voteup_p1(); - void voteup_p0(); - void voteup_m1(); - void voteup_m2(); - void downloadSelected(); - - void changedSortRank( int index ); - void changedSortPeriod( int index ); - void changedSortFrom( int index ); - void changedSortTop( int index ); - - void updateLinks(); - void addLinkComment( void ); - void toggleWindows( void ); - - void openLink ( QTreeWidgetItem * item, int column ); - void changedItem(QTreeWidgetItem *curr, QTreeWidgetItem *prev); - void checkAnon(); - - void checkUpdate(); - - void addNewLink(); - -private: - -void updateComments(std::string rid, std::string pid); - - int mStart; /* start of rank list */ - std::string mLinkId; - - /* Worker Functions */ - /* (1) Update Display */ - - /* (2) Utility Fns */ - QTreeWidgetItem *getCurrentLine(); - - QTreeWidget *exampletreeWidget; - - // gui interface - RsPeers* mPeers; - RsFiles* mFiles; - - - /** Qt Designer generated object */ - Ui::LinksDialog ui; -}; - -#endif - diff --git a/plugins/LinksCloud/LinksDialog.ui b/plugins/LinksCloud/LinksDialog.ui deleted file mode 100644 index 6c2b06ab4..000000000 --- a/plugins/LinksCloud/LinksDialog.ui +++ /dev/null @@ -1,572 +0,0 @@ - - - LinksDialog - - - - 0 - 0 - 738 - 583 - - - - - 6 - - - 0 - - - - - - 0 - 0 - - - - Qt::Vertical - - - - - - - Qt::CustomContextMenu - - - - Title / Comment - - - - - Score - - - - - Peer / Link - - - - - - - - - - - - :/images/edit_remove24.png:/images/edit_remove24.png - - - - - - - Qt::Horizontal - - - - 16 - 20 - - - - - - - - - 75 - true - - - - Sort by - - - - - - - - Combo - - - - - Time - - - - :/images/kalarm.png:/images/kalarm.png - - - - - Ranking - - - - :/images/records.png:/images/records.png - - - - - - - - Qt::Horizontal - - - - 16 - 20 - - - - - - - - - 75 - true - - - - In last - - - - - - - - Month - - - - :/images/view_calendar_month.png:/images/view_calendar_month.png - - - - - Week - - - - :/images/view_calendar_week.png:/images/view_calendar_week.png - - - - - Day - - - - :/images/view_calendar_day.png:/images/view_calendar_day.png - - - - - - - - Qt::Horizontal - - - - 16 - 20 - - - - - - - - - 75 - true - - - - From - - - - - - - - All Peers - - - - :/images/user/friends24.png:/images/user/friends24.png - - - - - Own Links - - - - :/images/user/identity16.png:/images/user/identity16.png - - - - - - - - Qt::Horizontal - - - - 16 - 20 - - - - - - - - - 75 - true - - - - Show - - - - - - - - Top 100 - - - - :/images/records.png:/images/records.png - - - - - 101-200 - - - - - 201-300 - - - - - 301-400 - - - - - 401-500 - - - - - Bottom 100 - - - - - - - - QLabel{border: 2px solid #CCCCCC; -border-radius: 10px; -background: white; -padding:2} - - - true - - - Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - - 75 - true - - - - Link: - - - - - - - - - - - - - Qt::Horizontal - - - - 311 - 32 - - - - - - - - - 50 - false - - - - Add Anonymous Link - - - - - - - Add Link/Comment - - - - - - - - - - - Title: - - - - - - - QLineEdit{border: 2px solid #CCCCCC; -border-radius: 10px; -background: white;} - - - - - - - Score: - - - - - - - - +2 Great! - - - - :/images/filerating5.png:/images/filerating5.png - - - - - +1 Good - - - - :/images/filerating4.png:/images/filerating4.png - - - - - 0 Okay - - - - :/images/filerating3.png:/images/filerating3.png - - - - - -1 Sux - - - - :/images/filerating2.png:/images/filerating2.png - - - - - -2 Bad Link - - - - :/images/filerating1.png:/images/filerating1.png - - - - - - - - - - - - Url: - - - - - - - QLineEdit{border: 2px solid #CCCCCC; -border-radius: 10px; -background: white;} - - - - - - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - QTextEdit{border: 2px solid #CCCCCC; -border-radius: 10px; -background: white;} - - - - - - - - - - - - 16777215 - 32 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - 2 - - - - - - 24 - 24 - - - - - - - :/images/irkick.png - - - true - - - - - - - - 75 - true - - - - Links Cloud - - - - - - - Qt::Horizontal - - - - 596 - 15 - - - - - - - - Add new link - - - - :/images/edit_add24.png:/images/edit_add24.png - - - - 24 - 16 - - - - true - - - - - - - - - - - - - - diff --git a/plugins/LinksCloud/images/irkick.png b/plugins/LinksCloud/images/irkick.png deleted file mode 100644 index b399814ff..000000000 Binary files a/plugins/LinksCloud/images/irkick.png and /dev/null differ diff --git a/plugins/LinksCloud/lang/LinksCloud_ca_ES.qm b/plugins/LinksCloud/lang/LinksCloud_ca_ES.qm deleted file mode 100644 index 16b844877..000000000 Binary files a/plugins/LinksCloud/lang/LinksCloud_ca_ES.qm and /dev/null differ diff --git a/plugins/LinksCloud/lang/LinksCloud_ca_ES.ts b/plugins/LinksCloud/lang/LinksCloud_ca_ES.ts deleted file mode 100644 index a85af322f..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_ca_ES.ts +++ /dev/null @@ -1,329 +0,0 @@ - - - AddLinksDialog - - - - Add Link - Afegir enllaç - - - - Cancel - Cancel·la - - - - Add a new Link - Afegir un nou enllaç - - - - Title: - Títol: - - - - Url: - URL: - - - - Add Anonymous Link - Afegir enllaç anònim - - - - +2 Great! - +2 Fantàstic! - - - - +1 Good - +1 Molt bo - - - - 0 Okay - 0 Està bé - - - - -1 Sux - -1 És dolent - - - - -2 Bad Link - -2 Enllaç dolent - - - - Add Link to Cloud - Afegir enllaç al núvol - - - - New Link - Nou enllaç - - - - Add Link Failure - Afegir enllaç que falla - - - - Missing Link and/or Title - Enllaç i/o títol perdut - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - Aquest complement proporciona un conjunt d'enllaços en cau i un sistema de votar-los i promocionar-los. - - - - LinksCloud - NúvolEnllaços - - - - LinksDialog - - - Title / Comment - Títol / Comentari - - - - Score - Puntuació - - - - Peer / Link - Contacte / Enllaç - - - - Sort by - Ordenat per - - - - Combo - Combinació - - - - Time - Temps - - - - Ranking - Classificació - - - - In last - En l'últim - - - - Month - Mes - - - - Week - Setmana - - - - Day - Dia - - - - From - Des de - - - - All Peers - Tots els contactes - - - - Own Links - Enllaços propis - - - - Show - Mostra - - - - Top 100 - Top 100 - - - - 101-200 - 101-200 - - - - 201-300 - 201-300 - - - - 301-400 - 301-400 - - - - 401-500 - 401-500 - - - - Bottom 100 - Els últims 100 - - - - Link: - Enllaç: - - - - Add Anonymous Link - Afegir enllaç anònim - - - - Add Link/Comment - Afegir Enllaç/Comentari - - - - Title: - Títol: - - - - Score: - Puntuació: - - - - - +2 Great! - +2 Fantàstic! - - - - - +1 Good - +1 Molt bo - - - - - 0 Okay - 0 Està bé - - - - - -1 Sux - -1 És dolent - - - - - -2 Bad Link - -2 Enllaç dolent - - - - Url: - URL: - - - - Links Cloud - Núvol d'enllaços - - - - Add new link - Afegir nou enllaç - - - - Share Link Anonymously - Compartir enllaç anònimament - - - - Vote on Link - Votar un enllaç - - - - Download - Descarregar - - - - - - Add Link Failure - Afegir enllaç que falla - - - - Missing Link and/or Title - Enllaç i/o títol perdut - - - - Missing Link Data - Dades d'enllaç perdudes - - - - Missing Comment - Comentari perdut - - - - Link Title Not Changed - Títol d'enllaç no canviat - - - - Do you want to continue? - Vols continuar? - - - - Expand - Ampliar - - - - Hide - Amagar - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_cs.qm b/plugins/LinksCloud/lang/LinksCloud_cs.qm deleted file mode 100644 index 99e2ed5b8..000000000 Binary files a/plugins/LinksCloud/lang/LinksCloud_cs.qm and /dev/null differ diff --git a/plugins/LinksCloud/lang/LinksCloud_cs.ts b/plugins/LinksCloud/lang/LinksCloud_cs.ts deleted file mode 100644 index 78a6e743d..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_cs.ts +++ /dev/null @@ -1,329 +0,0 @@ - - - AddLinksDialog - - - - Add Link - Přidat odkaz - - - - Cancel - Zrušit - - - - Add a new Link - Přidat nový odkaz - - - - Title: - Titulek - - - - Url: - Url: - - - - Add Anonymous Link - Přidat anonymní odkaz - - - - +2 Great! - +2 Výborný - - - - +1 Good - +1 Dobrý - - - - 0 Okay - 0 OK - - - - -1 Sux - -1 Špatný - - - - -2 Bad Link - -2 Špatný odkaz - - - - Add Link to Cloud - Přidat odkaz do Cloudu - - - - New Link - Nový odkaz - - - - Add Link Failure - Přidání odkazu selhalo - - - - Missing Link and/or Title - Chybí odkaz nebo titulek - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - Tento zásuvný modul poskytuje sadu mezipaměti odkazů, a hlasovací systém na jejich podporu - - - - LinksCloud - LinksCloud - - - - LinksDialog - - - Title / Comment - Titulek / Komentáře - - - - Score - Skóre - - - - Peer / Link - Peer / Odkaz - - - - Sort by - Seřadit podle - - - - Combo - Dvojité - - - - Time - Čas - - - - Ranking - Žebříček - - - - In last - Jako poslední - - - - Month - Měsíc - - - - Week - Týden - - - - Day - Den - - - - From - Od - - - - All Peers - Všechny peery - - - - Own Links - Naše odkazy - - - - Show - Zobrazit - - - - Top 100 - Top 100 - - - - 101-200 - 101-200 - - - - 201-300 - 201-300 - - - - 301-400 - 301-400 - - - - 401-500 - 401-500 - - - - Bottom 100 - Spodní 100 - - - - Link: - Odkaz: - - - - Add Anonymous Link - Přidat anonymní odkaz - - - - Add Link/Comment - Přidat odkaz / komentář - - - - Title: - Titulek: - - - - Score: - Skóre: - - - - - +2 Great! - +2 Výborný - - - - - +1 Good - +1 Dobrý - - - - - 0 Okay - 0 OK - - - - - -1 Sux - -1 Špatný - - - - - -2 Bad Link - -2 Špatný odkaz - - - - Url: - Url: - - - - Links Cloud - Odkazový Cloud - - - - Add new link - Přidat nový odkaz - - - - Share Link Anonymously - Sdílet odkaz anonymně - - - - Vote on Link - Volte na odkaze - - - - Download - Stáhnout - - - - - - Add Link Failure - Přidání odkazu selhalo - - - - Missing Link and/or Title - Chybí odkaz nebo titulek - - - - Missing Link Data - Chybějí odkazová data - - - - Missing Comment - Chybějící komentář - - - - Link Title Not Changed - Nebyl zadán titulek odkazu - - - - Do you want to continue? - Chcete pokračovat? - - - - Expand - Rozbalit - - - - Hide - Skrýt - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_da.qm b/plugins/LinksCloud/lang/LinksCloud_da.qm deleted file mode 100644 index 552d8b3f4..000000000 Binary files a/plugins/LinksCloud/lang/LinksCloud_da.qm and /dev/null differ diff --git a/plugins/LinksCloud/lang/LinksCloud_da.ts b/plugins/LinksCloud/lang/LinksCloud_da.ts deleted file mode 100644 index c0f97a460..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_da.ts +++ /dev/null @@ -1,329 +0,0 @@ - - - AddLinksDialog - - - - Add Link - - - - - Cancel - Annuller - - - - Add a new Link - - - - - Title: - - - - - Url: - - - - - Add Anonymous Link - - - - - +2 Great! - - - - - +1 Good - - - - - 0 Okay - - - - - -1 Sux - - - - - -2 Bad Link - - - - - Add Link to Cloud - - - - - New Link - - - - - Add Link Failure - - - - - Missing Link and/or Title - - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - - - - - LinksCloud - - - - - LinksDialog - - - Title / Comment - - - - - Score - - - - - Peer / Link - - - - - Sort by - - - - - Combo - - - - - Time - - - - - Ranking - - - - - In last - - - - - Month - - - - - Week - - - - - Day - - - - - From - - - - - All Peers - - - - - Own Links - - - - - Show - - - - - Top 100 - - - - - 101-200 - - - - - 201-300 - - - - - 301-400 - - - - - 401-500 - - - - - Bottom 100 - - - - - Link: - - - - - Add Anonymous Link - - - - - Add Link/Comment - - - - - Title: - - - - - Score: - - - - - - +2 Great! - - - - - - +1 Good - - - - - - 0 Okay - - - - - - -1 Sux - - - - - - -2 Bad Link - - - - - Url: - - - - - Links Cloud - - - - - Add new link - - - - - Share Link Anonymously - - - - - Vote on Link - - - - - Download - - - - - - - Add Link Failure - - - - - Missing Link and/or Title - - - - - Missing Link Data - - - - - Missing Comment - - - - - Link Title Not Changed - - - - - Do you want to continue? - - - - - Expand - - - - - Hide - - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_de.qm b/plugins/LinksCloud/lang/LinksCloud_de.qm deleted file mode 100644 index 699706eaa..000000000 Binary files a/plugins/LinksCloud/lang/LinksCloud_de.qm and /dev/null differ diff --git a/plugins/LinksCloud/lang/LinksCloud_de.ts b/plugins/LinksCloud/lang/LinksCloud_de.ts deleted file mode 100644 index 83fb01ae8..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_de.ts +++ /dev/null @@ -1,329 +0,0 @@ - - - AddLinksDialog - - - - Add Link - Link hinzufügen - - - - Cancel - Abbrechen - - - - Add a new Link - Neuen Link hinzufügen - - - - Title: - Titel: - - - - Url: - Url: - - - - Add Anonymous Link - Anonym hinzufügen - - - - +2 Great! - +2 Großartig! - - - - +1 Good - +1 Gut - - - - 0 Okay - 0 In Ordnung - - - - -1 Sux - -1 Nervt - - - - -2 Bad Link - -2 Schlechter Link - - - - Add Link to Cloud - Link zur Wolke hinzufügen - - - - New Link - Neuer Link - - - - Add Link Failure - Link hinzufügen fehlgeschlagen - - - - Missing Link and/or Title - Titel und/oder Url fehlt - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - Dieses Plug-in stellt Links und ein Wahlsystem zur Verfügung, um sie zu verbreiten. - - - - LinksCloud - Verknüpfungswolke - - - - LinksDialog - - - Title / Comment - Titel / Kommentar - - - - Score - Punkte - - - - Peer / Link - Nachbar / Link - - - - Sort by - Sortiere nach - - - - Combo - Kombiniert - - - - Time - Zeit - - - - Ranking - Platzierung - - - - In last - Im letzten - - - - Month - Monat - - - - Week - Woche - - - - Day - Tag - - - - From - Von - - - - All Peers - Alle Nachbarn - - - - Own Links - Eigene Links - - - - Show - Zeige - - - - Top 100 - Top 100 - - - - 101-200 - 101-200 - - - - 201-300 - 201-300 - - - - 301-400 - 301-400 - - - - 401-500 - 401-500 - - - - Bottom 100 - Letzten 100 - - - - Link: - Link: - - - - Add Anonymous Link - Anonym hinzufügen - - - - Add Link/Comment - Link/Kommentar hinzufügen - - - - Title: - Titel: - - - - Score: - Punkte: - - - - - +2 Great! - +2 Großartig! - - - - - +1 Good - +1 Gut - - - - - 0 Okay - 0 In Ordnung - - - - - -1 Sux - -1 Nervt - - - - - -2 Bad Link - -2 Schlechter Link - - - - Url: - Url: - - - - Links Cloud - Verknüpfungswolke - - - - Add new link - Neuen Link hinzufügen - - - - Share Link Anonymously - Link anonym verteilen - - - - Vote on Link - Stimme für Link - - - - Download - Herunterladen - - - - - - Add Link Failure - Link hinzufügen fehlgeschlagen - - - - Missing Link and/or Title - Fehlender Link und/oder Titel - - - - Missing Link Data - Fehlende Linkdaten - - - - Missing Comment - Fehlender Kommentar - - - - Link Title Not Changed - Linktitel nicht geändert - - - - Do you want to continue? - Willst du fortfahren? - - - - Expand - Erweitern - - - - Hide - Verbergen - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_el.qm b/plugins/LinksCloud/lang/LinksCloud_el.qm deleted file mode 100644 index aafec7fb1..000000000 Binary files a/plugins/LinksCloud/lang/LinksCloud_el.qm and /dev/null differ diff --git a/plugins/LinksCloud/lang/LinksCloud_el.ts b/plugins/LinksCloud/lang/LinksCloud_el.ts deleted file mode 100644 index 854cf71d3..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_el.ts +++ /dev/null @@ -1,329 +0,0 @@ - - - AddLinksDialog - - - - Add Link - Προσθέστε σύνδεσμο - - - - Cancel - Διακοπη - - - - Add a new Link - Προσθέσετε ένα νέο σύνδεσμο - - - - Title: - Τίτλος: - - - - Url: - URL: - - - - Add Anonymous Link - Προσθέστε ανώνυμη σύνδεση - - - - +2 Great! - +2 Μεγάλη! - - - - +1 Good - +1 Καλή - - - - 0 Okay - Εντάξει 0 - - - - -1 Sux - -1 Sux - - - - -2 Bad Link - -2 Κακή σύνδεση - - - - Add Link to Cloud - Προσθήκη συνδέσεων σε σύννεφο - - - - New Link - Νέα σύνδεση - - - - Add Link Failure - Προσθέστε αποτυχία σύνδεσης - - - - Missing Link and/or Title - Συνδετικός κρίκος ή/και τίτλο - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - Αυτό το plugin παρέχει ένα σύνολο των προσωρινά αποθηκευμένων συνδέσεων, καθώς και ένα σύστημα ψηφοφορίας για την προώθηση τους. - - - - LinksCloud - LinksCloud - - - - LinksDialog - - - Title / Comment - Τίτλος / σχόλιο - - - - Score - Σκορ - - - - Peer / Link - Peer / Link - - - - Sort by - Ταξινόμηση κατά - - - - Combo - Combo - - - - Time - Χρόνος - - - - Ranking - Κατάταξη - - - - In last - Στο τελευταίο - - - - Month - Μήνα - - - - Week - Εβδομάδα - - - - Day - Ημέρα - - - - From - Απο - - - - All Peers - Όλοι οι φορείς - - - - Own Links - Δικες σας συνδέσεις - - - - Show - Εμφανιση - - - - Top 100 - Top 100 - - - - 101-200 - 101-200 - - - - 201-300 - 201-300 - - - - 301-400 - 301-400 - - - - 401-500 - 401-500 - - - - Bottom 100 - Κάτω 100 - - - - Link: - Σύνδεση: - - - - Add Anonymous Link - Προσθέστε ανώνυμη σύνδεση - - - - Add Link/Comment - Προσθέστε σύνδεσμο/σχόλιο - - - - Title: - Τίτλος: - - - - Score: - Βαθμολογία: - - - - - +2 Great! - +2 Μεγάλη! - - - - - +1 Good - +1 Καλή - - - - - 0 Okay - Εντάξει 0 - - - - - -1 Sux - -1 Sux - - - - - -2 Bad Link - -2 Κακή σύνδεση - - - - Url: - URL: - - - - Links Cloud - Συνδέσεις σύννεφο - - - - Add new link - Προσθέστε νέα σύνδεση - - - - Share Link Anonymously - Μοιράσμα σύνδεσης ανώνυμα - - - - Vote on Link - Ψηφίσμα σύνδεσης - - - - Download - Λυψη - - - - - - Add Link Failure - Προσθέστε αποτυχία σύνδεσης - - - - Missing Link and/or Title - Συνδετικός κρίκος ή/και τίτλο - - - - Missing Link Data - Ελλείπουσα σύνδεση δεδομένων - - - - Missing Comment - Λείπει το σχόλιο - - - - Link Title Not Changed - Τίτλος συνδέσμου, δεν αλλάζει - - - - Do you want to continue? - Θέλετε να συνεχίσετε; - - - - Expand - Επεκταση - - - - Hide - Αποκρυψη - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_en.qm b/plugins/LinksCloud/lang/LinksCloud_en.qm deleted file mode 100644 index 9dad8dffc..000000000 Binary files a/plugins/LinksCloud/lang/LinksCloud_en.qm and /dev/null differ diff --git a/plugins/LinksCloud/lang/LinksCloud_en.ts b/plugins/LinksCloud/lang/LinksCloud_en.ts deleted file mode 100644 index 4ca524d76..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_en.ts +++ /dev/null @@ -1,331 +0,0 @@ - - - - - AddLinksDialog - - - - Add Link - - - - - Cancel - - - - - Add a new Link - - - - - Title: - - - - - Url: - - - - - Add Anonymous Link - - - - - +2 Great! - - - - - +1 Good - - - - - 0 Okay - - - - - -1 Sux - - - - - -2 Bad Link - - - - - Add Link to Cloud - - - - - New Link - - - - - Add Link Failure - - - - - Missing Link and/or Title - - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - - - - - LinksCloud - - - - - LinksDialog - - - Title / Comment - - - - - Score - - - - - Peer / Link - - - - - Sort by - - - - - Combo - - - - - Time - - - - - Ranking - - - - - In last - - - - - Month - - - - - Week - - - - - Day - - - - - From - - - - - All Peers - - - - - Own Links - - - - - Show - - - - - Top 100 - - - - - 101-200 - - - - - 201-300 - - - - - 301-400 - - - - - 401-500 - - - - - Bottom 100 - - - - - Link: - - - - - Add Anonymous Link - - - - - Add Link/Comment - - - - - Title: - - - - - Score: - - - - - - +2 Great! - - - - - - +1 Good - - - - - - 0 Okay - - - - - - -1 Sux - - - - - - -2 Bad Link - - - - - Url: - - - - - Links Cloud - - - - - Add new link - - - - - Share Link Anonymously - - - - - Vote on Link - - - - - Download - - - - - - - Add Link Failure - - - - - Missing Link and/or Title - - - - - Missing Link Data - - - - - Missing Comment - - - - - Link Title Not Changed - - - - - Do you want to continue? - - - - - Expand - - - - - Hide - - - - diff --git a/plugins/LinksCloud/lang/LinksCloud_es.qm b/plugins/LinksCloud/lang/LinksCloud_es.qm deleted file mode 100644 index 33893d884..000000000 Binary files a/plugins/LinksCloud/lang/LinksCloud_es.qm and /dev/null differ diff --git a/plugins/LinksCloud/lang/LinksCloud_es.ts b/plugins/LinksCloud/lang/LinksCloud_es.ts deleted file mode 100644 index c112ac9b0..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_es.ts +++ /dev/null @@ -1,329 +0,0 @@ - - - AddLinksDialog - - - - Add Link - Añadir enlace - - - - Cancel - Cancelar - - - - Add a new Link - Añadir un nuevo enlace - - - - Title: - Título: - - - - Url: - Url: - - - - Add Anonymous Link - Añadir enlace anónimo - - - - +2 Great! - +2 ¡Excelente! - - - - +1 Good - +1 Muy bueno - - - - 0 Okay - 0 Bueno - - - - -1 Sux - -1 Pésimo - - - - -2 Bad Link - -2 Enlace malo - - - - Add Link to Cloud - Añadir enlace a la nube - - - - New Link - Nuevo enlace - - - - Add Link Failure - Añadir enlace fallido - - - - Missing Link and/or Title - Enlace y/o título perdido - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - Este plugin proporciona un conjunto de enlaces en caché, y un sistema de votación para promoverlos. - - - - LinksCloud - Enlace en la nube - - - - LinksDialog - - - Title / Comment - Título / Comentario - - - - Score - Puntuación - - - - Peer / Link - Pares / Enlace - - - - Sort by - Ordenar por - - - - Combo - Combinar - - - - Time - Hora - - - - Ranking - Clasificación - - - - In last - En la última - - - - Month - Mes - - - - Week - Semana - - - - Day - Día - - - - From - De - - - - All Peers - Todos los pares - - - - Own Links - Enlaces propios - - - - Show - Mostrar - - - - Top 100 - Top 100 - - - - 101-200 - 101-200 - - - - 201-300 - 201-300 - - - - 301-400 - 301-400 - - - - 401-500 - 401-500 - - - - Bottom 100 - Por debajo de 100 - - - - Link: - Enlace: - - - - Add Anonymous Link - Añadir enlace anónimo - - - - Add Link/Comment - Añadir enlace/comentario - - - - Title: - Título: - - - - Score: - Puntuación: - - - - - +2 Great! - +2 ¡Excelente! - - - - - +1 Good - +1 Muy bueno - - - - - 0 Okay - 0 Bueno - - - - - -1 Sux - -1 Pésimo - - - - - -2 Bad Link - -2 Enlace malo - - - - Url: - Url: - - - - Links Cloud - Enlaces en la nube - - - - Add new link - Añadir nuevo enlace - - - - Share Link Anonymously - Compartir enlace anónimamente - - - - Vote on Link - Votar el enlace - - - - Download - Descargar - - - - - - Add Link Failure - Añadir enlace fallido - - - - Missing Link and/or Title - Enlace y/o título perdido - - - - Missing Link Data - Faltan los datos del enlace - - - - Missing Comment - Falta el comentario - - - - Link Title Not Changed - El título del enlace no ha cambiado - - - - Do you want to continue? - ¿Desea continuar? - - - - Expand - Expandir - - - - Hide - Ocultar - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_fi.qm b/plugins/LinksCloud/lang/LinksCloud_fi.qm deleted file mode 100644 index 8a5a61a38..000000000 Binary files a/plugins/LinksCloud/lang/LinksCloud_fi.qm and /dev/null differ diff --git a/plugins/LinksCloud/lang/LinksCloud_fi.ts b/plugins/LinksCloud/lang/LinksCloud_fi.ts deleted file mode 100644 index 1a3818db9..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_fi.ts +++ /dev/null @@ -1,329 +0,0 @@ - - - AddLinksDialog - - - - Add Link - Lisää linkki - - - - Cancel - Peru - - - - Add a new Link - Lisää uusi linkki - - - - Title: - Otsikko: - - - - Url: - Url: - - - - Add Anonymous Link - Lisää nimetön linkki - - - - +2 Great! - +2 Loistava! - - - - +1 Good - +1 Hyvä - - - - 0 Okay - 0 Kohtalainen - - - - -1 Sux - -1 Huono - - - - -2 Bad Link - -2 Kelvoton linkki - - - - Add Link to Cloud - Lisää linkki pilveen - - - - New Link - Uusi linkki - - - - Add Link Failure - Vika lisättäessä linkkiä - - - - Missing Link and/or Title - Puuttuva linkki ja/tai otsikko - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - Tämä lisäosa näyttää joukon välimuistissa olevia linkkejä sekä äänestysjärjestelmän. - - - - LinksCloud - LinksCloud - - - - LinksDialog - - - Title / Comment - Otsikko / Kommentti - - - - Score - Pisteet - - - - Peer / Link - Vertainen / Linkki - - - - Sort by - Järjestä - - - - Combo - Yhdistelmä - - - - Time - Aika - - - - Ranking - Sijoitus - - - - In last - Viime - - - - Month - kuussa - - - - Week - viikolla - - - - Day - päivänä - - - - From - Lähettäjä - - - - All Peers - Kaikki vertaiset - - - - Own Links - Omat linkit - - - - Show - Näytä - - - - Top 100 - Ylimmät 100 - - - - 101-200 - 101-200 - - - - 201-300 - 201-300 - - - - 301-400 - 301-400 - - - - 401-500 - 401-500 - - - - Bottom 100 - Alimmat 100 - - - - Link: - Linkki: - - - - Add Anonymous Link - Lisää nimetön linkki - - - - Add Link/Comment - Lisää linkki/kommentti - - - - Title: - Otsikko: - - - - Score: - Pisteet: - - - - - +2 Great! - +2 Loistava! - - - - - +1 Good - +1 Hyvä - - - - - 0 Okay - 0 Kohtalainen - - - - - -1 Sux - -1 Huono - - - - - -2 Bad Link - -2 Kelvoton linkki - - - - Url: - Url: - - - - Links Cloud - Links Cloud - - - - Add new link - Lisää uusi linkki - - - - Share Link Anonymously - Jaa linkki nimettömänä - - - - Vote on Link - Äänestä linkkiä - - - - Download - Lataa - - - - - - Add Link Failure - Vika lisättäessä linkkiä - - - - Missing Link and/or Title - Puuttuva linkki ja/tai otsikko - - - - Missing Link Data - Linkin tiedot puuttuvat - - - - Missing Comment - Kommentti puuttuu - - - - Link Title Not Changed - Linkin otsikkoa ei muutettu - - - - Do you want to continue? - Haluatko jatkaa? - - - - Expand - Laajenna - - - - Hide - Piilota - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_fr.qm b/plugins/LinksCloud/lang/LinksCloud_fr.qm deleted file mode 100644 index 7d54ddc03..000000000 Binary files a/plugins/LinksCloud/lang/LinksCloud_fr.qm and /dev/null differ diff --git a/plugins/LinksCloud/lang/LinksCloud_fr.ts b/plugins/LinksCloud/lang/LinksCloud_fr.ts deleted file mode 100644 index 13c3c09c4..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_fr.ts +++ /dev/null @@ -1,329 +0,0 @@ - - - AddLinksDialog - - - - Add Link - Ajouter un lien - - - - Cancel - Annuler - - - - Add a new Link - Ajouter un nouveau lien - - - - Title: - Titre : - - - - Url: - Url : - - - - Add Anonymous Link - Ajouter un lien anonyme - - - - +2 Great! - +2 Parfait ! - - - - +1 Good - +1 Bien - - - - 0 Okay - 0 Ok - - - - -1 Sux - -1 Bof - - - - -2 Bad Link - -2 Mauvais lien - - - - Add Link to Cloud - Ajouter lien au nuage - - - - New Link - Nouveau lien - - - - Add Link Failure - Échec ajout de lien - - - - Missing Link and/or Title - Lien et/ou tiitre manquant - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - Cette extension fournit un ensemble de liens en cache, et un système de vote pour les promouvoir. - - - - LinksCloud - LinksCloud - - - - LinksDialog - - - Title / Comment - Titre / Commentaire - - - - Score - Score - - - - Peer / Link - Contact / Lien - - - - Sort by - Trier par - - - - Combo - Combiné - - - - Time - Temps - - - - Ranking - Classement - - - - In last - Par - - - - Month - Mois - - - - Week - Semaine - - - - Day - Jour - - - - From - De - - - - All Peers - Tous les contacts - - - - Own Links - Propre liens - - - - Show - Montrer - - - - Top 100 - Top 100 - - - - 101-200 - 101-200 - - - - 201-300 - 201-300 - - - - 301-400 - 301-400 - - - - 401-500 - 401-500 - - - - Bottom 100 - 100 derniers - - - - Link: - Lien : - - - - Add Anonymous Link - Ajouter un lien anonyme - - - - Add Link/Comment - Ajouter Lien/Commentaire - - - - Title: - Titre : - - - - Score: - Score : - - - - - +2 Great! - +2 Parfait ! - - - - - +1 Good - +1 Bien - - - - - 0 Okay - 0 Ok - - - - - -1 Sux - -1 Bof - - - - - -2 Bad Link - -2 Mauvais lien - - - - Url: - Url : - - - - Links Cloud - Links Cloud - - - - Add new link - Ajouter un nouveau lien - - - - Share Link Anonymously - Partager le lien anonymement - - - - Vote on Link - Vote sur le lien - - - - Download - Télécharger - - - - - - Add Link Failure - Échec de l'ajout du lien - - - - Missing Link and/or Title - Lien et/ou titre manquant(s) - - - - Missing Link Data - Data Link manquant - - - - Missing Comment - Commentaire manquant - - - - Link Title Not Changed - Le titre du lien n'a pas été changé - - - - Do you want to continue? - Voulez-vous continuer ? - - - - Expand - Montrer - - - - Hide - Cacher - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_hu.qm b/plugins/LinksCloud/lang/LinksCloud_hu.qm deleted file mode 100644 index 0c1c75ab0..000000000 Binary files a/plugins/LinksCloud/lang/LinksCloud_hu.qm and /dev/null differ diff --git a/plugins/LinksCloud/lang/LinksCloud_hu.ts b/plugins/LinksCloud/lang/LinksCloud_hu.ts deleted file mode 100644 index f611e2d1b..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_hu.ts +++ /dev/null @@ -1,329 +0,0 @@ - - - AddLinksDialog - - - - Add Link - Hivatkozás hozzáadása - - - - Cancel - Mégse - - - - Add a new Link - Új hivatkozás hozzáadása - - - - Title: - Cím: - - - - Url: - Url: - - - - Add Anonymous Link - Hivatkozás hozzáadása névtelenül - - - - +2 Great! - +2 Nagyon jó! - - - - +1 Good - +1 Tetszik - - - - 0 Okay - 0 Elmegy - - - - -1 Sux - -1 Rossz - - - - -2 Bad Link - -2 Nagyon rossz - - - - Add Link to Cloud - Hivatkozás hozzáadása a felhőhöz - - - - New Link - Új hivatkozás - - - - Add Link Failure - Hiba hozzáadása a hivatkozáshoz - - - - Missing Link and/or Title - Hiányzó hivatkozás és/vagy cím - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - Ez a beépülő sok hivatkozást tesz elérhetővé, melyek egy szavazási rendszer segítségével értékelhetőek. - - - - LinksCloud - Hivatkozásfelhő - - - - LinksDialog - - - Title / Comment - Cím / Hozzászólás - - - - Score - Pontszám - - - - Peer / Link - Partner / Hivatkozás - - - - Sort by - Rendezés - - - - Combo - Kombó - - - - Time - Idő - - - - Ranking - Értékelés - - - - In last - Utoljára - - - - Month - Hónap - - - - Week - Hét - - - - Day - Nap - - - - From - Tőle - - - - All Peers - Összes partner - - - - Own Links - Saját hivatkozások - - - - Show - Mutatás - - - - Top 100 - 100 Legjobb - - - - 101-200 - 101-200 - - - - 201-300 - 201-300 - - - - 301-400 - 301-400 - - - - 401-500 - 401-500 - - - - Bottom 100 - 100 Legrosszabb - - - - Link: - Hivatkozás: - - - - Add Anonymous Link - Hivatkozás hozzáadása névtelenül - - - - Add Link/Comment - Hivatkozás / Hozzászólás hozzáadása - - - - Title: - Cím: - - - - Score: - Pontszám: - - - - - +2 Great! - +2 Nagyon jó! - - - - - +1 Good - +1 Tetszik - - - - - 0 Okay - 0 Elmegy - - - - - -1 Sux - -1 Rossz - - - - - -2 Bad Link - -2 Nagyon rossz - - - - Url: - Url: - - - - Links Cloud - Hivatkozásfelhő - - - - Add new link - Új hivatkozás hozzáadása - - - - Share Link Anonymously - Hivatkozás megosztása névtelenül - - - - Vote on Link - Szavazás - - - - Download - Letöltés - - - - - - Add Link Failure - Hiba hozzáadása - - - - Missing Link and/or Title - Hiányzó hivatkozás és/vagy cím - - - - Missing Link Data - Hiányzó adat a hivatkozásnál - - - - Missing Comment - Hiányzó hozzászólás - - - - Link Title Not Changed - Hivatkozás címe nem változott meg - - - - Do you want to continue? - Folytatod? - - - - Expand - Lenyitás - - - - Hide - Elrejt - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_it.qm b/plugins/LinksCloud/lang/LinksCloud_it.qm deleted file mode 100644 index d3268be21..000000000 Binary files a/plugins/LinksCloud/lang/LinksCloud_it.qm and /dev/null differ diff --git a/plugins/LinksCloud/lang/LinksCloud_it.ts b/plugins/LinksCloud/lang/LinksCloud_it.ts deleted file mode 100644 index 93efcb778..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_it.ts +++ /dev/null @@ -1,329 +0,0 @@ - - - AddLinksDialog - - - - Add Link - Aggiungi collegamento - - - - Cancel - Annulla - - - - Add a new Link - Aggiungi nuovo collegamento - - - - Title: - Titolo: - - - - Url: - URL: - - - - Add Anonymous Link - Aggiungi collegamento anonimo - - - - +2 Great! - +2 Grande! - - - - +1 Good - +1 Buono - - - - 0 Okay - 0 OK - - - - -1 Sux - -1 Scoccia - - - - -2 Bad Link - -2 Cattivo collegamento - - - - Add Link to Cloud - Aggiungi collegamento alla nuvola - - - - New Link - Nuovo collegamento - - - - Add Link Failure - Errore aggiunta collegamento - - - - Missing Link and/or Title - Collegamento e/o autore mancanti - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - Il modulo aggiuntivo fornisce un insieme di collegamenti memorizzati, ed un sistema di voto per promuoverli. - - - - LinksCloud - Nuvola Collegamenti / LinksCloud - - - - LinksDialog - - - Title / Comment - Titolo / Commento - - - - Score - Punteggio - - - - Peer / Link - Contatto / Collegamento - - - - Sort by - Ordina per - - - - Combo - Combo - - - - Time - Tempo - - - - Ranking - Classifica - - - - In last - Alla fine - - - - Month - Mese - - - - Week - Settimana - - - - Day - Giorno - - - - From - Da - - - - All Peers - Tutti i contatti - - - - Own Links - Collegamenti propri - - - - Show - Mostra - - - - Top 100 - Top 100 - - - - 101-200 - 101-200 - - - - 201-300 - 201-300 - - - - 301-400 - 301-400 - - - - 401-500 - 401-500 - - - - Bottom 100 - Ultimi 100 - - - - Link: - Collegamento: - - - - Add Anonymous Link - Aggiungi collegamento anonimo - - - - Add Link/Comment - Aggiungi Collegamento/Commento - - - - Title: - Titolo: - - - - Score: - Punteggio: - - - - - +2 Great! - +2 Grande! - - - - - +1 Good - +1 Buono - - - - - 0 Okay - 0 Okay - - - - - -1 Sux - -1 Scoccia - - - - - -2 Bad Link - -2 Cattivo collegamento - - - - Url: - URL: - - - - Links Cloud - Nuvola collegamenti - - - - Add new link - Aggiungi nuovo collegamento - - - - Share Link Anonymously - Condividi collegamento anonimamente - - - - Vote on Link - Vota il collegamento - - - - Download - Scarica - - - - - - Add Link Failure - Aggiungi errore collegamento - - - - Missing Link and/or Title - Collegamento e/o titolo mancante - - - - Missing Link Data - Collegamento dati mancante - - - - Missing Comment - Commento mancante - - - - Link Title Not Changed - Titolo collegamento invariato - - - - Do you want to continue? - Vuoi continuare? - - - - Expand - Allarga - - - - Hide - Nascondi - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_ja_JP.qm b/plugins/LinksCloud/lang/LinksCloud_ja_JP.qm deleted file mode 100644 index 0fe587e78..000000000 Binary files a/plugins/LinksCloud/lang/LinksCloud_ja_JP.qm and /dev/null differ diff --git a/plugins/LinksCloud/lang/LinksCloud_ja_JP.ts b/plugins/LinksCloud/lang/LinksCloud_ja_JP.ts deleted file mode 100644 index 7ca2214dc..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_ja_JP.ts +++ /dev/null @@ -1,329 +0,0 @@ - - - AddLinksDialog - - - - Add Link - - - - - Cancel - キャンセル - - - - Add a new Link - - - - - Title: - - - - - Url: - - - - - Add Anonymous Link - - - - - +2 Great! - - - - - +1 Good - - - - - 0 Okay - - - - - -1 Sux - - - - - -2 Bad Link - - - - - Add Link to Cloud - - - - - New Link - - - - - Add Link Failure - - - - - Missing Link and/or Title - - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - - - - - LinksCloud - - - - - LinksDialog - - - Title / Comment - - - - - Score - - - - - Peer / Link - - - - - Sort by - - - - - Combo - - - - - Time - - - - - Ranking - - - - - In last - - - - - Month - - - - - Week - - - - - Day - - - - - From - - - - - All Peers - - - - - Own Links - - - - - Show - - - - - Top 100 - - - - - 101-200 - - - - - 201-300 - - - - - 301-400 - - - - - 401-500 - - - - - Bottom 100 - - - - - Link: - - - - - Add Anonymous Link - - - - - Add Link/Comment - - - - - Title: - - - - - Score: - - - - - - +2 Great! - - - - - - +1 Good - - - - - - 0 Okay - - - - - - -1 Sux - - - - - - -2 Bad Link - - - - - Url: - - - - - Links Cloud - - - - - Add new link - - - - - Share Link Anonymously - - - - - Vote on Link - - - - - Download - ダウンロード - - - - - - Add Link Failure - - - - - Missing Link and/or Title - - - - - Missing Link Data - - - - - Missing Comment - - - - - Link Title Not Changed - - - - - Do you want to continue? - - - - - Expand - 展開 - - - - Hide - 非表示 - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_ko.qm b/plugins/LinksCloud/lang/LinksCloud_ko.qm deleted file mode 100644 index 789c669e8..000000000 Binary files a/plugins/LinksCloud/lang/LinksCloud_ko.qm and /dev/null differ diff --git a/plugins/LinksCloud/lang/LinksCloud_ko.ts b/plugins/LinksCloud/lang/LinksCloud_ko.ts deleted file mode 100644 index c83b1b154..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_ko.ts +++ /dev/null @@ -1,329 +0,0 @@ - - - AddLinksDialog - - - - Add Link - 링크 추가 - - - - Cancel - 취소 - - - - Add a new Link - 새 링크 추가 - - - - Title: - 제목: - - - - Url: - 주소: - - - - Add Anonymous Link - 익명 링크 추가 - - - - +2 Great! - +2 멋져요 :D - - - - +1 Good - +1 좋아요 :) - - - - 0 Okay - 0 괜찮아요 : | - - - - -1 Sux - -1 어우 :S - - - - -2 Bad Link - -2 후졌어요 :( - - - - Add Link to Cloud - 클라우드에 링크 추가 - - - - New Link - 새 링크 - - - - Add Link Failure - 잘못된 링크 추가 - - - - Missing Link and/or Title - 링크 또는 제목이 빠졌습니다 - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - 이 플러그인은 캐시에 저장한 링크 모음과, 링크를 알리기 위한 투표 시스템을 제공합니다. - - - - LinksCloud - 링크클라우드 - - - - LinksDialog - - - Title / Comment - 제목 / 답글 - - - - Score - 점수 - - - - Peer / Link - 피어 / 링크 - - - - Sort by - 정렬순 - - - - Combo - 조합 - - - - Time - 시간 - - - - Ranking - 순위 - - - - In last - 최신 - - - - Month - - - - - Week - - - - - Day - - - - - From - 보낸이 - - - - All Peers - 모든 피어 - - - - Own Links - 소유한 링크 - - - - Show - 표시 - - - - Top 100 - 상위 100 - - - - 101-200 - 101-200 - - - - 201-300 - 201-300 - - - - 301-400 - 301-400 - - - - 401-500 - 401-500 - - - - Bottom 100 - 하위 100 - - - - Link: - 링크: - - - - Add Anonymous Link - 익명 링크 추가 - - - - Add Link/Comment - 링크/답글 추가 - - - - Title: - 제목: - - - - Score: - 점수: - - - - - +2 Great! - +2 멋져요 :D - - - - - +1 Good - +1 좋아요 :) - - - - - 0 Okay - 0 괜찮아요 : | - - - - - -1 Sux - -1 어우 :S - - - - - -2 Bad Link - -2 후졌어요 :( - - - - Url: - 주소: - - - - Links Cloud - 링크 클라우드 - - - - Add new link - 새 링크 추가 - - - - Share Link Anonymously - 익명으로 링크 공유 - - - - Vote on Link - 링크에 투표 - - - - Download - 다운로드 - - - - - - Add Link Failure - 잘못된 링크 추가 - - - - Missing Link and/or Title - 링크 또는 제목이 빠졌습니다 - - - - Missing Link Data - 링크 데이터가 빠졌습니다 - - - - Missing Comment - 답글이 빠졌습니다 - - - - Link Title Not Changed - 링크 제목이 바뀌지 않았습니다 - - - - Do you want to continue? - 계속하시겠습니까? - - - - Expand - 확장 - - - - Hide - 숨김 - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_lang.qrc b/plugins/LinksCloud/lang/LinksCloud_lang.qrc deleted file mode 100644 index dd737ab14..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_lang.qrc +++ /dev/null @@ -1,24 +0,0 @@ - - - LinksCloud_ca_ES.qm - LinksCloud_cs.qm - LinksCloud_da.qm - LinksCloud_de.qm - LinksCloud_el.qm - LinksCloud_en.qm - LinksCloud_es.qm - LinksCloud_fi.qm - LinksCloud_fr.qm - LinksCloud_hu.qm - LinksCloud_it.qm - LinksCloud_ja_JP.qm - LinksCloud_ko.qm - LinksCloud_nl.qm - LinksCloud_pl.qm - LinksCloud_ru.qm - LinksCloud_sv.qm - LinksCloud_tr.qm - LinksCloud_zh_CN.qm - - - diff --git a/plugins/LinksCloud/lang/LinksCloud_nl.qm b/plugins/LinksCloud/lang/LinksCloud_nl.qm deleted file mode 100644 index 48d6e3763..000000000 Binary files a/plugins/LinksCloud/lang/LinksCloud_nl.qm and /dev/null differ diff --git a/plugins/LinksCloud/lang/LinksCloud_nl.ts b/plugins/LinksCloud/lang/LinksCloud_nl.ts deleted file mode 100644 index 5ae75f5dc..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_nl.ts +++ /dev/null @@ -1,329 +0,0 @@ - - - AddLinksDialog - - - - Add Link - Voeg een Link toe - - - - Cancel - Annuleren - - - - Add a new Link - Voeg een nieuwe Link toe - - - - Title: - Titel: - - - - Url: - Url: - - - - Add Anonymous Link - Voeg een Anonieme Link toe - - - - +2 Great! - +2 Geweldig! - - - - +1 Good - +1 Goed - - - - 0 Okay - 0 Oke - - - - -1 Sux - -1 Slecht - - - - -2 Bad Link - -2 Slechte Link - - - - Add Link to Cloud - Voeg link toe aan de Cloud - - - - New Link - Nieuwe Link - - - - Add Link Failure - Link toevoegen mislukt - - - - Missing Link and/or Title - Ontbrekende Link en/of Titel - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - Deze plugin geeft u een set van gecachte links en een stem systeem om die te promoten - - - - LinksCloud - LinksCloud - - - - LinksDialog - - - Title / Comment - Titel / Opmerkingen - - - - Score - Score - - - - Peer / Link - Verbinding / Link - - - - Sort by - Sorteer op - - - - Combo - Combo - - - - Time - Tijd - - - - Ranking - Stand - - - - In last - In last - - - - Month - Maand - - - - Week - Week - - - - Day - Dag - - - - From - Van - - - - All Peers - Alle Verbindingen - - - - Own Links - Links eigenaar - - - - Show - Toon - - - - Top 100 - Top 100 - - - - 101-200 - 101-200 - - - - 201-300 - 201-300 - - - - 301-400 - 301-400 - - - - 401-500 - 401-500 - - - - Bottom 100 - Onderste 100 - - - - Link: - Link: - - - - Add Anonymous Link - Voeg een anonieme Link toe - - - - Add Link/Comment - Voeg Link/Opmerking toe - - - - Title: - Titel: - - - - Score: - Score: - - - - - +2 Great! - +2 Geweldig! - - - - - +1 Good - +1 Goed - - - - - 0 Okay - 0 Oke - - - - - -1 Sux - -1 Slecht - - - - - -2 Bad Link - -2 Slechte Link - - - - Url: - Url: - - - - Links Cloud - Links Cloud - - - - Add new link - Voeg een nieuwe Link toe - - - - Share Link Anonymously - Deel Link Anoniem - - - - Vote on Link - Stem op Link - - - - Download - Download - - - - - - Add Link Failure - Link toevoegen mislukt - - - - Missing Link and/or Title - Ontbrekende Link en/of Titel - - - - Missing Link Data - Ontbrekende Link data - - - - Missing Comment - Ontbrekende Opmerkingen - - - - Link Title Not Changed - Link titel niet veranderd - - - - Do you want to continue? - Wilt u doorgaan? - - - - Expand - Uitbreiden - - - - Hide - Verberg - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_pl.qm b/plugins/LinksCloud/lang/LinksCloud_pl.qm deleted file mode 100644 index b44eddac2..000000000 Binary files a/plugins/LinksCloud/lang/LinksCloud_pl.qm and /dev/null differ diff --git a/plugins/LinksCloud/lang/LinksCloud_pl.ts b/plugins/LinksCloud/lang/LinksCloud_pl.ts deleted file mode 100644 index 82d2624e4..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_pl.ts +++ /dev/null @@ -1,329 +0,0 @@ - - - AddLinksDialog - - - - Add Link - Dodaj Link - - - - Cancel - Anuluj - - - - Add a new Link - Dodaj nowy Link - - - - Title: - Tytuł: - - - - Url: - Url: - - - - Add Anonymous Link - Dodaj Link Anonimowy - - - - +2 Great! - +2 Świetne! - - - - +1 Good - +1 Dobre - - - - 0 Okay - 0 W porządku - - - - -1 Sux - -1 Ssie - - - - -2 Bad Link - -2 Zły Link - - - - Add Link to Cloud - Dodaj Link do Chmury - - - - New Link - Nowy Link - - - - Add Link Failure - - - - - Missing Link and/or Title - Brakujący Link i/lub Tytuł - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - - - - - LinksCloud - - - - - LinksDialog - - - Title / Comment - - - - - Score - - - - - Peer / Link - Peer / Link - - - - Sort by - Sortuj według - - - - Combo - - - - - Time - Czas - - - - Ranking - Ranking - - - - In last - W ostatnim - - - - Month - Miesiącu - - - - Week - Tygodniu - - - - Day - Dniu - - - - From - Od - - - - All Peers - - - - - Own Links - Własne Linki - - - - Show - Pokaż - - - - Top 100 - Top 100 - - - - 101-200 - 101-200 - - - - 201-300 - 201-300 - - - - 301-400 - 301-400 - - - - 401-500 - 401-500 - - - - Bottom 100 - Ostatnie 100 - - - - Link: - Link: - - - - Add Anonymous Link - Dodaj Link Anonimowy - - - - Add Link/Comment - Dodaj Link/komentarz - - - - Title: - Tytuł: - - - - Score: - - - - - - +2 Great! - +2 Świetne! - - - - - +1 Good - +1 Dobre - - - - - 0 Okay - 0 W porządku - - - - - -1 Sux - -1 Ssie - - - - - -2 Bad Link - -2 Zły Link - - - - Url: - Url: - - - - Links Cloud - - - - - Add new link - Dodaj nowy link - - - - Share Link Anonymously - Udostępnij Link Anonimowo - - - - Vote on Link - Głosuj na Link - - - - Download - Pobierz - - - - - - Add Link Failure - - - - - Missing Link and/or Title - Brakujący Link i/lub Tytuł - - - - Missing Link Data - - - - - Missing Comment - Brakujący Komentarz - - - - Link Title Not Changed - - - - - Do you want to continue? - Czy chcesz kontynuować? - - - - Expand - Rozwiń - - - - Hide - Ukryj - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_ru.qm b/plugins/LinksCloud/lang/LinksCloud_ru.qm deleted file mode 100644 index f3b0a7d71..000000000 Binary files a/plugins/LinksCloud/lang/LinksCloud_ru.qm and /dev/null differ diff --git a/plugins/LinksCloud/lang/LinksCloud_ru.ts b/plugins/LinksCloud/lang/LinksCloud_ru.ts deleted file mode 100644 index 1193c8ade..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_ru.ts +++ /dev/null @@ -1,329 +0,0 @@ - - - AddLinksDialog - - - - Add Link - - - - - Cancel - Отмена - - - - Add a new Link - - - - - Title: - Заголовок: - - - - Url: - - - - - Add Anonymous Link - - - - - +2 Great! - - - - - +1 Good - - - - - 0 Okay - - - - - -1 Sux - - - - - -2 Bad Link - - - - - Add Link to Cloud - - - - - New Link - - - - - Add Link Failure - - - - - Missing Link and/or Title - - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - - - - - LinksCloud - - - - - LinksDialog - - - Title / Comment - Название / комментарий - - - - Score - - - - - Peer / Link - - - - - Sort by - Сортировать по - - - - Combo - - - - - Time - - - - - Ranking - - - - - In last - - - - - Month - - - - - Week - - - - - Day - - - - - From - От - - - - All Peers - - - - - Own Links - - - - - Show - Показать - - - - Top 100 - - - - - 101-200 - - - - - 201-300 - - - - - 301-400 - - - - - 401-500 - - - - - Bottom 100 - - - - - Link: - - - - - Add Anonymous Link - - - - - Add Link/Comment - - - - - Title: - Заголовок: - - - - Score: - - - - - - +2 Great! - - - - - - +1 Good - - - - - - 0 Okay - - - - - - -1 Sux - - - - - - -2 Bad Link - - - - - Url: - - - - - Links Cloud - - - - - Add new link - - - - - Share Link Anonymously - - - - - Vote on Link - - - - - Download - Скачать - - - - - - Add Link Failure - - - - - Missing Link and/or Title - - - - - Missing Link Data - - - - - Missing Comment - - - - - Link Title Not Changed - - - - - Do you want to continue? - - - - - Expand - Раскрыть - - - - Hide - Скрыть - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_sv.qm b/plugins/LinksCloud/lang/LinksCloud_sv.qm deleted file mode 100644 index cf26cabdc..000000000 Binary files a/plugins/LinksCloud/lang/LinksCloud_sv.qm and /dev/null differ diff --git a/plugins/LinksCloud/lang/LinksCloud_sv.ts b/plugins/LinksCloud/lang/LinksCloud_sv.ts deleted file mode 100644 index deccb0a68..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_sv.ts +++ /dev/null @@ -1,329 +0,0 @@ - - - AddLinksDialog - - - - Add Link - Lägg till länk - - - - Cancel - Avbryt - - - - Add a new Link - Lägg till ny länk - - - - Title: - Titel: - - - - Url: - URL: - - - - Add Anonymous Link - Lägg till länk anonymt - - - - +2 Great! - +2 Toppen! - - - - +1 Good - +1 Bra - - - - 0 Okay - 0 Okay - - - - -1 Sux - -1 Suger - - - - -2 Bad Link - -2 Dålig länk - - - - Add Link to Cloud - Lägg till länk i molnet - - - - New Link - Ny länk - - - - Add Link Failure - Kunde inte lägga till länk - - - - Missing Link and/or Title - Länk och/eller titel saknas - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - Det här tilläggsprogrammet tillför en uppsättning cachade länkar, och ett poängsystem för att klassificera dem. - - - - LinksCloud - LänkMoln - - - - LinksDialog - - - Title / Comment - Titel / Kommentar - - - - Score - Poäng - - - - Peer / Link - Användare / Länk - - - - Sort by - Sortera enligt - - - - Combo - Kombo - - - - Time - Tid - - - - Ranking - Ranking - - - - In last - Sist in - - - - Month - Månad - - - - Week - Vecka - - - - Day - Dag - - - - From - Från - - - - All Peers - Alla användare - - - - Own Links - Egna länkar - - - - Show - Visa - - - - Top 100 - Topp 100 - - - - 101-200 - 101-200 - - - - 201-300 - 201-300 - - - - 301-400 - 301-400 - - - - 401-500 - 401-500 - - - - Bottom 100 - 100 från botten - - - - Link: - Länk: - - - - Add Anonymous Link - Lägg till länk anonymt - - - - Add Link/Comment - Lägg till länk/kommentar - - - - Title: - Titel: - - - - Score: - Poäng: - - - - - +2 Great! - +2 Toppen! - - - - - +1 Good - +1 Bra - - - - - 0 Okay - 0 Okay - - - - - -1 Sux - -1 Suger - - - - - -2 Bad Link - -2 Dålig länk - - - - Url: - URL: - - - - Links Cloud - Länkmoln - - - - Add new link - Lägg till ny länk - - - - Share Link Anonymously - Dela länk anonymt - - - - Vote on Link - Rösta på länk - - - - Download - Ladda ner - - - - - - Add Link Failure - Kunde inte lägga till länk - - - - Missing Link and/or Title - Länk och/eller titel saknas - - - - Missing Link Data - Länkdata saknas - - - - Missing Comment - Kommentar saknas - - - - Link Title Not Changed - Länktitel ej ändrad - - - - Do you want to continue? - Vill du fortsätta? - - - - Expand - Visa - - - - Hide - Dölj - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_tr.qm b/plugins/LinksCloud/lang/LinksCloud_tr.qm deleted file mode 100644 index 1d221ac5e..000000000 Binary files a/plugins/LinksCloud/lang/LinksCloud_tr.qm and /dev/null differ diff --git a/plugins/LinksCloud/lang/LinksCloud_tr.ts b/plugins/LinksCloud/lang/LinksCloud_tr.ts deleted file mode 100644 index 7f4d4b7aa..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_tr.ts +++ /dev/null @@ -1,329 +0,0 @@ - - - AddLinksDialog - - - - Add Link - Bağlantı Ekleyin - - - - Cancel - İptal - - - - Add a new Link - Yeni bir bağlantı ekleyin - - - - Title: - Başlık: - - - - Url: - İnternet adresi: - - - - Add Anonymous Link - Anonim Bağlantı Ekleyin - - - - +2 Great! - +2 Harika! - - - - +1 Good - +1 İyi - - - - 0 Okay - 0 İdare eder - - - - -1 Sux - -1 Yaramaz - - - - -2 Bad Link - -2 Kötü bağlantı - - - - Add Link to Cloud - Bağlantıyı Buluta Ekleyin - - - - New Link - Bağlantı Ekleyin - - - - Add Link Failure - Bağlantı Eklenemedi - - - - Missing Link and/or Title - Eksik Bağlantı ya da Başlık - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - Bu uyumlu ek, ön belleğe alınmış bağlantıları görüntüler ve oylanmasını sağlar. - - - - LinksCloud - BağlantıBulutu - - - - LinksDialog - - - Title / Comment - Başlık / Yorum - - - - Score - Not - - - - Peer / Link - Bağlantı - - - - Sort by - Sıralama - - - - Combo - Bir Arada - - - - Time - Zaman - - - - Ranking - Derece - - - - In last - Son - - - - Month - Ay - - - - Week - Hafta - - - - Day - Gün - - - - From - Kimden - - - - All Peers - Tüm Bağlantılar - - - - Own Links - Kendi Bağlantılarınız - - - - Show - Görüntüleyin - - - - Top 100 - Üst 100 - - - - 101-200 - 101-200 - - - - 201-300 - 201-300 - - - - 301-400 - 301-400 - - - - 401-500 - 401-500 - - - - Bottom 100 - Alt 100 - - - - Link: - Bağlantı: - - - - Add Anonymous Link - Anonim Bağlantı Ekleyin - - - - Add Link/Comment - Bağlantı/Yorum Ekleyin - - - - Title: - Başlık: - - - - Score: - Not: - - - - - +2 Great! - +2 Harika! - - - - - +1 Good - +1 İyi - - - - - 0 Okay - 0 İdare eder - - - - - -1 Sux - -1 Yaramaz - - - - - -2 Bad Link - -2 Kötü Bağlantı - - - - Url: - İnternet Adresi: - - - - Links Cloud - Bağlantı Bulutu - - - - Add new link - Bağlantı ekleyin - - - - Share Link Anonymously - Bağlantıyı Anonim Olarak Paylaşın - - - - Vote on Link - Bağlantıyı Oylayın - - - - Download - İndirin - - - - - - Add Link Failure - Bağlantı Eklenemedi - - - - Missing Link and/or Title - Eksik Bağlantı ya da Başlık - - - - Missing Link Data - Eksik Bağlantı Verisi - - - - Missing Comment - Eksik Yorum - - - - Link Title Not Changed - Bağlantı Başlığı Değişmedi - - - - Do you want to continue? - Devam etmek istiyor musunuz? - - - - Expand - Genişletin - - - - Hide - Gizleyin - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_zh_CN.qm b/plugins/LinksCloud/lang/LinksCloud_zh_CN.qm deleted file mode 100644 index a0b21b5c1..000000000 Binary files a/plugins/LinksCloud/lang/LinksCloud_zh_CN.qm and /dev/null differ diff --git a/plugins/LinksCloud/lang/LinksCloud_zh_CN.ts b/plugins/LinksCloud/lang/LinksCloud_zh_CN.ts deleted file mode 100644 index 32d9d80e1..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_zh_CN.ts +++ /dev/null @@ -1,329 +0,0 @@ - - - AddLinksDialog - - - - Add Link - 添加链接 - - - - Cancel - 取消 - - - - Add a new Link - 添加一个新的链接 - - - - Title: - 标题: - - - - Url: - 网址: - - - - Add Anonymous Link - 添加匿名链接 - - - - +2 Great! - +2 真棒! - - - - +1 Good - +1 不错 - - - - 0 Okay - 0 还行 - - - - -1 Sux - -1 差 - - - - -2 Bad Link - -2 很差 - - - - Add Link to Cloud - 添加链接到云端 - - - - New Link - 新链接 - - - - Add Link Failure - 添加链接失败 - - - - Missing Link and/or Title - 丢失链接和(或)标题 - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - 这个插件提供一些缓存链接,和一个给这些链接评分的投票系统。 - - - - LinksCloud - LinksCloud - - - - LinksDialog - - - Title / Comment - 标题/评论 - - - - Score - 得分 - - - - Peer / Link - 节点 / 链接 - - - - Sort by - 排序方式 - - - - Combo - 综合 - - - - Time - 时间 - - - - Ranking - 排行 - - - - In last - 前一 - - - - Month - 个月 - - - - Week - - - - - Day - - - - - From - 来自 - - - - All Peers - 所有节点 - - - - Own Links - 自己的链接 - - - - Show - 显示 - - - - Top 100 - 前100 - - - - 101-200 - 101-200 - - - - 201-300 - 201-300 - - - - 301-400 - 301-400 - - - - 401-500 - 401-500 - - - - Bottom 100 - 后100 - - - - Link: - 链接: - - - - Add Anonymous Link - 添加匿名链接 - - - - Add Link/Comment - 添加链接/评论 - - - - Title: - 标题: - - - - Score: - 得分: - - - - - +2 Great! - +2 真棒! - - - - - +1 Good - +1 不错 - - - - - 0 Okay - 0 还行 - - - - - -1 Sux - -1 烂 - - - - - -2 Bad Link - -2 很差 - - - - Url: - 网址: - - - - Links Cloud - Links Cloud - - - - Add new link - 添加新链接 - - - - Share Link Anonymously - 匿名分享链接 - - - - Vote on Link - 为链接投票 - - - - Download - 下载 - - - - - - Add Link Failure - 添加链接失败 - - - - Missing Link and/or Title - 丢失链接和(或)标题 - - - - Missing Link Data - 丢失链接信息 - - - - Missing Comment - 丢失评论 - - - - Link Title Not Changed - 链接名未改变 - - - - Do you want to continue? - 想要继续? - - - - Expand - 展开 - - - - Hide - 隐藏 - - - \ No newline at end of file diff --git a/plugins/LinksCloud/p3ranking.cc b/plugins/LinksCloud/p3ranking.cc deleted file mode 100644 index 2fb72b7a3..000000000 --- a/plugins/LinksCloud/p3ranking.cc +++ /dev/null @@ -1,1350 +0,0 @@ -/* - * libretroshare/src/services p3ranking.cc - * - * 3P/PQI network interface for RetroShare. - * - * Copyright 2007-2008 by Robert Fernie. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License Version 2 as published by the Free Software Foundation. - * - * This library 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA. - * - * Please report all bugs and problems to "retroshare@lunamutt.com". - * - */ - -#include "rsrankitems.h" -#include "p3ranking.h" -#include -#include - -#include "pqi/p3linkmgr.h" -#include "pqi/pqibin.h" -#include "pqi/authssl.h" -#include "pqi/pqistore.h" - -RsRanks *rsRanks = NULL ; - -const uint32_t RANK_MAX_FWD_OFFSET = (60 * 60 * 24 * 2); /* 2 Days */ -const uint32_t RANK_STORE_PERIOD = (60 * 60 * 24 * 30 * 6); /* 6 months */ - -const uint32_t FRIEND_RANK_REPUBLISH_PERIOD = 60; /* every minute for testing */ -//const uint32_t FRIEND_RANK_REPUBLISH_PERIOD = 1800; /* every 30 minutes */ - -std::string generateRandomLinkId(); - -/***** - * TODO - * (1) Streaming. - * (2) Ranking. - * - */ - -/********* - * #define RANK_DEBUG 1 - *********/ -#define RANK_DEBUG 1 - -p3Ranking::p3Ranking(RsPluginHandler* pgHandler) - : RsCacheService(RS_SERVICE_TYPE_RANK,CONFIG_TYPE_RANK_LINK,5, pgHandler), - mRepublish(false), mRepublishFriends(false), mRepublishFriendTS(0), mStorePeriod(RANK_STORE_PERIOD), mUpdated(true),mRankMtx(std::string("p3Ranking")) -{ - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - - mOwnId = pgHandler->getLinkMgr()->getOwnId(); - mViewPeriod = 60 * 60 * 24 * 30; /* one Month */ - mSortType = RS_RANK_ALG; -} - -bool p3Ranking::loadLocalCache(const RsCacheData &data) -{ - std::string filename = data.path + '/' + data.name; - std::string hash = data.hash; - //uint64_t size = data.size; - std::string source = data.pid; - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::loadLocalCache()"; - std::cerr << std::endl; - std::cerr << "\tSource: " << source; - std::cerr << std::endl; - std::cerr << "\tFilename: " << filename; - std::cerr << std::endl; - std::cerr << "\tHash: " << hash; - std::cerr << std::endl; - std::cerr << "\tSize: " << data.size; - std::cerr << std::endl; -#endif - - loadRankFile(filename, source); - - { - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - mRepublish = false; - } - - if (data.size > 0) /* don't refresh zero sized caches */ - { - refreshCache(data); - } - return true; -} - -int p3Ranking::loadCache(const RsCacheData &data) -{ - std::string filename = data.path + '/' + data.name; - std::string hash = data.hash; - //uint64_t size = data.size; - std::string source = data.pid; - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::loadCache()"; - std::cerr << std::endl; - std::cerr << "\tSource: " << source; - std::cerr << std::endl; - std::cerr << "\tFilename: " << filename; - std::cerr << std::endl; - std::cerr << "\tHash: " << hash; - std::cerr << std::endl; - std::cerr << "\tSize: " << data.size; - std::cerr << std::endl; -#endif - - loadRankFile(filename, source); - - - CacheStore::lockData(); /***** LOCK ****/ - locked_storeCacheEntry(data); - CacheStore::unlockData(); /***** UNLOCK ****/ - - return 1; -} - - -void p3Ranking::loadRankFile(std::string filename, std::string src) -{ - /* create the serialiser to load info */ - RsSerialiser *rsSerialiser = new RsSerialiser(); - rsSerialiser->addSerialType(new RsRankSerialiser()); - - uint32_t bioflags = BIN_FLAGS_HASH_DATA | BIN_FLAGS_READABLE; - BinInterface *bio = new BinFileInterface(filename.c_str(), bioflags); - pqistore *store = new pqistore(rsSerialiser, src, bio, BIN_FLAGS_READABLE); - - time_t now = time(NULL); - time_t min, max; - - { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - - min = now - mStorePeriod; - max = now + RANK_MAX_FWD_OFFSET; - - } /********** STACK LOCKED MTX ******/ - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::loadRankFile()"; - std::cerr << std::endl; - std::cerr << "\tSource: " << src; - std::cerr << std::endl; - std::cerr << "\tFilename: " << filename; - std::cerr << std::endl; -#endif - - RsItem *item; - RsRankLinkMsg *newMsg; - - while(NULL != (item = store->GetItem())) - { - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::loadRankFile() Got Item:"; - std::cerr << std::endl; - item->print(std::cerr, 10); - std::cerr << std::endl; -#endif - - if (NULL == (newMsg = dynamic_cast(item))) - { -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::loadRankFile() Item not LinkMsg (deleting):"; - std::cerr << std::endl; -#endif - - delete item; - } - /* check timestamp */ - else if (((time_t) newMsg->timestamp < min) || - ((time_t) newMsg->timestamp > max)) - { -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::loadRankFile() Outside TimeRange (deleting):"; - std::cerr << std::endl; -#endif - /* if outside range -> remove */ - delete newMsg; - } - else - { -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::loadRankFile() Loading Item"; - std::cerr << std::endl; -#endif - /* correct the source (if is a message from a friend) */ - newMsg->PeerId(newMsg->pid); - addRankMsg(newMsg); - } - } - - delete store; -} - - -void p3Ranking::publishMsgs(bool own) -{ - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::publishMsgs()"; - std::cerr << std::endl; -#endif - - std::string path = CacheSource::getCacheDir(); - uint16_t subid; - - - /* setup name / etc based on whether we're - * publishing own or friends... - */ - - /* determine filename */ - std::string tmpname; - if (own) - { - /* setup to publish own messages */ - rs_sprintf(tmpname, "rank-links-%ld.rsrl", time(NULL)); - subid = 1; - } - else - { - /* setup to publish friend messages */ - rs_sprintf(tmpname, "rank-friend-links-%ld.rsrl", time(NULL)); - subid = 2; - } - - std::string fname = path + "/" + tmpname; - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::publishMsgs() Storing to: " << fname; - std::cerr << std::endl; -#endif - - RsSerialiser *rsSerialiser = new RsSerialiser(); - rsSerialiser->addSerialType(new RsRankSerialiser()); - - uint32_t bioflags = BIN_FLAGS_HASH_DATA | BIN_FLAGS_WRITEABLE; - BinInterface *bio = new BinFileInterface(fname.c_str(), bioflags); - pqistore *store = new pqistore(rsSerialiser, mOwnId, bio, BIN_FLAGS_NO_DELETE | BIN_FLAGS_WRITEABLE); - - { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - - /* iterate through list */ - std::map::iterator it; - std::map::iterator cit; - - for(it = mData.begin(); it != mData.end(); it++) - { - if (own) - { - if (it->second.ownTag) - { - /* write to serialiser */ - RsItem *item = it->second.comments[mOwnId]; - if (item) - { - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::publishMsgs() Storing Item:"; - std::cerr << std::endl; - item->print(std::cerr, 10); - std::cerr << std::endl; -#endif - store->SendItem(item); - } - } - else - { -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::publishMsgs() Skipping Foreign item"; - std::cerr << std::endl; -#endif - } - } - else - { - /* if we have pushed it out already - don't bother */ - if (it->second.ownTag) - { -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::publishMsgs() (Friends) Skipping Own Item"; - std::cerr << std::endl; -#endif - continue; - } - - /* if we have some comments ... then a friend has recommended it - * serialise a sanitized version. - */ - if (it->second.comments.size() > 0) - { - RsRankLinkMsg *origmsg = (it->second.comments.begin())->second; - RsRankLinkMsg *msg = new RsRankLinkMsg(); - - /* copy anon data */ - -/*************************************************************************/ -/****************************** LINK SPECIFIC ****************************/ -/*************************************************************************/ - msg->clear(); - msg->PeerId(""); - msg->pid = ""; /* Anon */ - msg->rid = origmsg->rid; - msg->link = origmsg->link; - msg->title = origmsg->title; - msg->timestamp = origmsg->timestamp; - msg->score = 0; - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::publishMsgs() (Friends) Storing (Anon) Item:"; - std::cerr << std::endl; - msg->print(std::cerr, 10); - std::cerr << std::endl; -#endif - store->SendItem(msg); - - /* cleanup */ - delete msg; - } - } - } - - - /* now we also add our anon messages to the friends list */ - if (!own) - { - std::list::iterator ait; - for(ait=mAnon.begin(); ait != mAnon.end(); ait++) - { -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::publishMsgs() (Friends) Adding Own Anon Item:"; - std::cerr << std::endl; - (*ait)->print(std::cerr, 10); - std::cerr << std::endl; -#endif - store->SendItem(*ait); - } - } - - } /********** STACK LOCKED MTX ******/ - - /* flag as new info */ - RsCacheData data; - - { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - data.pid = mOwnId; - } /********** STACK LOCKED MTX ******/ - - data.cid = CacheId(CacheSource::getCacheType(), subid); - - data.path = path; - data.name = tmpname; - - data.hash = bio->gethash(); - data.size = bio->bytecount(); - data.recvd = time(NULL); - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::publishMsgs() refreshing Cache"; - std::cerr << std::endl; - std::cerr << "\tCache Path: " << data.path; - std::cerr << std::endl; - std::cerr << "\tCache Name: " << data.name; - std::cerr << std::endl; - std::cerr << "\tCache Hash: " << data.hash; - std::cerr << std::endl; - std::cerr << "\tCache Size: " << data.size; - std::cerr << std::endl; -#endif - if (data.size > 0) /* don't refresh zero sized caches */ - { - refreshCache(data); - } - - delete store; -} - - - -void p3Ranking::addRankMsg(RsRankLinkMsg *msg) -{ - /* find msg */ - std::string id = msg->PeerId(); - std::string rid = msg->rid; - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::addRankMsg() Item:"; - std::cerr << std::endl; - msg->print(std::cerr, 10); - std::cerr << std::endl; -#endif - - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - - std::map::iterator it; - it = mData.find(rid); - if (it == mData.end()) - { - /* add a new one */ - RankGroup grp; - grp.rid = rid; - grp.ownTag = false; - grp.rank = 0.0f; - -/*************************************************************************/ -/****************************** LINK SPECIFIC ****************************/ -/*************************************************************************/ - - grp.link = msg->link; - grp.title = msg->title; - -/*************************************************************************/ -/****************************** LINK SPECIFIC ****************************/ -/*************************************************************************/ - - mData[rid] = grp; - it = mData.find(rid); - - if (id == "") - { -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::addRankMsg() New Anon Link: mUpdated = true"; - std::cerr << std::endl; -#endif - locked_reSortGroup(it->second); - mUpdated = true; - } - } - - /**** If it is an anonymous Link (ie Friend of a Friend) Drop out now ***/ - if (id == "") - { - return; - } - - /* check for old comment */ - std::map::iterator cit; - cit = (it->second).comments.find(id); - - /* Check that it is different! */ - bool newComment = false; - if ((it->second).comments.end() == cit) - { - newComment = true; - } - else - { - RsRankLinkMsg *old = cit->second; - if ((msg->timestamp != old->timestamp) || - (msg->comment != old->comment)) - { - newComment = true; - } - } - - if (newComment) - { -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::addRankMsg() New Comment"; - std::cerr << std::endl; -#endif - /* clean up old */ - if ((it->second).comments.end() != cit) - { - delete (cit->second); - (it->second).comments.erase(cit); - } - - /* add in */ - (it->second).comments[id] = msg; - - /* republish? */ - if (id == mOwnId) - { - it->second.ownTag = true; - mRepublish = true; -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::addRankMsg() Own Comment: mRepublish = true"; - std::cerr << std::endl; -#endif - } - else - { - mRepublishFriends = true; -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::addRankMsg() Other Comment: mRepublishFriends = true"; - std::cerr << "p3Ranking::addRankMsg() Old Comment ignoring"; - std::cerr << std::endl; -#endif - } - - locked_reSortGroup(it->second); - - mUpdated = true; - } - else - { - delete msg; -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::addRankMsg() Old Comment ignoring"; - std::cerr << std::endl; -#endif - } -} - - -/***************** Sorting ****************/ - -bool p3Ranking::setSortPeriod(uint32_t period) -{ - bool reSort = false; - - { - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - reSort = (mViewPeriod != period); - mViewPeriod = period; - } - - - if (reSort) - { - sortAllMsgs(); - } - - return true; -} - -bool p3Ranking::setSortMethod(uint32_t type) -{ - bool reSort = false; - - { - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - reSort = (mSortType != type); - mSortType = type; - } - - if (reSort) - { - sortAllMsgs(); - } - - return true; -} - -bool p3Ranking::clearPeerFilter() -{ - bool reSort = false; - - { - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - reSort = (mPeerFilter.size() > 0); - mPeerFilter.clear(); - } - - - if (reSort) - { - sortAllMsgs(); - } - - return true; -} - -bool p3Ranking::setPeerFilter(std::list peers) -{ - { - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - mPeerFilter = peers; - } - - sortAllMsgs(); - - return true; -} - -float p3Ranking::locked_calcRank(RankGroup &grp) -{ - /* Ranking Calculations ..... - */ - - time_t now = time(NULL); - time_t minTime = now-mViewPeriod; - bool doFilter = (mPeerFilter.size() > 0); - bool doScore = (mSortType & RS_RANK_SCORE); - bool doTime = (mSortType & RS_RANK_TIME); - - uint32_t count = 0; - float algScore = 0; - float comboScore = 0; - float popScore = 0; - -#ifdef RANK_DEBUG - std::string normlink(grp.link.begin(), grp.link.end()); - std::cerr << "p3Ranking::locked_calcRank() for: " << normlink; - std::cerr << std::endl; - std::cerr << "Period: " << mViewPeriod; - std::cerr << " doFilter: " << doFilter; - std::cerr << " doScore: " << doScore; - std::cerr << " doTime: " << doTime; - std::cerr << std::endl; -#endif - - std::map::iterator it; - for(it = grp.comments.begin(); it != grp.comments.end(); it++) - { -#ifdef RANK_DEBUG - std::cerr << "Comment by:" << it->first << " age: " << now - it->second->timestamp; - std::cerr << std::endl; -#endif - if (doFilter) - { - if (mPeerFilter.end() == - std::find(mPeerFilter.begin(), mPeerFilter.end(), it->first)) - { - continue; /* skip it */ -#ifdef RANK_DEBUG - std::cerr << "\tFiltered Out"; - std::cerr << std::endl; -#endif - - } - } - - /* if Scoring is involved... drop old ones */ - if ((doScore) && ((time_t) it->second->timestamp < minTime)) - { -#ifdef RANK_DEBUG - std::cerr << "\tToo Old"; - std::cerr << std::endl; -#endif - continue; - } - - time_t deltaT; - if ((time_t) it->second->timestamp > now) - { - deltaT = it->second->timestamp - now; - } - else - { - deltaT = now - it->second->timestamp; - } - float timeScore = ((float) mViewPeriod - deltaT) / (mViewPeriod + 0.01); - -#ifdef RANK_DEBUG - std::cerr << "\tTimeScore: " << timeScore; - std::cerr << std::endl; -#endif - - /* algScore is sum of (filtered) timeScores */ - /* timeScore is average of (all) timeScores */ - /* popScore is just count of valid scores */ - - algScore += timeScore; - count++; - - /* for more advanced scoring (where each peer gives a score +2 -> -2) */ - /* combo = SUM value * timeScore */ - /* time = same as before (average) */ - /* popScore = SUM value */ - - float value = it->second->score; - comboScore += value * timeScore; - popScore += value; - } - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::locked_calcRank() algScore: " << algScore; - std::cerr << " Count: " << count; - std::cerr << std::endl; -#endif - - if ((count <= 0) || (algScore <= 0)) - { -#ifdef RANK_DEBUG - std::cerr << "Final score: 0"; - std::cerr << std::endl; -#endif - return 0; - } - - if ((doScore) && (doTime)) - { -#ifdef RANK_DEBUG - std::cerr << "Old (alg) score:" << algScore; - std::cerr << std::endl; - std::cerr << "Final (Combo) score:" << comboScore; - std::cerr << std::endl; -#endif - - if (comboScore < 0) - { -#ifdef RANK_DEBUG - std::cerr << "Combo score reset = 0"; - std::cerr << std::endl; -#endif - comboScore = 0; - } - return comboScore; - - } - else if (doScore) - { -#ifdef RANK_DEBUG - std::cerr << "Old (tally) score:" << count; - std::cerr << std::endl; - std::cerr << "Final (pop) score:" << popScore; - std::cerr << std::endl; -#endif - if (popScore < 0) - { -#ifdef RANK_DEBUG - std::cerr << "Pop score reset = 0"; - std::cerr << std::endl; -#endif - popScore = 0; - } - return popScore; - } - else if (doTime) - { -#ifdef RANK_DEBUG - std::cerr << "Final (time) score:" << algScore / count; - std::cerr << std::endl; -#endif - return algScore / count; - } - return 0; -} - - -void p3Ranking::locked_reSortGroup(RankGroup &grp) -{ - std::string rid = grp.rid; - - /* remove from existings rankings */ - std::multimap::iterator rit; - rit = mRankings.lower_bound(grp.rank); - for(; (rit != mRankings.end()) && (rit->first == grp.rank); rit++) - { - if (rit->second == rid) - { - mRankings.erase(rit); - break; - } - } - - /* add it back in */ - grp.rank = locked_calcRank(grp); - mRankings.insert( - std::pair(grp.rank, rid)); -} - -void p3Ranking::sortAllMsgs() -{ - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - - /* iterate through list and re-score each one */ - std::map::iterator it; - - mRankings.clear(); - - for(it = mData.begin(); it != mData.end(); it++) - { - (it->second).rank = locked_calcRank(it->second); - if (it->second.rank < 0) - { - it->second.rank = 0; - } - - mRankings.insert( - std::pair - (it->second.rank, it->first)); - } -} - -/******** ACCESS *************/ - - /* get Ids */ -uint32_t p3Ranking::getRankingsCount() -{ - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - - return mRankings.size(); -} - -float p3Ranking::getMaxRank() -{ - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - - if (mRankings.size() == 0) - return 0; - - return mRankings.rbegin()->first; -} - -bool p3Ranking::getRankings(uint32_t first, uint32_t count, std::list &rids) -{ - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::getRankings() First: " << first << " Count: " << count; - std::cerr << std::endl; -#endif - - uint32_t i = 0; - std::multimap::reverse_iterator rit; - for(rit = mRankings.rbegin(); (i < first) && (rit != mRankings.rend()); rit++, i++); - - i = 0; - for(; (i < count) && (rit != mRankings.rend()); rit++, i++) - { - rids.push_back(rit->second); - } - return true; -} - - -bool p3Ranking::getRankDetails(std::string rid, RsRankDetails &details) -{ - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - - /* get the details. */ - - std::map::iterator it; - it = mData.find(rid); - if (mData.end() == it) - { - return false; - } - -/*************************************************************************/ -/****************************** LINK SPECIFIC ****************************/ -/*************************************************************************/ - - details.rid = it->first; - details.link = (it->second).link; - details.title = (it->second).title; - details.rank = (it->second).rank; - details.ownTag = (it->second).ownTag; - -/*************************************************************************/ -/****************************** LINK SPECIFIC ****************************/ -/*************************************************************************/ - - std::map::iterator cit; - for(cit = (it->second).comments.begin(); - cit != (it->second).comments.end(); cit++) - { - RsRankComment comm; - comm.id = (cit->second)->PeerId(); - comm.timestamp = (cit->second)->timestamp; - comm.comment = (cit->second)->comment; - comm.score = (cit->second)->score; - - details.comments.push_back(comm); - } - - return true; -} - - -void p3Ranking::tick() -{ - bool repub = false; - bool repubFriends = false; - - { - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - repub = mRepublish; - repubFriends = mRepublishFriends && (time(NULL) > mRepublishFriendTS); - } - - if (repub) - { - publishMsgs(true); - - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - mRepublish = false; - } - - - if (repubFriends) - { - publishMsgs(false); - - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - mRepublishFriends = false; - mRepublishFriendTS = time(NULL) + FRIEND_RANK_REPUBLISH_PERIOD; - } - - -} - -bool p3Ranking::updated() -{ - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - - if (mUpdated) - { - mUpdated = false; - return true; - } - return false; -} - -/***** NEW CONTENT *****/ -/*************************************************************************/ -/****************************** LINK SPECIFIC ****************************/ -/*************************************************************************/ -std::string p3Ranking::newRankMsg(std::wstring link, std::wstring title, std::wstring comment, int32_t score) -{ - /* generate an id */ - std::string rid = generateRandomLinkId(); - - RsRankLinkMsg *msg = new RsRankLinkMsg(); - - time_t now = time(NULL); - - { - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - msg->PeerId(mOwnId); - msg->pid = mOwnId; - } - - msg->rid = rid; - msg->title = title; - msg->timestamp = now; - msg->comment = comment; - msg->score = score; - - msg->linktype = RS_LINK_TYPE_WEB; - msg->link = link; - - - addRankMsg(msg); - - return rid; -} - - -/*************************************************************************/ -/****************************** LINK SPECIFIC ****************************/ -/*************************************************************************/ -bool p3Ranking::updateComment(std::string rid, std::wstring comment, int32_t score) -{ - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::updateComment() rid:" << rid; - std::cerr << std::endl; -#endif - RsRankLinkMsg *msg = NULL; - - { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - - std::map::iterator it; - it = mData.find(rid); - if (it == mData.end()) - { - /* missing group -> fail */ - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::updateComment() Failed - noData"; - std::cerr << std::endl; -#endif - return false; - } - - msg = new RsRankLinkMsg(); - - time_t now = time(NULL); - - msg->PeerId(mOwnId); - msg->pid = mOwnId; - msg->rid = rid; - msg->timestamp = now; - msg->title = (it->second).title; - msg->comment = comment; - msg->score = score; - - msg->linktype = RS_LINK_TYPE_WEB; - msg->link = (it->second).link; - - } /********** STACK UNLOCKED MTX ******/ - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::updateComment() Item:"; - std::cerr << std::endl; - msg->print(std::cerr, 10); - std::cerr << std::endl; -#endif - - addRankMsg(msg); - return true; -} - -/*************************************************************************/ -/****************************** LINK SPECIFIC ****************************/ -/*************************************************************************/ -std::string p3Ranking::anonRankMsg(std::string rid, std::wstring link, std::wstring title) -{ - bool alreadyExists = true; - - if (rid == "") - { - alreadyExists = false; - /* generate an id */ - rid = generateRandomLinkId(); - } - - RsRankLinkMsg *msg1 = new RsRankLinkMsg(); - RsRankLinkMsg *msg2 = new RsRankLinkMsg(); - - time_t now = time(NULL); - - { - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - msg1->PeerId(""); - msg1->pid = ""; - - msg2->PeerId(""); - msg2->pid = ""; - } - - msg1->rid = rid; - msg1->title = title; - msg1->timestamp = now; - msg1->comment.clear(); - msg1->score = 0; - - msg1->linktype = RS_LINK_TYPE_WEB; - msg1->link = link; - - msg2->rid = rid; - msg2->title = title; - msg2->timestamp = now; - msg2->comment.clear(); - msg2->score = 0; - - msg2->linktype = RS_LINK_TYPE_WEB; - msg2->link = link; - - if (alreadyExists) - { - delete msg1; - } - else - { - addRankMsg(msg1); - } - - addAnonToList(msg2); - - return rid; -} - - - -pqistore *createStore(std::string file, std::string src, bool reading) -{ - - RsSerialiser *rsSerialiser = new RsSerialiser(); - rsSerialiser->addSerialType(new RsRankSerialiser()); - - uint32_t bioflags = BIN_FLAGS_HASH_DATA; - if (reading) - { - bioflags |= BIN_FLAGS_READABLE; - } - else - { - bioflags |= BIN_FLAGS_WRITEABLE; - } - - /* bin flags: READ | WRITE | HASH_DATA */ - BinInterface *bio = new BinFileInterface(file.c_str(), bioflags); - /* store flags: NO_DELETE (yes) | NO_CLOSE (no) */ - pqistore *store = new pqistore(rsSerialiser, src, bio, BIN_FLAGS_NO_DELETE | (bioflags & BIN_FLAGS_WRITEABLE)); - - return store; -} - -std::string generateRandomLinkId() -{ - std::string out; -/********************************** WINDOWS/UNIX SPECIFIC PART ******************/ -#ifndef WINDOWS_SYS - /* 4 bytes per random number: 4 x 4 = 16 bytes */ - for(int i = 0; i < 4; i++) - { - uint32_t rint = random(); - rs_sprintf_append(out, "%08x", rint); - } -#else - srand(time(NULL)); - /* 2 bytes per random number: 8 x 2 = 16 bytes */ - for(int i = 0; i < 8; i++) - { - uint16_t rint = rand(); /* only gives 16 bits */ - rs_sprintf_append(out, "%04x", rint); - } -#endif -/********************************** WINDOWS/UNIX SPECIFIC PART ******************/ - return out; -} - - -/*************************************************************************/ -/****************************** LINK SPECIFIC ****************************/ -/*************************************************************************/ -void p3Ranking::createDummyData() -{ - RsRankLinkMsg *msg = new RsRankLinkMsg(); - - time_t now = time(NULL); - - msg->PeerId(mOwnId); - msg->pid = mOwnId; - msg->rid = "0001"; - msg->title = L"Original Awesome Site!"; - msg->timestamp = now - 60 * 60 * 24 * 15; - msg->link = L"http://www.retroshare.org"; - msg->comment = L"Retroshares Website"; - msg->score = 1; - - addRankMsg(msg); - - msg = new RsRankLinkMsg(); - msg->PeerId(mOwnId); - msg->pid = mOwnId; - msg->rid = "0002"; - msg->title = L"Awesome Site!"; - msg->timestamp = now - 123; - msg->link = L"http://www.lunamutt.org"; - msg->comment = L"Lunamutt's Website"; - msg->score = 1; - - addRankMsg(msg); - - msg = new RsRankLinkMsg(); - msg->PeerId("ALTID"); - msg->pid = "ALTID"; - msg->rid = "0002"; - msg->title = L"Awesome Site!"; - msg->timestamp = now - 60 * 60 * 24 * 29; - msg->link = L"http://www.lunamutt.org"; - msg->comment = L"Lunamutt's Website (TWO) How Long can this comment be!\n"; - msg->comment += L"What happens to the second line?\n"; - msg->comment += L"And a 3rd!"; - msg->score = 1; - - addRankMsg(msg); - - msg = new RsRankLinkMsg(); - msg->PeerId("ALTID2"); - msg->pid = "ALTID2"; - msg->rid = "0002"; - msg->title = L"Awesome Site!"; - msg->timestamp = now - 60 * 60 * 7; - msg->link = L"http://www.lunamutt.org"; - msg->comment += L"A Short Comment"; - msg->score = 1; - - addRankMsg(msg); - - - /***** Third one ****/ - - msg = new RsRankLinkMsg(); - msg->PeerId(mOwnId); - msg->pid = mOwnId; - msg->rid = "0003"; - msg->title = L"Weird Site!"; - msg->timestamp = now - 60 * 60; - msg->link = L"http://www.lunamutt.com"; - msg->comment = L""; - msg->score = 1; - - addRankMsg(msg); - - msg = new RsRankLinkMsg(); - msg->PeerId("ALTID"); - msg->pid = "ALTID"; - msg->rid = "0003"; - msg->title = L"Weird Site!"; - msg->timestamp = now - 60 * 60 * 24 * 2; - msg->link = L"http://www.lunamutt.com"; - msg->comment = L""; - msg->score = 1; - - addRankMsg(msg); - -} - - -/***************************************************************************/ -/****************************** CONFIGURATION HANDLING *********************/ -/***************************************************************************/ - -/**** Store Anon Links: OVERLOADED FROM p3Config ****/ - -RsSerialiser *p3Ranking::setupSerialiser() -{ - RsSerialiser *rss = new RsSerialiser(); - - /* add in the types we need! */ - rss->addSerialType(new RsRankSerialiser()); - return rss; -} - -bool p3Ranking::addAnonToList(RsRankLinkMsg *msg) -{ - { - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - std::list::iterator it; - for(it = mAnon.begin(); it != mAnon.end(); it++) - { - if (msg->rid == (*it)->rid) - break; - } - - if (it != mAnon.end()) - { - delete msg; - return false; - } - - mAnon.push_back(msg); - mRepublishFriends = true; - } - - IndicateConfigChanged(); /**** INDICATE CONFIG CHANGED! *****/ - return true; -} - -bool p3Ranking::saveList(bool &cleanup, std::list & saveData) -{ - - mRankMtx.lock(); /*********************** LOCK *******/ - - cleanup = false; - - std::list::iterator it; - for(it = mAnon.begin(); it != mAnon.end(); it++) - { - saveData.push_back(*it); - } - - /* list completed! */ - return true; -} - -void p3Ranking::saveDone() -{ - mRankMtx.unlock(); /*********************** UNLOCK *******/ - return; -} - -bool p3Ranking::loadList(std::list& load) -{ - std::list::iterator it; - RsRankLinkMsg *msg; - -#ifdef SERVER_DEBUG - std::cerr << "p3Ranking::loadList() Item Count: " << load.size(); - std::cerr << std::endl; -#endif - - time_t now = time(NULL); - time_t min, max; - - { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - - min = now - mStorePeriod; - max = now + RANK_MAX_FWD_OFFSET; - - } /********** STACK LOCKED MTX ******/ - - for(it = load.begin(); it != load.end(); it++) - { - /* switch on type */ - if (NULL != (msg = dynamic_cast(*it))) - { - /* check date -> if old expire */ - if (((time_t) msg->timestamp < min) || - ((time_t) msg->timestamp > max)) - { -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::loadList() Outside TimeRange (deleting Own Anon):"; - std::cerr << std::endl; -#endif - /* if outside range -> remove */ - delete msg; - continue; - } - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::loadList() Anon TimeRange ok"; - std::cerr << std::endl; -#endif - msg->PeerId(""); - msg->pid = ""; - - RsRankLinkMsg *msg2 = new RsRankLinkMsg(); - msg2->clear(); - msg2->PeerId(msg->PeerId()); - msg2->pid = msg->pid; - msg2->rid = msg->rid; - msg2->title = msg->title; - msg2->timestamp = msg->timestamp; - msg2->comment.clear(); - msg2->score = 0; - - msg2->linktype = msg->linktype; - msg2->link = msg->link; - - /* make a copy to add into standard map */ - addRankMsg(msg); - - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - mAnon.push_back(msg2); - } - else - { - /* cleanup */ - delete (*it); - } - } - - return true; - -} - diff --git a/plugins/LinksCloud/p3ranking.h b/plugins/LinksCloud/p3ranking.h deleted file mode 100644 index 13a5cdeac..000000000 --- a/plugins/LinksCloud/p3ranking.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * libretroshare/src/services: p3ranking.h - * - * 3P/PQI network interface for RetroShare. - * - * Copyright 2007-2008 by Robert Fernie. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License Version 2 as published by the Free Software Foundation. - * - * This library 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA. - * - * Please report all bugs and problems to "retroshare@lunamutt.com". - * - */ - -#ifndef P3_GENERIC_RANKING_HEADER -#define P3_GENERIC_RANKING_HEADER - -class pqistore ; - -#include "retroshare/rsplugin.h" -#include "plugins/rscacheservice.h" - -#include "rsrank.h" - -/* - * A Generic Ranking system. - * Each User provides one cache... - * - * can be overloaded for specific types - * (links, shares, photos etc) - * - * This is not generic yet!!! - */ - -class RsRankMsg; -class RsRankLinkMsg; - -const uint16_t RS_SERVICE_TYPE_RANK = 0x0002 ; -const uint32_t CONFIG_TYPE_RANK_LINK = 0x0011 ; - -class RankGroup -{ - public: - - std::string rid; /* Random Id */ - std::wstring link; - std::wstring title; - float rank; - bool ownTag; - std::map comments; -}; - -class p3Ranking: public RsCacheService, public RsRanks -{ - public: - - p3Ranking(RsPluginHandler* pgHandler) ; - - - /******************************* CACHE SOURCE / STORE Interface *********************/ - - /* overloaded functions from Cache Source */ - virtual bool loadLocalCache(const RsCacheData &data); - - /* overloaded functions from Cache Store */ - virtual int loadCache(const RsCacheData &data); - - /******************************* CACHE SOURCE / STORE Interface *********************/ - - public: - - /************* Extern Interface *******/ - - /* changed */ - virtual bool updated(); - - /* Set Sort Methods */ - virtual bool setSortPeriod(uint32_t period); - virtual bool setSortMethod(uint32_t type); - virtual bool clearPeerFilter(); - virtual bool setPeerFilter(std::list peers); - - /* get Ids */ - virtual uint32_t getRankingsCount(); - virtual float getMaxRank(); - virtual bool getRankings(uint32_t first, uint32_t count, std::list &rids); - virtual bool getRankDetails(std::string rid, RsRankDetails &details); - - /* Add New Comment / Msg */ - virtual std::string newRankMsg(std::wstring link, std::wstring title, std::wstring comment, int32_t score); - virtual bool updateComment(std::string rid, std::wstring comment, int32_t score); - virtual std::string anonRankMsg(std::string rid, std::wstring link, std::wstring title); - - - virtual void tick(); - - void loadRankFile(std::string filename, std::string src); - void addRankMsg(RsRankLinkMsg *msg); - void publishMsgs(bool own); - - float locked_calcRank(RankGroup &grp); /* returns 0->100 */ - void locked_reSortGroup(RankGroup &grp); - - void sortAllMsgs(); - pqistore *createStore(std::string file, std::string src, bool reading); - - - /****************** p3Config STUFF *******************/ - protected: - bool addAnonToList(RsRankLinkMsg *msg); - - virtual RsSerialiser *setupSerialiser(); - virtual bool saveList(bool &cleanup, std::list&); - virtual bool loadList(std::list& load); - virtual void saveDone(); - - private: - - void createDummyData(); - - uint32_t storePeriod; - p3LinkMgr *mConnMgr; - - RsMutex mRankMtx; - - /***** below here is locked *****/ - - bool mRepublish; - bool mRepublishFriends; - time_t mRepublishFriendTS; - - uint32_t mStorePeriod; - - std::string mOwnId; - bool mUpdated; - bool mRepost; - - std::map mData; - std::multimap mRankings; - - /* Filter/Sort params */ - std::list mPeerFilter; - uint32_t mViewPeriod; - uint32_t mSortType; - - /* Anonymous Link List */ - std::list mAnon; - -}; - -#endif - - - diff --git a/plugins/LinksCloud/rsrank.h b/plugins/LinksCloud/rsrank.h deleted file mode 100644 index a69425c91..000000000 --- a/plugins/LinksCloud/rsrank.h +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef RETROSHARE_RANKING_GUI_INTERFACE_H -#define RETROSHARE_RANKING_GUI_INTERFACE_H - -/* - * libretroshare/src/rsiface: rsrank.h - * - * RetroShare C++ Interface. - * - * Copyright 2007-2008 by Robert Fernie. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License Version 2 as published by the Free Software Foundation. - * - * This library 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA. - * - * Please report all bugs and problems to "retroshare@lunamutt.com". - * - */ - -#include -#include -#include - -/* The Main Interface Class - for information about your Peers */ -class RsRanks; -extern RsRanks *rsRanks; - -class RsRankComment -{ - public: - - std::string id; - std::wstring comment; - int32_t score; - time_t timestamp; -}; - -class RsRankDetails -{ - public: - - std::string rid; - std::wstring link; - std::wstring title; - float rank; - bool ownTag; - - std::list comments; -}; - -const uint32_t RS_RANK_SCORE = 0x0001; -const uint32_t RS_RANK_TIME = 0x0002; -const uint32_t RS_RANK_ALG = 0x0003; - -std::ostream &operator<<(std::ostream &out, const RsRankDetails &detail); - -class RsRanks -{ - public: - - RsRanks() { return; } -virtual ~RsRanks() { return; } - - /* needs update? */ -virtual bool updated() = 0; - - /* Set Sort Methods */ -virtual bool setSortPeriod(uint32_t period) = 0; -virtual bool setSortMethod(uint32_t type) = 0; -virtual bool clearPeerFilter() = 0; -virtual bool setPeerFilter(std::list peers) = 0; - - /* get Ids */ -virtual uint32_t getRankingsCount() = 0; -virtual float getMaxRank() = 0; -virtual bool getRankings(uint32_t first, uint32_t count, std::list &rids) = 0; -virtual bool getRankDetails(std::string rid, RsRankDetails &details) = 0; - - /* Add New Comment / Msg */ -virtual std::string newRankMsg(std::wstring link, std::wstring title, std::wstring comment, int32_t score) = 0; -virtual bool updateComment(std::string rid, std::wstring comment, int32_t score) = 0; - -virtual std::string anonRankMsg(std::string rid, std::wstring link, std::wstring title) = 0; - -}; - -#endif diff --git a/plugins/LinksCloud/rsrankitems.cc b/plugins/LinksCloud/rsrankitems.cc deleted file mode 100644 index dbae0de68..000000000 --- a/plugins/LinksCloud/rsrankitems.cc +++ /dev/null @@ -1,253 +0,0 @@ - -/* - * libretroshare/src/serialiser: rsbaseitems.cc - * - * RetroShare Serialiser. - * - * Copyright 2007-2008 by Robert Fernie. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License Version 2 as published by the Free Software Foundation. - * - * This library 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA. - * - * Please report all bugs and problems to "retroshare@lunamutt.com". - * - */ - -#include "serialiser/rsbaseserial.h" -#include "serialiser/rstlvbase.h" -#include "rsrankitems.h" - -#define RSSERIAL_DEBUG 1 -#include - -/*************************************************************************/ - -void RsRankMsg::clear() -{ - rid.clear(); - timestamp = 0; - title.clear(); - comment.clear(); -} - -std::ostream &RsRankMsg::print(std::ostream &out, uint16_t indent) -{ - printRsItemBase(out, "RsRankMsg", indent); - uint16_t int_Indent = indent + 2; - printIndent(out, int_Indent); - out << "rid: " << rid << std::endl; - - printIndent(out, int_Indent); - out << "timestamp: " << timestamp << std::endl; - - - printIndent(out, int_Indent); - - std::string cnv_title(title.begin(), title.end()); - out << "msg: " << cnv_title << std::endl; - - printIndent(out, int_Indent); - std::string cnv_comment(comment.begin(), comment.end()); - out << "comment: " << cnv_comment << std::endl; - - printIndent(out, int_Indent); - out << "score: " << score << std::endl; - - printRsItemEnd(out, "RsRankMsg", indent); - return out; -} - -/*************************************************************************/ - -void RsRankLinkMsg::clear() -{ - rid.clear(); - pid.clear(); - timestamp = 0; - title.clear(); - comment.clear(); - score = 0; - linktype = 0; - link.clear(); -} - -std::ostream &RsRankLinkMsg::print(std::ostream &out, uint16_t indent) -{ - printRsItemBase(out, "RsRankLinkMsg", indent); - uint16_t int_Indent = indent + 2; - printIndent(out, int_Indent); - out << "rid: " << rid << std::endl; - printIndent(out, int_Indent); - out << "pid: " << pid << std::endl; - - printIndent(out, int_Indent); - out << "timestamp: " << timestamp << std::endl; - - printIndent(out, int_Indent); - - std::string cnv_title(title.begin(), title.end()); - out << "msg: " << cnv_title << std::endl; - - printIndent(out, int_Indent); - std::string cnv_comment(comment.begin(), comment.end()); - out << "comment: " << cnv_comment << std::endl; - - printIndent(out, int_Indent); - out << "score: " << score << std::endl; - - printIndent(out, int_Indent); - out << "linktype: " << linktype << std::endl; - printIndent(out, int_Indent); - std::string cnv_link(link.begin(), link.end()); - out << "link: " << cnv_link << std::endl; - - printRsItemEnd(out, "RsRankLinkMsg", indent); - return out; -} - - -uint32_t RsRankSerialiser::sizeLink(RsRankLinkMsg *item) -{ - uint32_t s = 8; /* header */ - s += GetTlvStringSize(item->rid); - s += GetTlvStringSize(item->pid); - s += 4; /* timestamp */ - s += GetTlvWideStringSize(item->title); - s += GetTlvWideStringSize(item->comment); - s += 4; /* score */ - s += 4; /* linktype */ - s += GetTlvWideStringSize(item->link); - - return s; -} - -/* serialise the data to the buffer */ -bool RsRankSerialiser::serialiseLink(RsRankLinkMsg *item, void *data, uint32_t *pktsize) -{ - uint32_t tlvsize = sizeLink(item); - uint32_t offset = 0; - - if (*pktsize < tlvsize) - return false; /* not enough space */ - - *pktsize = tlvsize; - - bool ok = true; - - ok &= setRsItemHeader(data, tlvsize, item->PacketId(), tlvsize); - - /* skip the header */ - offset += 8; - - /* add mandatory parts first */ - ok &= SetTlvString(data, tlvsize, &offset, TLV_TYPE_STR_GENID, item->rid); - ok &= SetTlvString(data, tlvsize, &offset, TLV_TYPE_STR_PEERID, item->pid); - - ok &= setRawUInt32(data, tlvsize, &offset, item->timestamp); - - ok &= SetTlvWideString(data, tlvsize, &offset, TLV_TYPE_WSTR_TITLE, item->title); - ok &= SetTlvWideString(data, tlvsize, &offset, TLV_TYPE_WSTR_COMMENT, item->comment); - - ok &= setRawUInt32(data, tlvsize, &offset, *((uint32_t *) &(item->score))); - - ok &= setRawUInt32(data, tlvsize, &offset, item->linktype); - - ok &= SetTlvWideString(data, tlvsize, &offset, TLV_TYPE_WSTR_LINK, item->link); - - if (offset != tlvsize) - { - ok = false; - std::cerr << "RsRankLinkSerialiser::serialiseLink() Size Error! " << std::endl; - } - - return ok; -} - -RsRankLinkMsg *RsRankSerialiser::deserialiseLink(void *data, uint32_t *pktsize) -{ - /* get the type and size */ - uint32_t rstype = getRsItemId(data); - uint32_t rssize = getRsItemSize(data); - - uint32_t offset = 0; - - - if ((RS_PKT_VERSION_SERVICE != getRsItemVersion(rstype)) || - (RS_SERVICE_TYPE_RANK != getRsItemService(rstype)) || - (RS_PKT_SUBTYPE_RANK_LINK3 != getRsItemSubType(rstype))) - { - return NULL; /* wrong type */ - } - - if (*pktsize < rssize) /* check size */ - return NULL; /* not enough data */ - - /* set the packet length */ - *pktsize = rssize; - - bool ok = true; - - /* ready to load */ - RsRankLinkMsg *item = new RsRankLinkMsg(); - item->clear(); - - /* skip the header */ - offset += 8; - - /* get mandatory parts first */ - ok &= GetTlvString(data, rssize, &offset, TLV_TYPE_STR_GENID, item->rid); - ok &= GetTlvString(data, rssize, &offset, TLV_TYPE_STR_PEERID, item->pid); - ok &= getRawUInt32(data, rssize, &offset, &(item->timestamp)); - ok &= GetTlvWideString(data, rssize, &offset, TLV_TYPE_WSTR_TITLE, item->title); - ok &= GetTlvWideString(data, rssize, &offset, TLV_TYPE_WSTR_COMMENT, item->comment); - ok &= getRawUInt32(data, rssize, &offset, (uint32_t *) &(item->score)); - ok &= getRawUInt32(data, rssize, &offset, &(item->linktype)); - ok &= GetTlvWideString(data, rssize, &offset, TLV_TYPE_WSTR_LINK, item->link); - - if (offset != rssize) - { - /* error */ - delete item; - return NULL; - } - - if (!ok) - { - delete item; - return NULL; - } - - return item; -} - - -uint32_t RsRankSerialiser::size(RsItem *item) -{ - return sizeLink((RsRankLinkMsg *) item); -} - -bool RsRankSerialiser::serialise(RsItem *item, void *data, uint32_t *pktsize) -{ - return serialiseLink((RsRankLinkMsg *) item, data, pktsize); -} - -RsItem *RsRankSerialiser::deserialise(void *data, uint32_t *pktsize) -{ - return deserialiseLink(data, pktsize); -} - - - -/*************************************************************************/ - diff --git a/plugins/LinksCloud/rsrankitems.h b/plugins/LinksCloud/rsrankitems.h deleted file mode 100644 index a3ddc78aa..000000000 --- a/plugins/LinksCloud/rsrankitems.h +++ /dev/null @@ -1,110 +0,0 @@ -#ifndef RS_RANK_ITEMS_H -#define RS_RANK_ITEMS_H - -/* - * libretroshare/src/serialiser: rsrankitems.h - * - * RetroShare Serialiser. - * - * Copyright 2007-2008 by Robert Fernie. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License Version 2 as published by the Free Software Foundation. - * - * This library 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA. - * - * Please report all bugs and problems to "retroshare@lunamutt.com". - * - */ - -#include "serialiser/rsserial.h" -#include "serialiser/rstlvtypes.h" - -#include "p3ranking.h" - -const uint8_t RS_PKT_SUBTYPE_RANK_LINK3 = 0x04; -const uint8_t RS_PKT_SUBTYPE_RANK_PHOTO = 0x05; - -/**************************************************************************/ - - -class RsRankMsg: public RsItem -{ - public: - RsRankMsg(uint8_t subtype) :RsItem(RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_RANK, subtype) { return; } - - virtual ~RsRankMsg() { return; } - virtual void clear(); - virtual std::ostream& print(std::ostream &out, uint16_t indent = 0); - - std::string rid; /* Random Id */ - std::string pid; /* Peer Id (cannot use RsItem::PeerId - as FoF transport!) */ - uint32_t timestamp; - std::wstring title; - std::wstring comment; - int32_t score; -}; - - -/* Flags */ -const uint32_t RS_LINK_TYPE_WEB = 0x0001; -const uint32_t RS_LINK_TYPE_OFF = 0x0002; - -class RsRankLinkMsg: public RsRankMsg -{ - public: - RsRankLinkMsg() - :RsRankMsg(RS_PKT_SUBTYPE_RANK_LINK3) { return; } -virtual ~RsRankLinkMsg() { return; } -virtual void clear(); -virtual std::ostream& print(std::ostream &out, uint16_t indent = 0); - - /**** SAME as RsRankMsg **** - std::string rid; - uint32_t timestamp; - std::wstring title; - std::wstring comment; - int32_t score; - ***************************/ - - /* Link specific Fields */ - uint32_t linktype; /* to be used later! */ - std::wstring link; -}; - -class RsRankSerialiser: public RsSerialType -{ - public: - RsRankSerialiser() - :RsSerialType(RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_RANK) - { return; } -virtual ~RsRankSerialiser() - { return; } - -virtual uint32_t size(RsItem *); -virtual bool serialise (RsItem *item, void *data, uint32_t *size); -virtual RsItem * deserialise(void *data, uint32_t *size); - - private: - - /* For RS_PKT_SUBTYPE_RANK_LINK */ -virtual uint32_t sizeLink(RsRankLinkMsg *); -virtual bool serialiseLink (RsRankLinkMsg *item, void *data, uint32_t *size); -virtual RsRankLinkMsg *deserialiseLink(void *data, uint32_t *size); - -}; - -/**************************************************************************/ - -#endif /* RS_RANK_ITEMS_H */ - - diff --git a/plugins/VOIP/VOIP.pro b/plugins/VOIP/VOIP.pro index e7f054553..e560a8501 100644 --- a/plugins/VOIP/VOIP.pro +++ b/plugins/VOIP/VOIP.pro @@ -24,6 +24,9 @@ linux-* { } win32 { + # ffmpeg + QMAKE_CXXFLAGS += -D__STDC_CONSTANT_MACROS + LIBS_DIR = $$PWD/../../../libs LIBS += -L"$$LIBS_DIR/lib/opencv" @@ -96,4 +99,4 @@ TRANSLATIONS += \ lang/VOIP_tr.ts \ lang/VOIP_zh_CN.ts -LIBS += -lspeex -lspeexdsp +LIBS += -lspeex -lspeexdsp -lavformat -lavcodec -lavutil diff --git a/plugins/VOIP/gui/AudioInputConfig.cpp b/plugins/VOIP/gui/AudioInputConfig.cpp index 5c7553ee8..d1503040b 100644 --- a/plugins/VOIP/gui/AudioInputConfig.cpp +++ b/plugins/VOIP/gui/AudioInputConfig.cpp @@ -29,16 +29,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include -//#include "AudioInput.h" -//#include "AudioOutput.h" #include "AudioStats.h" #include "AudioInputConfig.h" -//#include "Global.h" -//#include "NetworkConfig.h" #include "audiodevicehelper.h" #include "AudioWizard.h" +#include "gui/VideoProcessor.h" +#include "gui/common/RSGraphWidget.h" +#include "util/RsProtectedTimer.h" + #include #define iroundf(x) ( static_cast(x) ) @@ -51,11 +50,57 @@ void AudioInputDialog::showEvent(QShowEvent *) { qtTick->start(20); }*/ +class voipGraphSource: public RSGraphSource +{ +public: + voipGraphSource() : video_input(NULL) {} + + void setVideoInput(const QVideoInputDevice *vid) { video_input = vid ; } + + virtual QString displayName(int) const { return tr("Required bandwidth") ;} + + virtual QString displayValue(float v) const + { + if(v < 1000) + return QString::number(v,10,2) + " B/s" ; + else if(v < 1000*1024) + return QString::number(v/1024,10,2) + " KB/s" ; + else + return QString::number(v/(1024*1024),10,2) + " MB/s" ; + } + + virtual void getValues(std::map& vals) const + { + vals.clear() ; + + if(video_input) + vals[std::string("bw")] = video_input->currentBandwidth() ; + } + +private: + const QVideoInputDevice *video_input ; +}; + +void voipGraph::setVoipSource(voipGraphSource *gs) +{ +_src = gs ; +RSGraphWidget::setSource(gs) ; +} + +voipGraph::voipGraph(QWidget *parent) + : RSGraphWidget(parent) +{ + setFlags(RSGraphWidget::RSGRAPH_FLAGS_SHOW_LEGEND) ; + setFlags(RSGraphWidget::RSGRAPH_FLAGS_PAINT_STYLE_PLAIN) ; + + _src = NULL ; +} + /** Constructor */ AudioInputConfig::AudioInputConfig(QWidget * parent, Qt::WindowFlags flags) : ConfigPage(parent, flags) { - std::cerr << "Creating audioInputConfig object" << std::endl; + std::cerr << "Creating audioInputConfig object" << std::endl; /* Invoke the Qt Designer generated object setup routine */ ui.setupUi(this); @@ -67,15 +112,56 @@ AudioInputConfig::AudioInputConfig(QWidget * parent, Qt::WindowFlags flags) abSpeech = NULL; qtTick = NULL; - // Create the video pipeline. - // - videoInput = new QVideoInputDevice(this) ; - videoInput->setEchoVideoTarget(ui.videoDisplay) ; - videoInput->setVideoEncoder(NULL) ; + // Create the video pipeline. + // + videoInput = new QVideoInputDevice(this) ; + videoInput->setEchoVideoTarget(ui.videoDisplay) ; + + videoProcessor = new VideoProcessor() ; + videoProcessor->setDisplayTarget(NULL) ; + + videoProcessor->setMaximumBandwidth(ui.availableBW_SB->value()) ; + + videoInput->setVideoProcessor(videoProcessor) ; + + graph_source = new voipGraphSource ; + ui.voipBwGraph->setSource(graph_source); + + graph_source->setVideoInput(videoInput) ; + graph_source->setCollectionTimeLimit(1000*300) ; + graph_source->start() ; + + QObject::connect(ui.showEncoded_CB,SIGNAL(toggled(bool)),this,SLOT(togglePreview(bool))) ; + QObject::connect(ui.availableBW_SB,SIGNAL(valueChanged(double)),this,SLOT(updateAvailableBW(double))) ; +} + +void AudioInputConfig::updateAvailableBW(double r) +{ + std::cerr << "Setting max bandwidth to " << r << " KB/s" << std::endl; + videoProcessor->setMaximumBandwidth((uint32_t)(r*1024)) ; +} + +void AudioInputConfig::togglePreview(bool b) +{ + if(b) + { + videoInput->setEchoVideoTarget(NULL) ; + videoProcessor->setDisplayTarget(ui.videoDisplay) ; + } + else + { + videoInput->setEchoVideoTarget(ui.videoDisplay) ; + videoProcessor->setDisplayTarget(NULL) ; + } } AudioInputConfig::~AudioInputConfig() { + disconnect( qtTick, SIGNAL( timeout ( ) ), this, SLOT( on_Tick_timeout() ) ); + + graph_source->stop() ; + graph_source->setVideoInput(NULL) ; + std::cerr << "Deleting audioInputConfig object" << std::endl; if(videoInput != NULL) { @@ -102,7 +188,7 @@ void AudioInputConfig::load() //connect( ui.allowIpDeterminationCB, SIGNAL( toggled( bool ) ), this, SLOT( toggleIpDetermination(bool) ) ); //connect( ui.allowTunnelConnectionCB, SIGNAL( toggled( bool ) ), this, SLOT( toggleTunnelConnection(bool) ) ); - qtTick = new QTimer(this); + qtTick = new RsProtectedTimer(this); connect( qtTick, SIGNAL( timeout ( ) ), this, SLOT( on_Tick_timeout() ) ); qtTick->start(20); /*if (AudioInputRegistrar::qmNew) { @@ -266,8 +352,10 @@ void AudioInputConfig::on_qcbTransmit_currentIndexChanged(int v) { } -void AudioInputConfig::on_Tick_timeout() { - if (!inputAudioProcessor) { +void AudioInputConfig::on_Tick_timeout() +{ + if (!inputAudioProcessor) + { inputAudioProcessor = new QtSpeex::SpeexInputProcessor(); inputAudioProcessor->open(QIODevice::WriteOnly | QIODevice::Unbuffered); @@ -288,6 +376,15 @@ void AudioInputConfig::on_Tick_timeout() { abSpeech->iValue = iroundf(inputAudioProcessor->dVoiceAcivityLevel * 32767.0f + 0.5f); abSpeech->update(); + + // also transmit encoded video + RsVOIPDataChunk chunk ; + + while((!videoInput->stopped()) && videoInput->getNextEncodedPacket(chunk)) + { + videoProcessor->receiveEncodedData(chunk) ; + chunk.clear() ; + } } void AudioInputConfig::emptyBuffer() { diff --git a/plugins/VOIP/gui/AudioInputConfig.h b/plugins/VOIP/gui/AudioInputConfig.h index 1b64085a3..ef53c28e9 100644 --- a/plugins/VOIP/gui/AudioInputConfig.h +++ b/plugins/VOIP/gui/AudioInputConfig.h @@ -35,10 +35,27 @@ #include "retroshare-gui/configpage.h" -#include "ui_AudioInputConfig.h" #include "SpeexProcessor.h" #include "VideoProcessor.h" #include "AudioStats.h" +#include "gui/common/RSGraphWidget.h" + +class voipGraphSource ; + +class voipGraph: public RSGraphWidget +{ +public: + voipGraph(QWidget *parent) ; + + voipGraphSource *voipSource() const { return _src ; } + + void setVoipSource(voipGraphSource *gs) ; + +private: + voipGraphSource *_src ; +}; + +#include "ui_AudioInputConfig.h" class AudioInputConfig : public ConfigPage { @@ -52,8 +69,10 @@ class AudioInputConfig : public ConfigPage //VideoDecoder *videoDecoder ; //VideoEncoder *videoEncoder ; QVideoInputDevice *videoInput ; + VideoProcessor *videoProcessor ; bool loaded; + voipGraphSource *graph_source ; protected: QTimer *qtTick; @@ -74,10 +93,12 @@ class AudioInputConfig : public ConfigPage virtual QPixmap iconPixmap() const { return QPixmap(":/images/talking_on.svg") ; } virtual QString pageName() const { return tr("VOIP") ; } virtual QString helpText() const { return ""; } - - private slots: + +private slots: + void updateAvailableBW(double r); void loadSettings(); void emptyBuffer(); + void togglePreview(bool) ; void on_qsTransmitHold_valueChanged(int v); void on_qsAmp_valueChanged(int v); diff --git a/plugins/VOIP/gui/AudioInputConfig.ui b/plugins/VOIP/gui/AudioInputConfig.ui index 6aa071b4a..62e8c98a6 100644 --- a/plugins/VOIP/gui/AudioInputConfig.ui +++ b/plugins/VOIP/gui/AudioInputConfig.ui @@ -6,8 +6,8 @@ 0 0 - 501 - 406 + 1155 + 832 @@ -348,33 +348,92 @@ + + + + + + Video Processing + + + + + + + 170 + 128 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + - - - Video Processing + + + Available bandwidth: + + + + + + + <html><head/><body><p>Use this field to simulate the maximum bandwidth available so as to preview what the encoded video will look like with the corresponding compression rate.</p></body></html> + + + KB/s + + + 1 + + + 2.000000000000000 + + + 200.000000000000000 + + + 30.000000000000000 - - - - - - 170 - 128 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - + + + + <html><head/><body><p>Display encoded (and then decoded) frame, to check the codec's quality. If not selected, the image above only shows the frame that is grabbed from your camera.</p></body></html> + + + preview + + + @@ -397,6 +456,12 @@
gui/QVideoDevice.h
1 + + voipGraph + QFrame +
gui/AudioInputConfig.h
+ 1 +
qcbTransmit diff --git a/plugins/VOIP/gui/QVideoDevice.cpp b/plugins/VOIP/gui/QVideoDevice.cpp index eed14b58b..b81b7b79c 100644 --- a/plugins/VOIP/gui/QVideoDevice.cpp +++ b/plugins/VOIP/gui/QVideoDevice.cpp @@ -11,10 +11,15 @@ QVideoInputDevice::QVideoInputDevice(QWidget *parent) { _timer = NULL ; _capture_device = NULL ; - _video_encoder = NULL ; + _video_processor = NULL ; _echo_output_device = NULL ; } +bool QVideoInputDevice::stopped() +{ + return _timer == NULL ; +} + void QVideoInputDevice::stop() { if(_timer != NULL) @@ -54,46 +59,60 @@ void QVideoInputDevice::start() void QVideoInputDevice::grabFrame() { - IplImage *img=cvQueryFrame(_capture_device); + if(!_timer) + return ; + + IplImage *img=cvQueryFrame(_capture_device); - if(img == NULL) - { - std::cerr << "(EE) Cannot capture image from camera. Something's wrong." << std::endl; - return ; - } - // get the image data + if(img == NULL) + { + std::cerr << "(EE) Cannot capture image from camera. Something's wrong." << std::endl; + return ; + } + // get the image data - if(img->nChannels != 3) - { - std::cerr << "(EE) expected 3 channels. Got " << img->nChannels << std::endl; - return ; - } + if(img->nChannels != 3) + { + std::cerr << "(EE) expected 3 channels. Got " << img->nChannels << std::endl; + return ; + } // convert to RGB and copy to new buffer, because cvQueryFrame tells us to not modify the buffer cv::Mat img_rgb; cv::cvtColor(cv::Mat(img), img_rgb, CV_BGR2RGB); - static const int _encoded_width = 128 ; - static const int _encoded_height = 128 ; + QImage image = QImage(img_rgb.data,img_rgb.cols,img_rgb.rows,QImage::Format_RGB888); - QImage image = QImage(img_rgb.data,img_rgb.cols,img_rgb.rows,QImage::Format_RGB888).scaled(QSize(_encoded_width,_encoded_height),Qt::IgnoreAspectRatio,Qt::SmoothTransformation) ; + if(_video_processor != NULL) + { + _video_processor->processImage(image) ; - if(_video_encoder != NULL) - { - _video_encoder->addImage(image) ; - emit networkPacketReady() ; - } - if(_echo_output_device != NULL) _echo_output_device->showFrame(image) ; + emit networkPacketReady() ; + } + if(_echo_output_device != NULL) + _echo_output_device->showFrame(image) ; } bool QVideoInputDevice::getNextEncodedPacket(RsVOIPDataChunk& chunk) { - return _video_encoder->nextPacket(chunk) ; + if(!_timer) + return false ; + + if(_video_processor) + return _video_processor->nextEncodedPacket(chunk) ; + else + return false ; +} + +uint32_t QVideoInputDevice::currentBandwidth() const +{ + return _video_processor->currentBandwidthOut() ; } QVideoInputDevice::~QVideoInputDevice() { - stop() ; + stop() ; + _video_processor = NULL ; } @@ -110,6 +129,7 @@ void QVideoOutputDevice::showFrameOff() void QVideoOutputDevice::showFrame(const QImage& img) { - setPixmap(QPixmap::fromImage(img).scaled(minimumSize(),Qt::IgnoreAspectRatio,Qt::SmoothTransformation)) ; + std::cerr << "img.size = " << img.width() << " x " << img.height() << std::endl; + setPixmap(QPixmap::fromImage(img).scaled( QSize(height()*640/480,height()),Qt::IgnoreAspectRatio,Qt::SmoothTransformation)) ; } diff --git a/plugins/VOIP/gui/QVideoDevice.h b/plugins/VOIP/gui/QVideoDevice.h index 7cb62ca0c..cc92302a2 100644 --- a/plugins/VOIP/gui/QVideoDevice.h +++ b/plugins/VOIP/gui/QVideoDevice.h @@ -2,6 +2,7 @@ #include #include "interface/rsVOIP.h" +#include "gui/VideoProcessor.h" class VideoEncoder ; class CvCapture ; @@ -31,7 +32,7 @@ class QVideoInputDevice: public QObject // Captured images are sent to this encoder. Can be NULL. // - void setVideoEncoder(VideoEncoder *venc) { _video_encoder = venc ; } + void setVideoProcessor(VideoProcessor *venc) { _video_processor = venc ; } // All images received will be echoed to this target. We could use signal/slots, but it's // probably faster this way. Can be NULL. @@ -42,17 +43,23 @@ class QVideoInputDevice: public QObject // bool getNextEncodedPacket(RsVOIPDataChunk&) ; + // gets the estimated current bandwidth required to transmit the encoded data, in B/s + // + uint32_t currentBandwidth() const ; + + // control + void start() ; void stop() ; - - protected slots: + bool stopped(); +protected slots: void grabFrame() ; signals: void networkPacketReady() ; private: - VideoEncoder *_video_encoder ; + VideoProcessor *_video_processor ; QTimer *_timer ; CvCapture *_capture_device ; diff --git a/plugins/VOIP/gui/VOIPChatWidgetHolder.cpp b/plugins/VOIP/gui/VOIPChatWidgetHolder.cpp index 1d94960d7..f8760132d 100644 --- a/plugins/VOIP/gui/VOIPChatWidgetHolder.cpp +++ b/plugins/VOIP/gui/VOIPChatWidgetHolder.cpp @@ -123,8 +123,7 @@ VOIPChatWidgetHolder::VOIPChatWidgetHolder(ChatWidget *chatWidget, VOIPNotify *n inputAudioDevice = NULL ; inputVideoDevice = new QVideoInputDevice(mChatWidget) ; // not started yet ;-) - inputVideoProcessor = new JPEGVideoEncoder ; - outputVideoProcessor = new JPEGVideoDecoder ; + videoProcessor = new VideoProcessor ; // Make a widget with two video devices, one for echo, and one for the talking peer. videoWidget = new QWidget(mChatWidget) ; @@ -144,8 +143,8 @@ VOIPChatWidgetHolder::VOIPChatWidgetHolder(ChatWidget *chatWidget, VOIPNotify *n mChatWidget->addChatHorizontalWidget(videoWidget) ; inputVideoDevice->setEchoVideoTarget(echoVideoDevice) ; - inputVideoDevice->setVideoEncoder(inputVideoProcessor) ; - outputVideoProcessor->setDisplayTarget(outputVideoDevice) ; + inputVideoDevice->setVideoProcessor(videoProcessor) ; + videoProcessor->setDisplayTarget(outputVideoDevice) ; } VOIPChatWidgetHolder::~VOIPChatWidgetHolder() @@ -154,8 +153,7 @@ VOIPChatWidgetHolder::~VOIPChatWidgetHolder() inputAudioDevice->stop() ; delete inputVideoDevice ; - delete inputVideoProcessor ; - delete outputVideoProcessor ; + delete videoProcessor ; button_map::iterator it = buttonMapTakeVideo.begin(); while (it != buttonMapTakeVideo.end()) { @@ -287,42 +285,50 @@ void VOIPChatWidgetHolder::toggleVideoCapture() void VOIPChatWidgetHolder::addVideoData(const RsPeerId &peer_id, QByteArray* array) { - if (!videoCaptureToggleButton->isChecked()) { - if (mChatWidget) { - QString buttonName = QString::fromUtf8(rsPeers->getPeerName(peer_id).c_str()); - if (buttonName.isEmpty()) buttonName = "VoIP";//TODO maybe change all with GxsId - button_map::iterator it = buttonMapTakeVideo.find(buttonName); - if (it == buttonMapTakeVideo.end()){ - mChatWidget->addChatMsg(true, tr("VoIP Status"), QDateTime::currentDateTime(), QDateTime::currentDateTime() - , tr("%1 inviting you to start a video conversation. do you want Accept or Decline the invitation?").arg(buttonName), ChatWidget::MSGTYPE_SYSTEM); - RSButtonOnText *button = mChatWidget->getNewButtonOnTextBrowser(tr("Accept Video Call")); - button->setToolTip(tr("Activate camera")); - button->setStyleSheet(QString("border: 1px solid #199909;") - .append("font-size: 12pt; color: white;") - .append("min-width: 128px; min-height: 24px;") - .append("border-radius: 6px;") - .append("background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.67, " - "stop: 0 #22c70d, stop: 1 #116a06);") + if (!videoCaptureToggleButton->isChecked()) + { + if (mChatWidget) { + QString buttonName = QString::fromUtf8(rsPeers->getPeerName(peer_id).c_str()); + if (buttonName.isEmpty()) buttonName = "VoIP";//TODO maybe change all with GxsId + button_map::iterator it = buttonMapTakeVideo.find(buttonName); + if (it == buttonMapTakeVideo.end()){ + mChatWidget->addChatMsg(true, tr("VoIP Status"), QDateTime::currentDateTime(), QDateTime::currentDateTime() + , tr("%1 inviting you to start a video conversation. do you want Accept or Decline the invitation?").arg(buttonName), ChatWidget::MSGTYPE_SYSTEM); + RSButtonOnText *button = mChatWidget->getNewButtonOnTextBrowser(tr("Accept Video Call")); + button->setToolTip(tr("Activate camera")); + button->setStyleSheet(QString("border: 1px solid #199909;") + .append("font-size: 12pt; color: white;") + .append("min-width: 128px; min-height: 24px;") + .append("border-radius: 6px;") + .append("background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.67, " + "stop: 0 #22c70d, stop: 1 #116a06);") - ); + ); - button->updateImage(); + button->updateImage(); - connect(button,SIGNAL(clicked()),this,SLOT(startVideoCapture())); - connect(button,SIGNAL(mouseEnter()),this,SLOT(botMouseEnter())); - connect(button,SIGNAL(mouseLeave()),this,SLOT(botMouseLeave())); + connect(button,SIGNAL(clicked()),this,SLOT(startVideoCapture())); + connect(button,SIGNAL(mouseEnter()),this,SLOT(botMouseEnter())); + connect(button,SIGNAL(mouseLeave()),this,SLOT(botMouseLeave())); - buttonMapTakeVideo.insert(buttonName, button); - } - } + buttonMapTakeVideo.insert(buttonName, button); + } + } - //TODO make a sound for the incoming call -// soundManager->play(VOIP_SOUND_INCOMING_CALL); - if (mVOIPNotify) mVOIPNotify->notifyReceivedVoipVideoCall(peer_id); + //TODO make a sound for the incoming call + // soundManager->play(VOIP_SOUND_INCOMING_CALL); + if (mVOIPNotify) mVOIPNotify->notifyReceivedVoipVideoCall(peer_id); - } else { - outputVideoProcessor->receiveEncodedData((unsigned char *)array->data(),array->size()) ; - } + } + else + { + RsVOIPDataChunk chunk ; + chunk.type = RsVOIPDataChunk::RS_VOIP_DATA_TYPE_VIDEO ; + chunk.size = array->size() ; + chunk.data = array->data() ; + + videoProcessor->receiveEncodedData(chunk) ; + } } void VOIPChatWidgetHolder::botMouseEnter() @@ -359,7 +365,7 @@ void VOIPChatWidgetHolder::botMouseLeave() void VOIPChatWidgetHolder::setAcceptedBandwidth(uint32_t bytes_per_sec) { - inputVideoProcessor->setMaximumFrameRate(bytes_per_sec) ; + videoProcessor->setMaximumBandwidth(bytes_per_sec) ; } void VOIPChatWidgetHolder::addAudioData(const RsPeerId &peer_id, QByteArray* array) diff --git a/plugins/VOIP/gui/VOIPChatWidgetHolder.h b/plugins/VOIP/gui/VOIPChatWidgetHolder.h index 791a2dcf8..350f49f2c 100644 --- a/plugins/VOIP/gui/VOIPChatWidgetHolder.h +++ b/plugins/VOIP/gui/VOIPChatWidgetHolder.h @@ -34,8 +34,7 @@ class QAudioInput; class QAudioOutput; class QVideoInputDevice ; class QVideoOutputDevice ; -class VideoEncoder ; -class VideoDecoder ; +class VideoProcessor ; #define VOIP_SOUND_INCOMING_CALL "VOIP_incoming_call" @@ -82,8 +81,7 @@ protected: QWidget *videoWidget ; // pointer to call show/hide - VideoEncoder *inputVideoProcessor; - VideoDecoder *outputVideoProcessor; + VideoProcessor *videoProcessor; // Additional buttons to the chat bar QToolButton *audioListenToggleButton ; diff --git a/plugins/VOIP/gui/VideoProcessor.cpp b/plugins/VOIP/gui/VideoProcessor.cpp index 27343c412..20aca0410 100644 --- a/plugins/VOIP/gui/VideoProcessor.cpp +++ b/plugins/VOIP/gui/VideoProcessor.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include #include @@ -7,67 +9,677 @@ #include "VideoProcessor.h" #include "QVideoDevice.h" -VideoDecoder::VideoDecoder() +#include +#include + +#if defined(__MINGW32__) +#define memalign _aligned_malloc +#endif //MINGW + +extern "C" { +#include + +#include +#include +#include +#include +#include +#include +} +//#define DEBUG_MPEG_VIDEO 1 + +VideoProcessor::VideoProcessor() + :_encoded_frame_size(640,480) , vpMtx("VideoProcessor") { - _output_device = NULL ; + _decoded_output_device = NULL ; + + //_encoding_current_codec = VIDEO_PROCESSOR_CODEC_ID_JPEG_VIDEO; + _encoding_current_codec = VIDEO_PROCESSOR_CODEC_ID_MPEG_VIDEO; + + _estimated_bandwidth_in = 0 ; + _estimated_bandwidth_out = 0 ; + _target_bandwidth_out = 30*1024 ; // 30 KB/s + + _total_encoded_size_in = 0 ; + _total_encoded_size_out = 0 ; + + _last_bw_estimate_in_TS = time(NULL) ; + _last_bw_estimate_out_TS = time(NULL) ; } -bool VideoEncoder::addImage(const QImage& img) +VideoProcessor::~VideoProcessor() { - encodeData(img) ; - - return true ; + // clear encoding queue + + RS_STACK_MUTEX(vpMtx) ; + + while(!_encoded_out_queue.empty()) + { + _encoded_out_queue.back().clear() ; + _encoded_out_queue.pop_back() ; + } } -bool VideoEncoder::nextPacket(RsVOIPDataChunk& chunk) +bool VideoProcessor::processImage(const QImage& img) { - if(_out_queue.empty()) + VideoCodec *codec ; + + switch(_encoding_current_codec) + { + case VIDEO_PROCESSOR_CODEC_ID_JPEG_VIDEO: codec = &_jpeg_video_codec ; + break ; + case VIDEO_PROCESSOR_CODEC_ID_MPEG_VIDEO: codec = &_mpeg_video_codec ; + break ; + default: + codec = NULL ; + } + + // std::cerr << "reducing to " << _frame_size.width() << " x " << _frame_size.height() << std::endl; + + if(codec) + { + RsVOIPDataChunk chunk ; + + if(codec->encodeData(img.scaled(_encoded_frame_size,Qt::IgnoreAspectRatio,Qt::SmoothTransformation),_target_bandwidth_out,chunk) && chunk.size > 0) + { + RS_STACK_MUTEX(vpMtx) ; + _encoded_out_queue.push_back(chunk) ; + _total_encoded_size_out += chunk.size ; + } + + time_t now = time(NULL) ; + + if(now > _last_bw_estimate_out_TS) + { + RS_STACK_MUTEX(vpMtx) ; + + _estimated_bandwidth_out = uint32_t(0.75*_estimated_bandwidth_out + 0.25 * (_total_encoded_size_out / (float)(now - _last_bw_estimate_out_TS))) ; + + _total_encoded_size_out = 0 ; + _last_bw_estimate_out_TS = now ; + +#ifdef DEBUG_VIDEO_OUTPUT_DEVICE + std::cerr << "new bw estimate: " << _estimated_bw << std::endl; +#endif + } + + return true ; + } + else + { + std::cerr << "No codec for codec ID = " << _encoding_current_codec << ". Please call VideoProcessor::setCurrentCodec()" << std::endl; + return false ; + } +} + +bool VideoProcessor::nextEncodedPacket(RsVOIPDataChunk& chunk) +{ + RS_STACK_MUTEX(vpMtx) ; + if(_encoded_out_queue.empty()) return false ; - chunk = _out_queue.front() ; - _out_queue.pop_front() ; + chunk = _encoded_out_queue.front() ; + _encoded_out_queue.pop_front() ; return true ; } -void VideoDecoder::receiveEncodedData(const unsigned char *data,uint32_t size) +void VideoProcessor::setInternalFrameSize(QSize s) { - _output_device->showFrame(decodeData(data,size)) ; + _encoded_frame_size = s ; } -QImage JPEGVideoDecoder::decodeData(const unsigned char *encoded_image_data,uint32_t size) +void VideoProcessor::receiveEncodedData(const RsVOIPDataChunk& chunk) { - QByteArray qb((char*)encoded_image_data,size) ; - QImage image ; - if(image.loadFromData(qb,"JPEG")) - return image ; + static const int HEADER_SIZE = 4 ; + + // read frame type. Use first 4 bytes to give info about content. + // + // Byte Meaning Values + // 00 Codec CODEC_ID_JPEG_VIDEO Basic Jpeg codec + // CODEC_ID_DDWT_VIDEO Differential wavelet compression + // + // 01 Unused Might be useful later + // + // 0203 Flags Codec specific flags. + // + + if(chunk.size < HEADER_SIZE) + { + std::cerr << "JPEGVideoDecoder::decodeData(): Too small a data packet. size=" << chunk.size << std::endl; + return ; + } + + uint32_t codid = ((unsigned char *)chunk.data)[0] + (((unsigned char *)chunk.data)[1] << 8) ; + //uint16_t flags = ((unsigned char *)chunk.data)[2] + (((unsigned char *)chunk.data)[3] << 8) ; + + VideoCodec *codec ; + + switch(codid) + { + case VIDEO_PROCESSOR_CODEC_ID_JPEG_VIDEO: codec = &_jpeg_video_codec ; + break ; + case VIDEO_PROCESSOR_CODEC_ID_MPEG_VIDEO: codec = &_mpeg_video_codec ; + break ; + default: + codec = NULL ; + } + QImage img ; + + if(codec == NULL) + { + std::cerr << "Unknown decoding codec: " << codid << std::endl; + return ; + } + + { + RS_STACK_MUTEX(vpMtx) ; + _total_encoded_size_in += chunk.size ; + + time_t now = time(NULL) ; + + if(now > _last_bw_estimate_in_TS) + { + _estimated_bandwidth_in = uint32_t(0.75*_estimated_bandwidth_in + 0.25 * (_total_encoded_size_in / (float)(now - _last_bw_estimate_in_TS))) ; + + _total_encoded_size_in = 0 ; + _last_bw_estimate_in_TS = now ; + +#ifdef DEBUG_VIDEO_OUTPUT_DEVICE + std::cerr << "new bw estimate (in): " << _estimated_bandwidth_in << std::endl; +#endif + } + } + if(!codec->decodeData(chunk,img)) + { + std::cerr << "No image decoded. Probably in the middle of something..." << std::endl; + return ; + } + + if(_decoded_output_device) + _decoded_output_device->showFrame(img) ; +} + +void VideoProcessor::setMaximumBandwidth(uint32_t bytes_per_sec) +{ + std::cerr << "Video Encoder: maximum frame rate is set to " << bytes_per_sec << " Bps" << std::endl; + _target_bandwidth_out = bytes_per_sec ; +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +JPEGVideo::JPEGVideo() + : _encoded_ref_frame_max_distance(10),_encoded_ref_frame_count(10) +{ +} + +bool JPEGVideo::decodeData(const RsVOIPDataChunk& chunk,QImage& image) +{ + // now see if the frame is a differential frame, or just a reference frame. + + uint16_t codec = ((unsigned char *)chunk.data)[0] + (((unsigned char *)chunk.data)[1] << 8) ; + uint16_t flags = ((unsigned char *)chunk.data)[2] + (((unsigned char *)chunk.data)[3] << 8) ; + + assert(codec == VideoProcessor::VIDEO_PROCESSOR_CODEC_ID_JPEG_VIDEO) ; + + // un-compress image data + + QByteArray qb((char*)&((uint8_t*)chunk.data)[HEADER_SIZE],(int)chunk.size - HEADER_SIZE) ; + + if(!image.loadFromData(qb,"JPEG")) + { + std::cerr << "image.loadFromData(): returned an error.: " << std::endl; + return false ; + } + + if(flags & JPEG_VIDEO_FLAGS_DIFFERENTIAL_FRAME) + { + if(_decoded_reference_frame.size() != image.size()) + { + std::cerr << "Bad reference frame!" << std::endl; + return false ; + } + + QImage res = _decoded_reference_frame ; + + for(int i=0;i> 8) & 0xff ; + ((unsigned char *)voip_chunk.data)[2] = flags & 0xff ; + ((unsigned char *)voip_chunk.data)[3] = (flags >> 8) & 0xff ; + + memcpy(&((unsigned char*)voip_chunk.data)[HEADER_SIZE],qb.data(),qb.size()) ; + + voip_chunk.size = HEADER_SIZE + qb.size() ; + voip_chunk.type = RsVOIPDataChunk::RS_VOIP_DATA_TYPE_VIDEO ; + + return true ; +} + +FFmpegVideo::FFmpegVideo() +{ + // Encoding + + encoding_codec = NULL ; + encoding_frame_buffer = NULL ; + encoding_context = NULL ; + + //AVCodecID codec_id = AV_CODEC_ID_H264 ; + //AVCodecID codec_id = AV_CODEC_ID_MPEG2VIDEO; + AVCodecID codec_id = AV_CODEC_ID_MPEG4; + + uint8_t endcode[] = { 0, 0, 1, 0xb7 }; + + /* find the mpeg1 video encoder */ + encoding_codec = avcodec_find_encoder(codec_id); + + if (!encoding_codec) throw("AV codec not found for codec id ") ; + + encoding_context = avcodec_alloc_context3(encoding_codec); + + if (!encoding_context) throw std::runtime_error("AV: Could not allocate video codec encoding context"); + + /* put sample parameters */ + encoding_context->bit_rate = 10*1024 ; // default bitrate is 30KB/s + encoding_context->bit_rate_tolerance = encoding_context->bit_rate ; + +#ifdef USE_VARIABLE_BITRATE + encoding_context->rc_min_rate = 0; + encoding_context->rc_max_rate = 10*1024;//encoding_context->bit_rate; + encoding_context->rc_buffer_size = 10*1024*1024; + encoding_context->rc_initial_buffer_occupancy = (int) ( 0.9 * encoding_context->rc_buffer_size); + encoding_context->rc_max_available_vbv_use = 1.0; + encoding_context->rc_min_vbv_overflow_use = 0.0; +#else + encoding_context->rc_min_rate = 0; + encoding_context->rc_max_rate = 0; + encoding_context->rc_buffer_size = 0; +#endif + encoding_context->flags |= CODEC_FLAG_PSNR; + encoding_context->flags |= CODEC_FLAG_TRUNCATED; + encoding_context->flags |= CODEC_CAP_PARAM_CHANGE; + encoding_context->i_quant_factor = 0.769f; + encoding_context->b_quant_factor = 1.4f; + encoding_context->time_base.num = 1; + encoding_context->time_base.den = 15;//framesPerSecond; + encoding_context->qmin = 1; + encoding_context->qmax = 51; + encoding_context->max_qdiff = 4; + + //encoding_context->me_method = ME_HEX; + //encoding_context->max_b_frames = 4; + //encoding_context->flags |= CODEC_FLAG_LOW_DELAY; // MPEG2 only + //encoding_context->partitions = X264_PART_I4X4 | X264_PART_I8X8 | X264_PART_P8X8 | X264_PART_P4X4 | X264_PART_B8X8; + //encoding_context->crf = 0.0f; + //encoding_context->cqp = 26; + + /* resolution must be a multiple of two */ + encoding_context->width = 640;//176; + encoding_context->height = 480;//144; + /* frames per second */ + encoding_context->time_base = (AVRational){1,25}; + /* emit one intra frame every ten frames + * check frame pict_type before passing frame + * to encoder, if frame->pict_type is AV_PICTURE_TYPE_I + * then gop_size is ignored and the output of encoder + * will always be I frame irrespective to gop_size + */ + encoding_context->gop_size = 100; + //encoding_context->max_b_frames = 1; + encoding_context->pix_fmt = AV_PIX_FMT_YUV420P; //context->pix_fmt = AV_PIX_FMT_RGB24; + + if (codec_id == AV_CODEC_ID_H264) + av_opt_set(encoding_context->priv_data, "preset", "slow", 0); + + /* open it */ + if (avcodec_open2(encoding_context, encoding_codec, NULL) < 0) + throw std::runtime_error( "AV: Could not open codec context. Something's wrong."); + + encoding_frame_buffer = avcodec_alloc_frame() ;//(AVFrame*)malloc(sizeof(AVFrame)) ; + + if(!encoding_frame_buffer) + throw std::runtime_error("AV: could not allocate frame buffer.") ; + + encoding_frame_buffer->format = encoding_context->pix_fmt; + encoding_frame_buffer->width = encoding_context->width; + encoding_frame_buffer->height = encoding_context->height; + + /* the image can be allocated by any means and av_image_alloc() is + * just the most convenient way if av_malloc() is to be used */ + + int ret = av_image_alloc(encoding_frame_buffer->data, encoding_frame_buffer->linesize, + encoding_context->width, encoding_context->height, encoding_context->pix_fmt, 32); + + if (ret < 0) + throw std::runtime_error("AV: Could not allocate raw picture buffer"); + + encoding_frame_count = 0 ; + + // Decoding + + decoding_codec = avcodec_find_decoder(codec_id); + + if (!decoding_codec) + throw("AV codec not found for codec id ") ; + + decoding_context = avcodec_alloc_context3(decoding_codec); + + if(!decoding_context) + throw std::runtime_error("AV: Could not allocate video codec decoding context"); + + decoding_context->width = encoding_context->width; + decoding_context->height = encoding_context->height; + decoding_context->pix_fmt = AV_PIX_FMT_YUV420P; + + if(decoding_codec->capabilities & CODEC_CAP_TRUNCATED) + decoding_context->flags |= CODEC_FLAG_TRUNCATED; // we do not send complete frames + + if(avcodec_open2(decoding_context,decoding_codec,NULL) < 0) + throw("AV codec open action failed! ") ; + + decoding_frame_buffer = avcodec_alloc_frame() ;//(AVFrame*)malloc(sizeof(AVFrame)) ; + + av_init_packet(&decoding_buffer); + decoding_buffer.data = NULL ; + decoding_buffer.size = 0 ; + + //ret = av_image_alloc(decoding_frame_buffer->data, decoding_frame_buffer->linesize, decoding_context->width, decoding_context->height, decoding_context->pix_fmt, 32); + + //if (ret < 0) + //throw std::runtime_error("AV: Could not allocate raw picture buffer"); + + // debug +#ifdef DEBUG_MPEG_VIDEO + std::cerr << "Dumping captured data to file tmpvideo.mpg" << std::endl; + encoding_debug_file = fopen("tmpvideo.mpg","w") ; +#endif +} + +FFmpegVideo::~FFmpegVideo() +{ + avcodec_close(encoding_context); + avcodec_close(decoding_context); + av_free(encoding_context); + av_free(decoding_context); + av_freep(&encoding_frame_buffer->data[0]); + av_freep(&decoding_frame_buffer->data[0]); + free(encoding_frame_buffer); + free(decoding_frame_buffer); +} + +#define MAX_FFMPEG_ENCODING_BITRATE 81920 + +bool FFmpegVideo::encodeData(const QImage& image, uint32_t target_encoding_bitrate, RsVOIPDataChunk& voip_chunk) +{ +#ifdef DEBUG_MPEG_VIDEO + std::cerr << "Encoding frame of size " << image.width() << "x" << image.height() << ", resized to " << encoding_frame_buffer->width << "x" << encoding_frame_buffer->height << " : "; +#endif + QImage input ; + + if(target_encoding_bitrate > MAX_FFMPEG_ENCODING_BITRATE) + { + std::cerr << "Max encodign bitrate eexceeded. Capping to " << MAX_FFMPEG_ENCODING_BITRATE << std::endl; + target_encoding_bitrate = MAX_FFMPEG_ENCODING_BITRATE ; + } + //encoding_context->bit_rate = target_encoding_bitrate; + encoding_context->rc_max_rate = target_encoding_bitrate; + //encoding_context->bit_rate_tolerance = target_encoding_bitrate; + + if(image.width() != encoding_frame_buffer->width || image.height() != encoding_frame_buffer->height) + input = image.scaled(QSize(encoding_frame_buffer->width,encoding_frame_buffer->height),Qt::IgnoreAspectRatio,Qt::SmoothTransformation) ; + else + input = image ; + + /* prepare a dummy image */ + /* Y */ + for (int y = 0; y < encoding_context->height/2; y++) + for (int x = 0; x < encoding_context->width/2; x++) + { + QRgb pix00 = input.pixel(QPoint(2*x+0,2*y+0)) ; + QRgb pix01 = input.pixel(QPoint(2*x+0,2*y+1)) ; + QRgb pix10 = input.pixel(QPoint(2*x+1,2*y+0)) ; + QRgb pix11 = input.pixel(QPoint(2*x+1,2*y+1)) ; + + int R00 = (pix00 >> 16) & 0xff ; int G00 = (pix00 >> 8) & 0xff ; int B00 = (pix00 >> 0) & 0xff ; + int R01 = (pix01 >> 16) & 0xff ; int G01 = (pix01 >> 8) & 0xff ; int B01 = (pix01 >> 0) & 0xff ; + int R10 = (pix10 >> 16) & 0xff ; int G10 = (pix10 >> 8) & 0xff ; int B10 = (pix10 >> 0) & 0xff ; + int R11 = (pix11 >> 16) & 0xff ; int G11 = (pix11 >> 8) & 0xff ; int B11 = (pix11 >> 0) & 0xff ; + + int Y00 = (0.257 * R00) + (0.504 * G00) + (0.098 * B00) + 16 ; + int Y01 = (0.257 * R01) + (0.504 * G01) + (0.098 * B01) + 16 ; + int Y10 = (0.257 * R10) + (0.504 * G10) + (0.098 * B10) + 16 ; + int Y11 = (0.257 * R11) + (0.504 * G11) + (0.098 * B11) + 16 ; + + float R = 0.25*(R00+R01+R10+R11) ; + float G = 0.25*(G00+G01+G10+G11) ; + float B = 0.25*(B00+B01+B10+B11) ; + + int U = (0.439 * R) - (0.368 * G) - (0.071 * B) + 128 ; + int V = -(0.148 * R) - (0.291 * G) + (0.439 * B) + 128 ; + + encoding_frame_buffer->data[0][(2*y+0) * encoding_frame_buffer->linesize[0] + 2*x+0] = std::min(255,std::max(0,Y00)); // Y + encoding_frame_buffer->data[0][(2*y+0) * encoding_frame_buffer->linesize[0] + 2*x+1] = std::min(255,std::max(0,Y01)); // Y + encoding_frame_buffer->data[0][(2*y+1) * encoding_frame_buffer->linesize[0] + 2*x+0] = std::min(255,std::max(0,Y10)); // Y + encoding_frame_buffer->data[0][(2*y+1) * encoding_frame_buffer->linesize[0] + 2*x+1] = std::min(255,std::max(0,Y11)); // Y + + encoding_frame_buffer->data[1][y * encoding_frame_buffer->linesize[1] + x] = std::min(255,std::max(0,U));// Cr + encoding_frame_buffer->data[2][y * encoding_frame_buffer->linesize[2] + x] = std::min(255,std::max(0,V));// Cb + } + + + encoding_frame_buffer->pts = encoding_frame_count++; + + /* encode the image */ + + int got_output = 0; + + AVFrame *frame = encoding_frame_buffer ; + + AVPacket pkt ; + av_init_packet(&pkt); + pkt.data = NULL; // packet data will be allocated by the encoder + pkt.size = 0; + + // do + // { + int ret = avcodec_encode_video2(encoding_context, &pkt, frame, &got_output) ; + + if (ret < 0) + { + std::cerr << "Error encoding frame!" << std::endl; + return false ; + } + // frame = NULL ; // next attempts: do not encode anything. Do this to just flush the buffer + // + // } while(got_output) ; + + if(got_output) + { + voip_chunk.data = malloc(pkt.size + HEADER_SIZE) ; + uint32_t flags = 0; + + ((unsigned char *)voip_chunk.data)[0] = VideoProcessor::VIDEO_PROCESSOR_CODEC_ID_MPEG_VIDEO & 0xff ; + ((unsigned char *)voip_chunk.data)[1] = (VideoProcessor::VIDEO_PROCESSOR_CODEC_ID_MPEG_VIDEO >> 8) & 0xff ; + ((unsigned char *)voip_chunk.data)[2] = flags & 0xff ; + ((unsigned char *)voip_chunk.data)[3] = (flags >> 8) & 0xff ; + + memcpy(&((unsigned char*)voip_chunk.data)[HEADER_SIZE],pkt.data,pkt.size) ; + + voip_chunk.size = pkt.size + HEADER_SIZE; + voip_chunk.type = RsVOIPDataChunk::RS_VOIP_DATA_TYPE_VIDEO ; + +#ifdef DEBUG_MPEG_VIDEO + std::cerr << "Output : " << pkt.size << " bytes." << std::endl; + fwrite(pkt.data,1,pkt.size,encoding_debug_file) ; + fflush(encoding_debug_file) ; +#endif + av_free_packet(&pkt); + + return true ; + } else { - std::cerr << "image.loadFromData(): returned an error.: " << std::endl; - return QImage() ; + voip_chunk.data = NULL; + voip_chunk.size = 0; + voip_chunk.type = RsVOIPDataChunk::RS_VOIP_DATA_TYPE_VIDEO ; + + std::cerr << "No output produced." << std::endl; + return false ; } + } -void VideoEncoder::setMaximumFrameRate(uint32_t bytes_per_sec) +bool FFmpegVideo::decodeData(const RsVOIPDataChunk& chunk,QImage& image) { - std::cerr << "Video Encoder: maximum frame rate is set to " << bytes_per_sec << " Bps" << std::endl; -} - - -void JPEGVideoEncoder::encodeData(const QImage& image) -{ - QByteArray qb ; - - QBuffer buffer(&qb) ; - buffer.open(QIODevice::WriteOnly) ; - image.save(&buffer,"JPEG") ; - - RsVOIPDataChunk voip_chunk ; - voip_chunk.data = malloc(qb.size()); - memcpy(voip_chunk.data,qb.data(),qb.size()) ; - voip_chunk.size = qb.size() ; - voip_chunk.type = RsVOIPDataChunk::RS_VOIP_DATA_TYPE_VIDEO ; - - _out_queue.push_back(voip_chunk) ; +#ifdef DEBUG_MPEG_VIDEO + std::cerr << "Decoding data of size " << chunk.size << std::endl; +#endif + unsigned char *buff ; + + if(decoding_buffer.data != NULL) + { +#ifdef DEBUG_MPEG_VIDEO + std::cerr << "Completing buffer with size " << chunk.size - HEADER_SIZE + decoding_buffer.size << ": copying existing " + << decoding_buffer.size << " bytes. Adding new " << chunk.size - HEADER_SIZE<< " bytes " << std::endl; +#endif + + uint32_t s = chunk.size - HEADER_SIZE + decoding_buffer.size ; + unsigned char *tmp = (unsigned char*)memalign(16,s + FF_INPUT_BUFFER_PADDING_SIZE) ; + memset(tmp,0,s+FF_INPUT_BUFFER_PADDING_SIZE) ; + + memcpy(tmp,decoding_buffer.data,decoding_buffer.size) ; + + free(decoding_buffer.data) ; + + buff = &tmp[decoding_buffer.size] ; + decoding_buffer.size = s ; + decoding_buffer.data = tmp ; + } + else + { +#ifdef DEBUG_MPEG_VIDEO + std::cerr << "Allocating new buffer of size " << chunk.size - HEADER_SIZE << std::endl; +#endif + + decoding_buffer.data = (unsigned char *)memalign(16,chunk.size - HEADER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE) ; + decoding_buffer.size = chunk.size - HEADER_SIZE ; + memset(decoding_buffer.data,0,decoding_buffer.size + FF_INPUT_BUFFER_PADDING_SIZE) ; + + buff = decoding_buffer.data ; + } + + memcpy(buff,&((unsigned char*)chunk.data)[HEADER_SIZE],chunk.size - HEADER_SIZE) ; + + int got_frame = 0 ; + int len = avcodec_decode_video2(decoding_context,decoding_frame_buffer,&got_frame,&decoding_buffer) ; + + if(len < 0) + { + std::cerr << "Error decodign frame!" << std::endl; + return false ; + } +#ifdef DEBUG_MPEG_VIDEO + std::cerr << "Used " << len << " bytes out of " << decoding_buffer.size << ". got_frame = " << got_frame << std::endl; +#endif + + if(got_frame) + { + image = QImage(QSize(decoding_frame_buffer->width,decoding_frame_buffer->height),QImage::Format_ARGB32) ; + +#ifdef DEBUG_MPEG_VIDEO + std::cerr << "Decoded frame. Size=" << image.width() << "x" << image.height() << std::endl; +#endif + + for (int y = 0; y < decoding_frame_buffer->height; y++) + for (int x = 0; x < decoding_frame_buffer->width; x++) + { + int Y = decoding_frame_buffer->data[0][y * decoding_frame_buffer->linesize[0] + x] ; + int U = decoding_frame_buffer->data[1][(y/2) * decoding_frame_buffer->linesize[1] + x/2] ; + int V = decoding_frame_buffer->data[2][(y/2) * decoding_frame_buffer->linesize[2] + x/2] ; + + int B = std::min(255,std::max(0,(int)(1.164*(Y - 16) + 1.596*(V - 128)))) ; + int G = std::min(255,std::max(0,(int)(1.164*(Y - 16) - 0.813*(V - 128) - 0.391*(U - 128)))) ; + int R = std::min(255,std::max(0,(int)(1.164*(Y - 16) + 2.018*(U - 128)))) ; + + image.setPixel(QPoint(x,y),QRgb( 0xff000000 + (R << 16) + (G << 8) + B)) ; + } + } + + if(len == decoding_buffer.size) + { + free(decoding_buffer.data) ; + decoding_buffer.data = NULL; + decoding_buffer.size = 0; + } + else if(len != 0) + { +#ifdef DEBUG_MPEG_VIDEO + std::cerr << "Moving remaining data (" << decoding_buffer.size - len << " bytes) back to 0" << std::endl; +#endif + + memmove(decoding_buffer.data,decoding_buffer.data+len,decoding_buffer.size - len) ; + decoding_buffer.size -= len ; + } + + return true ; } diff --git a/plugins/VOIP/gui/VideoProcessor.h b/plugins/VOIP/gui/VideoProcessor.h index 56894bcea..a3869dc5e 100644 --- a/plugins/VOIP/gui/VideoProcessor.h +++ b/plugins/VOIP/gui/VideoProcessor.h @@ -4,87 +4,149 @@ #include #include "interface/rsVOIP.h" +extern "C" { +#include +} + class QVideoOutputDevice ; -// This class decodes video from a stream. It keeps a queue of -// decoded frame that needs to be retrieved using the getNextImage() method. -// -class VideoDecoder +class VideoCodec { - public: - VideoDecoder() ; - virtual ~VideoDecoder() {} - - // Gets the next image to be displayed. Once returned, the image should - // be cleared from the incoming queue. - // - void setDisplayTarget(QVideoOutputDevice *odev) { _output_device = odev ; } - - virtual void receiveEncodedData(const unsigned char *data,uint32_t size) ; - - // returns the current (measured) frame rate in bytes per second. - // - uint32_t currentFrameRate() const; - - private: - QVideoOutputDevice *_output_device ; - - std::list _image_queue ; - - // Incoming data is processed by a video codec and converted into images. - // - virtual QImage decodeData(const unsigned char *encoded_image,uint32_t encoded_image_size) = 0 ; - -// // This buffer accumulated incoming encoded data, until a full packet is obtained, -// // since the stream might not send images at once. When incoming images are decoded, the -// // data is removed from the buffer. -// // -// unsigned char *buffer ; -// uint32_t buffer_size ; -}; - -// This class encodes video using a video codec (possibly homemade, or based on existing codecs) -// and produces a data stream that is sent to the network transfer service (e.g. p3VOIP). -// -class VideoEncoder -{ - public: - VideoEncoder() {} - virtual ~VideoEncoder() {} - - // Takes the next image to be encoded. - // - bool addImage(const QImage& Image) ; - - bool packetReady() const { return !_out_queue.empty() ; } - bool nextPacket(RsVOIPDataChunk& ) ; - - // Used to tweak the compression ratio so that the video can stream ok. - // - void setMaximumFrameRate(uint32_t bytes_per_second) ; - - protected: - //virtual bool sendEncodedData(unsigned char *mem,uint32_t size) = 0 ; - virtual void encodeData(const QImage& image) = 0 ; - - std::list _out_queue ; +public: + virtual bool encodeData(const QImage& Image, uint32_t size_hint, RsVOIPDataChunk& chunk) = 0; + virtual bool decodeData(const RsVOIPDataChunk& chunk,QImage& image) = 0; + +protected: + static const uint32_t HEADER_SIZE = 0x04 ; }; // Now derive various image encoding/decoding algorithms. // -class JPEGVideoDecoder: public VideoDecoder +class JPEGVideo: public VideoCodec { - protected: - virtual QImage decodeData(const unsigned char *encoded_image,uint32_t encoded_image_size) ; +public: + JPEGVideo() ; + +protected: + virtual bool encodeData(const QImage& Image, uint32_t target_encoding_bitrate, RsVOIPDataChunk& chunk) ; + virtual bool decodeData(const RsVOIPDataChunk& chunk,QImage& image) ; + + static const uint32_t JPEG_VIDEO_FLAGS_DIFFERENTIAL_FRAME = 0x0001 ; +private: + QImage _decoded_reference_frame ; + QImage _encoded_reference_frame ; + + uint32_t _encoded_ref_frame_max_distance ; // max distance between two reference frames. + uint32_t _encoded_ref_frame_count ; }; -class JPEGVideoEncoder: public VideoEncoder +struct AVCodec ; +struct AVCodecContext ; +struct AVFrame ; +struct AVPacket ; + +class FFmpegVideo: public VideoCodec +{ +public: + FFmpegVideo() ; + ~FFmpegVideo() ; + +protected: + virtual bool encodeData(const QImage& Image, uint32_t target_encoding_bitrate, RsVOIPDataChunk& chunk) ; + virtual bool decodeData(const RsVOIPDataChunk& chunk,QImage& image) ; + +private: + AVCodec *encoding_codec; + AVCodec *decoding_codec; + AVCodecContext *encoding_context; + AVCodecContext *decoding_context; + AVFrame *encoding_frame_buffer ; + AVFrame *decoding_frame_buffer ; + AVPacket decoding_buffer; + uint64_t encoding_frame_count ; + + FILE *encoding_debug_file ; +}; + +// This class decodes video from a stream. It keeps a queue of +// decoded frame that needs to be retrieved using the getNextImage() method. +// +class VideoProcessor { public: - JPEGVideoEncoder() {} + VideoProcessor() ; + virtual ~VideoProcessor() ; + enum CodecId { + VIDEO_PROCESSOR_CODEC_ID_UNKNOWN = 0x0000, + VIDEO_PROCESSOR_CODEC_ID_JPEG_VIDEO = 0x0001, + VIDEO_PROCESSOR_CODEC_ID_DDWT_VIDEO = 0x0002, + VIDEO_PROCESSOR_CODEC_ID_MPEG_VIDEO = 0x0003 + }; + +// ===================================================================================== +// =------------------------------------ DECODING -------------------------------------= +// ===================================================================================== + + // Gets the next image to be displayed. Once returned, the image should + // be cleared from the incoming queue. + // + void setDisplayTarget(QVideoOutputDevice *odev) { _decoded_output_device = odev ; } + virtual void receiveEncodedData(const RsVOIPDataChunk& chunk) ; + + // returns the current (measured) frame rate in bytes per second. + // + uint32_t currentBandwidthIn() const { return _estimated_bandwidth_in ; } + + private: + QVideoOutputDevice *_decoded_output_device ; + std::list _decoded_image_queue ; + +// ===================================================================================== +// =------------------------------------ ENCODING -------------------------------------= +// ===================================================================================== + + public: + // Takes the next image to be encoded. + // + bool processImage(const QImage& Image) ; + bool encodedPacketReady() const { return !_encoded_out_queue.empty() ; } + bool nextEncodedPacket(RsVOIPDataChunk& ) ; + + // Used to tweak the compression ratio so that the video can stream ok. + // + void setMaximumBandwidth(uint32_t bytes_per_second) ; + void setInternalFrameSize(QSize) ; + + // returns the current encoding frame rate in bytes per second. + // + uint32_t currentBandwidthOut() const { return _estimated_bandwidth_out ; } + protected: - virtual void encodeData(const QImage& Image) ; + std::list _encoded_out_queue ; + QSize _encoded_frame_size ; + +// ===================================================================================== +// =------------------------------------- Codecs --------------------------------------= +// ===================================================================================== + + JPEGVideo _jpeg_video_codec ; + FFmpegVideo _mpeg_video_codec ; + + uint16_t _encoding_current_codec ; + + time_t _last_bw_estimate_in_TS; + time_t _last_bw_estimate_out_TS; + + uint32_t _total_encoded_size_in ; + uint32_t _total_encoded_size_out ; + + float _estimated_bandwidth_in ; + float _estimated_bandwidth_out ; + + float _target_bandwidth_out ; + + RsMutex vpMtx ; }; diff --git a/plugins/VOIP/interface/rsVOIP.h b/plugins/VOIP/interface/rsVOIP.h index 18f258769..25fd0cfbd 100644 --- a/plugins/VOIP/interface/rsVOIP.h +++ b/plugins/VOIP/interface/rsVOIP.h @@ -51,11 +51,15 @@ class RsVOIPPongResult struct RsVOIPDataChunk { - typedef enum { RS_VOIP_DATA_TYPE_AUDIO, RS_VOIP_DATA_TYPE_VIDEO } RsVOIPDataType ; + typedef enum { RS_VOIP_DATA_TYPE_UNKNOWN = 0x00, + RS_VOIP_DATA_TYPE_AUDIO = 0x01, + RS_VOIP_DATA_TYPE_VIDEO = 0x02 } RsVOIPDataType ; void *data ; // create/delete using malloc/free. uint32_t size ; RsVOIPDataType type ; // video or audio + + void clear() ; }; class RsVOIP diff --git a/plugins/VOIP/lang/VOIP_en.ts b/plugins/VOIP/lang/VOIP_en.ts index 6fff12491..05ec2f65f 100644 --- a/plugins/VOIP/lang/VOIP_en.ts +++ b/plugins/VOIP/lang/VOIP_en.ts @@ -1,6 +1,6 @@ - + AudioInput @@ -130,7 +130,7 @@ - + Video Processing @@ -138,7 +138,7 @@ AudioInputConfig - + Continuous @@ -168,7 +168,7 @@ - + VOIP @@ -366,7 +366,7 @@ - + This is the audio tuning wizard for RetroShare. This will help you correctly set the input levels of your sound card, and also set the correct parameters for sound processing in Retroshare. @@ -381,13 +381,13 @@ - + <p >Open your sound control panel and go to the recording settings. Make sure the microphone is selected as active input with maximum recording volume. If there's an option to enable a &quot;Microphone boost&quot; make sure it's checked. </p> <p>Speak loudly, as when you are annoyed or excited. Decrease the volume in the sound control panel until the bar below stays as high as possible in the green and orange but not the red zone while you speak. </p> - + Talk normally, and adjust the slider below so that the bar moves into green when you talk, and doesn't go into the orange zone. @@ -452,7 +452,7 @@ - + Congratulations. You should now be ready to enjoy a richer sound experience with Retroshare. @@ -460,7 +460,7 @@ QObject - + <h3>RetroShare VOIP plugin</h3><br/> * Contributors: Cyril Soler, Josselin Jacquard<br/> @@ -498,7 +498,7 @@ VOIP - + This plugin provides voice communication between friends in RetroShare. @@ -747,4 +747,12 @@ + + voipGraphSource + + + Required bandwidth + + + diff --git a/plugins/VOIP/services/p3VOIP.cc b/plugins/VOIP/services/p3VOIP.cc index d7377077c..fb164bd7c 100644 --- a/plugins/VOIP/services/p3VOIP.cc +++ b/plugins/VOIP/services/p3VOIP.cc @@ -147,6 +147,14 @@ RsServiceInfo p3VOIP::getServiceInfo() TURTLE_MIN_MINOR_VERSION); } +void RsVOIPDataChunk::clear() +{ + + if(data) + free(data) ; + data=NULL; + size=0 ; +} int p3VOIP::tick() { #ifdef DEBUG_VOIP diff --git a/plugins/VOIP/services/rsVOIPItems.cc b/plugins/VOIP/services/rsVOIPItems.cc index eb8842468..a75fa4c16 100644 --- a/plugins/VOIP/services/rsVOIPItems.cc +++ b/plugins/VOIP/services/rsVOIPItems.cc @@ -76,6 +76,19 @@ std::ostream& RsVOIPProtocolItem::print(std::ostream &out, uint16_t indent) printRsItemEnd(out, "RsVOIPProtocolItem", indent); return out; } +std::ostream& RsVOIPBandwidthItem::print(std::ostream &out, uint16_t indent) +{ + printRsItemBase(out, "RsVOIPBandwidthItem", indent); + uint16_t int_Indent = indent + 2; + printIndent(out, int_Indent); + out << "flags: " << std::hex << flags << std::dec << std::endl; + + printIndent(out, int_Indent); + out << "speed: " << bytes_per_sec << std::endl; + + printRsItemEnd(out, "RsVOIPBandwidthItem", indent); + return out; +} std::ostream& RsVOIPDataItem::print(std::ostream &out, uint16_t indent) { printRsItemBase(out, "RsVOIPDataItem", indent); @@ -100,6 +113,14 @@ uint32_t RsVOIPDataItem::serial_size() const return s; } +uint32_t RsVOIPBandwidthItem::serial_size() const +{ + uint32_t s = 8; /* header */ + s += 4; /* flags */ + s += 4; /* bandwidth */ + + return s; +} uint32_t RsVOIPProtocolItem::serial_size() const { uint32_t s = 8; /* header */ @@ -150,6 +171,40 @@ bool RsVOIPProtocolItem::serialise(void *data, uint32_t& pktsize) return ok; } +bool RsVOIPBandwidthItem::serialise(void *data, uint32_t& pktsize) +{ + uint32_t tlvsize = serial_size() ; + uint32_t offset = 0; + + if (pktsize < tlvsize) + return false; /* not enough space */ + + pktsize = tlvsize; + + bool ok = true; + + ok &= setRsItemHeader(data, tlvsize, PacketId(), tlvsize); + +#ifdef RSSERIAL_DEBUG + std::cerr << "RsVOIPSerialiser::serialiseVOIPBandwidthItem() Header: " << ok << std::endl; + std::cerr << "RsVOIPSerialiser::serialiseVOIPBandwidthItem() Size: " << tlvsize << std::endl; +#endif + + /* skip the header */ + offset += 8; + + /* add mandatory parts first */ + ok &= setRawUInt32(data, tlvsize, &offset, flags); + ok &= setRawUInt32(data, tlvsize, &offset, bytes_per_sec); + + if (offset != tlvsize) + { + ok = false; + std::cerr << "RsVOIPSerialiser::serialiseVOIPBandwidthItem() Size Error! " << std::endl; + } + + return ok; +} /* serialise the data to the buffer */ bool RsVOIPDataItem::serialise(void *data, uint32_t& pktsize) { @@ -254,6 +309,36 @@ RsVOIPProtocolItem::RsVOIPProtocolItem(void *data, uint32_t pktsize) if (!ok) throw std::runtime_error("Deserialisation error!") ; } +RsVOIPBandwidthItem::RsVOIPBandwidthItem(void *data, uint32_t pktsize) + : RsVOIPItem(RS_PKT_SUBTYPE_VOIP_BANDWIDTH) +{ + /* get the type and size */ + uint32_t rstype = getRsItemId(data); + uint32_t rssize = getRsItemSize(data); + + uint32_t offset = 0; + + if ((RS_PKT_VERSION_SERVICE != getRsItemVersion(rstype)) || (RS_SERVICE_TYPE_VOIP_PLUGIN != getRsItemService(rstype)) || (RS_PKT_SUBTYPE_VOIP_BANDWIDTH != getRsItemSubType(rstype))) + throw std::runtime_error("Wrong packet type!") ; + + if (pktsize < rssize) /* check size */ + throw std::runtime_error("Not enough size!") ; + + bool ok = true; + + /* skip the header */ + offset += 8; + + /* get mandatory parts first */ + ok &= getRawUInt32(data, rssize, &offset, &flags); + ok &= getRawUInt32(data, rssize, &offset, &bytes_per_sec); + + if (offset != rssize) + throw std::runtime_error("Deserialisation error!") ; + + if (!ok) + throw std::runtime_error("Deserialisation error!") ; +} RsVOIPPingItem::RsVOIPPingItem(void *data, uint32_t pktsize) : RsVOIPItem(RS_PKT_SUBTYPE_VOIP_PING) { diff --git a/plugins/VOIP/services/rsVOIPItems.h b/plugins/VOIP/services/rsVOIPItems.h index fa440ef19..7658ea4cc 100644 --- a/plugins/VOIP/services/rsVOIPItems.h +++ b/plugins/VOIP/services/rsVOIPItems.h @@ -55,11 +55,12 @@ const uint16_t RS_SERVICE_TYPE_VOIP_PLUGIN = 0xa021; -const uint8_t RS_PKT_SUBTYPE_VOIP_PING = 0x01; -const uint8_t RS_PKT_SUBTYPE_VOIP_PONG = 0x02; -const uint8_t RS_PKT_SUBTYPE_VOIP_PROTOCOL = 0x03 ; - // 0x04 is unused because of a change in the protocol -const uint8_t RS_PKT_SUBTYPE_VOIP_DATA = 0x05 ; +const uint8_t RS_PKT_SUBTYPE_VOIP_PING = 0x01; +const uint8_t RS_PKT_SUBTYPE_VOIP_PONG = 0x02; +const uint8_t RS_PKT_SUBTYPE_VOIP_PROTOCOL = 0x03 ; + // 0x04,0x05 is unused because of a change in the protocol +const uint8_t RS_PKT_SUBTYPE_VOIP_BANDWIDTH = 0x06 ; +const uint8_t RS_PKT_SUBTYPE_VOIP_DATA = 0x07 ; const uint8_t QOS_PRIORITY_RS_VOIP = 9 ; @@ -117,9 +118,27 @@ class RsVOIPDataItem: public RsVOIPItem uint32_t flags ; uint32_t data_size ; + void *voip_data ; }; +class RsVOIPBandwidthItem: public RsVOIPItem +{ + public: + RsVOIPBandwidthItem() :RsVOIPItem(RS_PKT_SUBTYPE_VOIP_BANDWIDTH) {} + RsVOIPBandwidthItem(void *data,uint32_t size) ; // de-serialization + + virtual bool serialise(void *data,uint32_t& size) ; + virtual uint32_t serial_size() const ; + + virtual ~RsVOIPBandwidthItem() {} + virtual std::ostream& print(std::ostream &out, uint16_t indent = 0); + + uint32_t flags ; // is that incoming or expected bandwidth? + uint32_t bytes_per_sec ; // bandwidth in bytes per sec. +}; + + class RsVOIPProtocolItem: public RsVOIPItem { public: diff --git a/retroshare-gui/src/gui/AboutDialog.cpp b/retroshare-gui/src/gui/AboutDialog.cpp index 26170558d..7d1a047d6 100644 --- a/retroshare-gui/src/gui/AboutDialog.cpp +++ b/retroshare-gui/src/gui/AboutDialog.cpp @@ -24,10 +24,15 @@ #include "HelpDialog.h" #include "rshare.h" +#include +#include #include #include #include "settings/rsharesettings.h" +#include +#include +#include #include #include #include @@ -721,3 +726,79 @@ NextPieceLabel::NextPieceLabel( QWidget* parent /* = 0*/ ) : QLabel(parent) setAlignment(Qt::AlignCenter); setAutoFillBackground(true); } + +static QString addLibraries(const std::string &name, const std::list &libraries) +{ + QString mTextEdit; + mTextEdit+=QString::fromUtf8(name.c_str()); + mTextEdit+="\n"; + + std::list::const_iterator libraryIt; + for (libraryIt = libraries.begin(); libraryIt != libraries.end(); ++libraryIt) { + + mTextEdit+=" - "; + mTextEdit+=QString::fromUtf8(libraryIt->mName.c_str()); + mTextEdit+=": "; + mTextEdit+=QString::fromUtf8(libraryIt->mVersion.c_str()); + mTextEdit+="\n"; + } + mTextEdit+="\n"; + return mTextEdit; +} + + +void AboutDialog::on_copy_button_clicked() +{ + QString verInfo; + QString rsVerString = "RetroShare Version: "; + rsVerString+=Rshare::retroshareVersion(true); + verInfo+=rsVerString; + verInfo+="\n"; + + +#if QT_VERSION >= QT_VERSION_CHECK (5, 0, 0) + #if QT_VERSION >= QT_VERSION_CHECK (5, 4, 0) + verInfo+=QSysInfo::prettyProductName(); + #endif +#else + #ifdef Q_OS_LINUX + verInfo+="Linux"; + #endif + #ifdef Q_OS_WIN + verInfo+="Windows"; + #endif + #ifdef Q_OS_MAC + verInfo+="Mac"; + #endif +#endif + verInfo+=" "; + QString qtver = QString("QT ")+QT_VERSION_STR; + verInfo+=qtver; + verInfo+="\n\n"; + + /* Add version numbers of libretroshare */ + std::list libraries; + RsControl::instance()->getLibraries(libraries); + verInfo+=addLibraries("libretroshare", libraries); + + /* Add version numbers of RetroShare */ + // Add versions here. Find a better place. + libraries.clear(); + libraries.push_back(RsLibraryInfo("Libmicrohttpd", MHD_get_version())); + verInfo+=addLibraries("RetroShare", libraries); + + /* Add version numbers of plugins */ + if (rsPlugins) { + for (int i = 0; i < rsPlugins->nbPlugins(); ++i) { + RsPlugin *plugin = rsPlugins->plugin(i); + if (plugin) { + libraries.clear(); + plugin->getLibraries(libraries); + verInfo+=addLibraries(plugin->getPluginName(), libraries); + } + } + } + + + QApplication::clipboard()->setText(verInfo); +} diff --git a/retroshare-gui/src/gui/AboutDialog.h b/retroshare-gui/src/gui/AboutDialog.h index d179d5959..c0095699b 100644 --- a/retroshare-gui/src/gui/AboutDialog.h +++ b/retroshare-gui/src/gui/AboutDialog.h @@ -50,6 +50,8 @@ private slots: void sl_levelChanged(int); void on_help_button_clicked(); + void on_copy_button_clicked(); + signals: void si_scoreChanged(QString); void si_maxScoreChanged(QString); diff --git a/retroshare-gui/src/gui/AboutDialog.ui b/retroshare-gui/src/gui/AboutDialog.ui index d43e9c110..d279f801c 100644 --- a/retroshare-gui/src/gui/AboutDialog.ui +++ b/retroshare-gui/src/gui/AboutDialog.ui @@ -23,7 +23,16 @@ true
- + + 9 + + + 9 + + + 9 + + 9 @@ -52,6 +61,17 @@
+ + + + Copy Info + + + + :/images/copy.png:/images/copy.png + + + @@ -76,7 +96,9 @@ - + + + close_button diff --git a/retroshare-gui/src/gui/ChatLobbyWidget.cpp b/retroshare-gui/src/gui/ChatLobbyWidget.cpp index 42b148411..298e172b6 100644 --- a/retroshare-gui/src/gui/ChatLobbyWidget.cpp +++ b/retroshare-gui/src/gui/ChatLobbyWidget.cpp @@ -22,18 +22,21 @@ #include "retroshare/rsnotify.h" #include "retroshare/rsidentity.h" +//#define CHAT_LOBBY_GUI_DEBUG 1 + #define COLUMN_NAME 0 #define COLUMN_USER_COUNT 1 #define COLUMN_TOPIC 2 #define COLUMN_SUBSCRIBED 3 #define COLUMN_COUNT 4 - #define COLUMN_DATA 0 -#define ROLE_SORT Qt::UserRole -#define ROLE_ID Qt::UserRole + 1 -#define ROLE_SUBSCRIBED Qt::UserRole + 2 -#define ROLE_PRIVACYLEVEL Qt::UserRole + 3 + +#define ROLE_SORT Qt::UserRole +#define ROLE_ID Qt::UserRole + 1 +#define ROLE_SUBSCRIBED Qt::UserRole + 2 +#define ROLE_PRIVACYLEVEL Qt::UserRole + 3 #define ROLE_AUTOSUBSCRIBE Qt::UserRole + 4 +#define ROLE_FLAGS Qt::UserRole + 5 #define TYPE_FOLDER 0 @@ -129,10 +132,12 @@ ChatLobbyWidget::ChatLobbyWidget(QWidget *parent, Qt::WindowFlags flags) ui.lobbyTreeWidget->setColumnHidden(COLUMN_SUBSCRIBED,true) ; ui.lobbyTreeWidget->setSortingEnabled(true) ; + float fact = QFontMetricsF(font()).height()/14.0f; + ui.lobbyTreeWidget->adjustSize(); - ui.lobbyTreeWidget->setColumnWidth(COLUMN_NAME,100); - ui.lobbyTreeWidget->setColumnWidth(COLUMN_USER_COUNT, 50); - ui.lobbyTreeWidget->setColumnWidth(COLUMN_TOPIC, 50); + ui.lobbyTreeWidget->setColumnWidth(COLUMN_NAME,100*fact); + ui.lobbyTreeWidget->setColumnWidth(COLUMN_USER_COUNT, 50*fact); + ui.lobbyTreeWidget->setColumnWidth(COLUMN_TOPIC, 50*fact); /** Setup the actions for the header context menu */ showUserCountAct= new QAction(headerItem->text(COLUMN_USER_COUNT),this); @@ -150,7 +155,7 @@ ChatLobbyWidget::ChatLobbyWidget(QWidget *parent, Qt::WindowFlags flags) ui.splitter->setStretchFactor(1, 1); QList sizes; - sizes << 200 << width(); // Qt calculates the right sizes + sizes << 200*fact << width(); // Qt calculates the right sizes ui.splitter->setSizes(sizes); lobbyChanged(); @@ -222,6 +227,25 @@ void ChatLobbyWidget::updateNotify(ChatLobbyId id, unsigned int count) } } +static bool trimAnonIds(std::list& lst) +{ + // trim down identities that are unsigned, because the lobby requires it. + bool removed = false ; + + RsIdentityDetails idd ; + + for(std::list::iterator it = lst.begin();it!=lst.end();) + if(!rsIdentity->getIdDetails(*it,idd) || !idd.mPgpLinked) + { + it = lst.erase(it) ; + removed= true ; + } + else + ++it ; + + return removed ; +} + void ChatLobbyWidget::lobbyTreeWidgetCustomPopupMenu(QPoint) { std::cerr << "Creating customPopupMennu" << std::endl; @@ -244,10 +268,19 @@ void ChatLobbyWidget::lobbyTreeWidgetCustomPopupMenu(QPoint) else { QTreeWidgetItem *item = ui.lobbyTreeWidget->currentItem(); - uint32_t item_flags = item->data(COLUMN_DATA,ROLE_ID).toUInt() ; + ChatLobbyId id = item->data(COLUMN_DATA, ROLE_ID).toULongLong(); + ChatLobbyFlags flags(item->data(COLUMN_DATA, ROLE_FLAGS).toUInt()); + + bool removed = false ; + if(flags & RS_CHAT_LOBBY_FLAGS_PGP_SIGNED) + removed = trimAnonIds(own_identities) ; + if(own_identities.empty()) { + if(removed) + contextMnu.addAction(QIcon(IMAGE_SUBSCRIBE), tr("Create a non anonymous identity and enter this lobby"), this, SLOT(createIdentityAndSubscribe())); + else contextMnu.addAction(QIcon(IMAGE_SUBSCRIBE), tr("Create an identity and enter this lobby"), this, SLOT(createIdentityAndSubscribe())); } else if(own_identities.size() == 1) @@ -300,7 +333,7 @@ void ChatLobbyWidget::lobbyChanged() updateDisplay(); } -static void updateItem(QTreeWidget *treeWidget, QTreeWidgetItem *item, ChatLobbyId id, const std::string &name, const std::string &topic, int count, bool subscribed, bool autoSubscribe) +static void updateItem(QTreeWidget *treeWidget, QTreeWidgetItem *item, ChatLobbyId id, const std::string &name, const std::string &topic, int count, bool subscribed, bool autoSubscribe,ChatLobbyFlags lobby_flags) { item->setText(COLUMN_NAME, QString::fromUtf8(name.c_str())); item->setData(COLUMN_NAME, ROLE_SORT, QString::fromUtf8(name.c_str())); @@ -323,9 +356,11 @@ static void updateItem(QTreeWidget *treeWidget, QTreeWidgetItem *item, ChatLobby item->setData(COLUMN_DATA, ROLE_ID, (qulonglong)id); item->setData(COLUMN_DATA, ROLE_SUBSCRIBED, subscribed); + item->setData(COLUMN_DATA, ROLE_FLAGS, lobby_flags.toUInt32()); item->setData(COLUMN_DATA, ROLE_AUTOSUBSCRIBE, autoSubscribe); QColor color = treeWidget->palette().color(QPalette::Active, QPalette::Text); + if (!subscribed) { // Average between Base and Text colors QColor color2 = treeWidget->palette().color(QPalette::Active, QPalette::Base); @@ -335,10 +370,15 @@ static void updateItem(QTreeWidget *treeWidget, QTreeWidgetItem *item, ChatLobby for (int column = 0; column < COLUMN_COUNT; ++column) { item->setTextColor(column, color); } - item->setToolTip(0,QObject::tr("Subject:")+" "+item->text(COLUMN_TOPIC)+"\n" + QString tooltipstr = QObject::tr("Subject:")+" "+item->text(COLUMN_TOPIC)+"\n" +QObject::tr("Participants:")+" "+QString::number(count)+"\n" +QObject::tr("Auto Subscribe:")+" "+(autoSubscribe? QObject::tr("enabled"): QObject::tr("disabled"))+"\n" - +QObject::tr("Id:")+" "+QString::number(id,16)) ; + +QObject::tr("Id:")+" "+QString::number(id,16) ; + + if(lobby_flags & RS_CHAT_LOBBY_FLAGS_PGP_SIGNED) + tooltipstr += QObject::tr("\nSecurity: no anonymous ids") ; + + item->setToolTip(0,tooltipstr) ; } void ChatLobbyWidget::addChatPage(ChatLobbyDialog *d) @@ -380,7 +420,6 @@ void ChatLobbyWidget::setCurrentChatPage(ChatLobbyDialog *d) } } -//#define CHAT_LOBBY_GUI_DEBUG void ChatLobbyWidget::updateDisplay() { #ifdef CHAT_LOBBY_GUI_DEBUG @@ -521,12 +560,15 @@ void ChatLobbyWidget::updateDisplay() } } + ChatLobbyFlags lobby_flags = lobby.lobby_flags ; + QIcon icon; if (item == NULL) { item = new RSTreeWidgetItem(compareRole, TYPE_LOBBY); icon = (lobby.lobby_flags & RS_CHAT_LOBBY_FLAGS_PUBLIC) ? QIcon(IMAGE_PUBLIC) : QIcon(IMAGE_PRIVATE); lobby_item->addChild(item); + } else { @@ -554,7 +596,7 @@ void ChatLobbyWidget::updateDisplay() } } - updateItem(ui.lobbyTreeWidget, item, lobby.lobby_id, lobby.lobby_name,lobby.lobby_topic, lobby.total_number_of_peers, subscribed, autoSubscribe); + updateItem(ui.lobbyTreeWidget, item, lobby.lobby_id, lobby.lobby_name,lobby.lobby_topic, lobby.total_number_of_peers, subscribed, autoSubscribe,lobby_flags); } // time_t now = time(NULL) ; @@ -589,7 +631,11 @@ void ChatLobbyWidget::updateDisplay() } QIcon icon; - if (item == NULL) { + + ChatLobbyFlags lobby_flags = lobby.lobby_flags ; + + if (item == NULL) + { item = new RSTreeWidgetItem(compareRole, TYPE_LOBBY); icon = (lobby.lobby_flags & RS_CHAT_LOBBY_FLAGS_PUBLIC) ? QIcon(IMAGE_PUBLIC) : QIcon(IMAGE_PRIVATE); itemParent->addChild(item); @@ -605,7 +651,7 @@ 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); + updateItem(ui.lobbyTreeWidget, item, lobby.lobby_id, lobby.lobby_name,lobby.lobby_topic, lobby.gxs_ids.size(), true, autoSubscribe,lobby_flags); } publicSubLobbyItem->setHidden(publicSubLobbyItem->childCount()==0); privateSubLobbyItem->setHidden(privateSubLobbyItem->childCount()==0); @@ -647,9 +693,14 @@ void ChatLobbyWidget::createIdentityAndSubscribe() return ; ChatLobbyId id = item->data(COLUMN_DATA, ROLE_ID).toULongLong(); + ChatLobbyFlags flags(item->data(COLUMN_DATA, ROLE_FLAGS).toUInt()); IdEditDialog dlg(this); dlg.setupNewId(false); + + if(flags & RS_CHAT_LOBBY_FLAGS_PGP_SIGNED) // + dlg.enforceNoAnonIds() ; + dlg.exec(); // fetch new id std::list own_ids; @@ -711,6 +762,7 @@ void ChatLobbyWidget::subscribeChatLobbyAtItem(QTreeWidgetItem *item) } ChatLobbyId id = item->data(COLUMN_DATA, ROLE_ID).toULongLong(); + ChatLobbyFlags flags ( item->data(COLUMN_DATA, ROLE_FLAGS).toUInt()); RsGxsId gxs_id ; std::list own_ids; @@ -726,6 +778,9 @@ void ChatLobbyWidget::subscribeChatLobbyAtItem(QTreeWidgetItem *item) { IdEditDialog dlg(this); dlg.setupNewId(false); + + if(flags & RS_CHAT_LOBBY_FLAGS_PGP_SIGNED) // + dlg.enforceNoAnonIds() ; dlg.exec(); // fetch new id if(!rsIdentity->getOwnIds(own_ids) || own_ids.empty()) @@ -733,7 +788,19 @@ void ChatLobbyWidget::subscribeChatLobbyAtItem(QTreeWidgetItem *item) gxs_id = own_ids.front(); } else + { rsMsgs->getDefaultIdentityForChatLobby(gxs_id); + + RsIdentityDetails idd ; + if(!rsIdentity->getIdDetails(gxs_id,idd)) + return ; + + if(flags & RS_CHAT_LOBBY_FLAGS_PGP_SIGNED) + { + QMessageBox::warning(NULL,tr("Default identity is anonymous"),tr("You cannot join this lobby with your default identity, since it is anonymous and the lobby forbids it.")) ; + return ; + } + } if(rsMsgs->joinVisibleChatLobby(id,gxs_id)) ChatDialog::chatFriend(ChatId(id),true) ; @@ -763,18 +830,25 @@ void ChatLobbyWidget::showBlankPage(ChatLobbyId id) std::list my_ids ; rsIdentity->getOwnIds(my_ids) ; + trimAnonIds(my_ids) ; + for(std::vector::const_iterator it(lobbies.begin());it!=lobbies.end();++it) if( (*it).lobby_id == id) { ui.lobbyname_lineEdit->setText( RsHtml::plainText(it->lobby_name) ); ui.lobbyid_lineEdit->setText( QString::number((*it).lobby_id,16) ); ui.lobbytopic_lineEdit->setText( RsHtml::plainText(it->lobby_topic) ); - ui.lobbytype_lineEdit->setText( (( (*it).lobby_flags & RS_CHAT_LOBBY_FLAGS_PUBLIC)?tr("Public"):tr("Private")) ); + ui.lobbytype_lineEdit->setText( (( (*it).lobby_flags & RS_CHAT_LOBBY_FLAGS_PUBLIC)?tr("Public"):tr("Private")) ); + ui.lobbysec_lineEdit->setText( (( (*it).lobby_flags & RS_CHAT_LOBBY_FLAGS_PGP_SIGNED)?tr("No anonymous IDs"):tr("Anonymous ids accepted")) ); ui.lobbypeers_lineEdit->setText( QString::number((*it).total_number_of_peers) ); QString text = tr("You're not subscribed to this lobby; Double click-it to enter and chat.") ; + if(my_ids.empty()) - text += "\n\n"+tr("You will need to create an identity in order to join chat lobbies.") ; + if( (*it).lobby_flags & RS_CHAT_LOBBY_FLAGS_PGP_SIGNED) + text += "\n\n"+tr("You will need to create a non anonymous identity in order to join this chat lobby.") ; + else + text += "\n\n"+tr("You will need to create an identity in order to join chat lobbies.") ; ui.lobbyInfoLabel->setText(text); return ; @@ -785,6 +859,7 @@ void ChatLobbyWidget::showBlankPage(ChatLobbyId id) ui.lobbytopic_lineEdit->clear(); ui.lobbytype_lineEdit->clear(); ui.lobbypeers_lineEdit->clear(); + ui.lobbysec_lineEdit->clear(); QString text = tr("No lobby selected. \nSelect lobbies at left to show details.\nDouble click lobbies to enter and chat.") ; ui.lobbyInfoLabel->setText(text) ; diff --git a/retroshare-gui/src/gui/ChatLobbyWidget.ui b/retroshare-gui/src/gui/ChatLobbyWidget.ui index 976359b74..05bfc61e4 100644 --- a/retroshare-gui/src/gui/ChatLobbyWidget.ui +++ b/retroshare-gui/src/gui/ChatLobbyWidget.ui @@ -6,21 +6,12 @@ 0 0 - 643 - 426 + 803 + 517 - - 0 - - - 0 - - - 0 - - + 0 @@ -99,7 +90,7 @@ Qt::Horizontal - + @@ -201,9 +192,6 @@ - - - Selected lobby info @@ -264,6 +252,19 @@ + + + + + 75 + true + + + + Security: + + + @@ -336,6 +337,13 @@ + + + + TextLabel + + + diff --git a/retroshare-gui/src/gui/FriendsDialog.cpp b/retroshare-gui/src/gui/FriendsDialog.cpp index b7dfe466c..9a5d3a3f0 100644 --- a/retroshare-gui/src/gui/FriendsDialog.cpp +++ b/retroshare-gui/src/gui/FriendsDialog.cpp @@ -142,9 +142,7 @@ QList sizes; // load settings RsAutoUpdatePage::lockAllEvents(); - ui.friendList->setColumnVisible(FriendList::COLUMN_STATE, false); ui.friendList->setColumnVisible(FriendList::COLUMN_LAST_CONTACT, false); - ui.friendList->setColumnVisible(FriendList::COLUMN_AVATAR, true); ui.friendList->setColumnVisible(FriendList::COLUMN_IP, false); ui.friendList->setShowGroups(true); processSettings(true); diff --git a/retroshare-gui/src/gui/GetStartedDialog.cpp b/retroshare-gui/src/gui/GetStartedDialog.cpp index 6d4f88d5a..6cf6b2593 100644 --- a/retroshare-gui/src/gui/GetStartedDialog.cpp +++ b/retroshare-gui/src/gui/GetStartedDialog.cpp @@ -189,7 +189,7 @@ void GetStartedDialog::tickFirewallChanged() static void sendMail(const QString &address, const QString &subject, QString body) { /* Only under windows do we need to do this! */ -#ifdef Q_WS_WIN +#ifdef Q_OS_WIN /* search and replace the end of lines with: "%0D%0A" */ body.replace("\n", "%0D%0A"); #endif @@ -343,7 +343,7 @@ void GetStartedDialog::emailSupport() #ifdef __APPLE__ - #ifdef Q_WS_MAC + #ifdef Q_OS_MAC switch(QSysInfo::MacintoshVersion) { case QSysInfo::MV_9: @@ -383,7 +383,7 @@ void GetStartedDialog::emailSupport() #else #if defined(_WIN32) || defined(__MINGW32__) // Windows - #ifdef Q_WS_WIN + #ifdef Q_OS_WIN switch(QSysInfo::windowsVersion()) { case QSysInfo::WV_32s: diff --git a/retroshare-gui/src/gui/Identity/IdDialog.cpp b/retroshare-gui/src/gui/Identity/IdDialog.cpp index 0409c007e..1189b2d37 100644 --- a/retroshare-gui/src/gui/Identity/IdDialog.cpp +++ b/retroshare-gui/src/gui/Identity/IdDialog.cpp @@ -81,9 +81,9 @@ IdDialog::IdDialog(QWidget *parent) : /* Setup UI helper */ mStateHelper = new UIStateHelper(this); -// mStateHelper->addWidget(IDDIALOG_IDLIST, ui->treeWidget_IdList); - mStateHelper->addLoadPlaceholder(IDDIALOG_IDLIST, ui->treeWidget_IdList, false); - mStateHelper->addClear(IDDIALOG_IDLIST, ui->treeWidget_IdList); +// mStateHelper->addWidget(IDDIALOG_IDLIST, ui->idTreeWidget); + mStateHelper->addLoadPlaceholder(IDDIALOG_IDLIST, ui->idTreeWidget, false); + mStateHelper->addClear(IDDIALOG_IDLIST, ui->idTreeWidget); mStateHelper->addWidget(IDDIALOG_IDDETAILS, ui->lineEdit_Nickname); mStateHelper->addWidget(IDDIALOG_IDDETAILS, ui->lineEdit_KeyId); @@ -142,8 +142,8 @@ IdDialog::IdDialog(QWidget *parent) : connect(ui->editIdentity, SIGNAL(triggered()), this, SLOT(editIdentity())); connect(ui->chatIdentity, SIGNAL(triggered()), this, SLOT(chatIdentity())); - connect(ui->treeWidget_IdList, SIGNAL(itemSelectionChanged()), this, SLOT(updateSelection())); - connect(ui->treeWidget_IdList, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(IdListCustomPopupMenu(QPoint))); + connect(ui->idTreeWidget, SIGNAL(itemSelectionChanged()), this, SLOT(updateSelection())); + connect(ui->idTreeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(IdListCustomPopupMenu(QPoint))); connect(ui->filterComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(filterComboBoxChanged())); connect(ui->filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString))); @@ -172,34 +172,29 @@ IdDialog::IdDialog(QWidget *parent) : ui->filterComboBox->setCurrentIndex(0); /* Add filter actions */ - QTreeWidgetItem *headerItem = ui->treeWidget_IdList->headerItem(); + QTreeWidgetItem *headerItem = ui->idTreeWidget->headerItem(); QString headerText = headerItem->text(RSID_COL_NICKNAME); ui->filterLineEdit->addFilter(QIcon(), headerText, RSID_COL_NICKNAME, QString("%1 %2").arg(tr("Search"), headerText)); headerText = headerItem->text(RSID_COL_KEYID); ui->filterLineEdit->addFilter(QIcon(), headerItem->text(RSID_COL_KEYID), RSID_COL_KEYID, QString("%1 %2").arg(tr("Search"), headerText)); - initializeHeader(true); - /* Setup tree */ - ui->treeWidget_IdList->sortByColumn(RSID_COL_NICKNAME, Qt::AscendingOrder); - ui->treeWidget_IdList->setContextMenuPolicy(Qt::CustomContextMenu) ; - - /** Setup the actions for the header context menu */ - hideIdAct= new QAction(headerItem->text(RSID_COL_KEYID),this); - hideIdAct->setCheckable(true); hideIdAct->setToolTip(tr("Show")+" "+hideIdAct->text()+" "+tr("column")); - connect(hideIdAct,SIGNAL(triggered(bool)),this,SLOT(setHideIdColumn(bool))) ; - - hideTypeAct= new QAction(headerItem->text(RSID_COL_IDTYPE),this); - hideTypeAct->setCheckable(true); hideTypeAct->setToolTip(tr("Show")+" "+hideTypeAct->text()+" "+tr("column")); - connect(hideTypeAct,SIGNAL(triggered(bool)),this,SLOT(setHideIdTypeColumn(bool))) ; - + ui->idTreeWidget->sortByColumn(RSID_COL_NICKNAME, Qt::AscendingOrder); + + ui->idTreeWidget->enableColumnCustomize(true); + ui->idTreeWidget->setColumnCustomizable(RSID_COL_NICKNAME, false); + + /* Set initial column width */ + int fontWidth = QFontMetricsF(ui->idTreeWidget->font()).width("W"); + ui->idTreeWidget->setColumnWidth(RSID_COL_NICKNAME, 18 * fontWidth); + ui->idTreeWidget->setColumnWidth(RSID_COL_KEYID, 25 * fontWidth); + ui->idTreeWidget->setColumnWidth(RSID_COL_IDTYPE, 18 * fontWidth); + mIdQueue = new TokenQueue(rsIdentity->getTokenService(), this); mStateHelper->setActive(IDDIALOG_IDDETAILS, false); mStateHelper->setActive(IDDIALOG_REPLIST, false); - ui->treeWidget_IdList->setColumnHidden(RSID_COL_IDTYPE, true); - // Hiding RepList until that part is finished. //ui->treeWidget_RepList->setVisible(false); ui->toolButton_Reputation->setVisible(false); @@ -243,18 +238,6 @@ IdDialog::~IdDialog() delete(mIdQueue); } -void IdDialog::initializeHeader(bool ) -{ - /* Set header resize modes and initial section sizes ID TreeView*/ - QHeaderView * _idheader = ui->treeWidget_IdList->header () ; - _idheader->resizeSection ( RSID_COL_NICKNAME, 170 ); - _idheader->resizeSection ( RSID_COL_KEYID, 120 ); - _idheader->resizeSection ( RSID_COL_IDTYPE, 170 ); - - - -} - void IdDialog::todo() { QMessageBox::information(this, "Todo", @@ -265,19 +248,17 @@ void IdDialog::todo() void IdDialog::processSettings(bool load) { - QHeaderView *header = ui->treeWidget_IdList->header(); - Settings->beginGroup("IdDialog"); + // state of peer tree + ui->idTreeWidget->processSettings(load); + if (load) { // load settings // filterColumn ui->filterLineEdit->setCurrentFilter(Settings->value("filterColumn", RSID_COL_NICKNAME).toInt()); - // state of thread tree - header->restoreState(Settings->value("IdList").toByteArray()); - // state of splitter ui->splitter->restoreState(Settings->value("splitter").toByteArray()); } else { @@ -286,9 +267,6 @@ void IdDialog::processSettings(bool load) // filterColumn Settings->setValue("filterColumn", ui->filterLineEdit->currentFilter()); - // state of thread tree - Settings->setValue("IdList", header->saveState()); - // state of splitter Settings->setValue("splitter", ui->splitter->saveState()); } @@ -308,7 +286,7 @@ void IdDialog::filterChanged(const QString& /*text*/) void IdDialog::updateSelection() { - QTreeWidgetItem *item = ui->treeWidget_IdList->currentItem(); + QTreeWidgetItem *item = ui->idTreeWidget->currentItem(); RsGxsGroupId id; if (item) { @@ -478,7 +456,7 @@ void IdDialog::insertIdList(uint32_t token) RsPgpId ownPgpId = rsPeers->getGPGOwnId(); /* Update existing and remove not existing items */ - QTreeWidgetItemIterator itemIterator(ui->treeWidget_IdList); + QTreeWidgetItemIterator itemIterator(ui->idTreeWidget); QTreeWidgetItem *item = NULL; while ((item = *itemIterator) != NULL) { ++itemIterator; @@ -510,7 +488,7 @@ void IdDialog::insertIdList(uint32_t token) item = NULL; if (fillIdListItem(*vit, item, ownPgpId, accept)) { - ui->treeWidget_IdList->addTopLevelItem(item); + ui->idTreeWidget->addTopLevelItem(item); } } @@ -853,7 +831,7 @@ void IdDialog::addIdentity() void IdDialog::removeIdentity() { - QTreeWidgetItem *item = ui->treeWidget_IdList->currentItem(); + QTreeWidgetItem *item = ui->idTreeWidget->currentItem(); if (!item) { #ifdef ID_DEBUG @@ -876,7 +854,7 @@ void IdDialog::removeIdentity() void IdDialog::editIdentity() { - QTreeWidgetItem *item = ui->treeWidget_IdList->currentItem(); + QTreeWidgetItem *item = ui->idTreeWidget->currentItem(); if (!item) { #ifdef ID_DEBUG @@ -901,7 +879,7 @@ void IdDialog::filterIds() int filterColumn = ui->filterLineEdit->currentFilter(); QString text = ui->filterLineEdit->text(); - ui->treeWidget_IdList->filterItems(filterColumn, text); + ui->idTreeWidget->filterItems(filterColumn, text); } void IdDialog::requestRepList() @@ -970,7 +948,7 @@ void IdDialog::IdListCustomPopupMenu( QPoint ) std::list own_identities ; rsIdentity->getOwnIds(own_identities) ; - QTreeWidgetItem *item = ui->treeWidget_IdList->currentItem(); + QTreeWidgetItem *item = ui->idTreeWidget->currentItem(); if (item) { uint32_t item_flags = item->data(RSID_COL_KEYID,Qt::UserRole).toUInt() ; @@ -1015,19 +993,12 @@ void IdDialog::IdListCustomPopupMenu( QPoint ) contextMnu.addSeparator(); - hideIdAct->setChecked(!ui->treeWidget_IdList->isColumnHidden(RSID_COL_KEYID)); - hideTypeAct->setChecked(!ui->treeWidget_IdList->isColumnHidden(RSID_COL_IDTYPE)); - - QMenu *menu = contextMnu.addMenu(tr("Columns")); - menu->addAction(hideIdAct); - menu->addAction(hideTypeAct); - contextMnu.exec(QCursor::pos()); } void IdDialog::chatIdentity() { - QTreeWidgetItem *item = ui->treeWidget_IdList->currentItem(); + QTreeWidgetItem *item = ui->idTreeWidget->currentItem(); if (!item) { std::cerr << "IdDialog::editIdentity() Invalid item"; @@ -1050,7 +1021,7 @@ void IdDialog::chatIdentity() void IdDialog::sendMsg() { - QTreeWidgetItem *item = ui->treeWidget_IdList->currentItem(); + QTreeWidgetItem *item = ui->idTreeWidget->currentItem(); if (!item) { return; @@ -1070,34 +1041,3 @@ void IdDialog::sendMsg() /* window will destroy itself! */ } - -void IdDialog::setHideIdColumn(bool show) -{ - if (ui->treeWidget_IdList->isColumnHidden(RSID_COL_KEYID) == show) { - ui->treeWidget_IdList->setColumnHidden(RSID_COL_KEYID, !show); - } - ui->treeWidget_IdList->header()->setVisible(getNumColVisible()>1); - - initializeHeader(true); -} - -void IdDialog::setHideIdTypeColumn(bool show) -{ - if (ui->treeWidget_IdList->isColumnHidden(RSID_COL_IDTYPE) == show) { - ui->treeWidget_IdList->setColumnHidden(RSID_COL_IDTYPE, !show); - } - ui->treeWidget_IdList->header()->setVisible(getNumColVisible()>1); - - initializeHeader(true); -} - -int IdDialog::getNumColVisible() -{ - int iNumColVis=0; - for (int iColumn = 0; iColumn treeWidget_IdList->isColumnHidden(iColumn)) { - ++iNumColVis; - } - } - return iNumColVis; -} diff --git a/retroshare-gui/src/gui/Identity/IdDialog.h b/retroshare-gui/src/gui/Identity/IdDialog.h index 4ab354989..a46a6ce73 100644 --- a/retroshare-gui/src/gui/Identity/IdDialog.h +++ b/retroshare-gui/src/gui/Identity/IdDialog.h @@ -74,9 +74,6 @@ private slots: /** Create the context popup menu and it's submenus */ void IdListCustomPopupMenu( QPoint point ); - - void setHideIdColumn(bool hide); - void setHideIdTypeColumn(bool hide); private: void processSettings(bool load); @@ -95,19 +92,12 @@ private: void requestIdEdit(std::string &id); void showIdEdit(uint32_t token); - - void initializeHeader(bool); private: TokenQueue *mIdQueue; UIStateHelper *mStateHelper; RsGxsGroupId mId; - - /** Defines the actions for the header context menu */ - QAction* hideIdAct; - QAction* hideTypeAct; - int getNumColVisible(); /* UI - Designer */ Ui::IdDialog *ui; diff --git a/retroshare-gui/src/gui/Identity/IdDialog.ui b/retroshare-gui/src/gui/Identity/IdDialog.ui index a8914b9fa..4109e6bcb 100644 --- a/retroshare-gui/src/gui/Identity/IdDialog.ui +++ b/retroshare-gui/src/gui/Identity/IdDialog.ui @@ -177,22 +177,22 @@ - + 0 0 - - - 22 - 22 - + + Qt::CustomContextMenu true + + false + Identity name @@ -725,7 +725,7 @@ todoPushButton - treeWidget_IdList + idTreeWidget lineEdit_Nickname lineEdit_KeyId lineEdit_GpgId diff --git a/retroshare-gui/src/gui/Identity/IdEditDialog.cpp b/retroshare-gui/src/gui/Identity/IdEditDialog.cpp index 20d0306dc..e4bbc7662 100644 --- a/retroshare-gui/src/gui/Identity/IdEditDialog.cpp +++ b/retroshare-gui/src/gui/Identity/IdEditDialog.cpp @@ -207,7 +207,13 @@ void IdEditDialog::setupExistingId(const RsGxsGroupId &keyId) groupIds.push_back(keyId); uint32_t token; - mIdQueue->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, groupIds, IDEDITDIALOG_LOADID); + mIdQueue->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, groupIds, IDEDITDIALOG_LOADID); +} + +void IdEditDialog::enforceNoAnonIds() +{ + ui->radioButton_GpgId->setChecked(true); + ui->radioButton_GpgId->setEnabled(false); } void IdEditDialog::loadExistingId(uint32_t token) diff --git a/retroshare-gui/src/gui/Identity/IdEditDialog.h b/retroshare-gui/src/gui/Identity/IdEditDialog.h index ccda8a045..d46cd7de3 100644 --- a/retroshare-gui/src/gui/Identity/IdEditDialog.h +++ b/retroshare-gui/src/gui/Identity/IdEditDialog.h @@ -47,6 +47,7 @@ public: void setupNewId(bool pseudo); void setupExistingId(const RsGxsGroupId &keyId); + void enforceNoAnonIds() ; RsGxsGroupId groupId() { return mGroupId; } diff --git a/retroshare-gui/src/gui/MainWindow.cpp b/retroshare-gui/src/gui/MainWindow.cpp index 4e5f6fa63..be269db84 100644 --- a/retroshare-gui/src/gui/MainWindow.cpp +++ b/retroshare-gui/src/gui/MainWindow.cpp @@ -202,7 +202,7 @@ MainWindow::MainWindow(QWidget* parent, Qt::WindowFlags flags) nameAndLocation = QString("%1 (%2)").arg(QString::fromUtf8(pd.name.c_str())).arg(QString::fromUtf8(pd.location.c_str())); } - setWindowTitle(tr("RetroShare %1 a secure decentralized communication platform").arg(Rshare::retroshareVersion(false)) + " - " + nameAndLocation); + setWindowTitle(tr("RetroShare %1 a secure decentralized communication platform").arg(Rshare::retroshareVersion(true)) + " - " + nameAndLocation); /* add url handler for RetroShare links */ QDesktopServices::setUrlHandler(RSLINK_SCHEME, this, "retroshareLinkActivated"); @@ -391,17 +391,17 @@ void MainWindow::initStackedPage() std::cerr << "Looking for interfaces in existing plugins:" << std::endl; for(int i = 0;inbPlugins();++i) { - QIcon icon ; + MainPage *pluginPage = NULL; + QIcon icon, *pIcon = NULL; - if(rsPlugins->plugin(i) != NULL && rsPlugins->plugin(i)->qt_page() != NULL) + if(rsPlugins->plugin(i) != NULL && (pluginPage = rsPlugins->plugin(i)->qt_page()) != NULL) { - if(rsPlugins->plugin(i)->qt_icon() != NULL) - icon = *rsPlugins->plugin(i)->qt_icon() ; + if((pIcon = rsPlugins->plugin(i)->qt_icon()) != NULL) + icon = *pIcon ; else icon = QIcon(":images/extension_48.png") ; std::cerr << " Addign widget page for plugin " << rsPlugins->plugin(i)->getPluginName() << std::endl; - MainPage *pluginPage = rsPlugins->plugin(i)->qt_page(); pluginPage->setIconPixmap(icon); pluginPage->setPageName(QString::fromUtf8(rsPlugins->plugin(i)->getPluginName().c_str())); addPage(pluginPage, grp, ¬ify); diff --git a/retroshare-gui/src/gui/MessengerWindow.cpp b/retroshare-gui/src/gui/MessengerWindow.cpp index d8bb1364e..097089b85 100644 --- a/retroshare-gui/src/gui/MessengerWindow.cpp +++ b/retroshare-gui/src/gui/MessengerWindow.cpp @@ -142,13 +142,10 @@ MessengerWindow::MessengerWindow(QWidget* parent, Qt::WindowFlags flags) // load settings RsAutoUpdatePage::lockAllEvents(); - ui.friendList->setColumnVisible(FriendList::COLUMN_STATE, false); ui.friendList->setColumnVisible(FriendList::COLUMN_LAST_CONTACT, false); - ui.friendList->setColumnVisible(FriendList::COLUMN_AVATAR, true); ui.friendList->setColumnVisible(FriendList::COLUMN_IP, false); ui.friendList->setShowGroups(false); processSettings(true); - ui.friendList->setBigName(true); RsAutoUpdatePage::unlockAllEvents(); // add self nick diff --git a/retroshare-gui/src/gui/NetworkDialog.cpp b/retroshare-gui/src/gui/NetworkDialog.cpp index d15d50f5a..16ee66b0d 100644 --- a/retroshare-gui/src/gui/NetworkDialog.cpp +++ b/retroshare-gui/src/gui/NetworkDialog.cpp @@ -169,10 +169,6 @@ NetworkDialog::NetworkDialog(QWidget *parent) //updateNetworkStatus(); //loadtabsettings(); - /* Hide platform specific features */ -#ifdef Q_WS_WIN - -#endif } void NetworkDialog::changeEvent(QEvent *e) diff --git a/retroshare-gui/src/gui/PhotoShare/PhotoDialog.cpp b/retroshare-gui/src/gui/PhotoShare/PhotoDialog.cpp index c0091de74..cb338091a 100644 --- a/retroshare-gui/src/gui/PhotoShare/PhotoDialog.cpp +++ b/retroshare-gui/src/gui/PhotoShare/PhotoDialog.cpp @@ -220,7 +220,7 @@ void PhotoDialog::setFullScreen() if (!isFullScreen()) { // hide menu & toolbars -#ifdef Q_WS_X11 +#ifdef Q_OS_LINUX show(); raise(); setWindowState( windowState() | Qt::WindowFullScreen ); diff --git a/retroshare-gui/src/gui/PhotoShare/PhotoSlideShow.cpp b/retroshare-gui/src/gui/PhotoShare/PhotoSlideShow.cpp index fee31fd71..fa21d07bc 100644 --- a/retroshare-gui/src/gui/PhotoShare/PhotoSlideShow.cpp +++ b/retroshare-gui/src/gui/PhotoShare/PhotoSlideShow.cpp @@ -299,7 +299,7 @@ void PhotoSlideShow::setFullScreen() if (!isFullScreen()) { // hide menu & toolbars -#ifdef Q_WS_X11 +#ifdef Q_OS_LINUX show(); raise(); setWindowState( windowState() | Qt::WindowFullScreen ); diff --git a/retroshare-gui/src/gui/Posted/PostedListWidget.cpp b/retroshare-gui/src/gui/Posted/PostedListWidget.cpp index d5b191392..586b673ed 100644 --- a/retroshare-gui/src/gui/Posted/PostedListWidget.cpp +++ b/retroshare-gui/src/gui/Posted/PostedListWidget.cpp @@ -44,14 +44,14 @@ PostedListWidget::PostedListWidget(const RsGxsGroupId &postedId, QWidget *parent ui->setupUi(this); /* Setup UI helper */ + mStateHelper->addWidget(mTokenTypeAllPosts, ui->hotSortButton); + mStateHelper->addWidget(mTokenTypeAllPosts, ui->newSortButton); + mStateHelper->addWidget(mTokenTypeAllPosts, ui->topSortButton); + mStateHelper->addWidget(mTokenTypePosts, ui->hotSortButton); mStateHelper->addWidget(mTokenTypePosts, ui->newSortButton); mStateHelper->addWidget(mTokenTypePosts, ui->topSortButton); - mStateHelper->addWidget(mTokenTypeRelatedPosts, ui->hotSortButton); - mStateHelper->addWidget(mTokenTypeRelatedPosts, ui->newSortButton); - mStateHelper->addWidget(mTokenTypeRelatedPosts, ui->topSortButton); - mStateHelper->addWidget(mTokenTypeGroupData, ui->submitPostButton); mStateHelper->addWidget(mTokenTypeGroupData, ui->subscribeToolButton); @@ -107,7 +107,7 @@ void PostedListWidget::processSettings(bool /*load*/) QIcon PostedListWidget::groupIcon() { - if (mStateHelper->isLoading(mTokenTypeGroupData) || mStateHelper->isLoading(mTokenTypePosts)) { + if (mStateHelper->isLoading(mTokenTypeGroupData) || mStateHelper->isLoading(mTokenTypeAllPosts)) { // return QIcon(":/images/kalarm.png"); } @@ -526,7 +526,7 @@ bool PostedListWidget::insertGroupData(const uint32_t &token, RsGroupMetaData &m return false; } -void PostedListWidget::insertPosts(const uint32_t &token, GxsMessageFramePostThread */*thread*/) +void PostedListWidget::insertAllPosts(const uint32_t &token, GxsMessageFramePostThread */*thread*/) { std::vector posts; rsPosted->getPostData(token, posts); @@ -541,10 +541,10 @@ void PostedListWidget::insertPosts(const uint32_t &token, GxsMessageFramePostThr applyRanking(); } -void PostedListWidget::insertRelatedPosts(const uint32_t &token) +void PostedListWidget::insertPosts(const uint32_t &token) { std::vector posts; - rsPosted->getRelatedPosts(token, posts); + rsPosted->getPostData(token, posts); std::vector::iterator vit; for(vit = posts.begin(); vit != posts.end(); ++vit) diff --git a/retroshare-gui/src/gui/Posted/PostedListWidget.h b/retroshare-gui/src/gui/Posted/PostedListWidget.h index 7a9348d64..be6c5411f 100644 --- a/retroshare-gui/src/gui/Posted/PostedListWidget.h +++ b/retroshare-gui/src/gui/Posted/PostedListWidget.h @@ -60,8 +60,8 @@ public: protected: /* GxsMessageFramePostWidget */ virtual bool insertGroupData(const uint32_t &token, RsGroupMetaData &metaData); - virtual void insertPosts(const uint32_t &token, GxsMessageFramePostThread *thread); - virtual void insertRelatedPosts(const uint32_t &token); + virtual void insertAllPosts(const uint32_t &token, GxsMessageFramePostThread *thread); + virtual void insertPosts(const uint32_t &token); virtual void clearPosts(); virtual bool navigatePostItem(const RsGxsMessageId& msgId); diff --git a/retroshare-gui/src/gui/QuickStartWizard.cpp b/retroshare-gui/src/gui/QuickStartWizard.cpp index 297030509..bc684b7bf 100644 --- a/retroshare-gui/src/gui/QuickStartWizard.cpp +++ b/retroshare-gui/src/gui/QuickStartWizard.cpp @@ -66,7 +66,7 @@ QuickStartWizard::QuickStartWizard(QWidget *parent) : ui.shareddirList->horizontalHeader()->setStretchLastSection(false); /* Hide platform specific features */ -#ifndef Q_WS_WIN +#ifndef Q_OS_WIN ui.checkBoxRunRetroshareAtSystemStartup->setVisible(false); ui.chkRunRetroshareAtSystemStartupMinimized->setVisible(false); #endif @@ -192,7 +192,7 @@ void QuickStartWizard::on_pushButtonSystemFinish_clicked() { Settings->setStartMinimized(ui.checkBoxStartMinimized->isChecked()); Settings->setValue("doQuit", ui.checkBoxQuit->isChecked()); -#ifdef Q_WS_WIN +#ifdef Q_OS_WIN Settings->setRunRetroshareOnBoot(ui.checkBoxRunRetroshareAtSystemStartup->isChecked(), ui.chkRunRetroshareAtSystemStartupMinimized->isChecked()); #endif @@ -381,7 +381,7 @@ bool QuickStartWizard::messageBoxOk(QString msg) void QuickStartWizard::loadGeneral() { -#ifdef Q_WS_WIN +#ifdef Q_OS_WIN bool minimized; ui.checkBoxRunRetroshareAtSystemStartup->setChecked(Settings->runRetroshareOnBoot(minimized)); ui.chkRunRetroshareAtSystemStartupMinimized->setChecked(minimized); diff --git a/retroshare-gui/src/gui/RetroShareLink.cpp b/retroshare-gui/src/gui/RetroShareLink.cpp index 9766e6fc8..702b73369 100644 --- a/retroshare-gui/src/gui/RetroShareLink.cpp +++ b/retroshare-gui/src/gui/RetroShareLink.cpp @@ -43,6 +43,7 @@ #include "util/misc.h" #include "common/PeerDefs.h" #include "common/RsCollectionFile.h" +#include #include "gui/connect/ConnectFriendWizard.h" #include "gui/connect/ConfCertDialog.h" #include "gui/connect/PGPKeyDialog.h" @@ -986,7 +987,7 @@ static void processList(const QStringList &list, const QString &textSingular, co } QString content; - if (fileAdd.size()) { + if (!fileAdd.isEmpty()) { processList(fileAdd, QObject::tr("Add file"), QObject::tr("Add files"), content); } @@ -1012,6 +1013,7 @@ static void processList(const QStringList &list, const QString &textSingular, co int countInvalid = 0; int countUnknown = 0; + int countFileOpened = 0; bool needNotifySuccess = false; // file @@ -1045,8 +1047,8 @@ static void processList(const QStringList &list, const QString &textSingular, co QStringList messageReceipientUnknown; // Certificate - QStringList GPGBase64Strings ; - QStringList SSLIds ; + //QStringList GPGBase64Strings ; + //QStringList SSLIds ; // summary QList processedList; @@ -1069,7 +1071,7 @@ static void processList(const QStringList &list, const QString &textSingular, co { case TYPE_UNKNOWN: ++countUnknown; - break; + break; case TYPE_CERTIFICATE: { @@ -1086,7 +1088,7 @@ static void processList(const QStringList &list, const QString &textSingular, co connectFriendWizard.exec(); needNotifySuccess = false; } - break ; + break ; case TYPE_PUBLIC_MSG: { @@ -1104,7 +1106,7 @@ static void processList(const QStringList &list, const QString &textSingular, co // // MessageComposer::msgDistantPeer(link._hash.toStdString(),link._GPGid.toStdString()) ; } - break ; + break ; case TYPE_FILE: case TYPE_EXTRAFILE: @@ -1150,13 +1152,41 @@ static void processList(const QStringList &list, const QString &textSingular, co flag |= RSLINK_PROCESS_NOTIFY_BAD_CHARS ; } + bool bFileOpened = false; + FileInfo fi; + if (rsFiles->alreadyHaveFile(RsFileHash(link.hash().toStdString()), fi)) { + /* make path for downloaded file */ + std::string path; + path = fi.path;//Shared files has path with filename included + if (fi.downloadStatus == FT_STATE_COMPLETE) + path = fi.path + "/" + fi.fname; + + QFileInfo qinfo; + qinfo.setFile(QString::fromUtf8(path.c_str())); + if (qinfo.exists() && qinfo.isFile()) { + QString question = ""; + question += QObject::tr("This file already exists. Do you want to open it ?"); + question += "

" + cleanname + ""; + + QMessageBox mb(QObject::tr("Confirmation"), question, QMessageBox::Question, QMessageBox::Yes,QMessageBox::No, 0); + if (mb.exec() == QMessageBox::Yes) { + ++countFileOpened; + bFileOpened = true; + /* open file with a suitable application */ + if (!RsUrlHandler::openUrl(QUrl::fromLocalFile(qinfo.absoluteFilePath()))) { + std::cerr << "RetroShareLink::process(): can't open file " << path << std::endl; + } + } + } + } + if (rsFiles->FileRequest(cleanname.toUtf8().constData(), RsFileHash(link.hash().toStdString()), link.size(), "", RS_FILE_REQ_ANONYMOUS_ROUTING, srcIds)) { fileAdded.append(link.name()); } else { - fileExist.append(link.name()); + if (!bFileOpened) fileExist.append(link.name()); } - break; } + break; case TYPE_PERSON: { @@ -1170,7 +1200,6 @@ static void processList(const QStringList &list, const QString &textSingular, co else personNotFound.append(PeerDefs::rsid(link.name().toUtf8().constData(), RsPgpId(link.hash().toStdString()))); - break; // needNotifySuccess = true; // RsPeerDetails detail; @@ -1198,8 +1227,8 @@ static void processList(const QStringList &list, const QString &textSingular, co // } // // personNotFound.append(PeerDefs::rsid(link.name().toUtf8().constData(), RsPgpId(link.hash().toStdString()))); -// break; } + break; case TYPE_FORUM: @@ -1227,8 +1256,9 @@ static void processList(const QStringList &list, const QString &textSingular, co forumMsgUnknown.append(link.name()); } } - break; } + break; + case TYPE_CHANNEL: { #ifdef DEBUG_RSLINK @@ -1254,8 +1284,8 @@ static void processList(const QStringList &list, const QString &textSingular, co channelMsgUnknown.append(link.name()); } } - break; } + break; case TYPE_SEARCH: { @@ -1272,8 +1302,8 @@ static void processList(const QStringList &list, const QString &textSingular, co MainWindow::showWindow(MainWindow::Search); searchDialog->searchKeywords(link.name()); searchStarted.append(link.name()); - break; } + break; case TYPE_MESSAGE: { @@ -1322,7 +1352,7 @@ static void processList(const QStringList &list, const QString &textSingular, co } messageReceipientUnknown.append(PeerDefs::rsidFromId(RsPeerId(link.hash().toStdString()))); } - break; + break; default: std::cerr << " RetroShareLink::process unknown type: " << link.type() << std::endl; @@ -1358,60 +1388,60 @@ static void processList(const QStringList &list, const QString &textSingular, co // file if (flag & RSLINK_PROCESS_NOTIFY_SUCCESS) { - if (fileAdded.size()) { + if (!fileAdded.isEmpty()) { processList(fileAdded, QObject::tr("File added"), QObject::tr("Files added"), result); } } if (flag & RSLINK_PROCESS_NOTIFY_ERROR) { - if (fileExist.size()) { + if (!fileExist.isEmpty()) { processList(fileExist, QObject::tr("File exist"), QObject::tr("Files exist"), result); } } // person if (flag & RSLINK_PROCESS_NOTIFY_SUCCESS) { - if (personAdded.size()) { + if (!personAdded.isEmpty()) { processList(personAdded, QObject::tr("Friend added"), QObject::tr("Friends added"), result); } } if (flag & RSLINK_PROCESS_NOTIFY_ERROR) { - if (personExist.size()) { + if (!personExist.isEmpty()) { processList(personExist, QObject::tr("Friend exist"), QObject::tr("Friends exist"), result); } - if (personFailed.size()) { + if (!personFailed.isEmpty()) { processList(personFailed, QObject::tr("Friend not added"), QObject::tr("Friends not added"), result); } - if (personNotFound.size()) { + if (!personNotFound.isEmpty()) { processList(personNotFound, QObject::tr("Friend not found"), QObject::tr("Friends not found"), result); } } // forum if (flag & RSLINK_PROCESS_NOTIFY_ERROR) { - if (forumUnknown.size()) { + if (!forumUnknown.isEmpty()) { processList(forumUnknown, QObject::tr("Forum not found"), QObject::tr("Forums not found"), result); } - if (forumMsgUnknown.size()) { + if (!forumMsgUnknown.isEmpty()) { processList(forumMsgUnknown, QObject::tr("Forum message not found"), QObject::tr("Forum messages not found"), result); } } // channel if (flag & RSLINK_PROCESS_NOTIFY_ERROR) { - if (channelUnknown.size()) { + if (!channelUnknown.isEmpty()) { processList(channelUnknown, QObject::tr("Channel not found"), QObject::tr("Channels not found"), result); } - if (channelMsgUnknown.size()) { + if (!channelMsgUnknown.isEmpty()) { processList(channelMsgUnknown, QObject::tr("Channel message not found"), QObject::tr("Channel messages not found"), result); } } // message if (flag & RSLINK_PROCESS_NOTIFY_ERROR) { - if (messageReceipientNotAccepted.size()) { + if (!messageReceipientNotAccepted.isEmpty()) { processList(messageReceipientNotAccepted, QObject::tr("Recipient not accepted"), QObject::tr("Recipients not accepted"), result); } - if (messageReceipientUnknown.size()) { + if (!messageReceipientUnknown.isEmpty()) { processList(messageReceipientUnknown, QObject::tr("Unkown recipient"), QObject::tr("Unkown recipients"), result); } } @@ -1427,7 +1457,7 @@ static void processList(const QStringList &list, const QString &textSingular, co if(flag & RSLINK_PROCESS_NOTIFY_BAD_CHARS) result += QString("
%1").arg(QObject::tr("Warning: forbidden characters found in filenames. \nCharacters \",|,/,\\,<,>,*,? will be replaced by '_'.")) ; - if (result.isEmpty() == false) { + if ((result.isEmpty() == false) && (links.count() > countFileOpened)) { //Don't count files opened QMessageBox mb(QObject::tr("Result"), "" + result + "", QMessageBox::Information, QMessageBox::Ok, 0, 0); mb.exec(); } diff --git a/retroshare-gui/src/gui/SearchDialog.cpp b/retroshare-gui/src/gui/SearchDialog.cpp index ef813d8f7..ea2a7d933 100644 --- a/retroshare-gui/src/gui/SearchDialog.cpp +++ b/retroshare-gui/src/gui/SearchDialog.cpp @@ -213,10 +213,6 @@ SearchDialog::SearchDialog(QWidget *parent) checkText(ui.lineEdit->text()); -/* Hide platform specific features */ -#ifdef Q_WS_WIN - -#endif } SearchDialog::~SearchDialog() diff --git a/retroshare-gui/src/gui/SoundManager.cpp b/retroshare-gui/src/gui/SoundManager.cpp index 2021a4373..0a5f117fd 100644 --- a/retroshare-gui/src/gui/SoundManager.cpp +++ b/retroshare-gui/src/gui/SoundManager.cpp @@ -70,11 +70,7 @@ SoundManager::SoundManager() : QObject() void SoundManager::soundEvents(SoundEvents &events) { -#ifdef WINDOWS_SYS - QDir baseDir = QDir(qApp->applicationDirPath() + "/sounds"); -#else - QDir baseDir = QDir("/usr/share/RetroShare06/sounds"); -#endif + QDir baseDir = QDir(QString::fromUtf8(RsAccounts::DataDirectory().c_str()) + "/sounds"); events.mDefaultPath = baseDir.absolutePath(); diff --git a/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp b/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp index b695cc62e..a72c72bae 100644 --- a/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp +++ b/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include "ChatLobbyDialog.h" #include "gui/ChatLobbyWidget.h" @@ -81,8 +82,8 @@ ChatLobbyDialog::ChatLobbyDialog(const ChatLobbyId& lid, QWidget *parent, Qt::Wi // Add a button to invite friends. // inviteFriendsButton = new QToolButton ; - inviteFriendsButton->setMinimumSize(QSize(2*S,2*S)) ; - inviteFriendsButton->setMaximumSize(QSize(2*S,2*S)) ; + inviteFriendsButton->setMinimumSize(QSize(2*S,2*S)) ; + inviteFriendsButton->setMaximumSize(QSize(2*S,2*S)) ; inviteFriendsButton->setText(QString()) ; inviteFriendsButton->setAutoRaise(true) ; inviteFriendsButton->setToolTip(tr("Invite friends to this lobby")); @@ -106,8 +107,14 @@ ChatLobbyDialog::ChatLobbyDialog(const ChatLobbyId& lid, QWidget *parent, Qt::Wi ownIdChooser = new GxsIdChooser() ; ownIdChooser->loadIds(IDCHOOSER_ID_REQUIRED,current_id) ; + + QWidgetAction *checkableAction = new QWidgetAction(this); + checkableAction->setDefaultWidget(ownIdChooser); + + ui.chatWidget->addToolsAction(checkableAction); + //getChatWidget()->addChatBarWidget(ownIdChooser); + - getChatWidget()->addChatBarWidget(ownIdChooser) ; connect(ownIdChooser,SIGNAL(currentIndexChanged(int)),this,SLOT(changeNickname())) ; @@ -664,7 +671,7 @@ void ChatLobbyDialog::displayLobbyEvent(int event_type, const RsGxsId& gxs_id, c ui.chatWidget->addChatMsg(true, tr("Lobby management"), QDateTime::currentDateTime(), QDateTime::currentDateTime(), - tr("%1 changed his name to: %2").arg(name).arg(newname), + tr("%1 changed his name to: %2").arg(RsHtml::plainText(name)).arg(RsHtml::plainText(newname)), ChatWidget::MSGTYPE_SYSTEM); // TODO if a user was muted and changed his name, update mute list, but only, when the muted peer, dont change his name to a other peer in your chat lobby diff --git a/retroshare-gui/src/gui/chat/ChatLobbyDialog.h b/retroshare-gui/src/gui/chat/ChatLobbyDialog.h index 1aa742573..7729abba8 100644 --- a/retroshare-gui/src/gui/chat/ChatLobbyDialog.h +++ b/retroshare-gui/src/gui/chat/ChatLobbyDialog.h @@ -29,6 +29,7 @@ class GxsIdChooser ; class QToolButton; +class QWidgetAction; class ChatLobbyDialog: public ChatDialog { @@ -55,7 +56,7 @@ private slots: signals: void lobbyLeave(ChatLobbyId) ; void typingEventReceived(ChatLobbyId) ; - void messageReceived(bool incoming, ChatLobbyId lobby_id, QDateTime time, QString senderName, QString msg) ; + void messageReceived(bool incoming, ChatLobbyId lobby_id, QDateTime time, QString senderName, QString msg) ; void peerJoined(ChatLobbyId) ; void peerLeft(ChatLobbyId) ; @@ -102,6 +103,7 @@ private: QAction *muteAct; QAction *distantChatAct; + QWidgetAction *checkableAction; GxsIdChooser *ownIdChooser ; }; diff --git a/retroshare-gui/src/gui/chat/ChatLobbyUserNotify.cpp b/retroshare-gui/src/gui/chat/ChatLobbyUserNotify.cpp index 68c31417b..bed476b7f 100644 --- a/retroshare-gui/src/gui/chat/ChatLobbyUserNotify.cpp +++ b/retroshare-gui/src/gui/chat/ChatLobbyUserNotify.cpp @@ -28,6 +28,7 @@ #include "gui/settings/rsharesettings.h" #include "util/DateTime.h" #include +#include ChatLobbyUserNotify::ChatLobbyUserNotify(QObject *parent) : UserNotify(parent) @@ -257,9 +258,8 @@ void ChatLobbyUserNotify::chatLobbyNewMessage(ChatLobbyId lobby_id, QDateTime ti if ((bGetNickName || bFoundTextToNotify || _bCountUnRead)){ QString strAnchor = time.toString(Qt::ISODate); - strAnchor.append("_").append(senderName); MsgData msgData; - msgData.text=msg; + msgData.text=RsHtml::plainText(senderName) + ": " + msg; msgData.unread=!(bGetNickName || bFoundTextToNotify); _listMsg[lobby_id][strAnchor]=msgData; diff --git a/retroshare-gui/src/gui/chat/ChatStyle.cpp b/retroshare-gui/src/gui/chat/ChatStyle.cpp index d7759f4d5..7bc382dbd 100644 --- a/retroshare-gui/src/gui/chat/ChatStyle.cpp +++ b/retroshare-gui/src/gui/chat/ChatStyle.cpp @@ -144,35 +144,30 @@ void ChatStyle::styleChanged(int styleType) } } -static QString getBaseDir() +static QStringList getBaseDirList() { - // application path - QString baseDir = QString::fromUtf8(RsAccounts::ConfigDirectory().c_str()); + // Search chat styles in config dir and data dir (is application dir for portable) + QStringList baseDirs; + baseDirs.append(QString::fromUtf8(RsAccounts::ConfigDirectory().c_str())); + baseDirs.append(QString::fromUtf8(RsAccounts::DataDirectory().c_str())); -#ifdef WIN32 - if (RsInit::isPortable ()) { - // application dir for portable version - baseDir = QApplication::applicationDirPath(); - } -#endif - - return baseDir; + return baseDirs; } bool ChatStyle::setStylePath(const QString &stylePath, const QString &styleVariant) { m_styleType = TYPE_UNKNOWN; - m_styleDir.setPath(getBaseDir()); - if (m_styleDir.cd(stylePath) == false) { - m_styleDir = QDir(""); - m_styleVariant.clear(); - return false; + foreach (QString dir, getBaseDirList()) { + m_styleDir.setPath(dir); + if (m_styleDir.cd(stylePath)) { + m_styleVariant = styleVariant; + return true; + } } - - m_styleVariant = styleVariant; - - return true; + m_styleDir.setPath(""); + m_styleVariant.clear(); + return false; } bool ChatStyle::setStyleFromSettings(enumStyleType styleType) @@ -471,9 +466,6 @@ static bool getStyleInfo(QString stylePath, QString stylePathRelative, ChatStyle { styles.clear(); - // base dir - QDir baseDir(getBaseDir()); - ChatStyleInfo standardInfo; QString stylePath; @@ -516,25 +508,27 @@ static bool getStyleInfo(QString stylePath, QString stylePathRelative, ChatStyle return false; } - QDir dir(baseDir); - if (dir.cd("stylesheets") == false) { - // no user styles available - return true; - } - - // get all style directories - QFileInfoList dirList = dir.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name); - - // iterate style directories and get info - for (QFileInfoList::iterator it = dirList.begin(); it != dirList.end(); ++it) { - QDir styleDir = QDir(it->absoluteFilePath()); - if (styleDir.cd(stylePath) == false) { - // no user styles available + foreach (QDir baseDir, getBaseDirList()) { + QDir dir(baseDir); + if (dir.cd("stylesheets") == false) { + // no user styles available here continue; } - ChatStyleInfo info; - if (getStyleInfo(styleDir.absolutePath(), baseDir.relativeFilePath(styleDir.absolutePath()), info)) { - styles.append(info); + + // get all style directories + QFileInfoList dirList = dir.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name); + + // iterate style directories and get info + for (QFileInfoList::iterator it = dirList.begin(); it != dirList.end(); ++it) { + QDir styleDir = QDir(it->absoluteFilePath()); + if (styleDir.cd(stylePath) == false) { + // no user styles available + continue; + } + ChatStyleInfo info; + if (getStyleInfo(styleDir.absolutePath(), baseDir.relativeFilePath(styleDir.absolutePath()), info)) { + styles.append(info); + } } } diff --git a/retroshare-gui/src/gui/chat/ChatWidget.cpp b/retroshare-gui/src/gui/chat/ChatWidget.cpp index 5e8067577..42344c4c8 100644 --- a/retroshare-gui/src/gui/chat/ChatWidget.cpp +++ b/retroshare-gui/src/gui/chat/ChatWidget.cpp @@ -298,6 +298,9 @@ void ChatWidget::init(const ChatId &chat_id, const QString &title) // initialize first custom state string QString customStateString = QString::fromUtf8(rsMsgs->getCustomStateString(chatId.toPeerId()).c_str()); updatePeersCustomStateString(QString::fromStdString(chatId.toPeerId().toStdString()), customStateString); + } else if (chatType() == CHATTYPE_DISTANT){ + hist_chat_type = RS_HISTORY_TYPE_PRIVATE ; + messageCount = Settings->getPrivateChatHistoryCount(); } else if(chatId.isBroadcast()){ hist_chat_type = RS_HISTORY_TYPE_PUBLIC; messageCount = Settings->getPublicChatHistoryCount(); @@ -321,8 +324,21 @@ void ChatWidget::init(const ChatId &chat_id, const QString &title) // it can happen that a message is first added to the message history // and later the gui receives the message through notify // avoid this by not adding history entries if their age is < 2secs - if((time(NULL)-2) > historyIt->recvTime) - addChatMsg(historyIt->incoming, QString::fromUtf8(historyIt->peerName.c_str()), QDateTime::fromTime_t(historyIt->sendTime), QDateTime::fromTime_t(historyIt->recvTime), QString::fromUtf8(historyIt->message.c_str()), MSGTYPE_HISTORY); + if ((time(NULL)-2) <= historyIt->recvTime) + continue; + + QString name; + if (chatId.isLobbyId() || chatId.isGxsId()) { + RsIdentityDetails details; + if (rsIdentity->getIdDetails(RsGxsId(historyIt->peerName), details)) + name = QString::fromUtf8(details.mNickname.c_str()); + else + name = QString::fromUtf8(historyIt->peerName.c_str()); + } else { + name = QString::fromUtf8(historyIt->peerName.c_str()); + } + + addChatMsg(historyIt->incoming, name, QDateTime::fromTime_t(historyIt->sendTime), QDateTime::fromTime_t(historyIt->recvTime), QString::fromUtf8(historyIt->message.c_str()), MSGTYPE_HISTORY); } } } @@ -432,7 +448,7 @@ bool ChatWidget::eventFilter(QObject *obj, QEvent *event) } } - if (chatType() == CHATTYPE_LOBBY) { + if (notify && chatType() == CHATTYPE_LOBBY) { if ((event->type() == QEvent::KeyPress) || (event->type() == QEvent::MouseMove) || (event->type() == QEvent::Enter) @@ -444,9 +460,11 @@ bool ChatWidget::eventFilter(QObject *obj, QEvent *event) QPoint bottom_right(ui->textBrowser->viewport()->width() - 1, ui->textBrowser->viewport()->height() - 1); int end_pos = ui->textBrowser->cursorForPosition(bottom_right).position(); cursor.setPosition(end_pos, QTextCursor::KeepAnchor); - - if (!cursor.selectedText().isEmpty()){ - QRegExp rx("toUtf8(); - std::string stdString=std::string(bytArray.begin(),bytArray.end()); - if (notify) notify->chatLobbyCleared(chatId.toLobbyId() - ,QString::fromUtf8(stdString.c_str()) - ,obj != ui->textBrowser && obj != ui->textBrowser->viewport());//, true); + notify->chatLobbyCleared(chatId.toLobbyId(), *it); } - } + } } } } @@ -474,11 +488,11 @@ bool ChatWidget::eventFilter(QObject *obj, QEvent *event) QKeyEvent *keyEvent = static_cast(event); if (keyEvent) { - if (keyEvent->key() == Qt::Key_Delete ) { + if (notify && keyEvent->key() == Qt::Key_Delete) { // Delete key pressed if (ui->textBrowser->textCursor().selectedText().length() > 0) { if (chatType() == CHATTYPE_LOBBY) { - QRegExp rx("textBrowser->textCursor().selection().toHtml(); QStringList anchors; @@ -489,9 +503,7 @@ bool ChatWidget::eventFilter(QObject *obj, QEvent *event) } for (QStringList::iterator it=anchors.begin();it!=anchors.end();++it) { - QByteArray bytArray=it->toUtf8(); - std::string stdString=std::string(bytArray.begin(),bytArray.end()); - if (notify) notify->chatLobbyCleared(chatId.toLobbyId(), QString::fromUtf8(stdString.c_str())); + notify->chatLobbyCleared(chatId.toLobbyId(), *it); } } @@ -513,7 +525,7 @@ bool ChatWidget::eventFilter(QObject *obj, QEvent *event) cursor.select(QTextCursor::WordUnderCursor); QString toolTipText = ""; if (!cursor.selectedText().isEmpty()){ - QRegExp rx("(event); if (keyEvent) { QString qsTextToFind=ui->leSearch->text(); - if (((qsTextToFind.length()>iCharToStartSearch) || (keyEvent->key()==Qt::Key_Return)) && (keyEvent->text().length()>0)) + if (keyEvent->key()==Qt::Key_Backspace) { + qsTextToFind=qsTextToFind.left(qsTextToFind.length()-1);// "\010" + } else if (keyEvent->key()==Qt::Key_Tab) { // "\011" + } else if (keyEvent->key()==Qt::Key_Return) { // "\015" + } else if (keyEvent->text().length()==1) + qsTextToFind+=keyEvent->text(); + if (((qsTextToFind.length()>=iCharToStartSearch) || (keyEvent->key()==Qt::Key_Return)) && (keyEvent->text().length()>0)) { - if (keyEvent->key()==Qt::Key_Backspace) { - qsTextToFind=qsTextToFind.left(qsTextToFind.length()-1);// "\010" - } else if (keyEvent->key()==Qt::Key_Tab) { // "\011" - } else if (keyEvent->key()==Qt::Key_Return) { // "\015" - } else if (keyEvent->text().length()==1) - qsTextToFind+=keyEvent->text(); findText(qsTextToFind); } else { @@ -886,9 +898,11 @@ void ChatWidget::addChatMsg(bool incoming, const QString &name, const QDateTime QString formatMsg = chatStyle.formatMessage(type, name, dtTimestamp, formattedMessage, formatFlag); QString timeStamp = dtTimestamp.toString(Qt::ISODate); - formatMsg.prepend(QString("").arg(timeStamp).arg(name)); + formatMsg.prepend(QString("").arg(timeStamp)); //To call this anchor do: ui->textBrowser->scrollToAnchor(QString("%1_%2").arg(timeStamp).arg(name)); - ui->textBrowser->textCursor().setBlockFormat(QTextBlockFormat ()); + QTextCursor textCursor = QTextCursor(ui->textBrowser->textCursor()); + textCursor.movePosition(QTextCursor::End); + textCursor.setBlockFormat(QTextBlockFormat ()); ui->textBrowser->append(formatMsg); if (ui->leSearch->isVisible()) { diff --git a/retroshare-gui/src/gui/chat/ChatWidget.h b/retroshare-gui/src/gui/chat/ChatWidget.h index abd6ae628..312f9d879 100644 --- a/retroshare-gui/src/gui/chat/ChatWidget.h +++ b/retroshare-gui/src/gui/chat/ChatWidget.h @@ -238,6 +238,9 @@ private: QTextCursor qtcMark; + int lastUpdateCursorPos; + int lastUpdateCursorEnd; + TransferRequestFlags mDefaultExtraFileFlags ; // flags for extra files shared in this chat. Will be 0 by default, but might be ANONYMOUS for chat lobbies. QDate lastMsgDate ; diff --git a/retroshare-gui/src/gui/chat/CreateLobbyDialog.cpp b/retroshare-gui/src/gui/chat/CreateLobbyDialog.cpp index b76b312c8..2d1a75829 100644 --- a/retroshare-gui/src/gui/chat/CreateLobbyDialog.cpp +++ b/retroshare-gui/src/gui/chat/CreateLobbyDialog.cpp @@ -47,17 +47,17 @@ CreateLobbyDialog::CreateLobbyDialog(const std::set& peer_list, int pr ui->idChooser_CB->loadIds(IDCHOOSER_ID_REQUIRED, default_identity); -//#if QT_VERSION >= 0x040700 -// ui->lobbyName_LE->setPlaceholderText(tr("Put a sensible lobby name here")) ; -// ui->nickName_LE->setPlaceholderText(tr("Your nickname for this lobby (Change default name in options->chat)")) ; -//#endif -// ui->nickName_LE->setText(QString::fromUtf8(default_nick.c_str())) ; +#if QT_VERSION >= 0x040700 + ui->lobbyName_LE->setPlaceholderText(tr("Put a sensible lobby name here")); + ui->lobbyTopic_LE->setPlaceholderText(tr("Set a descriptive topic here")); +#endif connect( ui->buttonBox, SIGNAL(accepted()), this, SLOT(createLobby())); connect( ui->buttonBox, SIGNAL(rejected()), this, SLOT(close())); connect( ui->lobbyName_LE, SIGNAL( textChanged ( QString ) ), this, SLOT( checkTextFields( ) ) ); connect( ui->lobbyTopic_LE, SIGNAL( textChanged ( QString ) ), this, SLOT( checkTextFields( ) ) ); - connect( ui->idChooser_CB, SIGNAL( currentChanged ( int ) ), this, SLOT( checkTextFields( ) ) ); + connect( ui->idChooser_CB, SIGNAL( currentIndexChanged ( int ) ), this, SLOT( checkTextFields( ) ) ); + connect( ui->pgp_signed_CB, SIGNAL( toggled ( bool ) ), this, SLOT( checkTextFields( ) ) ); /* initialize key share list */ ui->keyShareList->setHeaderText(tr("Contacts:")); @@ -105,6 +105,13 @@ void CreateLobbyDialog::checkTextFields() ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true) ; break ; } + + RsIdentityDetails(idd) ; + + rsIdentity->getIdDetails(id,idd) ; + + if( (!idd.mPgpKnown) && ui->pgp_signed_CB->isChecked()) + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false) ; } void CreateLobbyDialog::createLobby() @@ -128,6 +135,7 @@ void CreateLobbyDialog::createLobby() case GxsIdChooser::NoId: case GxsIdChooser::None: return ; + default: break ; } // add to group @@ -136,6 +144,9 @@ void CreateLobbyDialog::createLobby() if(ui->security_CB->currentIndex() == 0) lobby_flags |= RS_CHAT_LOBBY_FLAGS_PUBLIC ; + if(ui->pgp_signed_CB->isChecked()) + lobby_flags |= RS_CHAT_LOBBY_FLAGS_PGP_SIGNED ; + ChatLobbyId id = rsMsgs->createChatLobby(lobby_name,gxs_id, lobby_topic, shareList, lobby_flags); std::cerr << "gui: Created chat lobby " << std::hex << id << std::dec << std::endl ; diff --git a/retroshare-gui/src/gui/chat/CreateLobbyDialog.ui b/retroshare-gui/src/gui/chat/CreateLobbyDialog.ui index 8df887385..1d2340e08 100644 --- a/retroshare-gui/src/gui/chat/CreateLobbyDialog.ui +++ b/retroshare-gui/src/gui/chat/CreateLobbyDialog.ui @@ -6,7 +6,7 @@ 0 0 - 787 + 800 486
@@ -86,7 +86,7 @@ - Security policy: + Visibility: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -110,6 +110,29 @@ + + + + <html><head/><body><p>If you check this, only PGP-signed ids can be used to join and talk in this lobby. This limitation prevents anonymous spamming as it becomes possible for at least some people in the lobby to locate the spammer's node.</p></body></html> + + + require PGP-signed identities + + + + + + + Qt::LeftToRight + + + Security: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + +
diff --git a/retroshare-gui/src/gui/common/ElidedLabel.cpp b/retroshare-gui/src/gui/common/ElidedLabel.cpp index ebc77f31f..a18aaf299 100644 --- a/retroshare-gui/src/gui/common/ElidedLabel.cpp +++ b/retroshare-gui/src/gui/common/ElidedLabel.cpp @@ -40,23 +40,30 @@ #include "ElidedLabel.h" -#include -#include #include +#include #include +#include +#include +#include ElidedLabel::ElidedLabel(const QString &text, QWidget *parent) : QLabel(parent) , mElided(false) + , mOnlyPlainText(false) , mContent(text) { + mRectElision = QRect(); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); } ElidedLabel::ElidedLabel(QWidget *parent) : QLabel(parent) , mElided(false) + , mOnlyPlainText(false) + , mContent("") { + mRectElision = QRect(); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); } @@ -66,6 +73,12 @@ void ElidedLabel::setText(const QString &newText) update(); } +void ElidedLabel::setOnlyPlainText(const bool &value) +{ + mOnlyPlainText = value; + update(); +} + void ElidedLabel::clear() { mContent.clear(); @@ -75,43 +88,138 @@ void ElidedLabel::clear() void ElidedLabel::paintEvent(QPaintEvent *event) { QLabel::paintEvent(event); - + QList > lLines; + QString elidedLastLine = ""; QPainter painter(this); QFontMetrics fontMetrics = painter.fontMetrics(); QRect cr = contentsRect(); cr.adjust(margin(), margin(), -margin(), -margin()); bool didElide = false; + QChar ellipsisChar(0x2026);//= "…" int lineSpacing = fontMetrics.lineSpacing(); - int x, y = x =cr.top()+(cr.height()-lineSpacing)/2; - - QTextLayout textLayout(mContent, painter.font()); + int y = 0; + + QString plainText = ""; + if (mOnlyPlainText) + { + plainText = mContent; + } else { + QTextDocument td; + td.setHtml(mContent); + plainText = td.toPlainText(); + } + plainText = plainText.replace("\n",QChar(QChar::LineSeparator)); + plainText = plainText.replace("\r",QChar(QChar::LineSeparator)); + + QTextLayout textLayout(plainText, painter.font()); + QTextOption to = textLayout.textOption(); + to.setAlignment(alignment()); + to.setWrapMode(wordWrap() ? QTextOption::WrapAtWordBoundaryOrAnywhere : QTextOption::NoWrap); + textLayout.setTextOption(to); + textLayout.beginLayout(); forever { + //Get new line for text. QTextLine line = textLayout.createLine(); - + if (!line.isValid()) - break; - - line.setLineWidth(cr.width()+2*x); + break;// No more line to write + + line.setLineWidth(cr.width()); int nextLineY = y + lineSpacing; - - if (cr.height() >= nextLineY + lineSpacing) { - line.draw(&painter, QPoint(x, y)); + + if ((cr.height() >= nextLineY + lineSpacing) && wordWrap()) { + //Line written normaly, next line will too + lLines.append(QPair(line, QPoint(0, y))); y = nextLineY; } else { - QString lastLine = mContent.mid(line.textStart()); - QString elidedLastLine = fontMetrics.elidedText(lastLine, Qt::ElideRight, cr.width()); - painter.drawText(QPoint(x, y + fontMetrics.ascent()), elidedLastLine); - line = textLayout.createLine(); - didElide = line.isValid(); - break; + //The next line can't be written. + QString lastLine = plainText.mid(line.textStart()).split(QChar(QChar::LineSeparator)).at(0); + QTextLine lineEnd = textLayout.createLine(); + if (!lineEnd.isValid() && (wordWrap() + || (fontMetrics.width(lastLine) < cr.width()))) { + //No more text for next line so this one is OK + lLines.append(QPair(line, QPoint(0, y))); + elidedLastLine=""; + didElide = false; + } else { + //Text is left, so get elided text + if (lastLine == "") { + elidedLastLine = ellipsisChar; + } else { + elidedLastLine = fontMetrics.elidedText(lastLine, Qt::ElideRight, cr.width()-1); + if (elidedLastLine.right(1) != ellipsisChar) + elidedLastLine.append(ellipsisChar);//New line at end + } + didElide = true; + break; + } } } textLayout.endLayout(); - + + int iTransX, iTransY = iTransX = 0; + int iHeight = lLines.count() * lineSpacing; + if (didElide) iHeight += lineSpacing; + + //Compute lines translation with alignment + if (alignment() & Qt::AlignTop) + iTransY = 0; + if (alignment() & Qt::AlignBottom) + iTransY = cr.height() - iHeight; + if (alignment() & Qt::AlignVCenter) + iTransY = (cr.height() - iHeight) / 2; + + QPair pair; + QPoint lastPos(-1,-1); + //Now we know how many lines to redraw at good position + foreach (pair, lLines){ + lastPos = pair.second + QPoint(0, iTransY); + pair.first.draw(&painter, lastPos); + } + + //Print last elided line + if (didElide) { + int width = fontMetrics.width(elidedLastLine); + if (lastPos.y() == -1){ + y = iTransY;// Only one line + } else { + y = lastPos.y() + lineSpacing; + } + if (width < cr.width()){ + //Text don't taking all line (with line break), so align it + if (alignment() & Qt::AlignLeft) + iTransX = 0; + if (alignment() & Qt::AlignRight) + iTransX = cr.width() - width; + if (alignment() & Qt::AlignHCenter) + iTransX = (cr.width() - width) / 2; + if (alignment() & Qt::AlignJustify) + iTransX = 0; + } + + painter.drawText(QPoint(iTransX, y + fontMetrics.ascent()), elidedLastLine); + //Draw button to get ToolTip + mRectElision = QRect(iTransX + width - fontMetrics.width(ellipsisChar) + , y + , fontMetrics.width(ellipsisChar) + , fontMetrics.height() - 1); + painter.drawRoundRect(mRectElision); + } else { + mRectElision = QRect(); + } + + //Send signal if changed if (didElide != mElided) { mElided = didElide; emit elisionChanged(didElide); } } + +void ElidedLabel::mousePressEvent(QMouseEvent *ev) +{ + if (mElided && (ev->buttons()==Qt::LeftButton) && (mRectElision.contains(ev->pos()))){ + QToolTip::showText(mapToGlobal(QPoint(0, 0)),QString("") + mContent + QString("")); + } +} diff --git a/retroshare-gui/src/gui/common/ElidedLabel.h b/retroshare-gui/src/gui/common/ElidedLabel.h index 3015209a8..db51aef79 100644 --- a/retroshare-gui/src/gui/common/ElidedLabel.h +++ b/retroshare-gui/src/gui/common/ElidedLabel.h @@ -52,6 +52,7 @@ class ElidedLabel : public QLabel Q_OBJECT Q_PROPERTY(QString text READ text WRITE setText) Q_PROPERTY(bool isElided READ isElided) + Q_PROPERTY(bool isOnlyPlainText READ isOnlyPlainText WRITE setOnlyPlainText) public: ElidedLabel(const QString &text, QWidget *parent = 0); @@ -59,20 +60,25 @@ public: const QString & text() const { return mContent; } bool isElided() const { return mElided; } + bool isOnlyPlainText() const { return mOnlyPlainText; } public slots: void setText(const QString &text); + void setOnlyPlainText(const bool &value); void clear(); protected: void paintEvent(QPaintEvent *event); + void mousePressEvent(QMouseEvent *ev); signals: void elisionChanged(bool elided); private: bool mElided; + bool mOnlyPlainText; QString mContent; + QRect mRectElision; }; #endif // ELIDEDLABEL_H diff --git a/retroshare-gui/src/gui/common/Emoticons.cpp b/retroshare-gui/src/gui/common/Emoticons.cpp index 8b2041e27..9ba3b1501 100644 --- a/retroshare-gui/src/gui/common/Emoticons.cpp +++ b/retroshare-gui/src/gui/common/Emoticons.cpp @@ -40,7 +40,7 @@ void Emoticons::load() QString sm_codes; bool internalEmoticons = true; -#if defined(Q_OS_WIN32) +#if defined(Q_OS_WIN) // first try external emoticons QFile sm_file(QApplication::applicationDirPath() + "/emoticons/emotes.acs"); if(sm_file.open(QIODevice::ReadOnly)) diff --git a/retroshare-gui/src/gui/common/FriendList.cpp b/retroshare-gui/src/gui/common/FriendList.cpp index 7e8db11d8..3dbdfdd13 100644 --- a/retroshare-gui/src/gui/common/FriendList.cpp +++ b/retroshare-gui/src/gui/common/FriendList.cpp @@ -26,7 +26,10 @@ #include #include #include +#include +#include +#include "rsserver/rsaccounts.h" #include "retroshare/rspeers.h" #include "GroupDefs.h" @@ -52,6 +55,7 @@ #include "util/QtVersion.h" #include "gui/chat/ChatUserNotify.h" #include "gui/connect/ConnectProgressDialog.h" +#include "gui/common/ElidedLabel.h" #include "FriendList.h" #include "ui_FriendList.h" @@ -73,20 +77,18 @@ #define IMAGE_COLLAPSE ":/images/edit_remove24.png" /* Images for Status icons */ #define IMAGE_AVAILABLE ":/images/user/identityavaiblecyan24.png" -#define IMAGE_CONNECT2 ":/images/reload24.png" #define IMAGE_PASTELINK ":/images/pasterslink.png" #define IMAGE_GROUP24 ":/images/user/group24.png" #define COLUMN_DATA 0 // column for storing the userdata id -#define COLUMN_AVATAR_WIDTH 42 - -#define ROLE_SORT Qt::UserRole -#define ROLE_ID Qt::UserRole + 1 -#define ROLE_STANDARD Qt::UserRole + 2 -// to store the best ssl id for pgp items -// the best id decides which avatar image we want to display at the pgpg item -#define ROLE_BEST_SSL Qt::UserRole + 3 +#define ROLE_ID Qt::UserRole +#define ROLE_STANDARD Qt::UserRole + 1 +#define ROLE_SORT_GROUP Qt::UserRole + 2 +#define ROLE_SORT_STANDARD_GROUP Qt::UserRole + 3 +#define ROLE_SORT_NAME Qt::UserRole + 4 +#define ROLE_SORT_STATE Qt::UserRole + 5 +#define ROLE_FILTER Qt::UserRole + 6 #define TYPE_GPG 0 #define TYPE_SSL 1 @@ -101,20 +103,18 @@ #define PEER_STATE_INACTIVE 5 #define PEER_STATE_OFFLINE 6 -#define BuildStateSortString(bEnabled,sName,nState) bEnabled ? (QString ("%1").arg(nState) + " " + sName) : sName - - /****** * #define FRIENDS_DEBUG 1 *****/ +Q_DECLARE_METATYPE(ElidedLabel*) + FriendList::FriendList(QWidget *parent) : RsAutoUpdatePage(1500, parent), ui(new Ui::FriendList), - m_compareRole(new RSTreeWidgetItemCompareRole), - mBigName(false), + mCompareRole(new RSTreeWidgetItemCompareRole), mShowGroups(true), - mHideState(true), + mShowState(false), mHideUnconnected(false), groupsHasChanged(false), openGroups(NULL), @@ -122,37 +122,31 @@ FriendList::FriendList(QWidget *parent) : { ui->setupUi(this); - m_compareRole->setRole(COLUMN_NAME, ROLE_SORT); - m_compareRole->setRole(COLUMN_STATE, ROLE_SORT); - m_compareRole->setRole(COLUMN_LAST_CONTACT, ROLE_SORT); - m_compareRole->setRole(COLUMN_IP, ROLE_SORT); - m_compareRole->setRole(COLUMN_AVATAR, ROLE_STANDARD); - connect(ui->peerTreeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(peerTreeWidgetCustomPopupMenu())); connect(ui->peerTreeWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, SLOT(chatfriend(QTreeWidgetItem *))); connect(NotifyQt::getInstance(), SIGNAL(groupsChanged(int)), this, SLOT(groupsChanged())); connect(NotifyQt::getInstance(), SIGNAL(friendsChanged()), this, SLOT(insertPeers())); - connect(NotifyQt::getInstance(), SIGNAL(peerHasNewAvatar(const QString&)), this, SLOT(updateAvatar(const QString&))); connect(ui->actionHideOfflineFriends, SIGNAL(triggered(bool)), this, SLOT(setHideUnconnected(bool))); - connect(ui->actionHideState, SIGNAL(triggered(bool)), this, SLOT(setHideState(bool))); + connect(ui->actionShowState, SIGNAL(triggered(bool)), this, SLOT(setShowState(bool))); connect(ui->actionShowGroups, SIGNAL(triggered(bool)), this, SLOT(setShowGroups(bool))); + connect(ui->actionExportFriendlist, SIGNAL(triggered()), this, SLOT(exportFriendlistClicked())); + connect(ui->actionImportFriendlist, SIGNAL(triggered()), this, SLOT(importFriendlistClicked())); connect(ui->filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterItems(QString))); ui->filterLineEdit->setPlaceholderText(tr("Search")) ; ui->filterLineEdit->showFilterIcon(); - initializeHeader(false); + mActionSortByState = new QAction(tr("Sort by state"), this); + mActionSortByState->setCheckable(true); + connect(mActionSortByState, SIGNAL(toggled(bool)), this, SLOT(sortByState(bool))); + ui->peerTreeWidget->addHeaderContextMenuAction(mActionSortByState); - ui->peerTreeWidget->sortItems(COLUMN_NAME, Qt::AscendingOrder); - - // set header text aligment - QTreeWidgetItem *headerItem = ui->peerTreeWidget->headerItem(); - headerItem->setTextAlignment(COLUMN_NAME, Qt::AlignHCenter | Qt::AlignVCenter); - headerItem->setTextAlignment(COLUMN_STATE, Qt::AlignLeft | Qt::AlignVCenter); - headerItem->setTextAlignment(COLUMN_AVATAR, Qt::AlignLeft | Qt::AlignVCenter); + /* Set sort */ + sortByColumn(COLUMN_NAME, Qt::AscendingOrder); + sortByState(false); // workaround for Qt bug, should be solved in next Qt release 4.7.0 // http://bugreports.qt.nokia.com/browse/QTBUG-8270 @@ -160,8 +154,22 @@ FriendList::FriendList(QWidget *parent) : connect(Shortcut, SIGNAL(activated()), this, SLOT(removefriend())); /* Initialize tree */ - ui->peerTreeWidget->setColumnCustomizable(true); + ui->peerTreeWidget->enableColumnCustomize(true); + ui->peerTreeWidget->setColumnCustomizable(COLUMN_NAME, false); connect(ui->peerTreeWidget, SIGNAL(columnVisibleChanged(int,bool)), this, SLOT(peerTreeColumnVisibleChanged(int,bool))); + connect(ui->peerTreeWidget, SIGNAL(itemCollapsed(QTreeWidgetItem*)), this, SLOT(peerTreeItemCollapsedExpanded(QTreeWidgetItem*))); + connect(ui->peerTreeWidget, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SLOT(peerTreeItemCollapsedExpanded(QTreeWidgetItem*))); + + QFontMetricsF fontMetrics(ui->peerTreeWidget->font()); + + /* Set initial column width */ + int fontWidth = fontMetrics.width("W"); + ui->peerTreeWidget->setColumnWidth(COLUMN_NAME, 22 * fontWidth); + ui->peerTreeWidget->setColumnWidth(COLUMN_LAST_CONTACT, 12 * fontWidth); + ui->peerTreeWidget->setColumnWidth(COLUMN_IP, 15 * fontWidth); + + int avatarHeight = fontMetrics.height() * 3; + ui->peerTreeWidget->setIconSize(QSize(avatarHeight, avatarHeight)); /* Initialize display menu */ createDisplayMenu(); @@ -170,7 +178,7 @@ FriendList::FriendList(QWidget *parent) : FriendList::~FriendList() { delete ui; - delete(m_compareRole); + delete(mCompareRole); } void FriendList::addToolButton(QToolButton *toolButton) @@ -190,6 +198,7 @@ void FriendList::addToolButton(QToolButton *toolButton) void FriendList::processSettings(bool load) { // state of peer tree + ui->peerTreeWidget->setSettingsVersion(2); ui->peerTreeWidget->processSettings(load); if (load) { @@ -200,9 +209,12 @@ void FriendList::processSettings(bool load) // states setHideUnconnected(Settings->value("hideUnconnected", mHideUnconnected).toBool()); - setHideState(Settings->value("hideState", mHideState).toBool()); + setShowState(Settings->value("showState", mShowState).toBool()); setShowGroups(Settings->value("showGroups", mShowGroups).toBool()); + // sort + sortByState(Settings->value("sortByState", isSortByState()).toBool()); + // open groups int arrayIndex = Settings->beginReadArray("Groups"); for (int index = 0; index < arrayIndex; ++index) { @@ -210,18 +222,17 @@ void FriendList::processSettings(bool load) addGroupToExpand(Settings->value("open").toString().toStdString()); } Settings->endArray(); - - initializeHeader(true); - peerTreeColumnVisibleChanged(COLUMN_STATE, !ui->peerTreeWidget->isColumnHidden(COLUMN_STATE)); } else { // save settings // states Settings->setValue("hideUnconnected", mHideUnconnected); - Settings->setValue("hideState", mHideState); - Settings->setValue("rootIsDecorated", ui->peerTreeWidget->rootIsDecorated()); + Settings->setValue("showState", mShowState); Settings->setValue("showGroups", mShowGroups); + // sort + Settings->setValue("sortByState", isSortByState()); + // open groups Settings->beginWriteArray("Groups"); int arrayIndex = 0; @@ -248,22 +259,6 @@ void FriendList::changeEvent(QEvent *e) } } -void FriendList::initializeHeader(bool /*afterLoadSettings*/) -{ - // set column size - QHeaderView *header = ui->peerTreeWidget->header(); - QHeaderView_setSectionsMovable(header, true); - //QHeaderView_setSectionResizeModeColumn(header, COLUMN_NAME, QHeaderView::Stretch); - QHeaderView_setSectionResizeModeColumn(header, COLUMN_NAME, QHeaderView::Interactive); - QHeaderView_setSectionResizeModeColumn(header, COLUMN_STATE, QHeaderView::Interactive); - QHeaderView_setSectionResizeModeColumn(header, COLUMN_LAST_CONTACT, QHeaderView::Interactive); - QHeaderView_setSectionResizeModeColumn(header, COLUMN_IP, QHeaderView::Interactive); - QHeaderView_setSectionResizeModeColumn(header, COLUMN_AVATAR, QHeaderView::Fixed); - header->setStretchLastSection(false); - - header->resizeSection(COLUMN_AVATAR, COLUMN_AVATAR_WIDTH); -} - /* Utility Fns */ inline std::string getRsId(QTreeWidgetItem *item) { @@ -476,30 +471,54 @@ void FriendList::groupsChanged() insertPeers(); } -void FriendList::updateAvatar(const QString& id) +static QIcon createAvatar(const QPixmap &avatar, const QPixmap &overlay) { - if (ui->peerTreeWidget->isColumnHidden(COLUMN_AVATAR)) - return; + int avatarWidth = avatar.width(); + int avatarHeight = avatar.height(); - QTreeWidgetItemIterator it(ui->peerTreeWidget); - while (*it) { - // case ssl item - if ((*it)->type() == TYPE_SSL && id == (*it)->data(COLUMN_DATA, ROLE_ID).toString()) { - if ((*it)->parent() != NULL && (*it)->parent()->type() == TYPE_GPG) { - QPixmap avatar; - AvatarDefs::getAvatarFromSslId(RsPeerId(id.toStdString()), avatar); - QIcon avatar_icon(avatar); - (*it)->setIcon(COLUMN_AVATAR, avatar_icon); - } - } - // case pgp item - if ((*it)->type() == TYPE_GPG && id == (*it)->data(COLUMN_DATA, ROLE_BEST_SSL).toString()) { - QPixmap avatar; - AvatarDefs::getAvatarFromSslId(RsPeerId(id.toStdString()), avatar); - QIcon avatar_icon(avatar); - (*it)->setIcon(COLUMN_AVATAR, avatar_icon); - } - ++it; + QPixmap pixmap(avatar); + + int overlayWidth = avatarWidth / 2.5; + int overlayHeight = avatarHeight / 2.5; + int overlayX = avatarWidth - overlayWidth; + int overlayY = avatarHeight - overlayHeight; + + QPainter painter(&pixmap); + painter.drawPixmap(overlayX, overlayY, overlayWidth, overlayHeight, overlay); + + QIcon icon; + icon.addPixmap(pixmap); + return icon; +} + +static void getNameWidget(QTreeWidget *treeWidget, QTreeWidgetItem *item, ElidedLabel *&nameLabel, ElidedLabel *&textLabel) +{ + QWidget *widget = treeWidget->itemWidget(item, FriendList::COLUMN_NAME); + + if (!widget) { + widget = new QWidget; + nameLabel = new ElidedLabel(widget); + textLabel = new ElidedLabel(widget); + + widget->setProperty("nameLabel", qVariantFromValue(nameLabel)); + widget->setProperty("textLabel", qVariantFromValue(textLabel)); + + QVBoxLayout *layout = new QVBoxLayout; + layout->setSpacing(0); + layout->setContentsMargins(3, 0, 0, 0); + + nameLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); + textLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); + + layout->addWidget(nameLabel); + layout->addWidget(textLabel); + + widget->setLayout(layout); + + treeWidget->setItemWidget(item, FriendList::COLUMN_NAME, widget); + } else { + nameLabel = widget->property("nameLabel").value(); + textLabel = widget->property("textLabel").value(); } } @@ -509,7 +528,7 @@ void FriendList::updateAvatar(const QString& id) * If enabled, peers are sorted in their associated groups. * Groups are only updated, when groupsHasChanged is true. */ -void FriendList::insertPeers() +void FriendList::insertPeers() { if (RsAutoUpdatePage::eventsLocked()) return; @@ -518,8 +537,6 @@ void FriendList::insertPeers() std::cerr << "FriendList::insertPeers() called." << std::endl; #endif - bool isStatusColumnHidden = ui->peerTreeWidget->isColumnHidden(COLUMN_STATE); - bool isAvatarColumnHidden = ui->peerTreeWidget->isColumnHidden(COLUMN_AVATAR); int columnCount = ui->peerTreeWidget->columnCount(); std::list statusInfo; @@ -562,72 +579,72 @@ void FriendList::insertPeers() ++itemIterator; switch (item->type()) { case TYPE_GPG: - { - QTreeWidgetItem *parent = item->parent(); - RsPgpId gpg_widget_id ( getRsId(item)); + { + QTreeWidgetItem *parent = item->parent(); + RsPgpId gpg_widget_id ( getRsId(item)); - // remove items that are not friends anymore - if (std::find(gpgFriends.begin(), gpgFriends.end(), gpg_widget_id) == gpgFriends.end()) { - if (parent) { - delete(parent->takeChild(parent->indexOfChild(item))); - } else { - delete(peerTreeWidget->takeTopLevelItem(peerTreeWidget->indexOfTopLevelItem(item))); + // remove items that are not friends anymore + if (std::find(gpgFriends.begin(), gpgFriends.end(), gpg_widget_id) == gpgFriends.end()) { + if (parent) { + delete(parent->takeChild(parent->indexOfChild(item))); + } else { + delete(peerTreeWidget->takeTopLevelItem(peerTreeWidget->indexOfTopLevelItem(item))); + } + break; } - break; - } - if (mShowGroups && groupsHasChanged) { - if (parent) { - if (parent->type() == TYPE_GROUP) { - std::string groupId = getRsId(parent); + if (mShowGroups && groupsHasChanged) { + if (parent) { + if (parent->type() == TYPE_GROUP) { + std::string groupId = getRsId(parent); - // the parent is a group, check if the gpg id is assigned to the group - for (groupIt = groupInfoList.begin(); groupIt != groupInfoList.end(); ++groupIt) { - if (groupIt->id == groupId) { - if (std::find(groupIt->peerIds.begin(), groupIt->peerIds.end(), gpg_widget_id) == groupIt->peerIds.end()) { - delete(parent->takeChild(parent->indexOfChild(item))); + // the parent is a group, check if the gpg id is assigned to the group + for (groupIt = groupInfoList.begin(); groupIt != groupInfoList.end(); ++groupIt) { + if (groupIt->id == groupId) { + if (std::find(groupIt->peerIds.begin(), groupIt->peerIds.end(), gpg_widget_id) == groupIt->peerIds.end()) { + delete(parent->takeChild(parent->indexOfChild(item))); + } + break; } + } + } + } else { + // gpg item without group, check if the gpg id is assigned to a group + for (groupIt = groupInfoList.begin(); groupIt != groupInfoList.end(); ++groupIt) { + if (std::find(groupIt->peerIds.begin(), groupIt->peerIds.end(), gpg_widget_id) != groupIt->peerIds.end()) { + delete(peerTreeWidget->takeTopLevelItem(peerTreeWidget->indexOfTopLevelItem(item))); break; } } } - } else { - // gpg item without group, check if the gpg id is assigned to a group - for (groupIt = groupInfoList.begin(); groupIt != groupInfoList.end(); ++groupIt) { - if (std::find(groupIt->peerIds.begin(), groupIt->peerIds.end(), gpg_widget_id) != groupIt->peerIds.end()) { - delete(peerTreeWidget->takeTopLevelItem(peerTreeWidget->indexOfTopLevelItem(item))); - break; - } - } } } - } break; case TYPE_GROUP: - { - if (!mShowGroups) { - if (item->parent()) { - delete(item->parent()->takeChild(item->parent()->indexOfChild(item))); - } else { - delete(peerTreeWidget->takeTopLevelItem(peerTreeWidget->indexOfTopLevelItem(item))); - } - } else if (groupsHasChanged) { - // remove deleted groups - std::string groupId = getRsId(item); - for (groupIt = groupInfoList.begin(); groupIt != groupInfoList.end(); ++groupIt) { - if (groupIt->id == groupId) { - break; - } - } - if (groupIt == groupInfoList.end() || groupIt->peerIds.empty()) { + { + if (!mShowGroups) { if (item->parent()) { delete(item->parent()->takeChild(item->parent()->indexOfChild(item))); } else { delete(peerTreeWidget->takeTopLevelItem(peerTreeWidget->indexOfTopLevelItem(item))); } + } else if (groupsHasChanged) { + // remove deleted groups + std::string groupId = getRsId(item); + for (groupIt = groupInfoList.begin(); groupIt != groupInfoList.end(); ++groupIt) { + if (groupIt->id == groupId) { + break; + } + } + if (groupIt == groupInfoList.end() || groupIt->peerIds.empty()) { + if (item->parent()) { + delete(item->parent()->takeChild(item->parent()->indexOfChild(item))); + } else { + delete(peerTreeWidget->takeTopLevelItem(peerTreeWidget->indexOfTopLevelItem(item))); + } + } } } - } break; } } @@ -662,13 +679,12 @@ void FriendList::insertPeers() if (groupItem == NULL) { // add group item - groupItem = new RSTreeWidgetItem(m_compareRole, TYPE_GROUP); + groupItem = new RSTreeWidgetItem(mCompareRole, TYPE_GROUP); /* Add item to the list. Add here, because for setHidden the item must be added */ peerTreeWidget->addTopLevelItem(groupItem); groupItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless); - groupItem->setSizeHint(COLUMN_NAME, QSize(26, 26)); groupItem->setTextAlignment(COLUMN_NAME, Qt::AlignLeft | Qt::AlignVCenter); groupItem->setIcon(COLUMN_NAME, QIcon(IMAGE_GROUP24)); groupItem->setForeground(COLUMN_NAME, QBrush(textColorGroup())); @@ -677,6 +693,12 @@ void FriendList::insertPeers() groupItem->setData(COLUMN_DATA, ROLE_ID, QString::fromStdString(groupInfo->id)); groupItem->setData(COLUMN_DATA, ROLE_STANDARD, (groupInfo->flag & RS_GROUP_FLAG_STANDARD) ? true : false); + /* Sort data */ + for (int i = 0; i < columnCount; ++i) { + groupItem->setData(i, ROLE_SORT_GROUP, 1); + groupItem->setData(i, ROLE_SORT_STANDARD_GROUP, (groupInfo->flag & RS_GROUP_FLAG_STANDARD) ? 0 : 1); + groupItem->setData(i, ROLE_SORT_STATE, 0); + } } else { // remove all gpg items that are not more assigned int childCount = groupItem->childCount(); @@ -703,404 +725,468 @@ void FriendList::insertPeers() // iterate through gpg friends for (gpgIt = gpgFriends.begin(); gpgIt != gpgFriends.end(); ++gpgIt) - { - RsPgpId gpgId = *gpgIt; + { + RsPgpId gpgId = *gpgIt; - if (mShowGroups) { - if (groupInfo) { - // we fill a group, check if gpg id is assigned - if (std::find(groupInfo->peerIds.begin(), groupInfo->peerIds.end(), gpgId) == groupInfo->peerIds.end()) { - continue; - } - } else { - // we fill the not assigned gpg ids - if (std::find(fillGpgIds.begin(), fillGpgIds.end(), gpgId) != fillGpgIds.end()) { - continue; + if (mShowGroups) { + if (groupInfo) { + // we fill a group, check if gpg id is assigned + if (std::find(groupInfo->peerIds.begin(), groupInfo->peerIds.end(), gpgId) == groupInfo->peerIds.end()) { + continue; + } + } else { + // we fill the not assigned gpg ids + if (std::find(fillGpgIds.begin(), fillGpgIds.end(), gpgId) != fillGpgIds.end()) { + continue; + } } + + // add equal too, its no problem + fillGpgIds.push_back(gpgId); } - // add equal too, its no problem - fillGpgIds.push_back(gpgId); - } - - //add the gpg friends + //add the gpg friends #ifdef FRIENDS_DEBUG - std::cerr << "FriendList::insertPeers() inserting gpg_id : " << gpgId << std::endl; + std::cerr << "FriendList::insertPeers() inserting gpg_id : " << gpgId << std::endl; #endif - /* make a widget per friend */ - QTreeWidgetItem *gpgItem = NULL; - QTreeWidgetItem *gpgItemLoop = NULL; + /* make a widget per friend */ + QTreeWidgetItem *gpgItem = NULL; + QTreeWidgetItem *gpgItemLoop = NULL; - // search existing gpg item - int itemCount = groupItem ? groupItem->childCount() : peerTreeWidget->topLevelItemCount(); - for (int index = 0; index < itemCount; ++index) { - gpgItemLoop = groupItem ? groupItem->child(index) : peerTreeWidget->topLevelItem(index); - if (gpgItemLoop->type() == TYPE_GPG && getRsId(gpgItemLoop) == gpgId.toStdString()) { - gpgItem = gpgItemLoop; - break; - } - } - - RsPeerDetails detail; - 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) { - delete(groupItem->takeChild(groupItem->indexOfChild(gpgItem))); - } else { - delete (peerTreeWidget->takeTopLevelItem(peerTreeWidget->indexOfTopLevelItem(gpgItem))); - } - } - continue; - } - - if (gpgItem == NULL) { - // create gpg item and add it to tree - gpgItem = new RSTreeWidgetItem(m_compareRole, TYPE_GPG); //set type to 0 for custom popup menu - - /* Add gpg item to the list. Add here, because for setHidden the item must be added */ - if (groupItem) { - groupItem->addChild(gpgItem); - } else { - peerTreeWidget->addTopLevelItem(gpgItem); - } - - gpgItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless); - gpgItem->setTextAlignment(COLUMN_NAME, Qt::AlignLeft | Qt::AlignVCenter); - - /* not displayed, used to find back the item */ - gpgItem->setData(COLUMN_DATA, ROLE_ID, QString::fromStdString(detail.gpg_id.toStdString())); - } - - if (mBigName && !mHideState && isStatusColumnHidden) { - gpgItem->setSizeHint(COLUMN_NAME, QSize(40, 40)); - } else { - gpgItem->setSizeHint(COLUMN_NAME, QSize(26, 26)); - } - - ++availableCount; - - QString gpgItemText = QString::fromUtf8(detail.name.c_str()); - - // remove items that are not friends anymore - int childCount = gpgItem->childCount(); - int childIndex = 0; - while (childIndex < childCount) { - std::string ssl_id = getRsId(gpgItem->child(childIndex)); - if (!rsPeers->isFriend(RsPeerId(ssl_id))) { - delete (gpgItem->takeChild(childIndex)); - // count again - childCount = gpgItem->childCount(); - } else { - ++childIndex; - } - } - - // 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 - RsPeerId bestSslId; // for gpg item - QString bestCustomStateString;// for gpg item - std::list sslContacts; - QDateTime lastContact; - QString itemIP; - - rsPeers->getAssociatedSSLIds(detail.gpg_id, sslContacts); - for (std::list::iterator sslIt = sslContacts.begin(); sslIt != sslContacts.end(); ++sslIt) { - QTreeWidgetItem *sslItem = NULL; - RsPeerId sslId = *sslIt; - - //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; + // search existing gpg item + int itemCount = groupItem ? groupItem->childCount() : peerTreeWidget->topLevelItemCount(); + for (int index = 0; index < itemCount; ++index) { + gpgItemLoop = groupItem ? groupItem->child(index) : peerTreeWidget->topLevelItem(index); + if (gpgItemLoop->type() == TYPE_GPG && getRsId(gpgItemLoop) == gpgId.toStdString()) { + gpgItem = gpgItemLoop; 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); + RsPeerDetails detail; + 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) { + delete(groupItem->takeChild(groupItem->indexOfChild(gpgItem))); + } else { + delete (peerTreeWidget->takeTopLevelItem(peerTreeWidget->indexOfTopLevelItem(gpgItem))); + } } continue; } - if (newChild) { - sslItem = new RSTreeWidgetItem(m_compareRole, TYPE_SSL); //set type to 1 for custom popup menu + 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 -#ifdef FRIENDS_DEBUG - std::cerr << "FriendList::insertPeers() inserting sslItem." << std::endl; -#endif + /* Add gpg item to the list. Add here, because for setHidden the item must be added */ + if (groupItem) { + groupItem->addChild(gpgItem); + } else { + peerTreeWidget->addTopLevelItem(gpgItem); + } - /* Add ssl child to the list. Add here, because for setHidden the item must be added */ - gpgItem->addChild(sslItem); + gpgItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless); + gpgItem->setTextAlignment(COLUMN_NAME, Qt::AlignLeft | Qt::AlignVCenter); + + /* not displayed, used to find back the item */ + gpgItem->setData(COLUMN_DATA, ROLE_ID, QString::fromStdString(detail.gpg_id.toStdString())); + + /* Sort data */ + for (int i = 0; i < columnCount; ++i) { + gpgItem->setData(i, ROLE_SORT_GROUP, 2); + gpgItem->setData(i, ROLE_SORT_STANDARD_GROUP, 1); + } } - /* not displayed, used to find back the item */ - sslItem->setData(COLUMN_DATA, ROLE_ID, QString::fromStdString(sslDetail.id.toStdString())); + ++availableCount; - if (!isAvatarColumnHidden) - updateAvatar(QString::fromStdString(sslDetail.id.toStdString())); - - QString sText; - QString customStateString; - if (sslDetail.state & RS_PEER_STATE_CONNECTED) { - customStateString = QString::fromUtf8(rsMsgs->getCustomStateString(sslDetail.id).c_str()); - } - sText = QString::fromUtf8(sslDetail.location.c_str()); - if (customStateString.isEmpty() == false) { - sText += " - " + customStateString; + // remove items that are not friends anymore + int childCount = gpgItem->childCount(); + int childIndex = 0; + while (childIndex < childCount) { + std::string ssl_id = getRsId(gpgItem->child(childIndex)); + if (!rsPeers->isFriend(RsPeerId(ssl_id))) { + delete (gpgItem->takeChild(childIndex)); + // count again + childCount = gpgItem->childCount(); + } else { + ++childIndex; + } } - QString connectStateString = StatusDefs::connectStateWithoutTransportTypeString(sslDetail); - if (!isStatusColumnHidden) { - sslItem->setText(COLUMN_STATE, connectStateString); - } else if (!mHideState && connectStateString.isEmpty() == false) { - sText += " [" + connectStateString + "]"; - } - sslItem->setText( COLUMN_NAME, sText); + // 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 sslContacts; + QDateTime bestLastContact; + QString bestIP; + QPixmap bestAvatar; - if (isStatusColumnHidden == true && mHideState == true) { - /* Show the state as tooltip */ - sslItem->setToolTip(COLUMN_NAME, connectStateString); - } else { - sslItem->setToolTip(COLUMN_NAME, ""); - } + rsPeers->getAssociatedSSLIds(detail.gpg_id, sslContacts); + for (std::list::iterator sslIt = sslContacts.begin(); sslIt != sslContacts.end(); ++sslIt) { + QTreeWidgetItem *sslItem = NULL; + RsPeerId sslId = *sslIt; - // sort node - sslItem->setData(COLUMN_STATE, ROLE_SORT, sText); - - /* 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, sslLastContact); - if (sslLastContact > lastContact) { - lastContact = sslLastContact; - } - - /* IP */ - - QString sslItemIP = (sslDetail.state & RS_PEER_STATE_CONNECTED) ? StatusDefs::connectStateIpString(sslDetail) : QString("---"); - - sslItem->setData(COLUMN_IP, Qt::DisplayRole, QVariant(sslItemIP)); - sslItem->setData(COLUMN_IP, ROLE_SORT, sslItemIP); - if (sslItemIP != itemIP) { - itemIP = sslItemIP; - } - - /* change color and icon */ - QIcon sslIcon; - QFont sslFont; - QColor sslColor; - if (sslDetail.state & RS_PEER_STATE_CONNECTED) { - // get the status info for this ssl id - int peerState = 0; - int rsState = 0; - std::list::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; - bestSslId = sslId; - bestRSState = rsState; - bestCustomStateString = customStateString; - } else if (peerState == bestPeerState) { - /* equal state */ - if (mBigName && 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; - bestSslId = sslId; - bestRSState = rsState; - bestCustomStateString = customStateString; - } - } + // 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; } } - sslItem->setHidden(false); - gpg_connected = true; + 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; + } - sslIcon = QIcon(":/images/connect_established.png"); + 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 */ + sslItem->setData(COLUMN_DATA, ROLE_ID, QString::fromStdString(sslDetail.id.toStdString())); + + /* 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::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); - 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_OFFLINE; + sslItem->setHidden(mHideUnconnected); + if (sslDetail.connectState) { + sslOverlayIcon = QPixmap(":/images/connect_creating.png"); + } else { + sslOverlayIcon = QPixmap(StatusDefs::imageStatus(RS_STATUS_OFFLINE)); + } - if (sslDetail.connectState) { - sslIcon = QIcon(":/images/connect_creating.png"); + 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 { - sslIcon = QIcon(":/images/connect_no.png"); + if (!customStateString.isEmpty()) { + sslText = customStateString; + } + + /* Show the state as tooltip */ + sslItem->setToolTip(COLUMN_NAME, connectStateString); } - sslFont.setBold(true); - sslColor = mTextColorStatus[RS_STATUS_ONLINE]; + /* 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); + } + } + + QString gpgName = QString::fromUtf8(detail.name.c_str()); + QString gpgText; + QFont gpgFont; + QColor gpgColor; + + bool showInfoAtGpgItem = !gpgItem->isExpanded(); + + QPixmap gpgOverlayIcon; + if (gpg_connected) { + gpgItem->setHidden(false); + + ++onlineCount; + + if (bestPeerState == 0) { + // show as online + bestPeerState = PEER_STATE_ONLINE; + bestRSState = RS_STATUS_ONLINE; + } + + gpgColor = mTextColorStatus[bestRSState]; + gpgFont = StatusDefs::font(bestRSState); + + if (showInfoAtGpgItem) { + gpgOverlayIcon = QPixmap(StatusDefs::imageStatus(bestRSState)); + + if (mShowState) { + gpgText = StatusDefs::name(bestRSState); + if (!bestCustomStateString.isEmpty()) { + gpgText += " [" + bestCustomStateString + "]"; + } + } else { + if (!bestCustomStateString.isEmpty()) { + gpgText = bestCustomStateString; + } + } + } + } else if (gpg_online) { + gpgItem->setHidden(mHideUnconnected); + ++onlineCount; + bestPeerState = PEER_STATE_AVAILABLE; + + gpgFont.setBold(true); + gpgColor = mTextColorStatus[RS_STATUS_ONLINE]; + + if (showInfoAtGpgItem) { + if (mShowState) { + gpgText += tr("Available"); + } + + gpgOverlayIcon = QPixmap(IMAGE_AVAILABLE); + } } else { - sslItem->setHidden(mHideUnconnected); - if (sslDetail.connectState) { - sslIcon = QIcon(":/images/connect_creating.png"); - } else { - sslIcon = QIcon(":/images/connect_no.png"); + bestPeerState = PEER_STATE_OFFLINE; + gpgItem->setHidden(mHideUnconnected); + + gpgFont = StatusDefs::font(RS_STATUS_OFFLINE); + gpgColor = mTextColorStatus[RS_STATUS_OFFLINE]; + + if (showInfoAtGpgItem) { + if (mShowState) { + gpgText += StatusDefs::name(RS_STATUS_OFFLINE); + } + + gpgOverlayIcon = QPixmap(StatusDefs::imageStatus(RS_STATUS_OFFLINE)); } - - sslFont.setBold(false); - sslColor = mTextColorStatus[RS_STATUS_OFFLINE]; } - if (std::find(privateChatIds.begin(), privateChatIds.end(), sslDetail.id) != privateChatIds.end()) { - // private chat is available - sslIcon = QIcon(":/images/chat.png"); - gpg_hasPrivateChat = true; + if (gpg_hasPrivateChat) { + gpgOverlayIcon = QPixmap(":/images/chat.png"); } - sslItem -> setIcon(COLUMN_NAME, sslIcon); + + gpgItem->setIcon(COLUMN_NAME, createAvatar(bestAvatar.isNull() ? QPixmap(AVATAR_DEFAULT_IMAGE) : bestAvatar, gpgOverlayIcon)); + + /* Create or get gpg label */ + ElidedLabel *gpgNameLabel = NULL; + ElidedLabel *gpgTextLabel = NULL; + + getNameWidget(ui->peerTreeWidget, gpgItem, gpgNameLabel, gpgTextLabel); + + if (gpgNameLabel) { + gpgNameLabel->setText(gpgName); + gpgNameLabel->setFont(gpgFont); + + QPalette palette = gpgNameLabel->palette(); + palette.setColor(gpgNameLabel->foregroundRole(), gpgColor); + + gpgNameLabel->setPalette(palette); + } + if (gpgTextLabel) { + gpgTextLabel->setText(gpgText); + gpgTextLabel->setVisible(!gpgText.isEmpty()); + } + + // Filter + gpgItem->setData(COLUMN_NAME, ROLE_FILTER, gpgName); + + gpgItem->setData(COLUMN_LAST_CONTACT, Qt::DisplayRole, showInfoAtGpgItem ? QVariant(bestLastContact) : ""); + gpgItem->setData(COLUMN_LAST_CONTACT, ROLE_SORT_NAME, showInfoAtGpgItem ? QVariant(bestLastContact) : ""); + gpgItem->setText(COLUMN_IP, showInfoAtGpgItem ? bestIP : ""); + gpgItem->setData(COLUMN_IP, ROLE_SORT_NAME, showInfoAtGpgItem ? bestIP : ""); + + /* Sort data */ + gpgItem->setData(COLUMN_NAME, ROLE_SORT_NAME, gpgName); for (int i = 0; i < columnCount; ++i) { - sslItem -> setTextColor(i, sslColor); - sslItem -> setFont(i, sslFont); + gpgItem->setData(i, ROLE_SORT_STATE, bestPeerState); + + gpgItem->setTextColor(i, gpgColor); + gpgItem->setFont(i, gpgFont); + } + + if (openPeers != NULL && openPeers->find(gpgId.toStdString()) != openPeers->end()) { + gpgItem->setExpanded(true); } } - QIcon gpgIcon; - if (gpg_connected) { - gpgItem->setHidden(false); - - ++onlineCount; - - if (bestPeerState == 0) { - // show as online - bestPeerState = PEER_STATE_ONLINE; - bestRSState = RS_STATUS_ONLINE; - } - - QColor textColor = mTextColorStatus[bestRSState]; - QFont font = StatusDefs::font(bestRSState); - for(int i = 0; i < columnCount; ++i) { - gpgItem->setTextColor(i, textColor); - gpgItem->setFont(i, font); - } - - gpgIcon = QIcon(StatusDefs::imageStatus(bestRSState)); - - if (!isStatusColumnHidden) { - gpgItem->setText(COLUMN_STATE, StatusDefs::name(bestRSState)); - } - - if (isStatusColumnHidden && mBigName && !mHideState) { - if (bestCustomStateString.isEmpty()) { - gpgItemText += "\n" + StatusDefs::name(bestRSState); - } else { - gpgItemText += "\n" + bestCustomStateString; - } - } else if (isStatusColumnHidden && !mHideState){ - gpgItemText += " - " + StatusDefs::name(bestRSState); - } - } else if (gpg_online) { - if (!isStatusColumnHidden) { - gpgItem->setText(COLUMN_STATE, tr("Available")); - } else if (!mHideState && !mBigName) { - gpgItemText += " - " + tr("Available") ; - } - - bestPeerState = PEER_STATE_AVAILABLE; - ++onlineCount; - gpgItem->setHidden(mHideUnconnected); - gpgIcon = QIcon(IMAGE_AVAILABLE); - - QFont font; - font.setBold(true); - QColor textColor = mTextColorStatus[RS_STATUS_ONLINE]; - for(int i = 0; i < columnCount; ++i) { - gpgItem->setTextColor(i, textColor); - gpgItem->setFont(i,font); - } - } else { - if (!isStatusColumnHidden) { - gpgItem->setText(COLUMN_STATE, StatusDefs::name(RS_STATUS_OFFLINE)); - } else if (!mHideState && !mBigName) { - gpgItemText += " - " + StatusDefs::name(RS_STATUS_OFFLINE) ; - } - - bestPeerState = PEER_STATE_OFFLINE; - gpgItem->setHidden(mHideUnconnected); - gpgIcon = QIcon(StatusDefs::imageStatus(RS_STATUS_OFFLINE)); - - QColor textColor = mTextColorStatus[RS_STATUS_OFFLINE]; - QFont font = StatusDefs::font(RS_STATUS_OFFLINE); - for(int i = 0; i < columnCount; ++i) { - gpgItem->setTextColor(i, textColor); - gpgItem->setFont(i, font); - } - } - - if (gpg_hasPrivateChat) { - gpgIcon = QIcon(":/images/chat.png"); - } - - if (!isAvatarColumnHidden){ - QPixmap avatar; - AvatarDefs::getAvatarFromSslId(bestSslId, avatar); - QIcon avatar_icon(avatar); - gpgItem->setIcon(COLUMN_AVATAR, avatar_icon); - // tell the avatar callback which avatar must be filled in at this place - gpgItem->setData(COLUMN_DATA, ROLE_BEST_SSL, QString::fromStdString(bestSslId.toStdString())); - } - - gpgItem->setText(COLUMN_NAME, gpgItemText); - gpgItem->setData(COLUMN_NAME, ROLE_SORT, "2 " + gpgItemText); - gpgItem->setData(COLUMN_STATE, ROLE_SORT, "2 " + BuildStateSortString(true, gpgItemText, bestPeerState)); - gpgItem->setIcon(COLUMN_NAME, gpgIcon); - gpgItem->setData(COLUMN_LAST_CONTACT, Qt::DisplayRole, QVariant(lastContact)); - gpgItem->setData(COLUMN_LAST_CONTACT, ROLE_SORT, "2 " + lastContact.toString("yyyyMMdd_hhmmss")); - gpgItem->setData(COLUMN_IP, Qt::DisplayRole, QVariant()); - gpgItem->setData(COLUMN_IP, ROLE_SORT, "2 " + itemIP); - - if (openPeers != NULL && openPeers->find(gpgId.toStdString()) != openPeers->end()) { - gpgItem->setExpanded(true); - } - } - if (groupInfo && groupItem) { if ((groupInfo->flag & RS_GROUP_FLAG_STANDARD) && groupItem->childCount() == 0) { // there are some dead id's assigned @@ -1109,8 +1195,12 @@ void FriendList::insertPeers() groupItem->setHidden(false); QString groupName = GroupDefs::name(*groupInfo); groupItem->setText(COLUMN_NAME, QString("%1 (%2/%3)").arg(groupName).arg(onlineCount).arg(availableCount)); - // show first the standard groups, than the user groups - groupItem->setData(COLUMN_NAME, ROLE_SORT, ((groupInfo->flag & RS_GROUP_FLAG_STANDARD) ? "0 " : "1 ") + groupName); + + // Filter + groupItem->setData(COLUMN_NAME, ROLE_FILTER, groupName); + + /* Sort data */ + groupItem->setData(COLUMN_NAME, ROLE_SORT_NAME, groupName); } } @@ -1135,6 +1225,8 @@ void FriendList::insertPeers() delete(openPeers); openPeers = NULL; } + + ui->peerTreeWidget->resort(); } /** @@ -1458,7 +1550,6 @@ void FriendList::connectfriend() QTreeWidgetItem *item = c->child(childIndex); if (item->type() == TYPE_SSL) { rsPeers->connectAttempt(RsPeerId(getRsId(item))); - item->setIcon(COLUMN_NAME,(QIcon(IMAGE_CONNECT2))); // Launch ProgressDialog, only if single SSL child. if (childCount == 1) @@ -1470,7 +1561,6 @@ void FriendList::connectfriend() } else { //this is a SSL key rsPeers->connectAttempt(RsPeerId(getRsId(c))); - c->setIcon(COLUMN_NAME,(QIcon(IMAGE_CONNECT2))); // Launch ProgressDialog. ConnectProgressDialog::showProgress(RsPeerId(getRsId(c))); } @@ -1668,6 +1758,413 @@ void FriendList::removeGroup() rsPeers->removeGroup(groupId); } +void FriendList::exportFriendlistClicked() +{ + QString fileName; + if(!importExportFriendlistFileDialog(fileName, false)) + // error was already shown - just return + return; + + if(!exportFriendlist(fileName)) + // error was already shown - just return + return; + + QMessageBox mbox; + mbox.setIcon(QMessageBox::Information); + mbox.setText(tr("Done!")); + mbox.setInformativeText(tr("Your friendlist is stored at:\n") + fileName + + tr("\n(keep in mind that the file is unencrypted!)")); + mbox.setStandardButtons(QMessageBox::Ok); + mbox.exec(); +} + +void FriendList::importFriendlistClicked() +{ + QString fileName; + if(!importExportFriendlistFileDialog(fileName, true)) + // error was already shown - just return + return; + + bool errorPeers, errorGroups; + if(importFriendlist(fileName, errorPeers, errorGroups)) { + QMessageBox mbox; + mbox.setIcon(QMessageBox::Information); + mbox.setText(tr("Done!")); + mbox.setInformativeText(tr("Your friendlist was imported from:\n") + fileName); + mbox.setStandardButtons(QMessageBox::Ok); + mbox.exec(); + } else { + QMessageBox mbox; + mbox.setIcon(QMessageBox::Warning); + mbox.setText(tr("Done - but errors happened!")); + mbox.setInformativeText(tr("Your friendlist was imported from:\n") + fileName + + (errorPeers ? tr("\nat least one peer was not added") : "") + + (errorGroups ? tr("\nat least one peer was not added to a group") : "") + ); + mbox.setStandardButtons(QMessageBox::Ok); + mbox.exec(); + } +} + +/** + * @brief opens a file dialog to select a file containing a friendlist + * @param fileName file containing a friendlist + * @param import show dialog for importing (true) or exporting (false) friendlist + * @return success or failure + * + * This function also shows an error message when no valid file was selected + */ +bool FriendList::importExportFriendlistFileDialog(QString &fileName, bool import) +{ + if(!misc::getSaveFileName(this, + RshareSettings::LASTDIR_CERT, + (import ? tr("Select file for importing yoour friendlist from") : + tr("Select a file for exporting your friendlist to")), + tr("XML File (*.xml);;All Files (*)"), + fileName, + NULL, + (import ? QFileDialog::DontConfirmOverwrite : (QFileDialog::Options)0) + )) { + // show error to user + QMessageBox mbox; + mbox.setIcon(QMessageBox::Warning); + mbox.setText(tr("Error")); + mbox.setInformativeText(tr("Failed to get a file!")); + mbox.setStandardButtons(QMessageBox::Ok); + mbox.exec(); + return false; + } + return true; +} + +/** + * @brief exports friendlist to a given file + * @param fileName file for storing friendlist + * @return success or failure + * + * This function also shows an error message when the selected file is invalid/not writable + */ +bool FriendList::exportFriendlist(QString &fileName) +{ + QDomDocument doc("FriendListWithGroups"); + QDomElement root = doc.createElement("root"); + doc.appendChild(root); + + QFile file(fileName); + if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) { + // show error to user + QMessageBox mbox; + mbox.setIcon(QMessageBox::Warning); + mbox.setText(tr("Error")); + mbox.setInformativeText(tr("File is not writeable!\n") + fileName); + mbox.setStandardButtons(QMessageBox::Ok); + mbox.exec(); + return false; + } + + std::list gpg_ids; + rsPeers->getGPGAcceptedList(gpg_ids); + + std::list group_info_list; + rsPeers->getGroupInfoList(group_info_list); + + QDomElement pgpIDs = doc.createElement("pgpIDs"); + RsPeerDetails detailPGP; + for(std::list::iterator list_iter = gpg_ids.begin(); list_iter != gpg_ids.end(); list_iter++) { + rsPeers->getGPGDetails(*list_iter, detailPGP); + QDomElement pgpID = doc.createElement("pgpID"); + // these values aren't used and just stored for better human readability + pgpID.setAttribute("id", QString::fromStdString(detailPGP.gpg_id.toStdString())); + pgpID.setAttribute("name", QString::fromUtf8(detailPGP.name.c_str())); + + std::list ssl_ids; + rsPeers->getAssociatedSSLIds(*list_iter, ssl_ids); + for(std::list::iterator list_iter = ssl_ids.begin(); list_iter != ssl_ids.end(); list_iter++) { + RsPeerDetails detailSSL; + if (!rsPeers->getPeerDetails(*list_iter, detailSSL)) + continue; + + std::string certificate = rsPeers->GetRetroshareInvite(detailSSL.id, true); + // remove \n from certificate + certificate.erase(std::remove(certificate.begin(), certificate.end(), '\n'), certificate.end()); + + QDomElement sslID = doc.createElement("sslID"); + // these values aren't used and just stored for better human readability + sslID.setAttribute("sslID", QString::fromStdString(detailSSL.id.toStdString())); + if(!detailSSL.location.empty()) + sslID.setAttribute("location", QString::fromUtf8(detailSSL.location.c_str())); + + // required values + sslID.setAttribute("certificate", QString::fromStdString(certificate)); + sslID.setAttribute("service_perm_flags", detailSSL.service_perm_flags.toUInt32()); + + pgpID.appendChild(sslID); + } + pgpIDs.appendChild(pgpID); + } + root.appendChild(pgpIDs); + + QDomElement groups = doc.createElement("groups"); + for(std::list::iterator list_iter = group_info_list.begin(); list_iter != group_info_list.end(); list_iter++) { + RsGroupInfo group_info = *list_iter; + + //skip groups without peers + if(group_info.peerIds.empty()) + continue; + + QDomElement group = doc.createElement("group"); + // id is not needed since it may differ between locatiosn / pgp ids (groups are identified by name) + group.setAttribute("name", QString::fromUtf8(group_info.name.c_str())); + group.setAttribute("flag", group_info.flag); + + for(std::set::iterator i = group_info.peerIds.begin(); i != group_info.peerIds.end(); i++) { + QDomElement pgpID = doc.createElement("pgpID"); + std::string pid = i->toStdString(); + pgpID.setAttribute("id", QString::fromStdString(pid)); + group.appendChild(pgpID); + } + groups.appendChild(group); + } + root.appendChild(groups); + + QTextStream ts(&file); + ts.setCodec("UTF-8"); + ts << doc.toString(); + file.close(); + + return true; +} + +/** + * @brief helper function to show a message box + */ +void showXMLParsingError() +{ + // show error to user + QMessageBox mbox; + mbox.setIcon(QMessageBox::Warning); + mbox.setText(QObject::tr("Error")); + mbox.setInformativeText(QObject::tr("unable to parse XML file!")); + mbox.setStandardButtons(QMessageBox::Ok); + mbox.exec(); +} + +/** + * @brief Imports friends from a given file + * @param fileName file to load friends from + * @param errorPeers an error occured while adding a peer + * @param errorGroups an error occured while adding a peer to a group + * @return success or failure (an error can also happen when adding a peer and/or adding a peer to a group fails at least once) + */ +bool FriendList::importFriendlist(QString &fileName, bool &errorPeers, bool &errorGroups) +{ + QDomDocument doc; + // load from file + { + QFile file(fileName); + + if (!file.open(QIODevice::ReadOnly)) { + // show error to user + QMessageBox mbox; + mbox.setIcon(QMessageBox::Warning); + mbox.setText(tr("Error")); + mbox.setInformativeText(tr("File is not readable!\n") + fileName); + mbox.setStandardButtons(QMessageBox::Ok); + mbox.exec(); + return false; + } + + bool ok = doc.setContent(&file); + file.close(); + + if(!ok) { + showXMLParsingError(); + return false; + } + } + + QDomElement root = doc.documentElement(); + if(root.tagName() != "root") { + showXMLParsingError(); + return false; + } + + errorPeers = false; + errorGroups = false; + + uint32_t error_code; + std::string error_string; + RsPeerDetails rsPeerDetails; + RsPeerId rsPeerID; + RsPgpId rsPgpID; + + // lock all events for faster processing + RsAutoUpdatePage::lockAllEvents(); + + // pgp and ssl IDs + QDomElement pgpIDs; + { + QDomNodeList nodes = root.elementsByTagName("pgpIDs"); + if(nodes.isEmpty() || nodes.size() != 1){ + showXMLParsingError(); + return false; + } + + pgpIDs = nodes.item(0).toElement(); + if(pgpIDs.isNull()){ + showXMLParsingError(); + return false; + } + } + QDomNode pgpIDElem = pgpIDs.firstChildElement("pgpID"); + while (!pgpIDElem.isNull()) { + QDomElement sslIDElem = pgpIDElem.firstChildElement("sslID"); + while (!sslIDElem.isNull()) { + rsPeerID.clear(); + rsPgpID.clear(); + + // load everything needed from the pubkey string + std::string pubkey = sslIDElem.attribute("certificate").toStdString(); + if(rsPeers->loadDetailsFromStringCert(pubkey, rsPeerDetails, error_code)) { + if(rsPeers->loadCertificateFromString(pubkey, rsPeerID, rsPgpID, error_string)) { + ServicePermissionFlags service_perm_flags(sslIDElem.attribute("service_perm_flags").toInt()); + + // everything is loaded - start setting things + if (!rsPeerDetails.id.isNull() && !rsPeerDetails.gpg_id.isNull()) { + // pgp and ssl ID are available + rsPeers->addFriend(rsPeerDetails.id, rsPeerDetails.gpg_id, service_perm_flags); + if(rsPeerDetails.isHiddenNode) { + // for hidden notes + if (!rsPeerDetails.hiddenNodeAddress.empty() && rsPeerDetails.hiddenNodePort) + rsPeers->setHiddenNode(rsPeerDetails.id, rsPeerDetails.hiddenNodeAddress, rsPeerDetails.hiddenNodePort); + } else { + // for normal nodes + if (!rsPeerDetails.extAddr.empty() && rsPeerDetails.extPort) + rsPeers->setExtAddress(rsPeerDetails.id, rsPeerDetails.extAddr, rsPeerDetails.extPort); + if (!rsPeerDetails.localAddr.empty() && rsPeerDetails.localPort) + rsPeers->setLocalAddress(rsPeerDetails.id, rsPeerDetails.localAddr, rsPeerDetails.localPort); + if (!rsPeerDetails.dyndns.empty()) + rsPeers->setDynDNS(rsPeerDetails.id, rsPeerDetails.dyndns); + if (!rsPeerDetails.location.empty()) + rsPeers->setLocation(rsPeerDetails.id, rsPeerDetails.location); + } + } else if (!rsPeerDetails.gpg_id.isNull()) { + // only pgp id is avaiable + RsPeerId pid; + rsPeers->addFriend(pid, rsPeerDetails.gpg_id, service_perm_flags); + } else { + errorPeers = true; + std::cerr << "FriendList::importFriendlist(): error while processing SSL id: " << sslIDElem.attribute("sslID", "invalid").toStdString() << std::endl; + } + } else { + errorPeers = true; + std::cerr << "FriendList::importFriendlist(): failed to get peer detaisl from public key (SSL id: " << sslIDElem.attribute("sslID", "invalid").toStdString() << " - error: " << error_string << ")" << std::endl; + } + } else { + errorPeers = true; + std::cerr << "FriendList::importFriendlist(): failed to get peer detaisl from public key (SSL id: " << sslIDElem.attribute("sslID", "invalid").toStdString() << " - error: " << error_code << ")" << std::endl; + } + sslIDElem = sslIDElem.nextSiblingElement("sslID"); + } + pgpIDElem = pgpIDElem.nextSiblingElement("pgpID"); + } + + // groups + QDomElement groups; + { + QDomNodeList nodes = root.elementsByTagName("groups"); + if(nodes.isEmpty() || nodes.size() != 1){ + showXMLParsingError(); + return false; + } + + groups = nodes.item(0).toElement(); + if(groups.isNull()){ + showXMLParsingError(); + return false; + } + } + QDomElement group = groups.firstChildElement("group"); + while (!group.isNull()) { + // get name and flags and try to get the group ID + std::string groupName = group.attribute("name").toStdString(); + uint32_t flag = group.attribute("flag").toInt(); + std::string groupId; + if(getOrCreateGroup(groupName, flag, groupId)) { + // group id found! + QDomElement pgpID = group.firstChildElement("pgpID"); + while (!pgpID.isNull()) { + // add pgp id to group + RsPgpId rsPgpId(pgpID.attribute("id").toStdString()); + if(rsPgpID.isNull() || !rsPeers->assignPeerToGroup(groupId, rsPgpId, true)) { + errorGroups = true; + std::cerr << "FriendList::importFriendlist(): failed to add '" << rsPeers->getGPGName(rsPgpId) << "'' to group '" << groupName << "'" << std::endl; + } + + pgpID = pgpID.nextSiblingElement("pgpID"); + } + pgpID = pgpID.nextSiblingElement("pgpID"); + } else { + errorGroups = true; + std::cerr << "FriendList::importFriendlist(): failed to find/create group '" << groupName << "'" << std::endl; + } + group = group.nextSiblingElement("group"); + } + + // unlock events + RsAutoUpdatePage::unlockAllEvents(); + + return !(errorPeers || errorGroups); +} + +/** + * @brief Gets the groups ID for a given group name + * @param name group name to search for + * @param id groupd id for the given name + * @return success or fail + */ +bool FriendList::getGroupIdByName(const std::string &name, std::string &id) +{ + std::list grpList; + if(!rsPeers->getGroupInfoList(grpList)) + return false; + + foreach (const RsGroupInfo &grp, grpList) { + if(grp.name == name) { + id = grp.id; + return true; + } + } + + return false; +} + +/** + * @brief Gets the groups ID for a given group name. If no groupd was it will create one + * @param name group name to search for + * @param flag flag to use when creating the group + * @param id groupd id + * @return success or failure + */ +bool FriendList::getOrCreateGroup(const std::string &name, const uint &flag, std::string &id) +{ + if(getGroupIdByName(name, id)) + return true; + + // -> create one + RsGroupInfo grp; + grp.id = "0"; // RS will generate an ID + grp.name = name; + grp.flag = flag; + + if(!rsPeers->addGroup(grp)) + return false; + + // try again + return getGroupIdByName(name, id); +} + + void FriendList::setHideUnconnected(bool hidden) { if (mHideUnconnected != hidden) { @@ -1687,32 +2184,58 @@ void FriendList::sortByColumn(Column column, Qt::SortOrder sortOrder) ui->peerTreeWidget->sortByColumn(column, sortOrder); } -void FriendList::peerTreeColumnVisibleChanged(int column, bool visible) +void FriendList::peerTreeColumnVisibleChanged(int /*column*/, bool visible) { - switch (column) { - case COLUMN_NAME: - case COLUMN_AVATAR: - case COLUMN_LAST_CONTACT: - case COLUMN_IP: - break; - case COLUMN_STATE: - ui->actionHideState->setEnabled(!visible); - break; - } - if (visible) { insertPeers(); } } -void FriendList::setHideState(bool hidden) +void FriendList::peerTreeItemCollapsedExpanded(QTreeWidgetItem *item) { - if (mHideState != hidden) { - mHideState = hidden; + if (!item) { + return; + } + + if (item->type() == TYPE_GPG) { insertPeers(); } } +void FriendList::setShowState(bool show) +{ + if (mShowState != show) { + mShowState = show; + insertPeers(); + } +} + +void FriendList::sortByState(bool sort) +{ + int columnCount = ui->peerTreeWidget->columnCount(); + for (int i = 0; i < columnCount; ++i) { + mCompareRole->setRole(i, ROLE_SORT_GROUP); + mCompareRole->addRole(i, ROLE_SORT_STANDARD_GROUP); + + if (sort) { + mCompareRole->addRole(i, ROLE_SORT_STATE); + mCompareRole->addRole(i, ROLE_SORT_NAME); + } else { + mCompareRole->addRole(i, ROLE_SORT_NAME); + mCompareRole->addRole(i, ROLE_SORT_STATE); + } + } + + mActionSortByState->setChecked(sort); + + ui->peerTreeWidget->resort(); +} + +bool FriendList::isSortByState() +{ + return mActionSortByState->isChecked(); +} + void FriendList::setShowGroups(bool show) { if (mShowGroups != show) { @@ -1735,42 +2258,13 @@ void FriendList::setShowGroups(bool show) } } -/** - * If set to true, the customStateString will be shwon in all gpg peer items, - * not only in the ssl ids (used in MessengerWindow). - * These items will then be doublespaced. - */ -void FriendList::setBigName(bool bigName) -{ - if (mBigName != bigName) { - mBigName = bigName; - - // Change the size of the already existing items - QSize newSize; - if (mBigName) { - newSize.setHeight(40); - newSize.setWidth(40); - } else { - newSize.setHeight(26); - newSize.setWidth(26); - } - QTreeWidgetItemIterator it(ui->peerTreeWidget); - while (*it) { - if ((*it)->type() == TYPE_GPG) { - (*it)->setSizeHint(COLUMN_NAME, newSize); - } - ++it; - } - } -} - /** * Hides all items that don't contain text in the name column. */ void FriendList::filterItems(const QString &text) { mFilterText = text; - ui->peerTreeWidget->filterItems(COLUMN_NAME, mFilterText); + ui->peerTreeWidget->filterItems(COLUMN_NAME, mFilterText, ROLE_FILTER); } /** @@ -1803,8 +2297,10 @@ void FriendList::createDisplayMenu() connect(displayMenu, SIGNAL(aboutToShow()), this, SLOT(updateMenu())); displayMenu->addAction(ui->actionHideOfflineFriends); - displayMenu->addAction(ui->actionHideState); + displayMenu->addAction(ui->actionShowState); displayMenu->addAction(ui->actionShowGroups); + displayMenu->addAction(ui->actionExportFriendlist); + displayMenu->addAction(ui->actionImportFriendlist); ui->displayButton->setMenu(displayMenu); } @@ -1812,6 +2308,6 @@ void FriendList::createDisplayMenu() void FriendList::updateMenu() { ui->actionHideOfflineFriends->setChecked(mHideUnconnected); - ui->actionHideState->setChecked(mHideState); + ui->actionShowState->setChecked(mShowState); ui->actionShowGroups->setChecked(mShowGroups); } diff --git a/retroshare-gui/src/gui/common/FriendList.h b/retroshare-gui/src/gui/common/FriendList.h index 8a559a99c..cd950a639 100644 --- a/retroshare-gui/src/gui/common/FriendList.h +++ b/retroshare-gui/src/gui/common/FriendList.h @@ -52,10 +52,8 @@ public: enum Column { COLUMN_NAME = 0, - COLUMN_AVATAR = 1, - COLUMN_STATE = 2, - COLUMN_LAST_CONTACT = 3, - COLUMN_IP = 4 + COLUMN_LAST_CONTACT = 1, + COLUMN_IP = 2 }; public: @@ -74,7 +72,9 @@ public: virtual void updateDisplay(); void setColumnVisible(Column column, bool visible); + void sortByColumn(Column column, Qt::SortOrder sortOrder); + bool isSortByState(); QColor textColorGroup() const { return mTextColorGroup; } QColor textColorStatusOffline() const { return mTextColorStatus[RS_STATUS_OFFLINE]; } @@ -92,14 +92,15 @@ public: public slots: void filterItems(const QString &text); + void sortByState(bool sort); - void setBigName(bool bigName); // show customStateString in second line of the name cell void setShowGroups(bool show); void setHideUnconnected(bool hidden); - void setHideState(bool hidden); + void setShowState(bool show); private slots: void peerTreeColumnVisibleChanged(int column, bool visible); + void peerTreeItemCollapsedExpanded(QTreeWidgetItem *item); protected: void changeEvent(QEvent *e); @@ -107,12 +108,12 @@ protected: private: Ui::FriendList *ui; - RSTreeWidgetItemCompareRole *m_compareRole; + RSTreeWidgetItemCompareRole *mCompareRole; + QAction *mActionSortByState; // Settings for peer list display - bool mBigName; bool mShowGroups; - bool mHideState; + bool mShowState; bool mHideUnconnected; QString mFilterText; @@ -126,14 +127,19 @@ private: QColor mTextColorStatus[RS_STATUS_COUNT]; QTreeWidgetItem *getCurrentPeer() const; - void initializeHeader(bool afterLoadSettings); void getSslIdsFromItem(QTreeWidgetItem *item, std::list &sslIds); + bool getOrCreateGroup(const std::string &name, const uint &flag, std::string &id); + bool getGroupIdByName(const std::string &name, std::string &id); + + bool importExportFriendlistFileDialog(QString &fileName, bool import); + bool exportFriendlist(QString &fileName); + bool importFriendlist(QString &fileName, bool &errorPeers, bool &errorGroups); + private slots: void groupsChanged(); void insertPeers(); void peerTreeWidgetCustomPopupMenu(); - void updateAvatar(const QString &); void updateMenu(); void pastePerson(); @@ -161,6 +167,9 @@ private slots: void editGroup(); void removeGroup(); + void exportFriendlistClicked(); + void importFriendlistClicked(); + // void inviteToLobby(); // void createchatlobby(); // void unsubscribeToLobby(); diff --git a/retroshare-gui/src/gui/common/FriendList.ui b/retroshare-gui/src/gui/common/FriendList.ui index 0f114a198..cc6921319 100644 --- a/retroshare-gui/src/gui/common/FriendList.ui +++ b/retroshare-gui/src/gui/common/FriendList.ui @@ -14,7 +14,16 @@ 0 - + + 0 + + + 0 + + + 0 + + 0 @@ -29,7 +38,16 @@ 3 - + + 2 + + + 2 + + + 2 + + 2 @@ -75,18 +93,6 @@ Qt::CustomContextMenu - - - 38 - 38 - - - - 1 - - - 20 - true @@ -97,7 +103,7 @@ false - 5 + 3 false @@ -106,15 +112,8 @@ Friend nodes - - - - Avatar - - - - - Status + + AlignCenter @@ -138,15 +137,15 @@ Hide Offline Friends - + true - - false - - Hide State + Show State + + + Show State @@ -160,6 +159,22 @@ Show Groups + + + export friendlist + + + export your friendlist including groups + + + + + import friendlist + + + import your friendlist including groups + + diff --git a/retroshare-gui/src/gui/common/FriendSelectionWidget.cpp b/retroshare-gui/src/gui/common/FriendSelectionWidget.cpp index 19b8c63c6..3cc3ff3d0 100644 --- a/retroshare-gui/src/gui/common/FriendSelectionWidget.cpp +++ b/retroshare-gui/src/gui/common/FriendSelectionWidget.cpp @@ -21,6 +21,7 @@ ****************************************************************/ #include +#include #include "FriendSelectionWidget.h" #include "ui_FriendSelectionWidget.h" #include "gui/gxs/GxsIdDetails.h" @@ -44,8 +45,11 @@ #define IDDIALOG_IDLIST 1 -#define ROLE_ID Qt::UserRole -#define ROLE_SORT Qt::UserRole + 1 +#define ROLE_ID Qt::UserRole +#define ROLE_SORT_GROUP Qt::UserRole + 1 +#define ROLE_SORT_STANDARD_GROUP Qt::UserRole + 2 +#define ROLE_SORT_NAME Qt::UserRole + 3 +#define ROLE_SORT_STATE Qt::UserRole + 4 #define IMAGE_GROUP16 ":/images/user/group16.png" #define IMAGE_FRIENDINFO ":/images/peerdetails_16x16.png" @@ -94,15 +98,17 @@ FriendSelectionWidget::FriendSelectionWidget(QWidget *parent) connect(ui->friendList, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenuRequested(QPoint))); connect(ui->friendList, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(itemDoubleClicked(QTreeWidgetItem*,int))); connect(ui->friendList, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(itemChanged(QTreeWidgetItem*,int))); - connect(ui->selectAll_PB, SIGNAL(clicked()), this, SLOT(selectAll())); - connect(ui->deselectAll_PB, SIGNAL(clicked()), this, SLOT(deselectAll())); + connect(ui->friendList, SIGNAL(itemSelectionChanged()), this, SIGNAL(itemSelectionChanged())); connect(ui->filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterItems(QString))); connect(NotifyQt::getInstance(), SIGNAL(groupsChanged(int)), this, SLOT(groupsChanged(int))); connect(NotifyQt::getInstance(), SIGNAL(peerStatusChanged(const QString&,int)), this, SLOT(peerStatusChanged(const QString&,int))); mCompareRole = new RSTreeWidgetItemCompareRole; - mCompareRole->setRole(COLUMN_NAME, ROLE_SORT); + mActionSortByState = new QAction(tr("Sort by state"), this); + mActionSortByState->setCheckable(true); + connect(mActionSortByState, SIGNAL(toggled(bool)), this, SLOT(sortByState(bool))); + ui->friendList->addHeaderContextMenuAction(mActionSortByState); /* initialize list */ ui->friendList->setColumnCount(COLUMN_COUNT); @@ -110,6 +116,7 @@ FriendSelectionWidget::FriendSelectionWidget(QWidget *parent) /* sort list by name ascending */ ui->friendList->sortItems(COLUMN_NAME, Qt::AscendingOrder); + sortByState(false); ui->filterLineEdit->setPlaceholderText(tr("Search Friends")); ui->filterLineEdit->showFilterIcon(); @@ -156,17 +163,6 @@ void FriendSelectionWidget::setModus(Modus modus) break; } - if(modus == MODUS_CHECK) - { - ui->selectAll_PB->setHidden(false) ; - ui->deselectAll_PB->setHidden(false) ; - } - else - { - ui->selectAll_PB->setHidden(true) ; - ui->deselectAll_PB->setHidden(true) ; - } - fillList(); } @@ -216,8 +212,12 @@ static void initSslItem(QTreeWidgetItem *item, const RsPeerDetails &detail, cons } item->setIcon(COLUMN_NAME, QIcon(StatusDefs::imageUser(state))); - item->setData(COLUMN_DATA, ROLE_ID, QString::fromStdString(detail.id.toStdString())); - item->setData(COLUMN_DATA, ROLE_SORT, "2 " + name); + item->setData(COLUMN_DATA, ROLE_ID, QString::fromStdString(detail.id.toStdString())); + + item->setData(COLUMN_NAME, ROLE_SORT_GROUP, 1); + item->setData(COLUMN_NAME, ROLE_SORT_STANDARD_GROUP, 0); + item->setData(COLUMN_NAME, ROLE_SORT_STATE, (state != (int) RS_STATUS_OFFLINE) ? 0 : 1); + item->setData(COLUMN_NAME, ROLE_SORT_NAME, name); } void FriendSelectionWidget::fillList() @@ -349,7 +349,11 @@ void FriendSelectionWidget::secured_fillList() QString groupName = GroupDefs::name(*groupInfo); groupItem->setText(COLUMN_NAME, groupName); - groupItem->setData(COLUMN_DATA, ROLE_SORT, ((groupInfo->flag & RS_GROUP_FLAG_STANDARD) ? "0 " : "1 ") + groupName); + + groupItem->setData(COLUMN_NAME, ROLE_SORT_GROUP, 0); + groupItem->setData(COLUMN_NAME, ROLE_SORT_STANDARD_GROUP, (groupInfo->flag & RS_GROUP_FLAG_STANDARD) ? 0 : 1); + groupItem->setData(COLUMN_NAME, ROLE_SORT_STATE, 0); + groupItem->setData(COLUMN_NAME, ROLE_SORT_NAME, groupName); if (mListModus == MODUS_CHECK) { groupItem->setCheckState(0, Qt::Unchecked); @@ -411,8 +415,12 @@ void FriendSelectionWidget::secured_fillList() gpgItem->setFlags(Qt::ItemIsUserCheckable | gpgItem->flags()); gpgItem->setIcon(COLUMN_NAME, QIcon(StatusDefs::imageUser(state))); - gpgItem->setData(COLUMN_DATA, ROLE_ID, QString::fromStdString(detail.gpg_id.toStdString())); - gpgItem->setData(COLUMN_DATA, ROLE_SORT, "2 " + name); + gpgItem->setData(COLUMN_DATA, ROLE_ID, QString::fromStdString(detail.gpg_id.toStdString())); + + gpgItem->setData(COLUMN_NAME, ROLE_SORT_GROUP, 1); + gpgItem->setData(COLUMN_NAME, ROLE_SORT_STANDARD_GROUP, 0); + gpgItem->setData(COLUMN_NAME, ROLE_SORT_STATE, (state != (int) RS_STATUS_OFFLINE) ? 0 : 1); + gpgItem->setData(COLUMN_NAME, ROLE_SORT_NAME, name); if (mListModus == MODUS_CHECK) { gpgItem->setCheckState(0, Qt::Unchecked); @@ -542,7 +550,12 @@ void FriendSelectionWidget::secured_fillList() gxsItem->setFlags(Qt::ItemIsUserCheckable | gxsItem->flags()); gxsItem->setIcon(COLUMN_NAME, identicon); gxsItem->setData(COLUMN_DATA, ROLE_ID, QString::fromStdString(detail.mId.toStdString())); - gxsItem->setData(COLUMN_DATA, ROLE_SORT, "2 " + name); + + gxsItem->setData(COLUMN_NAME, ROLE_SORT_GROUP, 1); + gxsItem->setData(COLUMN_NAME, ROLE_SORT_STANDARD_GROUP, 0); +//TODO: online state for gxs items + gxsItem->setData(COLUMN_NAME, ROLE_SORT_STATE, 1); + gxsItem->setData(COLUMN_NAME, ROLE_SORT_NAME, name); if (mListModus == MODUS_CHECK) gxsItem->setCheckState(0, Qt::Unchecked); @@ -573,6 +586,8 @@ void FriendSelectionWidget::secured_fillList() mInFillList = false; + ui->friendList->resort(); + emit contentChanged(); } void FriendSelectionWidget::updateDisplay(bool) @@ -658,6 +673,7 @@ void FriendSelectionWidget::peerStatusChanged(const QString& peerId, int status) switch (idTypeFromItem(item)) { case IDTYPE_NONE: case IDTYPE_GROUP: + case IDTYPE_GXS: break; case IDTYPE_GPG: { @@ -672,6 +688,8 @@ void FriendSelectionWidget::peerStatusChanged(const QString& peerId, int status) item->setTextColor(COLUMN_NAME, color); item->setIcon(COLUMN_NAME, QIcon(StatusDefs::imageUser(gpgStatus))); + item->setData(COLUMN_NAME, ROLE_SORT_STATE, (gpgStatus != (int) RS_STATUS_OFFLINE) ? 0 : 1); + bFoundGPG = true; } } @@ -689,6 +707,8 @@ void FriendSelectionWidget::peerStatusChanged(const QString& peerId, int status) item->setTextColor(COLUMN_NAME, color); item->setIcon(COLUMN_NAME, QIcon(StatusDefs::imageUser(status))); + item->setData(COLUMN_NAME, ROLE_SORT_STATE, (status != (int) RS_STATUS_OFFLINE) ? 0 : 1); + bFoundSSL = true; } } @@ -714,11 +734,48 @@ void FriendSelectionWidget::peerStatusChanged(const QString& peerId, int status) } } } + + ui->friendList->resort(); } -void FriendSelectionWidget::contextMenuRequested(const QPoint &pos) +void FriendSelectionWidget::addContextMenuAction(QAction *action) { - emit customContextMenuRequested(pos); + mContextMenuActions.push_back(action); +} + +void FriendSelectionWidget::contextMenuRequested(const QPoint &/*pos*/) +{ + QMenu contextMenu(this); + + if (mListModus == MODUS_CHECK) { + contextMenu.addAction(QIcon(), tr("Mark all"), this, SLOT(selectAll())); + contextMenu.addAction(QIcon(), tr("Mark none"), this, SLOT(deselectAll())); + } + + if (!mContextMenuActions.isEmpty()) { + bool addSeparator = false; + if (!contextMenu.isEmpty()) { + // Check for visible action + foreach (QAction *action, mContextMenuActions) { + if (action->isVisible()) { + addSeparator = true; + break; + } + } + } + + if (addSeparator) { + contextMenu.addSeparator(); + } + + contextMenu.addActions(mContextMenuActions); + } + + if (contextMenu.isEmpty()) { + return; + } + + contextMenu.exec(QCursor::pos()); } void FriendSelectionWidget::itemDoubleClicked(QTreeWidgetItem *item, int /*column*/) @@ -1030,3 +1087,25 @@ std::string FriendSelectionWidget::idFromItem(QTreeWidgetItem *item) return item->data(COLUMN_DATA, ROLE_ID).toString().toStdString(); } +void FriendSelectionWidget::sortByState(bool sort) +{ + mCompareRole->setRole(COLUMN_NAME, ROLE_SORT_GROUP); + mCompareRole->addRole(COLUMN_NAME, ROLE_SORT_STANDARD_GROUP); + + if (sort) { + mCompareRole->addRole(COLUMN_NAME, ROLE_SORT_STATE); + mCompareRole->addRole(COLUMN_NAME, ROLE_SORT_NAME); + } else { + mCompareRole->addRole(COLUMN_NAME, ROLE_SORT_NAME); + mCompareRole->addRole(COLUMN_NAME, ROLE_SORT_STATE); + } + + mActionSortByState->setChecked(sort); + + ui->friendList->resort(); +} + +bool FriendSelectionWidget::isSortByState() +{ + return mActionSortByState->isChecked(); +} diff --git a/retroshare-gui/src/gui/common/FriendSelectionWidget.h b/retroshare-gui/src/gui/common/FriendSelectionWidget.h index 92bd6d0fc..22e571808 100644 --- a/retroshare-gui/src/gui/common/FriendSelectionWidget.h +++ b/retroshare-gui/src/gui/common/FriendSelectionWidget.h @@ -80,6 +80,8 @@ public: int addColumn(const QString &title); void start(); + bool isSortByState(); + int selectedItemCount(); std::string selectedId(IdType &idType); @@ -109,6 +111,9 @@ public: void setTextColorOnline(QColor color) { mTextColorOnline = color; } + // Add QAction to context menu (action won't be deleted) + void addContextMenuAction(QAction *action); + protected: void changeEvent(QEvent *e); @@ -118,9 +123,12 @@ protected: signals: void itemAdded(int idType, const QString &id, QTreeWidgetItem *item); void contentChanged(); - void customContextMenuRequested(const QPoint &pos); void doubleClicked(int idType, const QString &id); void itemChanged(int idType, const QString &id, QTreeWidgetItem *item, int column); + void itemSelectionChanged(); + +public slots: + void sortByState(bool sort); private slots: void groupsChanged(int type); @@ -142,6 +150,7 @@ private: void requestGXSIdList() ; +private: bool mStarted; RSTreeWidgetItemCompareRole *mCompareRole; Modus mListModus; @@ -150,6 +159,7 @@ private: bool mInGpgItemChanged; bool mInSslItemChanged; bool mInFillList; + QAction *mActionSortByState; /* Color definitions (for standard see qss.default) */ QColor mTextColorOnline; @@ -160,6 +170,7 @@ private: std::vector gxsIds ; TokenQueue *mIdQueue ; + QList mContextMenuActions; }; Q_DECLARE_OPERATORS_FOR_FLAGS(FriendSelectionWidget::ShowTypes) diff --git a/retroshare-gui/src/gui/common/FriendSelectionWidget.ui b/retroshare-gui/src/gui/common/FriendSelectionWidget.ui index 2ad0972b0..23d98c9b6 100644 --- a/retroshare-gui/src/gui/common/FriendSelectionWidget.ui +++ b/retroshare-gui/src/gui/common/FriendSelectionWidget.ui @@ -26,24 +26,10 @@ - - - - All - - - - - - - None - - - - + 20 @@ -80,6 +66,11 @@ QLineEdit
gui/common/LineEditClear.h
+ + RSTreeWidget + QTreeWidget +
gui/common/RSTreeWidget.h
+
diff --git a/retroshare-gui/src/gui/common/MimeTextEdit.cpp b/retroshare-gui/src/gui/common/MimeTextEdit.cpp index 1c51980c4..9513703d6 100644 --- a/retroshare-gui/src/gui/common/MimeTextEdit.cpp +++ b/retroshare-gui/src/gui/common/MimeTextEdit.cpp @@ -19,6 +19,8 @@ * Boston, MA 02110-1301, USA. ****************************************************************/ +#include +#include #include #include #include @@ -228,6 +230,7 @@ void MimeTextEdit::contextMenuEvent(QContextMenuEvent *e) QMenu *contextMenu = createStandardContextMenu(e->pos()); /* Add actions for pasting links */ + contextMenu->addAction( tr("Paste as plain text"), this, SLOT(pastePlainText())); contextMenu->addSeparator(); QAction *pasteLinkAction = contextMenu->addAction(QIcon(":/images/pasterslink.png"), tr("Paste RetroShare Link"), this, SLOT(pasteLink())); contextMenu->addAction(QIcon(":/images/pasterslink.png"), tr("Paste my certificate link"), this, SLOT(pasteOwnCertificateLink())); @@ -260,3 +263,8 @@ void MimeTextEdit::pasteOwnCertificateLink() insertHtml(link.toHtml() + " "); } } + +void MimeTextEdit::pastePlainText() +{ + insertPlainText(QApplication::clipboard()->text()); +} diff --git a/retroshare-gui/src/gui/common/MimeTextEdit.h b/retroshare-gui/src/gui/common/MimeTextEdit.h index 5ef5d6a5f..d28bb2c6e 100644 --- a/retroshare-gui/src/gui/common/MimeTextEdit.h +++ b/retroshare-gui/src/gui/common/MimeTextEdit.h @@ -58,7 +58,7 @@ private slots: void insertCompletion(const QString &completion); void pasteLink(); void pasteOwnCertificateLink(); - + void pastePlainText(); private: QString textUnderCursor() const; diff --git a/retroshare-gui/src/gui/common/RSGraphWidget.cpp b/retroshare-gui/src/gui/common/RSGraphWidget.cpp index 2f0e83d65..6d92166a4 100644 --- a/retroshare-gui/src/gui/common/RSGraphWidget.cpp +++ b/retroshare-gui/src/gui/common/RSGraphWidget.cpp @@ -518,7 +518,7 @@ void RSGraphWidget::paintTotals() int x = SCALE_WIDTH*fact + FS, y = 0; int rowHeight = FS; -#if !defined(Q_WS_MAC) +#if !defined(Q_OS_MAC) /* On Mac, we don't need vertical spacing between the text rows. */ rowHeight += 5; #endif diff --git a/retroshare-gui/src/gui/common/RSTreeWidget.cpp b/retroshare-gui/src/gui/common/RSTreeWidget.cpp index ef8e225ba..abbf766d3 100644 --- a/retroshare-gui/src/gui/common/RSTreeWidget.cpp +++ b/retroshare-gui/src/gui/common/RSTreeWidget.cpp @@ -29,7 +29,12 @@ RSTreeWidget::RSTreeWidget(QWidget *parent) : QTreeWidget(parent) { - mColumnCustomizable = false; + mEnableColumnCustomize = false; + mSettingsVersion = 0; // disabled + + QHeaderView *h = header(); + h->setContextMenuPolicy(Qt::CustomContextMenu); + connect(h, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(headerContextMenuRequested(QPoint))); } void RSTreeWidget::setPlaceholderText(const QString &text) @@ -76,11 +81,11 @@ void RSTreeWidget::mousePressEvent(QMouseEvent *event) QTreeWidget::mousePressEvent(event); } -void RSTreeWidget::filterItems(int filterColumn, const QString &text) +void RSTreeWidget::filterItems(int filterColumn, const QString &text, int role) { int count = topLevelItemCount(); for (int index = 0; index < count; ++index) { - filterItem(topLevelItem(index), filterColumn, text); + filterItem(topLevelItem(index), filterColumn, text, role); } QTreeWidgetItem *item = currentItem(); @@ -90,12 +95,12 @@ void RSTreeWidget::filterItems(int filterColumn, const QString &text) } } -bool RSTreeWidget::filterItem(QTreeWidgetItem *item, int filterColumn, const QString &text) +bool RSTreeWidget::filterItem(QTreeWidgetItem *item, int filterColumn, const QString &text, int role) { bool itemVisible = true; if (!text.isEmpty()) { - if (!item->text(filterColumn).contains(text, Qt::CaseInsensitive)) { + if (!item->data(filterColumn, role).toString().contains(text, Qt::CaseInsensitive)) { itemVisible = false; } } @@ -103,7 +108,7 @@ bool RSTreeWidget::filterItem(QTreeWidgetItem *item, int filterColumn, const QSt int visibleChildCount = 0; int count = item->childCount(); for (int index = 0; index < count; ++index) { - if (filterItem(item->child(index), filterColumn, text)) { + if (filterItem(item->child(index), filterColumn, text, role)) { ++visibleChildCount; } } @@ -117,55 +122,93 @@ bool RSTreeWidget::filterItem(QTreeWidgetItem *item, int filterColumn, const QSt return (itemVisible || visibleChildCount); } +void RSTreeWidget::setSettingsVersion(qint32 version) +{ + mSettingsVersion = version; +} + void RSTreeWidget::processSettings(bool load) { if (load) { - // load settings + // Load settings - // state of tree widget - header()->restoreState(Settings->value(objectName()).toByteArray()); + // State of tree widget + if (mSettingsVersion == 0 || Settings->value(QString("%1Version").arg(objectName())) == mSettingsVersion) { + // Compare version, because Qt can crash in restoreState after column changes + header()->restoreState(Settings->value(objectName()).toByteArray()); + } } else { - // save settings + // Save settings // state of tree widget Settings->setValue(objectName(), header()->saveState()); + + // Save version + if (mSettingsVersion) { + Settings->setValue(QString("%1Version").arg(objectName()), mSettingsVersion); + } } } -void RSTreeWidget::setColumnCustomizable(bool customizable) +void RSTreeWidget::enableColumnCustomize(bool customizable) { - if (customizable == mColumnCustomizable) { + if (customizable == mEnableColumnCustomize) { return; } - mColumnCustomizable = customizable; + mEnableColumnCustomize = customizable; +} - QHeaderView *h = header(); +void RSTreeWidget::setColumnCustomizable(int column, bool customizable) +{ + mColumnCustomizable[column] = customizable; +} - if (mColumnCustomizable) { - h->setContextMenuPolicy(Qt::CustomContextMenu); - connect(h, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(headerContextMenuRequested(QPoint))); - } else { - h->setContextMenuPolicy(Qt::DefaultContextMenu); - disconnect(h, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(headerContextMenuRequested(QPoint))); - } +void RSTreeWidget::addHeaderContextMenuAction(QAction *action) +{ + mHeaderContextMenuActions.push_back(action); } void RSTreeWidget::headerContextMenuRequested(const QPoint &pos) { - if (!mColumnCustomizable) { - return; - } - QMenu contextMenu(this); - QTreeWidgetItem *item = headerItem(); - int columnCount = item->columnCount(); - for (int column = 0; column < columnCount; ++column) { - QAction *action = contextMenu.addAction(QIcon(), item->text(column), this, SLOT(columnVisible())); - action->setCheckable(true); - action->setData(column); - action->setChecked(!isColumnHidden(column)); + if (mEnableColumnCustomize) { + QTreeWidgetItem *item = headerItem(); + int columnCount = item->columnCount(); + for (int column = 0; column < columnCount; ++column) { + QMap::const_iterator it = mColumnCustomizable.find(column); + if (it != mColumnCustomizable.end() && *it == false) { + continue; + } + QAction *action = contextMenu.addAction(QIcon(), item->text(column), this, SLOT(columnVisible())); + action->setCheckable(true); + action->setData(column); + action->setChecked(!isColumnHidden(column)); + } + } + + if (!mHeaderContextMenuActions.isEmpty()) { + bool addSeparator = false; + if (!contextMenu.isEmpty()) { + // Check for visible action + foreach (QAction *action, mHeaderContextMenuActions) { + if (action->isVisible()) { + addSeparator = true; + break; + } + } + } + + if (addSeparator) { + contextMenu.addSeparator(); + } + + contextMenu.addActions(mHeaderContextMenuActions); + } + + if (contextMenu.isEmpty()) { + return; } contextMenu.exec(mapToGlobal(pos)); @@ -184,3 +227,10 @@ void RSTreeWidget::columnVisible() emit columnVisibleChanged(column, visible); } + +void RSTreeWidget::resort() +{ + if (isSortingEnabled()) { + sortByColumn(header()->sortIndicatorSection(), header()->sortIndicatorOrder()); + } +} diff --git a/retroshare-gui/src/gui/common/RSTreeWidget.h b/retroshare-gui/src/gui/common/RSTreeWidget.h index 12c76ddf7..2261e836b 100644 --- a/retroshare-gui/src/gui/common/RSTreeWidget.h +++ b/retroshare-gui/src/gui/common/RSTreeWidget.h @@ -35,18 +35,25 @@ public: QString placeholderText() { return mPlaceholderText; } void setPlaceholderText(const QString &text); - void filterItems(int filterColumn, const QString &text); + void filterItems(int filterColumn, const QString &text, int role = Qt::DisplayRole); + void setSettingsVersion(qint32 version); void processSettings(bool load); - void setColumnCustomizable(bool customizable); + void enableColumnCustomize(bool customizable); + void setColumnCustomizable(int column, bool customizable); + + void resort(); + + // Add QAction to context menu (action won't be deleted) + void addHeaderContextMenuAction(QAction *action); signals: void signalMouseMiddleButtonClicked(QTreeWidgetItem *item); void columnVisibleChanged(int column, bool visible); private: - bool filterItem(QTreeWidgetItem *item, int filterColumn, const QString &text); + bool filterItem(QTreeWidgetItem *item, int filterColumn, const QString &text, int role); private slots: void headerContextMenuRequested(const QPoint &pos); @@ -58,7 +65,10 @@ protected: private: QString mPlaceholderText; - bool mColumnCustomizable; + bool mEnableColumnCustomize; + quint32 mSettingsVersion; + QMap mColumnCustomizable; + QList mHeaderContextMenuActions; }; #endif diff --git a/retroshare-gui/src/gui/common/StatusDefs.cpp b/retroshare-gui/src/gui/common/StatusDefs.cpp index 6ff7315a6..b0756c88f 100644 --- a/retroshare-gui/src/gui/common/StatusDefs.cpp +++ b/retroshare-gui/src/gui/common/StatusDefs.cpp @@ -86,15 +86,15 @@ const char *StatusDefs::imageStatus(unsigned int status) { switch (status) { case RS_STATUS_OFFLINE: - return ":/images/status/user-offline.png"; + return ":/icons/user-offline_64.png"; case RS_STATUS_AWAY: - return ":/images/status/user-away.png"; + return ":/icons/user-away_64.png"; case RS_STATUS_BUSY: - return ":/images/status/user-busy.png"; + return ":/icons/user-busy_64.png"; case RS_STATUS_ONLINE: - return ":/images/status/user-online.png"; + return ":/icons/user-online_64.png"; case RS_STATUS_INACTIVE: - return ":/images/status/user-away-extended.png"; + return ":/icons/user-away-extended_64.png"; } std::cerr << "StatusDefs::imageUser: Unknown status requested " << status; diff --git a/retroshare-gui/src/gui/connect/ConnectFriendWizard.cpp b/retroshare-gui/src/gui/connect/ConnectFriendWizard.cpp index fa4515af4..80aaf7698 100755 --- a/retroshare-gui/src/gui/connect/ConnectFriendWizard.cpp +++ b/retroshare-gui/src/gui/connect/ConnectFriendWizard.cpp @@ -77,7 +77,7 @@ ConnectFriendWizard::ConnectFriendWizard(QWidget *parent) : mTitleFontWeight = 0; // Standard // this define comes from Qt example. I don't have mac, so it wasn't tested -#ifndef Q_WS_MAC +#ifndef Q_OS_MAC setWizardStyle(ModernStyle); #endif @@ -568,7 +568,7 @@ void ConnectFriendWizard::initializePage(int id) static void sendMail(QString sAddress, QString sSubject, QString sBody) { -#ifdef Q_WS_WIN +#ifdef Q_OS_WIN /* search and replace the end of lines with: "%0D%0A" */ sBody.replace("\n", "%0D%0A"); #endif diff --git a/retroshare-gui/src/gui/gxs/GxsCommentDialog.cpp b/retroshare-gui/src/gui/gxs/GxsCommentDialog.cpp index aece38f77..cb97584b9 100644 --- a/retroshare-gui/src/gui/gxs/GxsCommentDialog.cpp +++ b/retroshare-gui/src/gui/gxs/GxsCommentDialog.cpp @@ -41,6 +41,10 @@ GxsCommentDialog::GxsCommentDialog(QWidget *parent, RsTokenService *token_servic //ui->postFrame->setVisible(false); ui->treeWidget->setup(token_service, comment_service); + + /* Set header resize modes and initial section sizes */ + QHeaderView * ttheader = ui->treeWidget->header () ; + ttheader->resizeSection (0, 440); /* fill in the available OwnIds for signing */ ui->idChooser->loadIds(IDCHOOSER_ID_REQUIRED, RsGxsId()); diff --git a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp index 71d60610f..cd873b6d0 100644 --- a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp +++ b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp @@ -73,6 +73,7 @@ GxsGroupFrameDialog::GxsGroupFrameDialog(RsGxsIfaceHelper *ifaceImpl, QWidget *p ui->setupUi(this); mInitialized = false; + mInFill = false; mCountChildMsgs = false; mYourGroups = NULL; mSubscribedGroups = NULL; @@ -555,6 +556,10 @@ GxsCommentDialog *GxsGroupFrameDialog::commentWidget(const RsGxsMessageId &msgId void GxsGroupFrameDialog::changedGroup(const QString &groupId) { + if (mInFill) { + return; + } + mGroupId = RsGxsGroupId(groupId.toStdString()); if (mGroupId.isNull()) { return; @@ -689,6 +694,8 @@ void GxsGroupFrameDialog::insertGroupsData(const std::list &gro return; } + mInFill = true; + std::list::const_iterator it; QList adminList; @@ -752,6 +759,8 @@ void GxsGroupFrameDialog::insertGroupsData(const std::list &gro ui->groupTreeWidget->fillGroupItems(mPopularGroups, popList); ui->groupTreeWidget->fillGroupItems(mOtherGroups, otherList); + mInFill = false; + /* Re-fill group */ if (!ui->groupTreeWidget->activateId(QString::fromStdString(mGroupId.toStdString()), true)) { mGroupId.clear(); diff --git a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h index 37d6ddd7b..db6e2bd38 100644 --- a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h +++ b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h @@ -175,6 +175,7 @@ protected: private: bool mInitialized; + bool mInFill; QString mSettingsName; RsGxsGroupId mGroupId; RsGxsIfaceHelper *mInterface; diff --git a/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp b/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp index cfc7eba1d..aab87ddf7 100644 --- a/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp +++ b/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp @@ -37,7 +37,7 @@ /* Images for tag icons */ #define IMAGE_LOADING ":/images/folder-draft.png" -#define IMAGE_PGPKNOWN ":/images/tags/pgp-known.png" +#define IMAGE_PGPKNOWN ":/images/contact.png" #define IMAGE_PGPUNKNOWN ":/images/tags/pgp-unknown.png" #define IMAGE_ANON ":/images/tags/anon.png" diff --git a/retroshare-gui/src/gui/gxs/GxsMessageFramePostWidget.cpp b/retroshare-gui/src/gui/gxs/GxsMessageFramePostWidget.cpp index 361910614..f9808a4d9 100644 --- a/retroshare-gui/src/gui/gxs/GxsMessageFramePostWidget.cpp +++ b/retroshare-gui/src/gui/gxs/GxsMessageFramePostWidget.cpp @@ -36,8 +36,8 @@ GxsMessageFramePostWidget::GxsMessageFramePostWidget(RsGxsIfaceHelper *ifaceImpl mFillThread = NULL; mTokenTypeGroupData = nextTokenType(); + mTokenTypeAllPosts = nextTokenType(); mTokenTypePosts = nextTokenType(); - mTokenTypeRelatedPosts = nextTokenType(); } GxsMessageFramePostWidget::~GxsMessageFramePostWidget() @@ -76,7 +76,7 @@ bool GxsMessageFramePostWidget::navigate(const RsGxsMessageId &msgId) return false; } - if (mStateHelper->isLoading(mTokenTypePosts) || mStateHelper->isLoading(mTokenTypeRelatedPosts)) { + if (mStateHelper->isLoading(mTokenTypeAllPosts) || mStateHelper->isLoading(mTokenTypePosts)) { mNavigatePendingMsgId = msgId; /* No information if group is available */ @@ -88,7 +88,7 @@ bool GxsMessageFramePostWidget::navigate(const RsGxsMessageId &msgId) bool GxsMessageFramePostWidget::isLoading() { - if (mStateHelper->isLoading(mTokenTypePosts) || mStateHelper->isLoading(mTokenTypeRelatedPosts)) { + if (mStateHelper->isLoading(mTokenTypeAllPosts) || mStateHelper->isLoading(mTokenTypePosts)) { return true; } @@ -100,7 +100,7 @@ void GxsMessageFramePostWidget::updateDisplay(bool complete) if (complete) { /* Fill complete */ requestGroupData(); - requestPosts(); + requestAllPosts(); return; } @@ -118,14 +118,14 @@ void GxsMessageFramePostWidget::updateDisplay(bool complete) if (!groupId().isNull() && std::find(grpIds.begin(), grpIds.end(), groupId()) != grpIds.end()) { updateGroup = true; /* Do we need to fill all posts? */ - requestPosts(); + requestAllPosts(); } else { std::map > msgs; getAllMsgIds(msgs); if (!msgs.empty()) { std::map >::const_iterator mit = msgs.find(groupId()); if (mit != msgs.end()) { - requestRelatedPosts(mit->second); + requestPosts(mit->second); } } } @@ -155,7 +155,7 @@ void GxsMessageFramePostWidget::fillThreadFinished() /* Current thread has finished */ mFillThread = NULL; - mStateHelper->setLoading(mTokenTypePosts, false); + mStateHelper->setLoading(mTokenTypeAllPosts, false); emit groupChanged(this); if (!mNavigatePendingMsgId.isNull()) { @@ -258,10 +258,10 @@ void GxsMessageFramePostWidget::loadGroupData(const uint32_t &token) emit groupChanged(this); } -void GxsMessageFramePostWidget::requestPosts() +void GxsMessageFramePostWidget::requestAllPosts() { #ifdef ENABLE_DEBUG - std::cerr << "GxsMessageFramePostWidget::requestPosts()"; + std::cerr << "GxsMessageFramePostWidget::requestAllPosts()"; std::cerr << std::endl; #endif @@ -269,7 +269,7 @@ void GxsMessageFramePostWidget::requestPosts() /* Request all posts */ - mTokenQueue->cancelActiveRequestTokens(mTokenTypePosts); + mTokenQueue->cancelActiveRequestTokens(mTokenTypeAllPosts); if (mFillThread) { /* Stop current fill thread */ @@ -277,20 +277,20 @@ void GxsMessageFramePostWidget::requestPosts() mFillThread = NULL; thread->stop(false); - mStateHelper->setLoading(mTokenTypePosts, false); + mStateHelper->setLoading(mTokenTypeAllPosts, false); } clearPosts(); if (groupId().isNull()) { - mStateHelper->setActive(mTokenTypePosts, false); - mStateHelper->setLoading(mTokenTypePosts, false); - mStateHelper->clear(mTokenTypePosts); + mStateHelper->setActive(mTokenTypeAllPosts, false); + mStateHelper->setLoading(mTokenTypeAllPosts, false); + mStateHelper->clear(mTokenTypeAllPosts); emit groupChanged(this); return; } - mStateHelper->setLoading(mTokenTypePosts, true); + mStateHelper->setLoading(mTokenTypeAllPosts, true); emit groupChanged(this); std::list groupIds; @@ -300,17 +300,17 @@ void GxsMessageFramePostWidget::requestPosts() opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA; uint32_t token; - mTokenQueue->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, groupIds, mTokenTypePosts); + mTokenQueue->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, groupIds, mTokenTypeAllPosts); } -void GxsMessageFramePostWidget::loadPosts(const uint32_t &token) +void GxsMessageFramePostWidget::loadAllPosts(const uint32_t &token) { #ifdef ENABLE_DEBUG - std::cerr << "GxsMessageFramePostWidget::loadPosts()"; + std::cerr << "GxsMessageFramePostWidget::loadAllPosts()"; std::cerr << std::endl; #endif - mStateHelper->setActive(mTokenTypePosts, true); + mStateHelper->setActive(mTokenTypeAllPosts, true); if (useThread()) { /* Create fill thread */ @@ -321,15 +321,15 @@ void GxsMessageFramePostWidget::loadPosts(const uint32_t &token) connect(mFillThread, SIGNAL(addPost(QVariant,bool,int,int)), this, SLOT(fillThreadAddPost(QVariant,bool,int,int)), Qt::BlockingQueuedConnection); #ifdef ENABLE_DEBUG - std::cerr << "GxsMessageFramePostWidget::loadPosts() Start fill thread" << std::endl; + std::cerr << "GxsMessageFramePostWidget::loadAllPosts() Start fill thread" << std::endl; #endif /* Start thread */ mFillThread->start(); } else { - insertPosts(token, NULL); + insertAllPosts(token, NULL); - mStateHelper->setLoading(mTokenTypePosts, false); + mStateHelper->setLoading(mTokenTypeAllPosts, false); if (!mNavigatePendingMsgId.isNull()) { navigate(mNavigatePendingMsgId); @@ -341,21 +341,21 @@ void GxsMessageFramePostWidget::loadPosts(const uint32_t &token) emit groupChanged(this); } -void GxsMessageFramePostWidget::requestRelatedPosts(const std::vector &msgIds) +void GxsMessageFramePostWidget::requestPosts(const std::vector &msgIds) { #ifdef ENABLE_DEBUG - std::cerr << "GxsMessageFramePostWidget::requestRelatedPosts()"; + std::cerr << "GxsMessageFramePostWidget::requestPosts()"; std::cerr << std::endl; #endif mNavigatePendingMsgId.clear(); - mTokenQueue->cancelActiveRequestTokens(mTokenTypeRelatedPosts); + mTokenQueue->cancelActiveRequestTokens(mTokenTypePosts); if (groupId().isNull()) { - mStateHelper->setActive(mTokenTypeRelatedPosts, false); - mStateHelper->setLoading(mTokenTypeRelatedPosts, false); - mStateHelper->clear(mTokenTypeRelatedPosts); + mStateHelper->setActive(mTokenTypePosts, false); + mStateHelper->setLoading(mTokenTypePosts, false); + mStateHelper->clear(mTokenTypePosts); emit groupChanged(this); return; } @@ -364,33 +364,30 @@ void GxsMessageFramePostWidget::requestRelatedPosts(const std::vectorsetLoading(mTokenTypeRelatedPosts, true); + mStateHelper->setLoading(mTokenTypePosts, true); emit groupChanged(this); RsTokReqOptions opts; - opts.mReqType = GXS_REQUEST_TYPE_MSG_RELATED_DATA; - opts.mOptions = RS_TOKREQOPT_MSG_VERSIONS; + opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA; uint32_t token; - std::vector relatedMsgIds; - for (std::vector::const_iterator msgIt = msgIds.begin(); msgIt != msgIds.end(); ++msgIt) { - relatedMsgIds.push_back(RsGxsGrpMsgIdPair(groupId(), *msgIt)); - } - mTokenQueue->requestMsgRelatedInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, relatedMsgIds, mTokenTypeRelatedPosts); + GxsMsgReq requestMsgIds; + requestMsgIds[groupId()] = msgIds; + mTokenQueue->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, requestMsgIds, mTokenTypePosts); } -void GxsMessageFramePostWidget::loadRelatedPosts(const uint32_t &token) +void GxsMessageFramePostWidget::loadPosts(const uint32_t &token) { #ifdef ENABLE_DEBUG - std::cerr << "GxsMessageFramePostWidget::loadRelatedPosts()"; + std::cerr << "GxsMessageFramePostWidget::loadPosts()"; std::cerr << std::endl; #endif - mStateHelper->setActive(mTokenTypeRelatedPosts, true); + mStateHelper->setActive(mTokenTypePosts, true); - insertRelatedPosts(token); + insertPosts(token); - mStateHelper->setLoading(mTokenTypeRelatedPosts, false); + mStateHelper->setLoading(mTokenTypePosts, false); emit groupChanged(this); if (!mNavigatePendingMsgId.isNull()) { @@ -414,13 +411,13 @@ void GxsMessageFramePostWidget::loadRequest(const TokenQueue *queue, const Token return; } - if (req.mUserType == mTokenTypePosts) { - loadPosts(req.mToken); + if (req.mUserType == mTokenTypeAllPosts) { + loadAllPosts(req.mToken); return; } - if (req.mUserType == mTokenTypeRelatedPosts) { - loadRelatedPosts(req.mToken); + if (req.mUserType == mTokenTypePosts) { + loadPosts(req.mToken); return; } } @@ -465,7 +462,7 @@ void GxsMessageFramePostThread::run() std::cerr << "GxsMessageFramePostThread::run()" << std::endl; #endif - mParent->insertPosts(mToken, this); + mParent->insertAllPosts(mToken, this); #ifdef ENABLE_DEBUG std::cerr << "GxsMessageFramePostThread::run() stopped: " << (stopped() ? "yes" : "no") << std::endl; diff --git a/retroshare-gui/src/gui/gxs/GxsMessageFramePostWidget.h b/retroshare-gui/src/gui/gxs/GxsMessageFramePostWidget.h index 2b9e54fa1..d01a0ca42 100644 --- a/retroshare-gui/src/gui/gxs/GxsMessageFramePostWidget.h +++ b/retroshare-gui/src/gui/gxs/GxsMessageFramePostWidget.h @@ -68,13 +68,13 @@ protected: void loadGroupData(const uint32_t &token); virtual bool insertGroupData(const uint32_t &token, RsGroupMetaData &metaData) = 0; - void requestPosts(); - void loadPosts(const uint32_t &token); - virtual void insertPosts(const uint32_t &token, GxsMessageFramePostThread *thread) = 0; + void requestAllPosts(); + void loadAllPosts(const uint32_t &token); + virtual void insertAllPosts(const uint32_t &token, GxsMessageFramePostThread *thread) = 0; - void requestRelatedPosts(const std::vector &msgIds); - void loadRelatedPosts(const uint32_t &token); - virtual void insertRelatedPosts(const uint32_t &token) = 0; + void requestPosts(const std::vector &msgIds); + void loadPosts(const uint32_t &token); + virtual void insertPosts(const uint32_t &token) = 0; private slots: void fillThreadFinished(); @@ -82,8 +82,8 @@ private slots: protected: uint32_t mTokenTypeGroupData; + uint32_t mTokenTypeAllPosts; uint32_t mTokenTypePosts; - uint32_t mTokenTypeRelatedPosts; RsGxsMessageId mNavigatePendingMsgId; private: diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.cpp index bf9ef2fdd..e6ddc8b8a 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.cpp @@ -55,11 +55,11 @@ GxsChannelPostsWidget::GxsChannelPostsWidget(const RsGxsGroupId &channelId, QWid /* Setup UI helper */ - mStateHelper->addWidget(mTokenTypePosts, ui->progressBar, UISTATE_LOADING_VISIBLE); - mStateHelper->addWidget(mTokenTypePosts, ui->loadingLabel, UISTATE_LOADING_VISIBLE); - mStateHelper->addWidget(mTokenTypePosts, ui->filterLineEdit); + mStateHelper->addWidget(mTokenTypeAllPosts, ui->progressBar, UISTATE_LOADING_VISIBLE); + mStateHelper->addWidget(mTokenTypeAllPosts, ui->loadingLabel, UISTATE_LOADING_VISIBLE); + mStateHelper->addWidget(mTokenTypeAllPosts, ui->filterLineEdit); - mStateHelper->addWidget(mTokenTypeRelatedPosts, ui->loadingLabel, UISTATE_LOADING_VISIBLE); + mStateHelper->addWidget(mTokenTypePosts, ui->loadingLabel, UISTATE_LOADING_VISIBLE); mStateHelper->addLoadPlaceholder(mTokenTypeGroupData, ui->nameLabel); @@ -175,7 +175,7 @@ void GxsChannelPostsWidget::groupNameChanged(const QString &name) QIcon GxsChannelPostsWidget::groupIcon() { - if (mStateHelper->isLoading(mTokenTypeGroupData) || mStateHelper->isLoading(mTokenTypePosts)) { + if (mStateHelper->isLoading(mTokenTypeGroupData) || mStateHelper->isLoading(mTokenTypeAllPosts)) { return QIcon(":/images/kalarm.png"); } @@ -488,7 +488,7 @@ bool GxsChannelPostsWidget::insertGroupData(const uint32_t &token, RsGroupMetaDa return false; } -void GxsChannelPostsWidget::insertPosts(const uint32_t &token, GxsMessageFramePostThread *thread) +void GxsChannelPostsWidget::insertAllPosts(const uint32_t &token, GxsMessageFramePostThread *thread) { std::vector posts; rsGxsChannels->getPostData(token, posts); @@ -496,10 +496,10 @@ void GxsChannelPostsWidget::insertPosts(const uint32_t &token, GxsMessageFramePo insertChannelPosts(posts, thread, false); } -void GxsChannelPostsWidget::insertRelatedPosts(const uint32_t &token) +void GxsChannelPostsWidget::insertPosts(const uint32_t &token) { std::vector posts; - rsGxsChannels->getRelatedPosts(token, posts); + rsGxsChannels->getPostData(token, posts); insertChannelPosts(posts, NULL, true); } diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.h index eb537f3f0..541fcc506 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.h @@ -67,8 +67,8 @@ protected: /* GxsMessageFramePostWidget */ virtual void groupNameChanged(const QString &name); virtual bool insertGroupData(const uint32_t &token, RsGroupMetaData &metaData); - virtual void insertPosts(const uint32_t &token, GxsMessageFramePostThread *thread); - virtual void insertRelatedPosts(const uint32_t &token); + virtual void insertAllPosts(const uint32_t &token, GxsMessageFramePostThread *thread); + virtual void insertPosts(const uint32_t &token); virtual void clearPosts(); virtual bool useThread() { return mUseThread; } virtual void fillThreadCreatePost(const QVariant &post, bool related, int current, int count); diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 676f400fb..e51527860 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -206,6 +206,7 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget ui->subscribeToolButton->setToolTip(tr("

Subscribing to the forum will gather \ available posts from your subscribed friends, and make the \ forum visible to all other friends.

Afterwards you can unsubscribe from the context menu of the forum list at left.

")); + ui->threadTreeWidget->enableColumnCustomize(true); } GxsForumThreadWidget::~GxsForumThreadWidget() diff --git a/retroshare-gui/src/gui/help/browser/helpbrowser.cpp b/retroshare-gui/src/gui/help/browser/helpbrowser.cpp index 333a80f69..46f88da3c 100644 --- a/retroshare-gui/src/gui/help/browser/helpbrowser.cpp +++ b/retroshare-gui/src/gui/help/browser/helpbrowser.cpp @@ -58,10 +58,10 @@ HelpBrowser::HelpBrowser(QWidget *parent) { /* Invoke Qt Designer generated QObject setup routine */ ui.setupUi(this); -#if defined(Q_WS_MAC) +#if defined(Q_OS_MAC) ui.actionHome->setShortcut(QString("Shift+Ctrl+H")); #endif -#if !defined(Q_WS_WIN) +#if !defined(Q_OS_WIN) ui.actionClose->setShortcut(QString("Ctrl+W")); #endif diff --git a/retroshare-gui/src/gui/help/version.html.in b/retroshare-gui/src/gui/help/version.html.in new file mode 100644 index 000000000..189d71df2 --- /dev/null +++ b/retroshare-gui/src/gui/help/version.html.in @@ -0,0 +1,4 @@ +Retroshare Gui version : +Git version : $Branch$ +$Hash$ +$Date$ \ No newline at end of file diff --git a/retroshare-gui/src/gui/icons.qrc b/retroshare-gui/src/gui/icons.qrc index 23fe2dbc0..8840c6087 100644 --- a/retroshare-gui/src/gui/icons.qrc +++ b/retroshare-gui/src/gui/icons.qrc @@ -55,5 +55,10 @@ icons/tile_downloaded_48.png icons/tile_downloading_48.png icons/tile_inactive_48.png + icons/user-away_64.png + icons/user-away-extended_64.png + icons/user-busy_64.png + icons/user-offline_64.png + icons/user-online_64.png diff --git a/retroshare-gui/src/gui/icons/user-away-extended_64.png b/retroshare-gui/src/gui/icons/user-away-extended_64.png new file mode 100644 index 000000000..e89dfde78 Binary files /dev/null and b/retroshare-gui/src/gui/icons/user-away-extended_64.png differ diff --git a/retroshare-gui/src/gui/icons/user-away_64.png b/retroshare-gui/src/gui/icons/user-away_64.png new file mode 100644 index 000000000..0f1334187 Binary files /dev/null and b/retroshare-gui/src/gui/icons/user-away_64.png differ diff --git a/retroshare-gui/src/gui/icons/user-busy_64.png b/retroshare-gui/src/gui/icons/user-busy_64.png new file mode 100644 index 000000000..fa2f3d0ad Binary files /dev/null and b/retroshare-gui/src/gui/icons/user-busy_64.png differ diff --git a/retroshare-gui/src/gui/icons/user-offline_64.png b/retroshare-gui/src/gui/icons/user-offline_64.png new file mode 100644 index 000000000..577b102d9 Binary files /dev/null and b/retroshare-gui/src/gui/icons/user-offline_64.png differ diff --git a/retroshare-gui/src/gui/icons/user-online_64.png b/retroshare-gui/src/gui/icons/user-online_64.png new file mode 100644 index 000000000..68d6fd1af Binary files /dev/null and b/retroshare-gui/src/gui/icons/user-online_64.png differ diff --git a/retroshare-gui/src/gui/im_history/ImHistoryBrowser.cpp b/retroshare-gui/src/gui/im_history/ImHistoryBrowser.cpp index 6e49396ef..f2d15a8c6 100644 --- a/retroshare-gui/src/gui/im_history/ImHistoryBrowser.cpp +++ b/retroshare-gui/src/gui/im_history/ImHistoryBrowser.cpp @@ -36,6 +36,7 @@ #include "rshare.h" #include +#include #include "gui/settings/rsharesettings.h" #include "gui/notifyqt.h" @@ -272,7 +273,19 @@ void ImHistoryBrowser::fillItem(QListWidgetItem *itemWidget, HistoryMsg& msg) } QString messageText = RsHtml().formatText(NULL, QString::fromUtf8(msg.message.c_str()), formatTextFlag); - QString formatMsg = style.formatMessage(type, QString::fromUtf8(msg.peerName.c_str()), QDateTime::fromTime_t(msg.sendTime), messageText); + + QString name; + if (m_chatId.isLobbyId() || m_chatId.isGxsId()) { + RsIdentityDetails details; + if (rsIdentity->getIdDetails(RsGxsId(msg.peerName), details)) + name = QString::fromUtf8(details.mNickname.c_str()); + else + name = QString::fromUtf8(msg.peerName.c_str()); + } else { + name = QString::fromUtf8(msg.peerName.c_str()); + } + + QString formatMsg = style.formatMessage(type, name, QDateTime::fromTime_t(msg.sendTime), messageText); itemWidget->setData(Qt::DisplayRole, qVariantFromValue(IMHistoryItemPainter(formatMsg))); itemWidget->setData(ROLE_MSGID, msg.msgId); diff --git a/retroshare-gui/src/gui/images.qrc b/retroshare-gui/src/gui/images.qrc index 924ba4f6a..de22823e7 100644 --- a/retroshare-gui/src/gui/images.qrc +++ b/retroshare-gui/src/gui/images.qrc @@ -60,10 +60,7 @@ images/btn_green.png images/btn_green_hover.png images/btn_green_pressed.png - images/connect_established.png - images/connect_established_low.png images/connect_creating.png - images/connect_no.png images/dht16.png images/dht32.png images/edit-clear-history.png @@ -424,7 +421,6 @@ images/replymail-pressed.png images/replymail24.png images/replymailall24-hover.png - images/reload24.png images/reset.png images/resume.png images/security-high-16.png @@ -694,11 +690,6 @@ images/tags/dev-translator.png images/tags/dev-patcher.png images/tags/developer.png - images/status/user-online.png - images/status/user-offline.png - images/status/user-busy.png - images/status/user-away-extended.png - images/status/user-away.png images/circles/circles_32.png images/circles/circles_64.png images/newsfeed/news-feed-32.png diff --git a/retroshare-gui/src/gui/images/connect_established.png b/retroshare-gui/src/gui/images/connect_established.png deleted file mode 100644 index 2c45f9d86..000000000 Binary files a/retroshare-gui/src/gui/images/connect_established.png and /dev/null differ diff --git a/retroshare-gui/src/gui/images/connect_established_low.png b/retroshare-gui/src/gui/images/connect_established_low.png deleted file mode 100644 index 75ad75032..000000000 Binary files a/retroshare-gui/src/gui/images/connect_established_low.png and /dev/null differ diff --git a/retroshare-gui/src/gui/images/connect_no.png b/retroshare-gui/src/gui/images/connect_no.png deleted file mode 100644 index 9605f62f5..000000000 Binary files a/retroshare-gui/src/gui/images/connect_no.png and /dev/null differ diff --git a/retroshare-gui/src/gui/images/reload24.png b/retroshare-gui/src/gui/images/reload24.png deleted file mode 100644 index be0e77052..000000000 Binary files a/retroshare-gui/src/gui/images/reload24.png and /dev/null differ diff --git a/retroshare-gui/src/gui/images/retroshare_win.rc b/retroshare-gui/src/gui/images/retroshare_win.rc index 404d6ecd2..76840ad79 100644 --- a/retroshare-gui/src/gui/images/retroshare_win.rc +++ b/retroshare-gui/src/gui/images/retroshare_win.rc @@ -5,11 +5,11 @@ IDI_ICON1 ICON "logo/logo_64.ico" #define STRINGIZER(version) #version -#define VERSION_STRING(major,minor,build,buildadd,revision) STRINGIZER(major) "." STRINGIZER(minor) "." STRINGIZER(build) buildadd "." STRINGIZER(revision) +#define VERSION_STRING(major,minor,build,buildadd,revision) STRINGIZER(major) "." STRINGIZER(minor) "." STRINGIZER(build) buildadd "." revision VS_VERSION_INFO VERSIONINFO -FILEVERSION RS_MAJOR_VERSION,RS_MINOR_VERSION,RS_BUILD_NUMBER,RS_REVISION_NUMBER -PRODUCTVERSION RS_MAJOR_VERSION,RS_MINOR_VERSION,RS_BUILD_NUMBER,RS_REVISION_NUMBER +FILEVERSION RS_MAJOR_VERSION,RS_MINOR_VERSION,RS_BUILD_NUMBER,0 +PRODUCTVERSION RS_MAJOR_VERSION,RS_MINOR_VERSION,RS_BUILD_NUMBER,0 FILEFLAGSMASK VS_FFI_FILEFLAGSMASK FILEFLAGS 0 FILEOS VOS_NT_WINDOWS32 @@ -22,11 +22,11 @@ BEGIN BEGIN VALUE "CompanyName", "" VALUE "FileDescription", "RetroShare" - VALUE "FileVersion", VERSION_STRING(RS_MAJOR_VERSION, RS_MINOR_VERSION, RS_BUILD_NUMBER, RS_BUILD_NUMBER_ADD, RS_REVISION_NUMBER) + VALUE "FileVersion", VERSION_STRING(RS_MAJOR_VERSION, RS_MINOR_VERSION, RS_BUILD_NUMBER, RS_BUILD_NUMBER_ADD, RS_REVISION_STRING) VALUE "InternalName", "RetroShare" VALUE "OriginalFilename", "RetroShare.exe" VALUE "ProductName", "RetroShare" - VALUE "ProductVersion", VERSION_STRING(RS_MAJOR_VERSION, RS_MINOR_VERSION, RS_BUILD_NUMBER, RS_BUILD_NUMBER_ADD, RS_REVISION_NUMBER) + VALUE "ProductVersion", VERSION_STRING(RS_MAJOR_VERSION, RS_MINOR_VERSION, RS_BUILD_NUMBER, RS_BUILD_NUMBER_ADD, RS_REVISION_STRING) VALUE "LegalCopyright", "" END END diff --git a/retroshare-gui/src/gui/images/status/user-away-extended.png b/retroshare-gui/src/gui/images/status/user-away-extended.png deleted file mode 100644 index e348a3060..000000000 Binary files a/retroshare-gui/src/gui/images/status/user-away-extended.png and /dev/null differ diff --git a/retroshare-gui/src/gui/images/status/user-away.png b/retroshare-gui/src/gui/images/status/user-away.png deleted file mode 100644 index 041e75868..000000000 Binary files a/retroshare-gui/src/gui/images/status/user-away.png and /dev/null differ diff --git a/retroshare-gui/src/gui/images/status/user-busy.png b/retroshare-gui/src/gui/images/status/user-busy.png deleted file mode 100644 index 85453b4e4..000000000 Binary files a/retroshare-gui/src/gui/images/status/user-busy.png and /dev/null differ diff --git a/retroshare-gui/src/gui/images/status/user-offline.png b/retroshare-gui/src/gui/images/status/user-offline.png deleted file mode 100644 index d896ddf92..000000000 Binary files a/retroshare-gui/src/gui/images/status/user-offline.png and /dev/null differ diff --git a/retroshare-gui/src/gui/images/status/user-online.png b/retroshare-gui/src/gui/images/status/user-online.png deleted file mode 100644 index 829ab55af..000000000 Binary files a/retroshare-gui/src/gui/images/status/user-online.png and /dev/null differ diff --git a/retroshare-gui/src/gui/msgs/MessageComposer.cpp b/retroshare-gui/src/gui/msgs/MessageComposer.cpp index 08ff494ea..16c58a20c 100644 --- a/retroshare-gui/src/gui/msgs/MessageComposer.cpp +++ b/retroshare-gui/src/gui/msgs/MessageComposer.cpp @@ -128,6 +128,7 @@ MessageComposer::MessageComposer(QWidget *parent, Qt::WindowFlags flags) setupEditActions(); setupViewActions(); setupInsertActions(); + setupContactActions(); m_compareRole = new RSTreeWidgetItemCompareRole; m_compareRole->setRole(COLUMN_CONTACT_NAME, ROLE_CONTACT_SORT); @@ -210,8 +211,8 @@ MessageComposer::MessageComposer(QWidget *parent, Qt::WindowFlags flags) connect(NotifyQt::getInstance(), SIGNAL(peerStatusChanged(const QString&,int)), this, SLOT(peerStatusChanged(const QString&,int))); connect(ui.friendSelectionWidget, SIGNAL(contentChanged()), this, SLOT(buildCompleter())); - connect(ui.friendSelectionWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenuMsgSendList(QPoint))); connect(ui.friendSelectionWidget, SIGNAL(doubleClicked(int,QString)), this, SLOT(addTo())); + connect(ui.friendSelectionWidget, SIGNAL(itemSelectionChanged()), this, SLOT(friendSelectionChanged())); /* hide the Tree +/- */ ui.msgFileList -> setRootIsDecorated( false ); @@ -698,35 +699,6 @@ void MessageComposer::contextMenuFileList(QPoint) contextMnu.exec(QCursor::pos()); } -void MessageComposer::contextMenuMsgSendList(QPoint) -{ - QMenu contextMnu(this); - - int selectedCount = ui.friendSelectionWidget->selectedItemCount(); - - FriendSelectionWidget::IdType idType; - ui.friendSelectionWidget->selectedId(idType); - - QAction *action = contextMnu.addAction(QIcon(), tr("Add to \"To\""), this, SLOT(addTo())); - action->setEnabled(selectedCount); - action = contextMnu.addAction(QIcon(), tr("Add to \"CC\""), this, SLOT(addCc())); - action->setEnabled(selectedCount); - action = contextMnu.addAction(QIcon(), tr("Add to \"BCC\""), this, SLOT(addBcc())); - action->setEnabled(selectedCount); - action = contextMnu.addAction(QIcon(), tr("Add as Recommend"), this, SLOT(addRecommend())); - action->setEnabled(selectedCount); - - contextMnu.addSeparator(); - - action = contextMnu.addAction(QIcon(IMAGE_FRIENDINFO), tr("Friend Details"), this, SLOT(friendDetails())); - action->setEnabled(selectedCount == 1 && idType == FriendSelectionWidget::IDTYPE_SSL); - - action = contextMnu.addAction(QIcon(), tr("Person Details"), this, SLOT(identityDetails())); - action->setEnabled(selectedCount == 1 && idType == FriendSelectionWidget::IDTYPE_GXS); - - contextMnu.exec(QCursor::pos()); -} - void MessageComposer::pasteRecommended() { QList links; @@ -2009,6 +1981,31 @@ void MessageComposer::setupFormatActions() } +void MessageComposer::setupContactActions() +{ + mActionAddTo = new QAction(tr("Add to \"To\""), this); + connect(mActionAddTo, SIGNAL(triggered(bool)), this, SLOT(addTo())); + mActionAddCC = new QAction(tr("Add to \"CC\""), this); + connect(mActionAddCC, SIGNAL(triggered(bool)), this, SLOT(addCc())); + mActionAddBCC = new QAction(tr("Add to \"BCC\""), this); + connect(mActionAddBCC, SIGNAL(triggered(bool)), this, SLOT(addBcc())); + mActionAddRecommend = new QAction(tr("Add as Recommend"), this); + connect(mActionAddRecommend, SIGNAL(triggered(bool)), this, SLOT(addRecommend())); + mActionContactDetails = new QAction(QIcon(IMAGE_FRIENDINFO), tr("Details"), this); + connect(mActionContactDetails, SIGNAL(triggered(bool)), this, SLOT(contactDetails())); + + ui.friendSelectionWidget->addContextMenuAction(mActionAddTo); + ui.friendSelectionWidget->addContextMenuAction(mActionAddCC); + ui.friendSelectionWidget->addContextMenuAction(mActionAddBCC); + ui.friendSelectionWidget->addContextMenuAction(mActionAddRecommend); + + QAction *action = new QAction(this); + action->setSeparator(true); + ui.friendSelectionWidget->addContextMenuAction(action); + + ui.friendSelectionWidget->addContextMenuAction(mActionContactDetails); +} + void MessageComposer::textBold() { QTextCharFormat fmt; @@ -2577,6 +2574,27 @@ void MessageComposer::filterComboBoxChanged(int i) } +void MessageComposer::friendSelectionChanged() +{ + std::set peerIds; + ui.friendSelectionWidget->selectedIds(peerIds, false); + + std::set gxsIds; + ui.friendSelectionWidget->selectedIds(gxsIds, false); + + int selectedCount = peerIds.size() + gxsIds.size(); + + mActionAddTo->setEnabled(selectedCount); + mActionAddCC->setEnabled(selectedCount); + mActionAddBCC->setEnabled(selectedCount); + mActionAddRecommend->setEnabled(selectedCount); + + FriendSelectionWidget::IdType idType; + ui.friendSelectionWidget->selectedId(idType); + + mActionContactDetails->setEnabled(selectedCount == 1 && (idType == FriendSelectionWidget::IDTYPE_SSL || idType == FriendSelectionWidget::IDTYPE_GXS)); +} + void MessageComposer::addTo() { addContact(TO); @@ -2613,35 +2631,37 @@ void MessageComposer::addRecommend() ui.msgText->setFocus(Qt::OtherFocusReason); } -void MessageComposer::friendDetails() +void MessageComposer::contactDetails() { FriendSelectionWidget::IdType idType; std::string id = ui.friendSelectionWidget->selectedId(idType); - if (id.empty() || idType != FriendSelectionWidget::IDTYPE_SSL) { + if (id.empty()) { return; } - ConfCertDialog::showIt(RsPeerId(id), ConfCertDialog::PageDetails); -} + switch (idType) { + case FriendSelectionWidget::IDTYPE_NONE: + case FriendSelectionWidget::IDTYPE_GROUP: + case FriendSelectionWidget::IDTYPE_GPG: + break; + case FriendSelectionWidget::IDTYPE_SSL: + ConfCertDialog::showIt(RsPeerId(id), ConfCertDialog::PageDetails); + break; + case FriendSelectionWidget::IDTYPE_GXS: + { + if (RsGxsGroupId(id).isNull()) { + return; + } -void MessageComposer::identityDetails() -{ - FriendSelectionWidget::IdType idType; - std::string id = ui.friendSelectionWidget->selectedId(idType); + IdDetailsDialog *dialog = new IdDetailsDialog(RsGxsGroupId(id)); + dialog->show(); - if (id.empty() || idType != FriendSelectionWidget::IDTYPE_GXS) { - return; + /* Dialog will destroy itself */ + } + break; } - if (RsGxsGroupId(id).isNull()) { - return; - } - - IdDetailsDialog *dialog = new IdDetailsDialog(RsGxsGroupId(id)); - dialog->show(); - - /* Dialog will destroy itself */ } void MessageComposer::tagAboutToShow() diff --git a/retroshare-gui/src/gui/msgs/MessageComposer.h b/retroshare-gui/src/gui/msgs/MessageComposer.h index 6f2811730..ad286d858 100644 --- a/retroshare-gui/src/gui/msgs/MessageComposer.h +++ b/retroshare-gui/src/gui/msgs/MessageComposer.h @@ -97,7 +97,6 @@ protected: private slots: /* toggle Contacts DockWidget */ void contextMenuFileList(QPoint); - void contextMenuMsgSendList(QPoint); void pasteRecommended(); void on_contactsdockWidget_visibilityChanged(bool visible); void toggleContacts(); @@ -153,10 +152,10 @@ private slots: void addBcc(); void addRecommend(); void editingRecipientFinished(); - void friendDetails(); - void identityDetails(); + void contactDetails(); void peerStatusChanged(const QString& peer_id, int status); + void friendSelectionChanged(); void tagAboutToShow(); void tagSet(int tagId, bool set); @@ -179,6 +178,7 @@ private: void setupViewActions(); void setupInsertActions(); void setupFormatActions(); + void setupContactActions(); bool load(const QString &f); bool maybeSave(); @@ -222,6 +222,11 @@ private: *actionUpperRoman; QAction *contactSidebarAction; + QAction *mActionAddTo; + QAction *mActionAddCC; + QAction *mActionAddBCC; + QAction *mActionAddRecommend; + QAction *mActionContactDetails; QTreeView *channelstreeView; diff --git a/retroshare-gui/src/gui/notifyqt.cpp b/retroshare-gui/src/gui/notifyqt.cpp index 9e32b09bf..a6b8b5457 100644 --- a/retroshare-gui/src/gui/notifyqt.cpp +++ b/retroshare-gui/src/gui/notifyqt.cpp @@ -29,6 +29,7 @@ #include "notifyqt.h" #include #include +#include #include #include "RsAutoUpdatePage.h" @@ -862,28 +863,23 @@ void NotifyQt::UpdateGUI() case RS_POPUP_CHATLOBBY: if ((popupflags & RS_POPUP_CHATLOBBY) && !_disableAllToaster) { - if(RsPeerId::SIZE_IN_BYTES < sizeof(ChatLobbyId)) - { - std::cerr << "NotifyQt::UpdateGUI() Error: ChatLobbyId does not fit into a RsPeerId, this should not happen!" << std::endl; - break; - } - RsPeerId vpid(id); // create virtual peer id - ChatLobbyId lobby_id; - // copy first bytes of virtual peer id, to make a chat lobby id - memcpy(&lobby_id, vpid.toByteArray(), sizeof(ChatLobbyId)); + ChatLobbyId lobby_id; + if(!rsMsgs->isLobbyId(RsPeerId(id), lobby_id)) + break; - ChatDialog *chatDialog = ChatDialog::getChat(ChatId(lobby_id)); - ChatWidget *chatWidget; + ChatDialog *chatDialog = ChatDialog::getChat(ChatId(lobby_id)); + ChatWidget *chatWidget; if (chatDialog && (chatWidget = chatDialog->getChatWidget()) && chatWidget->isActive()) { // do not show when active break; } ChatLobbyDialog *chatLobbyDialog = dynamic_cast(chatDialog); - if (!chatLobbyDialog || chatLobbyDialog->isParticipantMuted(RsGxsId(title))) + RsGxsId sender(title); + if (!chatLobbyDialog || chatLobbyDialog->isParticipantMuted(sender)) break; // participant is muted - toaster = new ToasterItem(new ChatLobbyToaster(lobby_id, QString::fromUtf8(title.c_str()), QString::fromUtf8(msg.c_str()))); + toaster = new ToasterItem(new ChatLobbyToaster(lobby_id, sender, QString::fromUtf8(msg.c_str()))); } break; case RS_POPUP_CONNECT_ATTEMPT: @@ -1002,8 +998,13 @@ void NotifyQt::testToasters(uint notifyFlags, /*RshareSettings::enumToasterPosit toaster = new ToasterItem(new GroupChatToaster(id, message)); break; case RS_POPUP_CHATLOBBY: - toaster = new ToasterItem(new ChatLobbyToaster(0, title, message)); - break; + { + std::list gxsid; + if(rsIdentity->getOwnIds(gxsid) && (gxsid.size() > 0)){ + toaster = new ToasterItem(new ChatLobbyToaster(0, gxsid.front(), message)); + } + break; + } case RS_POPUP_CONNECT_ATTEMPT: toaster = new ToasterItem(new FriendRequestToaster(pgpid, title, id)); break; diff --git a/retroshare-gui/src/gui/qss/chat/Bubble/history/img/bubble-blue/Thumbs.db b/retroshare-gui/src/gui/qss/chat/Bubble/history/img/bubble-blue/Thumbs.db deleted file mode 100644 index 51fc0dd9b..000000000 Binary files a/retroshare-gui/src/gui/qss/chat/Bubble/history/img/bubble-blue/Thumbs.db and /dev/null differ diff --git a/retroshare-gui/src/gui/qss/chat/Bubble/history/img/bubble-green/Thumbs.db b/retroshare-gui/src/gui/qss/chat/Bubble/history/img/bubble-green/Thumbs.db deleted file mode 100644 index 45743db64..000000000 Binary files a/retroshare-gui/src/gui/qss/chat/Bubble/history/img/bubble-green/Thumbs.db and /dev/null differ diff --git a/retroshare-gui/src/gui/qss/chat/Bubble/history/img/bubble-grey/Thumbs.db b/retroshare-gui/src/gui/qss/chat/Bubble/history/img/bubble-grey/Thumbs.db deleted file mode 100644 index 661167ad7..000000000 Binary files a/retroshare-gui/src/gui/qss/chat/Bubble/history/img/bubble-grey/Thumbs.db and /dev/null differ diff --git a/retroshare-gui/src/gui/qss/chat/Bubble/history/img/bubble-orange/Thumbs.db b/retroshare-gui/src/gui/qss/chat/Bubble/history/img/bubble-orange/Thumbs.db deleted file mode 100644 index 176321443..000000000 Binary files a/retroshare-gui/src/gui/qss/chat/Bubble/history/img/bubble-orange/Thumbs.db and /dev/null differ diff --git a/retroshare-gui/src/gui/qss/chat/Bubble/history/img/bubble-red/Thumbs.db b/retroshare-gui/src/gui/qss/chat/Bubble/history/img/bubble-red/Thumbs.db deleted file mode 100644 index 29c215386..000000000 Binary files a/retroshare-gui/src/gui/qss/chat/Bubble/history/img/bubble-red/Thumbs.db and /dev/null differ diff --git a/retroshare-gui/src/gui/qss/chat/Bubble/private/img/bubble-blue/Thumbs.db b/retroshare-gui/src/gui/qss/chat/Bubble/private/img/bubble-blue/Thumbs.db deleted file mode 100644 index ec9d60af8..000000000 Binary files a/retroshare-gui/src/gui/qss/chat/Bubble/private/img/bubble-blue/Thumbs.db and /dev/null differ diff --git a/retroshare-gui/src/gui/qss/chat/Bubble/private/img/bubble-green/Thumbs.db b/retroshare-gui/src/gui/qss/chat/Bubble/private/img/bubble-green/Thumbs.db deleted file mode 100644 index 92364f5a4..000000000 Binary files a/retroshare-gui/src/gui/qss/chat/Bubble/private/img/bubble-green/Thumbs.db and /dev/null differ diff --git a/retroshare-gui/src/gui/qss/chat/Bubble/private/img/bubble-grey/Thumbs.db b/retroshare-gui/src/gui/qss/chat/Bubble/private/img/bubble-grey/Thumbs.db deleted file mode 100644 index 5414352a9..000000000 Binary files a/retroshare-gui/src/gui/qss/chat/Bubble/private/img/bubble-grey/Thumbs.db and /dev/null differ diff --git a/retroshare-gui/src/gui/qss/chat/Bubble/private/img/bubble-orange/Thumbs.db b/retroshare-gui/src/gui/qss/chat/Bubble/private/img/bubble-orange/Thumbs.db deleted file mode 100644 index 06ecfb908..000000000 Binary files a/retroshare-gui/src/gui/qss/chat/Bubble/private/img/bubble-orange/Thumbs.db and /dev/null differ diff --git a/retroshare-gui/src/gui/qss/chat/Bubble/private/img/bubble-red/Thumbs.db b/retroshare-gui/src/gui/qss/chat/Bubble/private/img/bubble-red/Thumbs.db deleted file mode 100644 index ee2b09435..000000000 Binary files a/retroshare-gui/src/gui/qss/chat/Bubble/private/img/bubble-red/Thumbs.db and /dev/null differ diff --git a/retroshare-gui/src/gui/qss/chat/Bubble/private/system.htm b/retroshare-gui/src/gui/qss/chat/Bubble/private/system.htm index 103d2bca1..ec98b3b43 100644 --- a/retroshare-gui/src/gui/qss/chat/Bubble/private/system.htm +++ b/retroshare-gui/src/gui/qss/chat/Bubble/private/system.htm @@ -3,21 +3,35 @@ - +
+ + - - - + + + - - - + + + - - - + + +
%name% %time% - %message% + %message% +
+ + + + +
+   %name% - + %time% +
+ +
diff --git a/retroshare-gui/src/gui/qss/chat/Bubble/public/img/bubble-blue/Thumbs.db b/retroshare-gui/src/gui/qss/chat/Bubble/public/img/bubble-blue/Thumbs.db deleted file mode 100644 index 263562c46..000000000 Binary files a/retroshare-gui/src/gui/qss/chat/Bubble/public/img/bubble-blue/Thumbs.db and /dev/null differ diff --git a/retroshare-gui/src/gui/qss/chat/Bubble/public/img/bubble-green/Thumbs.db b/retroshare-gui/src/gui/qss/chat/Bubble/public/img/bubble-green/Thumbs.db deleted file mode 100644 index 17ff6a294..000000000 Binary files a/retroshare-gui/src/gui/qss/chat/Bubble/public/img/bubble-green/Thumbs.db and /dev/null differ diff --git a/retroshare-gui/src/gui/qss/chat/Bubble/public/img/bubble-grey/Thumbs.db b/retroshare-gui/src/gui/qss/chat/Bubble/public/img/bubble-grey/Thumbs.db deleted file mode 100644 index 6df764f22..000000000 Binary files a/retroshare-gui/src/gui/qss/chat/Bubble/public/img/bubble-grey/Thumbs.db and /dev/null differ diff --git a/retroshare-gui/src/gui/qss/chat/Bubble/public/img/bubble-orange/Thumbs.db b/retroshare-gui/src/gui/qss/chat/Bubble/public/img/bubble-orange/Thumbs.db deleted file mode 100644 index c28302245..000000000 Binary files a/retroshare-gui/src/gui/qss/chat/Bubble/public/img/bubble-orange/Thumbs.db and /dev/null differ diff --git a/retroshare-gui/src/gui/qss/chat/Bubble/public/img/bubble-red/Thumbs.db b/retroshare-gui/src/gui/qss/chat/Bubble/public/img/bubble-red/Thumbs.db deleted file mode 100644 index 9621f17b2..000000000 Binary files a/retroshare-gui/src/gui/qss/chat/Bubble/public/img/bubble-red/Thumbs.db and /dev/null differ diff --git a/retroshare-gui/src/gui/qss/chat/Bubble/public/system.htm b/retroshare-gui/src/gui/qss/chat/Bubble/public/system.htm index 103d2bca1..ec98b3b43 100644 --- a/retroshare-gui/src/gui/qss/chat/Bubble/public/system.htm +++ b/retroshare-gui/src/gui/qss/chat/Bubble/public/system.htm @@ -3,21 +3,35 @@ - +
+ + - - - + + + - - - + + + - - - + + +
%name% %time% - %message% + %message% +
+ + + + +
+   %name% - + %time% +
+ +
diff --git a/retroshare-gui/src/gui/qss/chat/Bubble/src/img/bubble-blue/Thumbs.db b/retroshare-gui/src/gui/qss/chat/Bubble/src/img/bubble-blue/Thumbs.db deleted file mode 100644 index caa46f1dd..000000000 Binary files a/retroshare-gui/src/gui/qss/chat/Bubble/src/img/bubble-blue/Thumbs.db and /dev/null differ diff --git a/retroshare-gui/src/gui/qss/chat/Bubble/src/img/bubble-grey/Thumbs.db b/retroshare-gui/src/gui/qss/chat/Bubble/src/img/bubble-grey/Thumbs.db deleted file mode 100644 index 4ad1ec358..000000000 Binary files a/retroshare-gui/src/gui/qss/chat/Bubble/src/img/bubble-grey/Thumbs.db and /dev/null differ diff --git a/retroshare-gui/src/gui/qss/chat/Bubble/src/img/bubble-orange/Thumbs.db b/retroshare-gui/src/gui/qss/chat/Bubble/src/img/bubble-orange/Thumbs.db deleted file mode 100644 index 261c414d5..000000000 Binary files a/retroshare-gui/src/gui/qss/chat/Bubble/src/img/bubble-orange/Thumbs.db and /dev/null differ diff --git a/retroshare-gui/src/gui/qss/chat/Bubble/src/img/bubble-red/Thumbs.db b/retroshare-gui/src/gui/qss/chat/Bubble/src/img/bubble-red/Thumbs.db deleted file mode 100644 index 834d280ef..000000000 Binary files a/retroshare-gui/src/gui/qss/chat/Bubble/src/img/bubble-red/Thumbs.db and /dev/null differ diff --git a/retroshare-gui/src/gui/qss/chat/Bubble_Compact/private/img/bubble-blue/Thumbs.db b/retroshare-gui/src/gui/qss/chat/Bubble_Compact/private/img/bubble-blue/Thumbs.db deleted file mode 100644 index d535bcd22..000000000 Binary files a/retroshare-gui/src/gui/qss/chat/Bubble_Compact/private/img/bubble-blue/Thumbs.db and /dev/null differ diff --git a/retroshare-gui/src/gui/qss/chat/Bubble_Compact/private/system.htm b/retroshare-gui/src/gui/qss/chat/Bubble_Compact/private/system.htm index 103d2bca1..ad8287db2 100644 --- a/retroshare-gui/src/gui/qss/chat/Bubble_Compact/private/system.htm +++ b/retroshare-gui/src/gui/qss/chat/Bubble_Compact/private/system.htm @@ -2,22 +2,28 @@ %css-style% +
- +
- - - + + + + - - - + + + + - - - + + + +
 %time%
%name% %time% - %message% %name%%message%
+
+ diff --git a/retroshare-gui/src/gui/qss/chat/standard/private/main.css b/retroshare-gui/src/gui/qss/chat/standard/private/main.css index 7bcf8c66d..a56f0da05 100644 --- a/retroshare-gui/src/gui/qss/chat/standard/private/main.css +++ b/retroshare-gui/src/gui/qss/chat/standard/private/main.css @@ -36,4 +36,5 @@ } .systemHeader { + background-color: rgba(241,231,103,1); } diff --git a/retroshare-gui/src/gui/settings/GeneralPage.cpp b/retroshare-gui/src/gui/settings/GeneralPage.cpp index cbe3ecda0..3eea9c701 100755 --- a/retroshare-gui/src/gui/settings/GeneralPage.cpp +++ b/retroshare-gui/src/gui/settings/GeneralPage.cpp @@ -42,7 +42,7 @@ GeneralPage::GeneralPage(QWidget * parent, Qt::WindowFlags flags) connect(ui.runStartWizard_PB,SIGNAL(clicked()), this,SLOT(runStartWizard())) ; /* Hide platform specific features */ -#ifdef Q_WS_WIN +#ifdef Q_OS_WIN #ifdef QT_DEBUG ui.chkRunRetroshareAtSystemStartup->setEnabled(false); @@ -79,7 +79,7 @@ bool GeneralPage::save(QString &/*errmsg*/) Settings->setValue("doQuit", ui.checkQuit->isChecked()); Settings->setCloseToTray(ui.checkCloseToTray->isChecked()); -#ifdef Q_WS_WIN +#ifdef Q_OS_WIN #ifndef QT_DEBUG Settings->setRunRetroshareOnBoot(ui.chkRunRetroshareAtSystemStartup->isChecked(), ui.chkRunRetroshareAtSystemStartupMinimized->isChecked()); @@ -117,7 +117,7 @@ bool GeneralPage::save(QString &/*errmsg*/) /** Loads the settings for this page */ void GeneralPage::load() { -#ifdef Q_WS_WIN +#ifdef Q_OS_WIN bool minimized; ui.chkRunRetroshareAtSystemStartup->setChecked(Settings->runRetroshareOnBoot(minimized)); ui.chkRunRetroshareAtSystemStartupMinimized->setChecked(minimized); diff --git a/retroshare-gui/src/gui/settings/PluginsPage.cpp b/retroshare-gui/src/gui/settings/PluginsPage.cpp index 23b4bb5a6..33b7bd1ac 100644 --- a/retroshare-gui/src/gui/settings/PluginsPage.cpp +++ b/retroshare-gui/src/gui/settings/PluginsPage.cpp @@ -90,8 +90,9 @@ PluginsPage::PluginsPage(QWidget * parent, Qt::WindowFlags flags) if(plugin!=NULL) { - if(plugin->qt_icon() != NULL) - plugin_icon = *plugin->qt_icon() ; + QIcon *icon = plugin->qt_icon(); + if(icon != NULL) + plugin_icon = *icon ; pluginTitle = QString::fromUtf8(plugin->getPluginName().c_str()) ; pluginDescription = QString::fromUtf8(plugin->getShortPluginDescription().c_str()) ; @@ -169,8 +170,9 @@ void PluginsPage::aboutPlugin(int i) { std::cerr << "Launching about window for plugin " << i << std::endl; - if(rsPlugins->plugin(i) != NULL && rsPlugins->plugin(i)->qt_about_page() != NULL) - rsPlugins->plugin(i)->qt_about_page()->exec() ; + QDialog *dialog = NULL; + if(rsPlugins->plugin(i) != NULL && (dialog = rsPlugins->plugin(i)->qt_about_page()) != NULL) + dialog->exec() ; } void PluginsPage::configurePlugin(int i) { diff --git a/retroshare-gui/src/gui/settings/RSPermissionMatrixWidget.cpp b/retroshare-gui/src/gui/settings/RSPermissionMatrixWidget.cpp index cf9486ae5..cd2ffcf72 100644 --- a/retroshare-gui/src/gui/settings/RSPermissionMatrixWidget.cpp +++ b/retroshare-gui/src/gui/settings/RSPermissionMatrixWidget.cpp @@ -67,6 +67,18 @@ RSPermissionMatrixWidget::RSPermissionMatrixWidget(QWidget *parent) _max_width = 400 ; _max_height = 0 ; + + mHideOffline = false; +} + +void RSPermissionMatrixWidget::setHideOffline(bool hide) +{ + if (mHideOffline == hide) { + return; + } + + mHideOffline = hide; + repaint(); } void RSPermissionMatrixWidget::updateDisplay() @@ -238,25 +250,21 @@ void RSPermissionMatrixWidget::paintEvent(QPaintEvent *) // sort list { - // RSPermissionMatrixWidgets parent is ServicePermissionsPage which holds the checkbox - ServicePermissionsPage *spp = dynamic_cast(parentWidget()); - if(spp != NULL) { - // sort out offline peers - if(spp->isHideOfflineChecked()) { - RsPeerDetails peerDetails; - for(std::list::iterator it = ssllist.begin(); it != ssllist.end();) { - rsPeers->getPeerDetails(*it, peerDetails); + // sort out offline peers + if(mHideOffline) { + RsPeerDetails peerDetails; + for(std::list::iterator it = ssllist.begin(); it != ssllist.end();) { + rsPeers->getPeerDetails(*it, peerDetails); - switch (peerDetails.connectState) { - case RS_PEER_CONNECTSTATE_OFFLINE: - case RS_PEER_CONNECTSTATE_TRYING_TCP: - case RS_PEER_CONNECTSTATE_TRYING_UDP: - it = ssllist.erase(it); - break; - default: - it++; - break; - } + switch (peerDetails.connectState) { + case RS_PEER_CONNECTSTATE_OFFLINE: + case RS_PEER_CONNECTSTATE_TRYING_TCP: + case RS_PEER_CONNECTSTATE_TRYING_UDP: + it = ssllist.erase(it); + break; + default: + it++; + break; } } } diff --git a/retroshare-gui/src/gui/settings/RSPermissionMatrixWidget.h b/retroshare-gui/src/gui/settings/RSPermissionMatrixWidget.h index 356521c78..b56c76a61 100644 --- a/retroshare-gui/src/gui/settings/RSPermissionMatrixWidget.h +++ b/retroshare-gui/src/gui/settings/RSPermissionMatrixWidget.h @@ -60,6 +60,9 @@ public: RSPermissionMatrixWidget(QWidget *parent=NULL); virtual ~RSPermissionMatrixWidget() ; +public slots: + void setHideOffline(bool hide); + protected slots: // Calls the internal source for a new data points; called by the timer. You might want to overload this // if the collection system needs it. Otherwise, the default method will call getValues() @@ -100,6 +103,8 @@ private: /** The current dimensions of the graph. */ QRect _rec; + bool mHideOffline; + static const float fROW_SIZE ; static const float fCOL_SIZE ; static const float fICON_SIZE_X ; diff --git a/retroshare-gui/src/gui/settings/ServerPage.ui b/retroshare-gui/src/gui/settings/ServerPage.ui index 354adb8ee..5a481d8b5 100755 --- a/retroshare-gui/src/gui/settings/ServerPage.ui +++ b/retroshare-gui/src/gui/settings/ServerPage.ui @@ -511,175 +511,178 @@ behind a firewall or a VPN.
- - - IP blacklist + + + 0 - - - - - Qt::CustomContextMenu - - - <html><head/><body><p>This list gets automatically filled with information gathered at multiple sources: masquerading peers reported by the DHT, IP ranges entered by you, and IP ranges reported by your friends. Default settings should protect you against large scale traffic relaying.</p><p>Automatically guessing masquerading IPs can put your friends IPs in the blacklist. In this case, use the context menu to whitelist them.</p></body></html> - - - true - - - QAbstractItemView::SingleSelection - - - false - - - true - - - - IP range + + + IP blacklist + + + + + + Qt::CustomContextMenu - - - - Status + + <html><head/><body><p>This list gets automatically filled with information gathered at multiple sources: masquerading peers reported by the DHT, IP ranges entered by you, and IP ranges reported by your friends. Default settings should protect you against large scale traffic relaying.</p><p>Automatically guessing masquerading IPs can put your friends IPs in the blacklist. In this case, use the context menu to whitelist them.</p></body></html> - - - - Origin + + true - - - - Reason + + QAbstractItemView::SingleSelection - - - - Comment + + false - - - - - - - <html><head/><body><p>This is very drastic, be careful. Since masquerading IPs might be actual real IPs, this option might cause disconnection, and will probably force you to add your friends' IPs into the whitelist.</p></body></html> - - - Ban every IP reported by your friends - - - - - - - <html><head/><body><p>Another drastic option. If you use it, be prepared to add your friends' IPs into the whitelist when needed.</p></body></html> - - - Ban every masquerading IP reported by your DHT - - - - - - - - - <html><head/><body><p>If used alone, this option protects you quite well from large scale IP masquerading.</p></body></html> - + + true + + - Automatically ban ranges of DHT masquerading IPs starting at + IP range - - - - - - IPs + + + + Status - - 2 + + + + Origin - - 255 + + + + Reason - - - - - - Qt::Horizontal + + + + Comment - - - 40 - 20 - - - - - - - - - - - - - IP whitelist - - - - - - Qt::CustomContextMenu - - - <html><head/><body><p>White listed IPs are gathered from the following sources: IPs coming inside a manually exchanged certificate, IP ranges entered by you in this window, or in the security feed items.</p><p>The default behavior for Retroshare is to (1) always allow connection to peers with IP in the whitelist, even if that IP is also blacklisted; (2) optionally require IPs to be in the whitelist. You can change this behavior for each peer in the &quot;Details&quot; window of each Retroshare node. </p></body></html> - - - true - - - QAbstractItemView::SingleSelection - - - false - - - true - - - - IP range + + + + + + + <html><head/><body><p>This is very drastic, be careful. Since masquerading IPs might be actual real IPs, this option might cause disconnection, and will probably force you to add your friends' IPs into the whitelist.</p></body></html> - - - Status + Ban every IP reported by your friends + + + + + + + <html><head/><body><p>Another drastic option. If you use it, be prepared to add your friends' IPs into the whitelist when needed.</p></body></html> - - - Origin + Ban every masquerading IP reported by your DHT - - - - Reason + + + + + + + + <html><head/><body><p>If used alone, this option protects you quite well from large scale IP masquerading.</p></body></html> + + + Automatically ban ranges of DHT masquerading IPs starting at + + + + + + + IPs + + + 2 + + + 255 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + IP whitelist + + + + + + Qt::CustomContextMenu - - - - Comment + + <html><head/><body><p>White listed IPs are gathered from the following sources: IPs coming inside a manually exchanged certificate, IP ranges entered by you in this window, or in the security feed items.</p><p>The default behavior for Retroshare is to (1) always allow connection to peers with IP in the whitelist, even if that IP is also blacklisted; (2) optionally require IPs to be in the whitelist. You can change this behavior for each peer in the &quot;Details&quot; window of each Retroshare node. </p></body></html> - - - - + + true + + + QAbstractItemView::SingleSelection + + + false + + + true + + + + IP range + + + + + Status + + + + + Origin + + + + + Reason + + + + + Comment + + + + + + diff --git a/retroshare-gui/src/gui/settings/ServicePermissionsPage.cpp b/retroshare-gui/src/gui/settings/ServicePermissionsPage.cpp index e755ec90e..5cf0a59c0 100644 --- a/retroshare-gui/src/gui/settings/ServicePermissionsPage.cpp +++ b/retroshare-gui/src/gui/settings/ServicePermissionsPage.cpp @@ -28,16 +28,19 @@ #include #include -#define PermissionStateUserRole (Qt::UserRole) -#define ServiceIdUserRole (Qt::UserRole + 1) -#define PeerIdUserRole (Qt::UserRole + 2) - -ServicePermissionsPage::ServicePermissionsPage(QWidget * parent, Qt::WindowFlags /*flags*/) +ServicePermissionsPage::ServicePermissionsPage(QWidget * parent, Qt::WindowFlags flags) : + ConfigPage(parent, flags) { /* Invoke the Qt Designer generated object setup routine */ ui.setupUi(this); + connect(ui.cb_hideOffline, SIGNAL(toggled(bool)), ui.frame, SLOT(setHideOffline(bool))); //QObject::connect(ui.tableWidget,SIGNAL(itemChanged(QTableWidgetItem *)), this, SLOT(tableItemChanged(QTableWidgetItem *))); + + ui.frame->setHideOffline(ui.cb_hideOffline->isChecked()); + + // Not implemented? + ui.pushButton->hide(); } QString ServicePermissionsPage::helpText() const @@ -52,10 +55,3 @@ QString ServicePermissionsPage::helpText() const

Be very careful: Some services depend on each other. For instance turning turtle OFF will also\ stop all anonymous transfer, distant chat and distant messaging.

"); } - -bool ServicePermissionsPage::isHideOfflineChecked() -{ - return ui.cb_hideOffline->checkState() == Qt::Checked; -} - - diff --git a/retroshare-gui/src/gui/settings/ServicePermissionsPage.h b/retroshare-gui/src/gui/settings/ServicePermissionsPage.h index 7566e6d92..1e4f5c973 100644 --- a/retroshare-gui/src/gui/settings/ServicePermissionsPage.h +++ b/retroshare-gui/src/gui/settings/ServicePermissionsPage.h @@ -44,10 +44,7 @@ public: virtual QString pageName() const { return tr("Permissions") ; } virtual QString helpText() const ; - bool isHideOfflineChecked(); - private: - Ui::ServicePermissionsPage ui; }; diff --git a/retroshare-gui/src/gui/settings/ServicePermissionsPage.ui b/retroshare-gui/src/gui/settings/ServicePermissionsPage.ui index e0144f137..488ba9518 100644 --- a/retroshare-gui/src/gui/settings/ServicePermissionsPage.ui +++ b/retroshare-gui/src/gui/settings/ServicePermissionsPage.ui @@ -11,6 +11,46 @@ + + + + QFrame::StyledPanel + + + QFrame::Raised + + + true + + + + + 0 + 0 + 619 + 280 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + @@ -52,22 +92,6 @@ - - - - - 0 - 0 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - diff --git a/retroshare-gui/src/gui/settings/rsharesettings.cpp b/retroshare-gui/src/gui/settings/rsharesettings.cpp index c803872d6..83fbf0563 100644 --- a/retroshare-gui/src/gui/settings/rsharesettings.cpp +++ b/retroshare-gui/src/gui/settings/rsharesettings.cpp @@ -33,7 +33,7 @@ #include #include -#if defined(Q_WS_WIN) +#if defined(Q_OS_WIN) #include #endif @@ -60,7 +60,7 @@ /* Default Retroshare Settings */ #define DEFAULT_OPACITY 100 -#if defined(Q_OS_WIN32) +#if defined(Q_OS_WIN) #define STARTUP_REG_KEY "Software\\Microsoft\\Windows\\CurrentVersion\\Run" #define RETROSHARE_REG_KEY "RetroShare" #endif @@ -104,11 +104,11 @@ void RshareSettings::initSettings() // use GTK as default style on ubuntu setDefault(SETTING_STYLE, "GTK+"); #else -#if defined(Q_WS_MAC) +#if defined(Q_OS_MAC) setDefault(SETTING_STYLE, "macintosh (aqua)"); #else static QStringList styles = QStyleFactory::keys(); -#if defined(Q_WS_WIN) +#if defined(Q_OS_WIN) if (styles.contains("windowsvista", Qt::CaseInsensitive)) setDefault(SETTING_STYLE, "windowsvista"); else if (styles.contains("windowsxp", Qt::CaseInsensitive)) @@ -710,7 +710,7 @@ RshareSettings::runRetroshareOnBoot(bool &minimized) { minimized = false; -#if defined(Q_WS_WIN) +#if defined(Q_OS_WIN) QString value = win32_registry_get_key_value(STARTUP_REG_KEY, RETROSHARE_REG_KEY); if (!value.isEmpty()) { @@ -729,9 +729,9 @@ RshareSettings::runRetroshareOnBoot(bool &minimized) void RshareSettings::setRunRetroshareOnBoot(bool run, bool minimized) { -#if defined(Q_WS_WIN) +#if defined(Q_OS_WIN) if (run) { - QString value = "\"" + QDir::convertSeparators(QCoreApplication::applicationFilePath()) + "\""; + QString value = "\"" + QDir::toNativeSeparators(QCoreApplication::applicationFilePath()) + "\""; if (minimized) { value += " -m"; @@ -748,17 +748,17 @@ RshareSettings::setRunRetroshareOnBoot(bool run, bool minimized) #endif } -#if defined(Q_WS_WIN) +#if defined(Q_OS_WIN) static QString getAppPathForProtocol() { - return "\"" + QDir::convertSeparators(QCoreApplication::applicationFilePath()) + "\" -r \"%1\""; + return "\"" + QDir::toNativeSeparators(QCoreApplication::applicationFilePath()) + "\" -r \"%1\""; } #endif /** Returns true if retroshare:// is registered as protocol */ bool RshareSettings::getRetroShareProtocol() { -#if defined(Q_WS_WIN) +#if defined(Q_OS_WIN) /* Check key */ QSettings retroshare("HKEY_CLASSES_ROOT\\retroshare", QSettings::NativeFormat); if (retroshare.contains("Default")) { @@ -780,7 +780,7 @@ bool RshareSettings::getRetroShareProtocol() /** Returns true if the user can set retroshare as protocol */ bool RshareSettings::canSetRetroShareProtocol() { -#if defined(Q_WS_WIN) +#if defined(Q_OS_WIN) QSettings retroshare("HKEY_CLASSES_ROOT\\retroshare", QSettings::NativeFormat); return retroshare.isWritable(); #else @@ -791,7 +791,7 @@ bool RshareSettings::canSetRetroShareProtocol() /** Register retroshare:// as protocol */ bool RshareSettings::setRetroShareProtocol(bool value) { -#if defined(Q_WS_WIN) +#if defined(Q_OS_WIN) if (value) { QSettings retroshare("HKEY_CLASSES_ROOT\\retroshare", QSettings::NativeFormat); retroshare.setValue("Default", "URL: RetroShare protocol"); diff --git a/retroshare-gui/src/gui/statistics/BandwidthGraphWindow.cpp b/retroshare-gui/src/gui/statistics/BandwidthGraphWindow.cpp index bc8c0c1bd..27bd8bb4b 100644 --- a/retroshare-gui/src/gui/statistics/BandwidthGraphWindow.cpp +++ b/retroshare-gui/src/gui/statistics/BandwidthGraphWindow.cpp @@ -57,7 +57,7 @@ BandwidthGraph::BandwidthGraph(QWidget *parent, Qt::WindowFlags flags) { /* Invoke Qt Designer generated QObject setup routine */ ui.setupUi(this); -#if defined(Q_WS_WIN) +#if defined(Q_OS_WIN) setShortcut("Esc", SLOT(close())); #else setShortcut("Ctrl+W", SLOT(close())); @@ -78,13 +78,13 @@ BandwidthGraph::BandwidthGraph(QWidget *parent, Qt::WindowFlags flags) loadSettings(); /* Turn off opacity group on unsupported platforms */ - #if defined(Q_WS_WIN) - if(!(QSysInfo::WV_2000 <= QSysInfo::WindowsVersion && QSysInfo::WindowsVersion <= QSysInfo::WV_2003)) { + #if defined(Q_OS_WIN) + if(!(QSysInfo::WV_2000 <= QSysInfo::WindowsVersion)) { ui.frmOpacity->setVisible(false); } #endif - #if defined(Q_WS_X11) + #if defined(Q_OS_LINUX) ui.frmOpacity->setVisible(false); #endif } @@ -236,11 +236,11 @@ void BandwidthGraph::setOpacity(int value) qreal newValue = value / 100.0; /* Opacity only supported by Mac and Win32 */ -#if defined(Q_WS_MAC) +#if defined(Q_OS_MAC) this->setWindowOpacity(newValue); ui.lblPercentOpacity->setText(QString::number(value)); -#elif defined(Q_WS_WIN) - if(QSysInfo::WV_2000 <= QSysInfo::WindowsVersion && QSysInfo::WindowsVersion <= QSysInfo::WV_2003) { +#elif defined(Q_OS_WIN) + if(QSysInfo::WV_2000 <= QSysInfo::WindowsVersion) { this->setWindowOpacity(newValue); ui.lblPercentOpacity->setText(QString::number(value)); } diff --git a/retroshare-gui/src/gui/statistics/DhtWindow.cpp b/retroshare-gui/src/gui/statistics/DhtWindow.cpp index 083c5ea58..5a971c010 100644 --- a/retroshare-gui/src/gui/statistics/DhtWindow.cpp +++ b/retroshare-gui/src/gui/statistics/DhtWindow.cpp @@ -36,11 +36,25 @@ #include "retroshare/rsconfig.h" #include "retroshare/rspeers.h" +#define DTW_COL_BUCKET 0 +#define DTW_COL_IPADDR 1 +#define DTW_COL_PEERID 2 +#define DTW_COL_FLAGS 3 +#define DTW_COL_FOUND 4 +#define DTW_COL_SEND 5 +#define DTW_COL_RECV 6 + DhtWindow::DhtWindow(QWidget *parent) : RsAutoUpdatePage(1000,parent) { ui.setupUi(this); - + + connect( ui.filterLineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(filterItems(QString))); + connect( ui.filterLineEdit, SIGNAL(filterChanged(int)), this, SLOT(filterColumnChanged(int))); + + /* add filter actions */ + ui.filterLineEdit->addFilter(QIcon(), tr("IP"), DTW_COL_IPADDR, tr("Search IP")); + ui.filterLineEdit->setCurrentFilter(DTW_COL_IPADDR); } DhtWindow::~DhtWindow() @@ -575,14 +589,6 @@ void DhtWindow::updateRelays() /****************************/ -#define DTW_COL_BUCKET 0 -#define DTW_COL_IPADDR 1 -#define DTW_COL_PEERID 2 -#define DTW_COL_FLAGS 3 -#define DTW_COL_FOUND 4 -#define DTW_COL_SEND 5 -#define DTW_COL_RECV 6 - class DhtTreeWidgetItem : public QTreeWidgetItem { public: @@ -664,6 +670,10 @@ void DhtWindow::updateDhtPeers() dht_item -> setData(DTW_COL_RECV, Qt::DisplayRole, lastrecvstr); ui.dhtTreeWidget->addTopLevelItem(dht_item); + + if (ui.filterLineEdit->text().isEmpty() == false) { + filterItems(ui.filterLineEdit->text()); + } } } @@ -700,3 +710,46 @@ void DhtWindow::getDHTStatus() // } // } } + +void DhtWindow::filterColumnChanged(int) +{ + filterItems(ui.filterLineEdit->text()); +} + +void DhtWindow::filterItems(const QString &text) +{ + int filterColumn = ui.filterLineEdit->currentFilter(); + + int count = ui.dhtTreeWidget->topLevelItemCount (); + for (int index = 0; index < count; ++index) { + filterItem(ui.dhtTreeWidget->topLevelItem(index), text, filterColumn); + } +} + +bool DhtWindow::filterItem(QTreeWidgetItem *item, const QString &text, int filterColumn) +{ + bool visible = true; + + if (text.isEmpty() == false) { + if (item->text(filterColumn).contains(text, Qt::CaseInsensitive) == false) { + visible = false; + } + } + + int visibleChildCount = 0; + int count = item->childCount(); + for (int index = 0; index < count; ++index) { + if (filterItem(item->child(index), text, filterColumn)) { + ++visibleChildCount; + } + } + + if (visible || visibleChildCount) { + item->setHidden(false); + } else { + item->setHidden(true); + } + + return (visible || visibleChildCount); +} + diff --git a/retroshare-gui/src/gui/statistics/DhtWindow.h b/retroshare-gui/src/gui/statistics/DhtWindow.h index d95d50cb1..83d550336 100644 --- a/retroshare-gui/src/gui/statistics/DhtWindow.h +++ b/retroshare-gui/src/gui/statistics/DhtWindow.h @@ -42,11 +42,17 @@ public: public slots: virtual void updateDisplay() ; + void filterColumnChanged(int); + void filterItems(const QString &text); + + protected: //void changeEvent(QEvent *e); private: + bool filterItem(QTreeWidgetItem *item, const QString &text, int filterColumn); + /** Qt Designer generated object */ Ui::DhtWindow ui; diff --git a/retroshare-gui/src/gui/statistics/DhtWindow.ui b/retroshare-gui/src/gui/statistics/DhtWindow.ui index 1a8425812..b2dfd8237 100644 --- a/retroshare-gui/src/gui/statistics/DhtWindow.ui +++ b/retroshare-gui/src/gui/statistics/DhtWindow.ui @@ -23,577 +23,628 @@ DHT - - - - - Qt::Vertical - - - + + + + + - + - - - - - - 75 - true - - - - Net Status: - - - - - - - Qt::LeftToRight - - - Net Status - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - - - - 75 - true - - - - Network Mode: - - - - - - - Network Mode - - - - - - - - - - - - 75 - true - - - - Nat Type: - - - - - - - Nat Type - - - - - - - - - - - - 75 - true - - - - Nat Hole: - - - - - - - Nat Hole - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - - - 75 - true - - - - Connect Mode: - - - - - - - - 0 - 0 - - - - Qt::LeftToRight - - - Connect Options - - - - - - - - - - - - 75 - true - - - - Peer Address: - - - - - - - - 0 - 0 - - - - Peer Address - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - - - - - - 75 - true - - - - Unreach: - - - - - - - - - - - - - - - - - - - 75 - true - - - - Online: - - - - - - - - - - - - - - - - - - - 75 - true - - - - Offline: - - - - - - - - - - - - - - - - - - - 75 - true - - - - DHT Peers: - - - - - - - - - - - - - - - - - - - Qt::Vertical + + + + 75 + true + + + + Net Status: - - + + + Qt::LeftToRight + + + Net Status + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + + + + + 75 + true + + + + Network Mode: + + + + + + + Network Mode + + + + + + + + + + + + 75 + true + + + + Nat Type: + + + + + + + Nat Type + + + + + + + + + + + + 75 + true + + + + Nat Hole: + + + + + + + Nat Hole + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + + + 75 + true + + + + Connect Mode: + + + + + + + + 0 + 0 + + + + Qt::LeftToRight + + + Connect Options + + + + + + + + + + + + 75 + true + + + + Peer Address: + + + + + + + + 0 + 0 + + + + Peer Address + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + - - - - - - 75 - true - - - - Disconnected: - - - - - - - - - - - - - - - - - - - 75 - true - - - - Direct: - - - - - - - - - - - - - - - - - - - 75 - true - - - - Proxy: - - - - - - - - - - - - - - - - - - - 75 - true - - - - Relay: - - - - - - - - - - - - - - - - Qt::Horizontal + + + + 75 + true + - - - 40 - 20 - + + Unreach: - + + + + + + + + + + + + + + + + 75 + true + + + + Online: + + + + + + + + + + + + + + + + + + + 75 + true + + + + Offline: + + + + + + + + + + + + + + + + + + + 75 + true + + + + DHT Peers: + + + + + + + + + + + + + + + + + + + Qt::Vertical + + + + + + + + + + + + + 75 + true + + + + Disconnected: + + + + + + + + + + + + + + + + + + + 75 + true + + + + Direct: + + + + + + + + + + + + + + + + + + + 75 + true + + + + Proxy: + + + + + + + + + + + + + + + + + + + 75 + true + + + + Relay: + + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + +
+ + + + + + 0 + + + + DHT + + + + + + Qt::CopyAction + + + QAbstractItemView::MultiSelection + + + true + + + + Bucket + + + + + IP:Port + + + + + Key + + + + + Status Flags + + + + + Found + + + + + Last Sent + + + + + Last Recv + + + + + + + + + + Filter: + + + + + + + Search Network + - - - true - - - - Name - - - - - PeerId - - - - - DHT Status - - - - - ConnectLogic - - - - - Connect Status - - - - - Connect Mode - - - - - Request Status - - - - - Cb Status - - - - - RsId - - + + + Peers + + + + + + true + + + + Name + + + + + PeerId + + + + + DHT Status + + + + + ConnectLogic + + + + + Connect Status + + + + + Connect Mode + + + + + Request Status + + + + + Cb Status + + + + + RsId + + + + + - - - true - - - - Bucket - - - - - IP:Port - - - - - Key - - - - - Status Flags - - - - - Found - - - - - Last Sent - - - - - Last Recv - - - - - - true - - - - Relay Mode - - - - - Source - - - - - Proxy - - - - - Destination - - - - - Class - - - - - Age - - - - - Last Sent - - - - - Bandwidth - - + + + Relay + + + + + + true + + + + Relay Mode + + + + + Source + + + + + Proxy + + + + + Destination + + + + + Class + + + + + Age + + + + + Last Sent + + + + + Bandwidth + + + + + @@ -636,6 +687,11 @@
gui/statistics/dhtgraph.h
1 + + LineEditClear + QLineEdit +
gui/common/LineEditClear.h
+
diff --git a/retroshare-gui/src/gui/statistics/GlobalRouterStatistics.cpp b/retroshare-gui/src/gui/statistics/GlobalRouterStatistics.cpp index 21bebe336..9aabeeeaf 100644 --- a/retroshare-gui/src/gui/statistics/GlobalRouterStatistics.cpp +++ b/retroshare-gui/src/gui/statistics/GlobalRouterStatistics.cpp @@ -294,6 +294,22 @@ void GlobalRouterStatisticsWidget::updateContent() oy += celly ; oy += celly ; + //print friends in the same order their prob is shown + QString FO = tr("Friend Order ("); + RsPeerDetails peer_ssl_details; + for(uint32_t i=0;igetPeerDetails(matrix_info.friend_ids[i], peer_ssl_details); + QString fn = QString::fromUtf8(peer_ssl_details.name.c_str()); + FO+=fn; + FO+=" "; + + } + FO+=")"; + + painter.drawText(ox+0*cellx,oy+fm_times.height(),FO) ; + oy += celly ; + oy += celly ; + static const int MaxKeySize = 20*fact ; painter.setFont(monospace_f) ; diff --git a/retroshare-gui/src/gui/toaster/ChatLobbyToaster.cpp b/retroshare-gui/src/gui/toaster/ChatLobbyToaster.cpp index 325d56f30..882004975 100644 --- a/retroshare-gui/src/gui/toaster/ChatLobbyToaster.cpp +++ b/retroshare-gui/src/gui/toaster/ChatLobbyToaster.cpp @@ -22,10 +22,11 @@ #include "ChatLobbyToaster.h" #include "gui/chat/ChatDialog.h" #include "util/HandleRichText.h" +#include #include -ChatLobbyToaster::ChatLobbyToaster(const ChatLobbyId &lobby_id, const QString &name, const QString &message): +ChatLobbyToaster::ChatLobbyToaster(const ChatLobbyId &lobby_id, const RsGxsId &sender_id, const QString &message): QWidget(NULL), mLobbyId(lobby_id) { /* Invoke the Qt Designer generated object setup routine */ @@ -39,7 +40,14 @@ ChatLobbyToaster::ChatLobbyToaster(const ChatLobbyId &lobby_id, const QString &n ui.avatarWidget->setFrameType(AvatarWidget::NORMAL_FRAME); ui.avatarWidget->setDefaultAvatar(":images/chat_64.png"); - QString lobbyName = RsHtml::plainText(name); + /* Get sender info */ + RsIdentityDetails idd; + if(!rsIdentity->getIdDetails(sender_id, idd)) + return; + + ui.avatarWidget->setId(ChatId(sender_id)); + + QString lobbyName = RsHtml::plainText(idd.mNickname); ChatLobbyInfo clinfo ; if(rsMsgs->getChatLobbyInfo(mLobbyId,clinfo)) diff --git a/retroshare-gui/src/gui/toaster/ChatLobbyToaster.h b/retroshare-gui/src/gui/toaster/ChatLobbyToaster.h index bc7c3d262..a5c18d8f2 100644 --- a/retroshare-gui/src/gui/toaster/ChatLobbyToaster.h +++ b/retroshare-gui/src/gui/toaster/ChatLobbyToaster.h @@ -36,7 +36,7 @@ class ChatLobbyToaster : public QWidget Q_OBJECT public: - ChatLobbyToaster(const ChatLobbyId &lobby_id, const QString &name, const QString &message); + ChatLobbyToaster(const ChatLobbyId &lobby_id, const RsGxsId &sender_id, const QString &message); private slots: void chatButtonSlot(); diff --git a/retroshare-gui/src/lang/retroshare_en.ts b/retroshare-gui/src/lang/retroshare_en.ts index 33cecc3f1..7b60e33c7 100644 --- a/retroshare-gui/src/lang/retroshare_en.ts +++ b/retroshare-gui/src/lang/retroshare_en.ts @@ -1,6 +1,6 @@ - + AWidget @@ -573,24 +573,36 @@ p, li { white-space: pre-wrap; } - + Icon Size = 8x8 - - + + Icon Size = 16x16 - - + + Icon Size = 24x24 - + + + Icon Size = 64x64 + + + + + + Icon Size = 128x128 + + + + Status Bar @@ -620,8 +632,8 @@ p, li { white-space: pre-wrap; } - - + + Icon Size = 32x32 @@ -733,7 +745,7 @@ p, li { white-space: pre-wrap; } BWGraphSource - + KB/s @@ -749,13 +761,13 @@ p, li { white-space: pre-wrap; } BandwidthGraph - + RetroShare Bandwidth Usage - + Show Settings @@ -810,7 +822,7 @@ p, li { white-space: pre-wrap; } - + Since: @@ -820,6 +832,31 @@ p, li { white-space: pre-wrap; } + + BandwidthStatsWidget + + + + Sum + + + + + + All + + + + + KB/s + + + + + Count + + + BwCtrlWindow @@ -883,7 +920,7 @@ p, li { white-space: pre-wrap; } - + TOTALS @@ -898,6 +935,44 @@ p, li { white-space: pre-wrap; } + + BwStatsWidget + + + Form + + + + + Friend: + + + + + Type: + + + + + Up + + + + + Down + + + + + Service: + + + + + Unit: + + + ChannelPage @@ -947,7 +1022,7 @@ p, li { white-space: pre-wrap; } - + Mute participant @@ -982,7 +1057,7 @@ p, li { white-space: pre-wrap; } - + Lobby chat @@ -1035,12 +1110,12 @@ p, li { white-space: pre-wrap; } - + Start private chat - + Decryption failed. @@ -1157,7 +1232,7 @@ p, li { white-space: pre-wrap; } - + Create chat lobby @@ -1208,7 +1283,7 @@ p, li { white-space: pre-wrap; } - + Search Name @@ -1218,7 +1293,12 @@ p, li { white-space: pre-wrap; } - + + <h1><img width="%1" src=":/icons/help_64.png">&nbsp;&nbsp;Chat Lobbies</h1> <p>Chat lobbies are distributed chat rooms, and work pretty much like IRC. They allow you to talk anonymously with tons of people without the need to make friends.</p> <p>A chat lobby can be public (your friends see it) or private (your friends can't see it, unless you invite them with <img src=":/images/add_24x24.png" width=%2/>). Once you have been invited to a private lobby, you will be able to see it when your friends are using it.</p> <p>The list at left shows chat lobbies your friends are participating in. You can either <ul> <li>Right click to create a new chat lobby</li> <li>Double click a chat lobby to enter, chat, and show it to your friends</li> </ul> Note: For the chat lobbies to work properly, your computer needs be on time. So check your system clock! </p> + + + + Columns @@ -1274,7 +1354,7 @@ Double click lobbies to enter and chat. - + Private Subscribed Lobbies @@ -1283,18 +1363,13 @@ Double click lobbies to enter and chat. Public Subscribed Lobbies - - - <h1><img width="32" src=":/images/64px_help.png">&nbsp;&nbsp;Chat Lobbies</h1> <p>Chat lobbies are distributed chat rooms, and work pretty much like IRC. They allow you to talk anonymously with tons of people without the need to make friends.</p> <p>A chat lobby can be public (your friends see it) or private (your friends can't see it, unless you invite them with <img src=":/images/add_24x24.png" width=12/>). Once you have been invited to a private lobby, you will be able to see it when your friends are using it.</p> <p>The list at left shows chat lobbies your friends are participating in. You can either <ul> <li>Right click to create a new chat lobby</li> <li>Double click a chat lobby to enter, chat, and show it to your friends</li> </ul> Note: For the chat lobbies to work properly, your computer needs be on time. So check your system clock! </p> - - Chat Lobbies - + Leave this lobby @@ -1324,7 +1399,7 @@ Double click lobbies to enter and chat. - + Show @@ -1377,7 +1452,7 @@ Double click lobbies to enter and chat. - + Quick Message @@ -4165,7 +4240,7 @@ Do you want to reject this message? - + DHT Off @@ -4285,7 +4360,7 @@ Do you want to reject this message? DhtWindow - + Net Status @@ -4315,7 +4390,7 @@ Do you want to reject this message? - + Name @@ -4360,7 +4435,7 @@ Do you want to reject this message? - + Bucket @@ -4386,17 +4461,17 @@ Do you want to reject this message? - + Last Sent - + Last Recv - + Relay Mode @@ -4431,7 +4506,7 @@ Do you want to reject this message? - + Unknown NetState @@ -4692,13 +4767,14 @@ Do you want to reject this message? - + + DHT - + Net Status: @@ -4768,7 +4844,27 @@ Do you want to reject this message? - + + Filter: + + + + + Search Network + + + + + Peers + + + + + Relay + + + + DHT Graph @@ -5011,7 +5107,7 @@ you plug it in. FileTransferInfoWidget - + Chunk map @@ -5186,7 +5282,7 @@ you plug it in. FlatStyle_RDM - + Friends Directories @@ -5262,31 +5358,17 @@ you plug it in. FriendList - - - Status - - - - - - + Last Contact - - - Avatar - - - - + Hide Offline Friends - + State @@ -5295,30 +5377,14 @@ you plug it in. Sort by State - - - Hide State - - - - - - Sort Descending Order - - - - - - Sort Ascending Order - - - - - Show Avatar Column - - + + Show State + + + + Name @@ -5328,33 +5394,13 @@ you plug it in. - - Sort by last contact - - - - - Show Last Contact Column - - - - - Set root is Decorated - - - - - Set Root Decorated - - - - + Show Groups - + Group @@ -5395,7 +5441,12 @@ you plug it in. - + + Search + + + + Move to group @@ -5425,40 +5476,22 @@ you plug it in. - - + Available - + Do you want to remove this Friend? - - Columns - - - - - - + IP - - Sort by IP - - - - - Show IP Column - - - - + Attempt to connect @@ -5468,7 +5501,7 @@ you plug it in. - + Display @@ -5478,12 +5511,12 @@ you plug it in. - + Sort by - + Node @@ -5493,17 +5526,17 @@ you plug it in. - + Do you want to remove this node? - + Friend nodes - + Send message to whole group @@ -5668,7 +5701,12 @@ you plug it in. - + + <h1><img width="32" src=":/icons/help_64.png">&nbsp;&nbsp;Network</h1> <p>The Network tab shows your friend Retroshare nodes: the neighbor Retroshare nodes that are connected to you. </p> <p>You can group nodes together to allow a finer level of information access, for instance to only allow some nodes to see some of your files.</p> <p>On the right, you will find 3 useful tabs: <ul> <li>Broadcast sends messages to all connected nodes at once</li> <li>Local network graph shows the network around you, based on discovery information</li> <li>Keyring contains node keys you collected, mostly forwarded to you by your friend nodes</li> </ul> </p> + + + + Retroshare broadcast chat: messages are sent to all connected friends. @@ -5684,12 +5722,7 @@ you plug it in. - - <h1><img width="32" src=":/images/64px_help.png">&nbsp;&nbsp;Network</h1> <p>The Network tab shows your friend Retroshare nodes: the neighbor Retroshare nodes that are connected to you. </p> <p>You can group nodes together to allow a finer level of information access, for instance to only allow some nodes to see some of your files.</p> <p>On the right, you will find 3 useful tabs: <ul> <li>Broadcast sends messages to all connected nodes at once</li> <li>Local network graph shows the network around you, based on discovery information</li> <li>Keyring contains node keys you collected, mostly forwarded to you by your friend nodes</li> </ul> </p> - - - - + Set your status message here. @@ -6652,7 +6685,7 @@ p, li { white-space: pre-wrap; } GroupTreeWidget - + Title @@ -6672,7 +6705,7 @@ p, li { white-space: pre-wrap; } - + Sort by Name @@ -6692,7 +6725,7 @@ p, li { white-space: pre-wrap; } - + You have admin rights @@ -6803,7 +6836,7 @@ p, li { white-space: pre-wrap; } GxsChannelDialog - + Channels @@ -6814,17 +6847,22 @@ p, li { white-space: pre-wrap; } - + Enable Auto-Download - + My Channels - + + <h1><img width="32" src=":/icons/help_64.png">&nbsp;&nbsp;Channels</h1> <p>Channels allow you to post data (e.g. movies, music) that will spread in the network</p> <p>You can see the channels your friends are subscribed to, and you automatically forward subscribed channels to your friends. This promotes good channels in the network.</p> <p>Only the channel's creator can post on that channel. Other peers in the network can only read from it, unless the channel is private. You can however share the posting rights or the reading rights with friend Retroshare nodes.</p> <p>Channels can be made anonymous, or attached to a Retroshare identity so that readers can contact you if needed. Enable "Allow Comments" if you want to let users comment on your posts.</p> <p>Channel posts get deleted after %1 months.</p> + + + + Subscribed Channels @@ -6839,13 +6877,29 @@ p, li { white-space: pre-wrap; } - + + Select channel download directory + + + + Disable Auto-Download - - <h1><img width="32" src=":/images/64px_help.png">&nbsp;&nbsp;Channels</h1> <p>Channels allow you to post data (e.g. movies, music) that will spread in the network</p> <p>You can see the channels your friends are subscribed to, and you automatically forward subscribed channels to your friends. This promotes good channels in the network.</p> <p>Only the channel's creator can post on that channel. Other peers in the network can only read from it, unless the channel is private. You can however share the posting rights or the reading rights with friend Retroshare nodes.</p> <p>Channels can be made anonymous, or attached to a Retroshare identity so that readers can contact you if needed. Enable "Allow Comments" if you want to let users comment on your posts.</p> <p>Channel posts get deleted after %1 months.</p> + + Set download directory + + + + + + [Default directory] + + + + + Specify... @@ -7186,7 +7240,7 @@ p, li { white-space: pre-wrap; } - + Disable Auto-Download @@ -7545,13 +7599,13 @@ before you can comment - + Author - + Loading @@ -7611,7 +7665,7 @@ before you can comment - + Reply @@ -7756,12 +7810,12 @@ before you can comment - + <p>Subscribing to the forum will gather available posts from your subscribed friends, and make the forum visible to all other friends.</p><p>Afterwards you can unsubscribe from the context menu of the forum list at left.</p> - + Reply with private message @@ -7777,7 +7831,12 @@ before you can comment GxsForumsDialog - + + <h1><img width="32" src=":/icons/help_64.png">&nbsp;&nbsp;Forums</h1> <p>Retroshare Forums look like internet forums, but they work in a decentralized way</p> <p>You see forums your friends are subscribed to, and you forward subscribed forums to your friends. This automatically promotes interesting forums in the network.</p> <p>Forum messages get deleted after %1 months.</p> + + + + Forums @@ -7807,11 +7866,6 @@ before you can comment Other Forums - - - <h1><img width="32" src=":/images/64px_help.png">&nbsp;&nbsp;Forums</h1> <p>Retroshare Forums look like internet forums, but they work in a decentralized way</p> <p>You see forums your friends are subscribed to, and you forward subscribed forums to your friends. This automatically promotes interesting forums in the network.</p> <p>Forum messages get deleted after %1 months.</p> - - GxsForumsFillThread @@ -8830,12 +8884,7 @@ p, li { white-space: pre-wrap; } - - <h1><img width="32" src=":/images/64px_help.png">&nbsp;&nbsp;Identities</h1> <p>In this tab you can create/edit pseudo-anonymous identities. </p> <p>Identities are used to securely identify your data: sign forum and channel posts, and receive feedback using Retroshare built-in email system, post comments after channel posts, etc.</p> <p> Identities can optionally be signed by your Retroshare node's certificate. Signed identities are easier to trust but are easily linked to your node's IP address. </p> <p> Anonymous identities allow you to anonymously interact with other users. They cannot be spoofed, but noone can prove who really owns a given identity. </p> - - - - + This identity is owned by you @@ -8905,7 +8954,12 @@ p, li { white-space: pre-wrap; } - + + <h1><img width="32" src=":/icons/help_64.png">&nbsp;&nbsp;Identities</h1> <p>In this tab you can create/edit pseudo-anonymous identities. </p> <p>Identities are used to securely identify your data: sign forum and channel posts, and receive feedback using Retroshare built-in email system, post comments after channel posts, etc.</p> <p> Identities can optionally be signed by your Retroshare node's certificate. Signed identities are easier to trust but are easily linked to your node's IP address. </p> <p> Anonymous identities allow you to anonymously interact with other users. They cannot be spoofed, but noone can prove who really owns a given identity. </p> + + + + Linked to a friend Retroshare node @@ -9202,13 +9256,13 @@ p, li { white-space: pre-wrap; } ImHistoryBrowser - + Message History - + Copy @@ -9306,7 +9360,7 @@ p, li { white-space: pre-wrap; } - + Options @@ -9340,12 +9394,12 @@ p, li { white-space: pre-wrap; } - + RetroShare %1 a secure decentralized communication platform - + Unfinished @@ -9379,7 +9433,12 @@ p, li { white-space: pre-wrap; } - + + Open Messenger + + + + Open Messages @@ -10523,7 +10582,7 @@ Do you want to save message ? MessagesDialog - + New Message @@ -10590,7 +10649,7 @@ Do you want to save message ? - + Tags @@ -10598,7 +10657,7 @@ Do you want to save message ? - + Inbox @@ -10695,7 +10754,7 @@ Do you want to save message ? - + Reply to All @@ -10713,12 +10772,12 @@ Do you want to save message ? - + From - + Date @@ -10746,12 +10805,12 @@ Do you want to save message ? - + Click to sort by from - + Click to sort by date @@ -10806,7 +10865,12 @@ Do you want to save message ? - + + <h1><img width="%1" src=":/icons/help_64.png">&nbsp;&nbsp;Messages</h1> <p>Retroshare has its own internal email system. You can send/receive emails to/from connected friend nodes.</p> <p>It is also possible to send messages to other people's Identities using the global routing system. These messages are always encrypted and signed, and are relayed by intermediate nodes until they reach their final destination. </p> <p>Distant messages stay into your Outbox until an acknowledgement of receipt has been received.</p> <p>Generally, you may use messages to recommend files to your friends by pasting file links, or recommend friend nodes to other friend nodes, in order to strenghten your network, or send feedback to a channel's owner.</p> + + + + Starred @@ -10913,12 +10977,12 @@ Do you want to save message ? - + Click to sort by signature - + This message was signed and the signature checks @@ -10932,11 +10996,6 @@ Do you want to save message ? This message comes from a distant person. - - - <h1><img width="32" src=":/images/64px_help.png">&nbsp;&nbsp;Messages</h1> <p>Retroshare has its own internal email system. You can send/receive emails to/from connected friend nodes.</p> <p>It is also possible to send messages to other people's Identities using the global routing system. These messages are always encrypted and are relayed by intermediate nodes until they reach their final destination. </p> <p>It is recommended to cryptographically sign distant messages, as a proof of your identity, using the <img width="16" src=":/images/stock_signature_ok.png"/> button in the message composer window. Distant messages stay into your Outbox until an acknowledgement of receipt has been received.</p> <p>Generally, you may use messages to recommend files to your friends by pasting file links, or recommend friend nodes to other friend nodes, in order to strenghten your network, or send feedback to a channel's owner.</p> - - MessengerWindow @@ -11036,7 +11095,7 @@ Do you want to save message ? - + Network Status Unknown @@ -11080,26 +11139,6 @@ Do you want to save message ? Forwarded Port - - - OK | RetroShare Server - - - - - Internet connection - - - - - No internet connection - - - - - No local network - - NetworkDialog @@ -11271,7 +11310,7 @@ For security, your keyring was previously backed-up to file - + Personal signature @@ -11337,7 +11376,7 @@ Right-click and select 'make friend' to be able to connect. - + Data inconsistency in the keyring. This is most probably a bug. Please contact the developers. @@ -11476,7 +11515,7 @@ Reported error: NewsFeed - + News Feed @@ -11495,18 +11534,13 @@ Reported error: This is a test. - - - <h1><img width="32" src=":/images/64px_help.png">&nbsp;&nbsp;News Feed</h1> <p>The News Feed displays the last events on your network, sorted by the time you received them. This gives you a summary of the activity of your friends. You can configure which events to show by pressing on <b>Options</b>. </p> <p>The various events shown are: <ul> <li>Connection attempts (useful to make friends with new people and control who's trying to reach you)</li> <li>Channel and Forum posts</li> <li>New Channels and Forums you can subscribe to</li> <li>Private messages from your friends</li> </ul> </p> - - News feed - + Newest on top @@ -11515,6 +11549,11 @@ Reported error: Oldest on top + + + <h1><img width="32" src=":/icons/help_64.png">&nbsp;&nbsp;News Feed</h1> <p>The News Feed displays the last events on your network, sorted by the time you received them. This gives you a summary of the activity of your friends. You can configure which events to show by pressing on <b>Options</b>. </p> <p>The various events shown are: <ul> <li>Connection attempts (useful to make friends with new people and control who's trying to reach you)</li> <li>Channel and Forum posts</li> <li>New Channels and Forums you can subscribe to</li> <li>Private messages from your friends</li> </ul> </p> + + NotifyPage @@ -11658,7 +11697,12 @@ Reported error: - + + <h1><img width="24" src=":/icons/help_64.png">&nbsp;&nbsp;Notify</h1> <p>Retroshare will notify you about what happens in your network. Depending on your usage, you may want to enable or disable some of the notifications. This page is designed for that!</p> + + + + Top Left @@ -11682,11 +11726,6 @@ Reported error: Notify - - - <h1><img width="24" src=":/images/64px_help.png">&nbsp;&nbsp;Notify</h1> <p>Retroshare will notify you about what happens in your network. Depending on your usage, you may want to enable or disable some of the notifications. This page is designed for that!</p> - - Disable All Toasters @@ -11846,24 +11885,6 @@ Reported error: - - OutQueueStatisticsWidget - - - Outqueue statistics - - - - - By priority: - - - - - By service : - - - PGPKeyDialog @@ -12683,13 +12704,13 @@ malicious behavior of crafted plugins. - - Plugins + + <h1><img width="24" src=":/icons/help_64.png">&nbsp;&nbsp;Plugins</h1> <p>Plugins are loaded from the directories listed in the bottom list.</p> <p>For security reasons, accepted plugins load automatically until the main Retroshare executable or the plugin library changes. In such a case, the user needs to confirm them again. After the program is started, you can enable a plugin manually by clicking on the "Enable" button and then restart Retroshare.</p> <p>If you want to develop your own plugins, contact the developpers team they will be happy to help you out!</p> - - <h1><img width="24" src=":/images/64px_help.png">&nbsp;&nbsp;Plugins</h1> <p>Plugins are loaded from the directories listed in the bottom list.</p> <p>For security reasons, accepted plugins load automatically until the main Retroshare executable or the plugin library changes. In such a case, the user needs to confirm them again. After the program is started, you can enable a plugin manually by clicking on the "Enable" button and then restart Retroshare.</p> <p>If you want to develop your own plugins, contact the developpers team they will be happy to help you out!</p> + + Plugins @@ -12860,7 +12881,12 @@ malicious behavior of crafted plugins. - + + <h1><img width="32" src=":/icons/help_64.png">&nbsp;&nbsp;Posted</h1> <p>The posted service allows you to share internet links, that spread among Retroshare nodes like forums and channels</p> <p>Links can be commented by subscribed users. A promotion system also gives the opportunity to enlight important links.</p> <p>There is no restriction on which links are shared. Be careful when clicking on them.</p> <p>Posted links get deleted after %1 months.</p> + + + + Create Topic @@ -12884,11 +12910,6 @@ malicious behavior of crafted plugins. Other Topics - - - <h1><img width="32" src=":/images/64px_help.png">&nbsp;&nbsp;Posted</h1> <p>The posted service allows you to share internet links, that spread among Retroshare nodes like forums and channels</p> <p>Links can be commented by subscribed users. A promotion system also gives the opportunity to enlight important links.</p> <p>There is no restriction on which links are shared. Be careful when clicking on them.</p> <p>Posted links get deleted after %1 months.</p> - - PostedGroupDialog @@ -13690,7 +13711,7 @@ Characters <b>",|,/,\,&lt;,&gt;,*,?</b> will be replace - + Deny friend @@ -13854,7 +13875,7 @@ Reported error is: - + enabled @@ -14209,7 +14230,7 @@ p, li { white-space: pre-wrap; } RSGraphWidget - + %1 KB @@ -14245,7 +14266,7 @@ p, li { white-space: pre-wrap; } RSPermissionMatrixWidget - + Allowed by default @@ -14276,7 +14297,7 @@ p, li { white-space: pre-wrap; } - Switched Off + Globally switched Off @@ -14298,7 +14319,7 @@ p, li { white-space: pre-wrap; } RSettingsWin - + Error Saving Configuration on page @@ -14407,7 +14428,7 @@ p, li { white-space: pre-wrap; } - <h1><img width="24" src=":/images/64px_help.png">&nbsp;&nbsp;Relays</h1> <p>By activating relays, you allow your Retroshare node to act as a bridge between Retroshare users who cannot connect directly, e.g. because they're firewalled.</p> <p>You may choose to act as a relay by checking <i>enable relay connections</i>, or simply benefit from other peers acting as relay, by checking <i>use relay servers</i>. For the former, you may specify the bandwidth allocated when acting as a relay for friends of you, for friends of your friends, or anyone in the Retroshare network.</p> <p>In any case, a Retroshare node acting as a relay cannot see the relayed traffic, since it is encrypted and authenticated by the two relayed nodes.</p> + <h1><img width="24" src=":/icons/help_64.png">&nbsp;&nbsp;Relays</h1> <p>By activating relays, you allow your Retroshare node to act as a bridge between Retroshare users who cannot connect directly, e.g. because they're firewalled.</p> <p>You may choose to act as a relay by checking <i>enable relay connections</i>, or simply benefit from other peers acting as relay, by checking <i>use relay servers</i>. For the former, you may specify the bandwidth allocated when acting as a relay for friends of you, for friends of your friends, or anyone in the Retroshare network.</p> <p>In any case, a Retroshare node acting as a relay cannot see the relayed traffic, since it is encrypted and authenticated by the two relayed nodes.</p> @@ -14432,7 +14453,7 @@ p, li { white-space: pre-wrap; } RetroshareDirModel - + NEW @@ -14868,29 +14889,6 @@ Reducing image to %1x%2 pixels? - - SFListDelegate - - - B - - - - - KB - - - - - MB - - - - - GB - - - SearchDialog @@ -15905,13 +15903,13 @@ Check your ports! - - <h1><img width="24" src=":/images/64px_help.png">&nbsp;&nbsp;Permissions</h1> <p>Permissions allow you to control which services are available to which friends</p> <p>Each interruptor shows two lights, indicating whether you or your friend has enabled that service. Both needs to be ON (showing <img height=20 src=":/images/switch11.png"/>) to let information transfer for a specific service/friend combination.</p> <p>For each service, the global switch <img height=20 src=":/images/global_switch_on.png"> / <img height=20 src=":/images/global_switch_off.png"> allow to turn a service ON/OFF for all friends at once.</p> <p>Be very careful: Some services depend on each other. For instance turning turtle OFF will also stop all anonymous transfer, distant chat and distant messaging.</p> + + hide offline - - hide offline + + <h1><img width="24" src=":/icons/help_64.png">&nbsp;&nbsp;Permissions</h1> <p>Permissions allow you to control which services are available to which friends</p> <p>Each interruptor shows two lights, indicating whether you or your friend has enabled that service. Both needs to be ON (showing <img height=20 src=":/images/switch11.png"/>) to let information transfer for a specific service/friend combination.</p> <p>For each service, the global switch <img height=20 src=":/images/global_switch_on.png"> / <img height=20 src=":/images/global_switch_off.png"> allow to turn a service ON/OFF for all friends at once.</p> <p>Be very careful: Some services depend on each other. For instance turning turtle OFF will also stop all anonymous transfer, distant chat and distant messaging.</p> @@ -16881,7 +16879,7 @@ p, li { white-space: pre-wrap; } TBoard - + Pause @@ -17268,25 +17266,25 @@ p, li { white-space: pre-wrap; } - + Slower - - + + Average - - + + Faster - + Random @@ -17311,7 +17309,12 @@ p, li { white-space: pre-wrap; } - + + <h1><img width="%1" src=":/icons/help_64.png">&nbsp;&nbsp;File Transfer</h1> <p>Retroshare brings two ways of transferring files: direct transfers from your friends, and distant anonymous tunnelled transfers. In addition, file transfer is multi-source and allows swarming (you can be a source while downloading)</p> <p>You can share files using the <img src=":/images/directoryadd_24x24_shadow.png" width=%2 /> icon from the left side bar. These files will be listed in the My Files tab. You can decide for each friend group whether they can or not see these files in their Friends Files tab</p> <p>The search tab reports files from your friends' file lists, and distant files that can be reached anonymously using the multi-hop tunnelling system.</p> + + + + Move in Queue... @@ -17471,7 +17474,7 @@ Try to be patient! - + Last Time Seen i.e: Last Time Receiced Data @@ -17577,7 +17580,7 @@ Try to be patient! - + Columns @@ -17587,7 +17590,7 @@ Try to be patient! - + Path i.e: Where file is saved @@ -17603,12 +17606,7 @@ Try to be patient! - - <h1><img width="32" src=":/images/64px_help.png">&nbsp;&nbsp;File Transfer</h1> <p>Retroshare brings two ways of transferring files: direct transfers from your friends, and distant anonymous tunnelled transfers. In addition, file transfer is multi-source and allows swarming (you can be a source while downloading)</p> <p>You can share files using the <img src=":/images/directoryadd_24x24_shadow.png" width=16 /> icon from the left side bar. These files will be listed in the My Files tab. You can decide for each friend group whether they can or not see these files in their Friends Files tab</p> <p>The search tab reports files from your friends' file lists, and distant files that can be reached anonymously using the multi-hop tunnelling system.</p> - - - - + Could not delete preview file @@ -17618,7 +17616,7 @@ Try to be patient! - + Create Collection... @@ -17633,7 +17631,7 @@ Try to be patient! - + Collection @@ -17648,12 +17646,12 @@ Try to be patient! - + Show file list transfers - + version: @@ -17689,7 +17687,7 @@ Try to be patient! - + Friends Directories @@ -18027,10 +18025,20 @@ Try to be patient! - + + <h1><img width="24" src=":/icons/help_64.png">&nbsp;&nbsp;Webinterface</h1> <p>The webinterface allows to control Retroshare from the browser. Multiple devices can share control over one Retroshare instance. So you could start a conversation on a tablet computer and later use a desktop computer to continue it.</p> <p>Warning: don't expose the webinterface to the internet, because there is no access control and no encryption. If you want to use the webinterface over the internet, use a SSH tunnel or a proxy to secure the connection.</p> + + + + Webinterface not enabled + + + The webinterface is not enabled. Enable it in Settings -> Webinterface. + + failed to start Webinterface @@ -18041,11 +18049,6 @@ Try to be patient! Webinterface - - - <h1><img width="24" src=":/images/64px_help.png">&nbsp;&nbsp;Webinterface</h1> <p>The webinterface allows to control Retroshare from the browser. Multiple devices can share control over one Retroshare instance. So you could start a conversation on a tablet computer and later use a desktop computer to continue it.</p> <p>Warning: don't expose the webinterface to the internet, because there is no access control and no encryption. If you want to use the webinterface over the internet, use a SSH tunnel or a proxy to secure the connection.</p> - - WikiAddDialog diff --git a/retroshare-gui/src/mingw32make.bat b/retroshare-gui/src/mingw32make.bat index ec970270a..bab087ec7 100644 --- a/retroshare-gui/src/mingw32make.bat +++ b/retroshare-gui/src/mingw32make.bat @@ -1,10 +1,11 @@ set QTDIR=C:\Qt\4.8.6 set MINGW=C:\MinGW +set GIT=C:\Program Files\Git -set PATH=%QTDIR%\bin;%MINGW%\bin;%PATH% +set PATH=%QTDIR%\bin;%MINGW%\bin;%GIT%\bin;%PATH% -qmake retroshare-gui.pro +qmake retroshare-gui.pro "CONFIG+=version_detail_bash_script" mingw32-make diff --git a/retroshare-gui/src/retroshare-gui.pro b/retroshare-gui/src/retroshare-gui.pro index bb724bb4c..97e37ef96 100644 --- a/retroshare-gui/src/retroshare-gui.pro +++ b/retroshare-gui/src/retroshare-gui.pro @@ -1,5 +1,8 @@ -QT += network xml script +!include("../../retroshare.pri"): error("Could not include file ../../retroshare.pri") + +QT += network xml CONFIG += qt gui uic qrc resources idle bitdht +CONFIG += link_prl # Plz never commit the .pro with these flags enabled. # Use this flag when developping new features only. @@ -44,7 +47,7 @@ unfinished { #CONFIG += blogs TEMPLATE = app -TARGET = RetroShare +TARGET = RetroShare06 DEFINES += RS_RELEASE_VERSION RCC_DIR = temp/qrc @@ -74,42 +77,47 @@ linux-* { QMAKE_CXXFLAGS *= -D_FILE_OFFSET_BITS=64 PRE_TARGETDEPS *= ../../libretroshare/src/lib/libretroshare.a - PRE_TARGETDEPS *= ../../openpgpsdk/src/lib/libops.a LIBS += ../../libretroshare/src/lib/libretroshare.a - LIBS += ../../openpgpsdk/src/lib/libops.a -lbz2 - LIBS += -lssl -lupnp -lixml -lXss -lgnome-keyring - LIBS *= -lcrypto -ldl -lX11 -lz + LIBS *= -lX11 -lXss LIBS += ../../supportlibs/pegmarkdown/lib/libpegmarkdown.a - SQLCIPHER_OK = $$system(pkg-config --exists sqlcipher && echo yes) - isEmpty(SQLCIPHER_OK) { -# We need a explicit path here, to force using the home version of sqlite3 that really encrypts the database. - - exists(../../../lib/sqlcipher/.libs/libsqlcipher.a) { - - LIBS += ../../../lib/sqlcipher/.libs/libsqlcipher.a - DEPENDPATH += ../../../lib/sqlcipher/src/ - INCLUDEPATH += ../../../lib/sqlcipher/src/ - DEPENDPATH += ../../../lib/sqlcipher/tsrc/ - INCLUDEPATH += ../../../lib/sqlcipher/tsrc/ - } else { - message(libsqlcipher.a not found. Compilation will not use SQLCIPHER. Database will be unencrypted.) - DEFINES *= NO_SQLCIPHER - LIBS *= -lsqlite3 - } - - } else { - LIBS += -lsqlcipher - } - - LIBS *= -lglib-2.0 - LIBS *= -rdynamic + #LIBS *= -lglib-2.0 + LIBS *= -rdynamic -ldl DEFINES *= HAVE_XSS # for idle time, libx screensaver extensions DEFINES *= UBUNTU } +unix { + target.path = "$${BIN_DIR}" + INSTALLS += target + + data_files.path="$${DATA_DIR}/" + data_files.files=sounds qss + INSTALLS += data_files + + style_files.path="$${DATA_DIR}/stylesheets" + style_files.files=gui/qss/chat/Bubble gui/qss/chat/Bubble_Compact + INSTALLS += style_files + + icon_files.path = "$${PREFIX}/share/icons/hicolor" + icon_files.files = ../../data/24x24 + icon_files.files += ../../data/48x48 + icon_files.files += ../../data/64x64 + icon_files.files += ../../data/128x128 + INSTALLS += icon_files + + desktop_files.path = "$${PREFIX}/share/applications" + desktop_files.files = ../../data/retroshare06.desktop + INSTALLS += desktop_files + + pixmap_files.path = "$${PREFIX}/share/pixmaps" + pixmap_files.files = ../../data/retroshare06.xpm + INSTALLS += pixmap_files + +} + linux-g++ { OBJECTS_DIR = temp/linux-g++/obj } @@ -119,16 +127,17 @@ linux-g++-64 { } version_detail_bash_script { - DEFINES += ADD_LIBRETROSHARE_VERSION_INFO - QMAKE_EXTRA_TARGETS += write_version_detail - PRE_TARGETDEPS = write_version_detail - write_version_detail.commands = ./version_detail.sh -} - -install_rs { - INSTALLS += binary_rs - binary_rs.path = $$(PREFIX)/usr/bin - binary_rs.files = ./RetroShare + linux-* { + DEFINES += ADD_LIBRETROSHARE_VERSION_INFO + QMAKE_EXTRA_TARGETS += write_version_detail + PRE_TARGETDEPS = write_version_detail + write_version_detail.commands = ./version_detail.sh + } + win32 { + QMAKE_EXTRA_TARGETS += write_version_detail + PRE_TARGETDEPS = write_version_detail + write_version_detail.commands = $$PWD/version_detail.bat + } } #################### Cross compilation for windows under Linux ################### @@ -158,7 +167,7 @@ win32-x-g++ { #################################### Windows ##################################### win32 { - debug { + CONFIG(debug, debug|release) { # show console output CONFIG += console } @@ -167,6 +176,9 @@ win32 { QMAKE_CFLAGS += -Wextra QMAKE_CXXFLAGS += -Wextra + # solve linker warnings because of the order of the libraries + QMAKE_LFLAGS += -Wl,--start-group + # Switch off optimization for release version QMAKE_CXXFLAGS_RELEASE -= -O2 QMAKE_CXXFLAGS_RELEASE += -O0 @@ -182,20 +194,16 @@ win32 { #QTPLUGIN += qjpeg PRE_TARGETDEPS *= ../../libretroshare/src/lib/libretroshare.a - PRE_TARGETDEPS *= ../../openpgpsdk/src/lib/libops.a LIBS_DIR = $$PWD/../../../libs LIBS += ../../libretroshare/src/lib/libretroshare.a - LIBS += ../../openpgpsdk/src/lib/libops.a -lbz2 LIBS += -L"$$LIBS_DIR/lib" LIBS += ../../supportlibs/pegmarkdown/lib/libpegmarkdown.a LIBS += -lsqlcipher - LIBS += -lssl -lcrypto -lpthread -lminiupnpc -lz -# added after bitdht -# LIBS += -lws2_32 + LIBS += -lssl -lcrypto -lpthread -lminiupnpc -lz -lws2_32 LIBS += -luuid -lole32 -liphlpapi -lcrypt32 -lgdi32 LIBS += -lole32 -lwinmm RC_FILE = gui/images/retroshare_win.rc @@ -232,7 +240,6 @@ macx { CONFIG += version_detail_bash_script LIBS += ../../libretroshare/src/lib/libretroshare.a - LIBS += ../../openpgpsdk/src/lib/libops.a -lbz2 LIBS += -lssl -lcrypto -lz #LIBS += -lssl -lcrypto -lz -lgpgme -lgpg-error -lassuan LIBS += ../../../miniupnpc-1.0/libminiupnpc.a @@ -270,10 +277,8 @@ openbsd-* { INCLUDEPATH *= /usr/local/include PRE_TARGETDEPS *= ../../libretroshare/src/lib/libretroshare.a - PRE_TARGETDEPS *= ../../openpgpsdk/src/lib/libops.a LIBS *= ../../libretroshare/src/lib/libretroshare.a - LIBS *= ../../openpgpsdk/src/lib/libops.a -lbz2 LIBS *= -lssl -lcrypto LIBS *= -lgpgme LIBS *= -lupnp @@ -295,11 +300,6 @@ openbsd-* { # ########################################### -bitdht { - LIBS += ../../libbitdht/src/lib/libbitdht.a - PRE_TARGETDEPS *= ../../libbitdht/src/lib/libbitdht.a -} - DEPENDPATH += . ../../libretroshare/src/ INCLUDEPATH += ../../libretroshare/src/ @@ -309,11 +309,6 @@ INCLUDEPATH += ../../libresapi/src PRE_TARGETDEPS *= ../../libresapi/src/lib/libresapi.a LIBS += ../../libresapi/src/lib/libresapi.a -lmicrohttpd -win32 { -# must be added after bitdht - LIBS += -lws2_32 -} - # Input HEADERS += rshare.h \ retroshare-gui/configpage.h \ diff --git a/retroshare-gui/src/rshare.cpp b/retroshare-gui/src/rshare.cpp index 46dbc8c3f..4528215d4 100644 --- a/retroshare-gui/src/rshare.cpp +++ b/retroshare-gui/src/rshare.cpp @@ -178,7 +178,7 @@ QString Rshare::retroshareVersion(bool withRevision) { QString version = QString("%1.%2.%3%4").arg(RS_MAJOR_VERSION).arg(RS_MINOR_VERSION).arg(RS_BUILD_NUMBER).arg(RS_BUILD_NUMBER_ADD); if (withRevision) { - version += QString(" %1 %2").arg(tr("Revision")).arg(RS_REVISION_NUMBER); + version += QString(" %1 %2").arg(tr("Revision")).arg(QString::number(RS_REVISION_NUMBER,16)); } return version; @@ -613,7 +613,7 @@ Rshare::dataDirectory() QString Rshare::defaultDataDirectory() { -#if defined(Q_OS_WIN32) +#if defined(Q_OS_WIN) return (win32_app_data_folder() + "\\RetroShare"); #else return (QDir::homePath() + "/.RetroShare"); diff --git a/retroshare-gui/src/svn_revision.bat b/retroshare-gui/src/svn_revision.bat deleted file mode 100644 index c32e950fc..000000000 --- a/retroshare-gui/src/svn_revision.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -"D:\Programme\TortoiseSVN\bin\SubWCRev" . util\rsguiversion.in util\rsguiversion.cpp \ No newline at end of file diff --git a/retroshare-gui/src/util/HandleRichText.cpp b/retroshare-gui/src/util/HandleRichText.cpp index edfef3a80..980dcbd88 100644 --- a/retroshare-gui/src/util/HandleRichText.cpp +++ b/retroshare-gui/src/util/HandleRichText.cpp @@ -416,7 +416,7 @@ QString RsHtml::formatText(QTextDocument *textDocument, const QString &text, ulo formattedText = doc.toString(-1); // -1 removes any annoying carriage return misinterpreted by QTextEdit if (flag & RSHTML_OPTIMIZEHTML_MASK) { - optimizeHtml(formattedText, flag & RSHTML_OPTIMIZEHTML_MASK, backgroundColor, desiredContrast); + optimizeHtml(formattedText, flag, backgroundColor, desiredContrast); } return formattedText; @@ -556,8 +556,49 @@ static void findBestColor(QString &val, qreal bglum, qreal desiredContrast) #endif // QT_VERSION < 0x040600 } -static void optimizeHtml(QDomDocument& doc, QDomElement& currentElement, unsigned int flag, qreal bglum, qreal desiredContrast) +/** + * @brief optimizeHtml: Optimize HTML Text in DomDocument to reduce size + * @param doc: QDomDocument containing Text to optimize + * @param currentElement: Current element optimized + * @param stylesList: List where to save all differents styles used in text + * @param knownStyle: List of known styles + */ +static void optimizeHtml(QDomDocument& doc + , QDomElement& currentElement + , QHash &stylesList + , QHash &knownStyle) { + bool bFirstP=true; + if (doc.documentElement().namedItem("style").toElement().attributeNode("RSOptimized").isAttr()) { + //Already optimized only get StyleList + QDomElement styleElem = doc.documentElement().namedItem("style").toElement(); + if (!styleElem.isElement()) return; //Not an element so a bad message. + QDomAttr styleAttr = styleElem.attributeNode("RSOptimized"); + if (!styleAttr.isAttr()) return; //Not an attribute so a bad message. + QString version = styleAttr.value(); + if (version == "v2") { + + QStringList allStyles = styleElem.text().split('}'); + foreach (QString style, allStyles){ + QStringList pair = style.split('{'); + if (pair.length()!=2) return; //Malformed style list so a bad message or last item. + QString keyvalue = pair.at(1); + keyvalue.replace(";",""); + QStringList* classUsingIt = new QStringList(pair.at(0).split(',')); + QStringList* exported = new QStringList(); + foreach (QString keyVal, *classUsingIt) { + if(!keyVal.trimmed().isEmpty()) { + exported->append(keyVal.trimmed().replace(".","")); + } + } + + stylesList.insert(keyvalue, exported); + } + } + + return; + } + if (currentElement.tagName().toLower() == "html") { // change to currentElement.setTagName("span"); @@ -570,62 +611,45 @@ static void optimizeHtml(QDomDocument& doc, QDomElement& currentElement, unsigne for (uint index = 0; index < children.length(); ) { QDomNode node = children.item(index); - // compress style attribute + // Compress style attribute styleNode = node.attributes().namedItem("style"); if (styleNode.isAttr()) { QDomAttr styleAttr = styleNode.toAttr(); - QString style = styleAttr.value().simplified(); + QString style = styleAttr.value().simplified().trimmed(); style.replace("margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px;", "margin:0px 0px 0px 0px;"); style.replace("; ", ";"); - if (flag) { + QString className = knownStyle.value(style); + if (className.isEmpty()) { + // Create a new class + className = QString("S%1").arg(knownStyle.count()); + knownStyle.insert(style, className); + + // Now add this for each attribute values QStringList styles = style.split(';'); - style.clear(); foreach (QString pair, styles) { - if (!pair.trimmed().isEmpty()) { - QStringList keyvalue = pair.split(':'); - if (keyvalue.length() == 2) { - QString key = keyvalue.at(0).trimmed(); - QString val = keyvalue.at(1).trimmed(); + pair.replace(" ",""); + if (!pair.isEmpty()) { + QStringList* stylesListItem = stylesList.value(pair); + if(!stylesListItem){ + // If value doesn't exist create it + stylesListItem = new QStringList(); + stylesList.insert(pair, stylesListItem); + } + //Add the new class to this value + stylesListItem->push_back(className); + } + } + } + style.clear(); - if ((flag & RSHTML_FORMATTEXT_REMOVE_FONT_FAMILY && key == "font-family") || - (flag & RSHTML_FORMATTEXT_REMOVE_FONT_SIZE && key == "font-size") || - (flag & RSHTML_FORMATTEXT_REMOVE_FONT_WEIGHT && key == "font-weight") || - (flag & RSHTML_FORMATTEXT_REMOVE_FONT_STYLE && key == "font-style")) { - continue; - } - if (flag & RSHTML_FORMATTEXT_REMOVE_COLOR) { - if (key == "color") { - continue; - } - } - else if (flag & RSHTML_FORMATTEXT_FIX_COLORS) { - if (key == "color") { - findBestColor(val, bglum, desiredContrast); - } - } - if (flag & (RSHTML_FORMATTEXT_REMOVE_COLOR | RSHTML_FORMATTEXT_FIX_COLORS)) { - if (key == "background" || key == "background-color") { - // Remove background color because if we change the text color, - // it can become unreadable on the original background. - // Also, FIX_COLORS is intended to display text on the default - // background color of the operating system. - continue; - } - } - - style += key + ":" + val + ";"; - } else { - style += pair + ";"; - } - } - } - } - if (style.isEmpty()) { node.attributes().removeNamedItem("style"); styleNode.clear(); - } else { - styleAttr.setValue(style); + + if (!className.isEmpty()) { + QDomNode classNode = doc.createAttribute("class"); + classNode.setNodeValue(className); + node.attributes().setNamedItem(classNode); } } @@ -662,18 +686,23 @@ static void optimizeHtml(QDomDocument& doc, QDomElement& currentElement, unsigne } // iterate children - optimizeHtml(doc, element, flag, bglum, desiredContrast); + optimizeHtml(doc, element, stylesList, knownStyle); //

if (element.tagName().toLower() == "p") { + //If it's the first

, replace it as otherwise make "\n" before first line + if (bFirstP) { + element.setTagName("span"); + bFirstP = false; + } //

if (element.attributes().size() == 1 && styleNode.isAttr()) { QString style = styleNode.toAttr().value().simplified(); - if (style == "margin:0px 0px 0px 0px;-qt-block-indent:0;text-indent:0px;" || - style.startsWith("-qt-paragraph-type:empty;margin:0px 0px 0px 0px;-qt-block-indent:0;text-indent:0px;")) { + if (style == "margin:0px 0px 0px 0px;-qt-block-indent:0;text-indent:0px;" + || style.startsWith("-qt-paragraph-type:empty;margin:0px 0px 0px 0px;-qt-block-indent:0;text-indent:0px;")) { if (addBR) { - // add
after a removed

before a removed

+ // add
after a removed

but not before a removed

QDomElement elementBr = doc.createElement("br"); currentElement.insertBefore(elementBr, element); ++index; @@ -681,51 +710,11 @@ static void optimizeHtml(QDomDocument& doc, QDomElement& currentElement, unsigne // remove Qt standard

or empty

index += element.childNodes().length(); removeElement(currentElement, element); - addBR = true; + // do not add extra
after empty paragraph, the paragraph already contains one + addBR = ! style.startsWith("-qt-paragraph-type:empty"); continue; } - // check for blockquote (not ready) - // style="margin-top:12px;margin-bottom:12px;margin-left:40px;margin-right:40px;-qt-block-indent:0;text-indent:0px;" -// int count = 0; // should be 6 -// QStringList styles = style.split(';'); -// foreach (QString pair, styles) { -// if (!pair.trimmed().isEmpty()) { -// QStringList keyvalue = pair.split(':'); -// if (keyvalue.length() == 2) { -// QString key = keyvalue.at(0).trimmed(); -// QString value = keyvalue.at(1).trimmed(); - -// if ((key == "margin-top" || key == "margin-bottom") && value == "12px") { -// ++count; -// continue; -// } -// if (key == "margin-left" || key == "margin-right") { -// ++count; -// continue; -// } -// if (key == "-qt-block-indent" && value == "0") { -// ++count; -// continue; -// } -// if (key == "text-indent" && value == "0px") { -// ++count; -// continue; -// } -// count = 0; -// break; -// } else { -// count = 0; -// break; -// } -// } -// } -// if (count == 6) { -// // change to "blockquote" -// element.setTagName("blockquote"); -// element.attributes().removeNamedItem("style"); -// element.setAttribute("type", "cite"); -// } } addBR = false; } @@ -734,7 +723,124 @@ static void optimizeHtml(QDomDocument& doc, QDomElement& currentElement, unsigne } } -void RsHtml::optimizeHtml(QTextEdit *textEdit, QString &text, unsigned int flag) +/** + * @brief styleCreate: Add styles filtered in QDomDocument. + * @param doc: QDomDocument containing all text formatted + * @param stylesList: List of all styles recognized + * @param flag: Bitfield of RSHTML_FORMATTEXT_* constants (they must be part of + * RSHTML_OPTIMIZEHTML_MASK). + * @param bglum: Luminance background color of the widget where the text will be + * displayed. Needed only if RSHTML_FORMATTEXT_FIX_COLORS + * is passed inside flag. + * @param desiredContrast: Minimum contrast between text and background color, + * between 1 and 21. + */ +static void styleCreate(QDomDocument& doc + , QHash stylesList + , unsigned int flag + , qreal bglum + , qreal desiredContrast) +{ + QDomElement styleElem; + do{ + if (doc.documentElement().namedItem("style").toElement().attributeNode("RSOptimized").isAttr()) { + QDomElement ele = doc.documentElement().namedItem("style").toElement(); + //Remove child before filter + if (!ele.isElement()) break; //Not an element so a bad message. + QDomAttr styleAttr = ele.attributeNode("RSOptimized"); + if (!styleAttr.isAttr()) break; //Not an attribute so a bad message. + QString version = styleAttr.value(); + if (version == "v2") { + styleElem = ele; + } + } + }while (false); //for break + + if(!styleElem.isElement()) { + styleElem = doc.createElement("style"); + // Creation of Style class list: