merged to upstream/master

This commit is contained in:
mr-alice 2016-06-18 16:59:01 -04:00
commit 8e2ff56f9a
395 changed files with 15613 additions and 45420 deletions

View File

@ -1,16 +1,13 @@
sudo: required
dist: trusty
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 libavutil-dev 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
- sudo apt-get install -y build-essential checkinstall cmake libavutil-dev libavcodec-dev libavformat-dev libbz2-dev libcurl4-openssl-dev libcv-dev libopencv-highgui-dev libhighgui-dev libgnome-keyring-dev libgstreamer-plugins-base0.10-dev libgstreamer0.10-dev libjasper-dev libjpeg-dev libmicrohttpd-dev libopencv-dev libprotobuf-dev libqt4-dev libspeex-dev libspeexdsp-dev libsqlite3-dev libssl-dev libswscale-dev libtbb-dev libtiff4-dev libupnp-dev libv4l-dev libxine-dev libxslt1-dev libxss-dev pkg-config protobuf-compiler python-dev 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
@ -32,7 +29,7 @@ addons:
branch_pattern: coverity_scan
before_script:
- qmake CONFIG+=NO_SQLCIPHER CONFIG+=tests
- qmake QMAKE_CC=$CC QMAKE_CXX=$CXX CONFIG+=NO_SQLCIPHER CONFIG+=tests
#script: make
script: if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then make && tests/unittests/unittests >/dev/null 2>&1 ; fi
@ -64,6 +61,3 @@ notifications:
#env:
# - RVM=2.0.0 LANG="en_US.UTF-8"
os:
- linux

View File

@ -2,6 +2,22 @@ RetroShare
==============================
RetroShare is a decentralized, private and secure commmunication and sharing platform. RetroShare provides filesharing, chat, messages, forums and channels.
Build Status
------------
| Platform | Build Status |
| :------------- | :------------- |
| GNU/Linux, MacOS, (via travis-ci) | [![Build Status](https://travis-ci.org/RetroShare/RetroShare.svg?branch=master)](https://travis-ci.org/RetroShare/RetroShare) |
| Windows, `MSys2` (via appveyor) | [![Build status](https://ci.appveyor.com/api/projects/status/axkopdqj9fc48kwe?svg=true)](https://ci.appveyor.com/project/PhenomRetroShare/retroshare) |
Compilation on Windows
----------------------------
Follow this file : [WindowsMSys2_InstallGuide.txt](https://github.com/RetroShare/RetroShare/blob/master/WindowsMSys2_InstallGuide.txt)
Compilation on MacOSX
----------------------------
Follow this file : [MacOS_X_InstallGuide.txt](https://github.com/RetroShare/RetroShare/blob/master/MacOS_X_InstallGuide.txt)
Compilation on Linux
----------------------------

210
appveyor.yml Normal file
View File

@ -0,0 +1,210 @@
# Notes:
# - Minimal appveyor.yml file is an empty file. All sections are optional.
# - Indent each level of configuration with 2 spaces. Do not use tabs!
# - All section names are case-sensitive.
# - Section names should be unique on each level.
# from example:
# https://github.com/Phonations/Joker/blob/master/appveyor.yml
# https://github.com/unicorn-engine/autobuild/blob/master/.appveyor.yml
#---------------------------------#
# general configuration #
#---------------------------------#
# version format
version: RetroShare 6.0.{build}-{branch}
# you can use {branch} name in version format too
# version: 1.0.{build}-{branch}
# branches to build
branches:
# whitelist
#only:
# - master
# blacklist
except:
- /^skipthisbranch$/
# Do not build on tags (GitHub only)
skip_tags: true
# Skipping commits with particular message or from user
skip_commits:
message: /Created.*\.(png|jpg|jpeg|bmp|gif)/ # Regex for matching commit message
#author: Anonymous # Commit author's username, name, email or regexp maching one of these.
#---------------------------------#
# environment configuration #
#---------------------------------#
# Operating system (build VM template)
#os: Windows Server 2012
# scripts that are called at very beginning, before repo cloning
init:
- git config --global core.autocrlf input
#To get RDP while compiling
- ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
on_finish:
#To get RDP running after compiling
#- ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
# clone directory
clone_folder: c:\projects\RetroShare
# fetch repository as zip archive
#shallow_clone: true # default is "false"
# set clone depth
clone_depth: 1 # clone entire repository history if not defined
environment:
global:
#Qt: https://www.appveyor.com/docs/installed-software#qt
QTDIR: C:\Qt\5.4\mingw491_32
MSYS2_ARCH: i686
TARGET: i686_32-pc-msys
# build cache to preserve files/folders between builds
cache:
- c:\projects\libs
# - packages -> **\packages.config # preserve "packages" directory in the root of build folder but will reset it if packages.config is modified
# - projectA\libs
# - node_modules # local npm modules
# - %APPDATA%\npm-cache # npm cache
# scripts that run after cloning repository
#install:
# # by default, all script lines are interpreted as batch
# - echo This is batch
# # to run script as a PowerShell command prepend it with ps:
# - ps: Write-Host 'This is PowerShell'
# # batch commands start from cmd:
# - cmd: echo This is batch again
# - cmd: set MY_VAR=12345
install:
# Configuring MSys2
- set PATH=C:\msys64\usr\bin;%PATH%
- set PATH=C:\msys64\mingw32\bin;%PATH%
# Configuring Qt
- set PATH=%QTDIR%\bin;C:\Qt\Tools\mingw491_32\bin;%PATH%
# Install all default programms
#- C:\msys64\usr\bin\bash -lc "pacman --noconfirm -Sy base-devel git mercurial cvs wget p7zip gcc perl ruby python2" #Already installed
- C:\msys64\usr\bin\bash -lc "pacman --noconfirm -Sy openssl-devel"
# Install toolchain
#- C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-i686-toolchain mingw-w64-x86_64-toolchain" #Already installed
# Install other binutils
- C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-i686-miniupnpc mingw-w64-x86_64-miniupnpc"
- C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-i686-sqlite3 mingw-w64-x86_64-sqlite3"
- C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-i686-speex mingw-w64-x86_64-speex"
- C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-i686-opencv mingw-w64-x86_64-opencv"
- C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-i686-ffmpeg mingw-w64-x86_64-ffmpeg"
- C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-i686-libmicrohttpd mingw-w64-x86_64-libmicrohttpd"
- C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-i686-libxslt mingw-w64-x86_64-libxslt"
# Hack for new MSys2
- copy C:\msys64\mingw32\i686-w64-mingw32\bin\ar.exe C:\msys64\mingw32\bin\i686-w64-mingw32-ar.exe
- copy C:\msys64\mingw32\i686-w64-mingw32\bin\ranlib.exe C:\msys64\mingw32\bin\i686-w64-mingw32-ranlib.exe
- copy C:\msys64\mingw32\bin\windres.exe C:\msys64\mingw32\bin\i686-w64-mingw32-windres.exe
- copy C:\msys64\mingw64\x86_64-w64-mingw32\bin\ar.exe C:\msys64\mingw64\bin\x86_64-w64-mingw32-ar.exe
- copy C:\msys64\mingw64\x86_64-w64-mingw32\bin\ranlib.exe C:\msys64\mingw64\bin\x86_64-w64-mingw32-ranlib.exe
- copy C:\msys64\mingw64\bin\windres.exe C:\msys64\mingw64\bin\x86_64-w64-mingw32-windres.exe
# Build missing Libs
- C:\msys64\mingw32_shell.bat -lc "cd /c/projects/RetroShare/msys2_build_libs/ && make"
# Clone RetroShare
#- git clone -q --branch={branch} https://github.com/RetroShare/RetroShare.git C:\projects\RetroShare
#---------------------------------#
# build configuration #
#---------------------------------#
# build platform, i.e. x86, x64, Any CPU. This setting is optional.
platform: x86
# to add several platforms to build matrix:
#platform:
# - x86
# - Any CPU
# build Configuration, i.e. Debug, Release, etc.
configuration: Release
# to add several configurations to build matrix:
#configuration:
# - Debug
# - Release
# scripts to run before build
before_build:
# scripts to run *after* solution is built and *before* automatic packaging occurs (web apps, NuGet packages, Azure Cloud Services)
before_package:
# scripts to run after build
after_build:
# to run your custom scripts instead of automatic MSBuild
build_script:
- cd C:\projects\RetroShare
- qmake
- make
# to disable automatic builds
#build: off
#---------------------------------#
# artifacts configuration #
#---------------------------------#
#artifacts:
#
# # pushing a single file
# - path: test.zip
#
# # pushing a single file with environment variable in path and "Deployment name" specified
# - path: MyProject\bin\$(configuration)
# name: myapp
#
# # pushing entire folder as a zip archive
# - path: logs
#---------------------------------#
# deployment configuration #
#---------------------------------#
#No deployment under unknown computer!!!
#---------------------------------#
# global handlers #
#---------------------------------#
# on successful build
#on_success:
# - do something
# on build failure
#on_failure:
# - do something
# after build failure or success
#on_finish:
# - do something
#---------------------------------#
# notifications #
#---------------------------------#
notifications:
# Email
- provider: Email
to:
- retrosharephenom@gmail.com
subject: 'Build {{status}}' # optional
message: "{{message}}, {{commitId}}, ..." # optional
on_build_status_changed: true

View File

@ -1,5 +1,364 @@
retroshare06 (0.6.0-1.XXXXXX~YYYYYY) YYYYYY; urgency=low
cbef014 csoler Sun, 29 May 2016 16:09:56 -0400 added regular test of circle auto-subscribe from cache, and auto-subscribe w
2bde81f csoler Sat, 28 May 2016 21:09:44 -0400 removed more debug info, improved tooltips
ccd72cb csoler Sat, 28 May 2016 20:58:28 -0400 removed some debug info. Added information tooltips on circles and ids in ci
9a328f6 csoler Sat, 28 May 2016 20:25:15 -0400 extended auto-subscribe to circles with admin flag
d114b83 csoler Sat, 28 May 2016 20:17:19 -0400 extended auto-subscribe to circles with requested membership
8b5e43f csoler Sat, 28 May 2016 17:18:25 -0400 remove subitems in circles member list when they are gone from cache
dafb2e6 csoler Fri, 27 May 2016 17:35:23 -0400 Merge pull request #396 from csoler/v0.6-Circles
cfdaa2c csoler Fri, 27 May 2016 17:09:13 -0400 removed debug info in p3gxscircles
d03d733 csoler Fri, 27 May 2016 12:44:14 -0400 Merge pull request #395 from hasufell/master
ed867c5 Julian Ospald Fri, 27 May 2016 18:07:28 +0200 Don't hardcode g++ in the toolchain settings
74b4d66 csoler Thu, 26 May 2016 21:16:21 -0400 added ifdef to allow to remove the sorting of circles into member/not member. To be tested for final decision
59aef8a csoler Thu, 26 May 2016 20:33:24 -0400 added packet slicing for large broadcast chat items, and output warning when chat of serialised item is too big. Als
ae5929e csoler Thu, 26 May 2016 18:58:48 -0400 fixed possible crash due to using a deleted item
a32bcba csoler Wed, 25 May 2016 21:17:09 -0400 changed Members to Invited members in circle creation dialog
d1f4e13 csoler Wed, 25 May 2016 19:04:45 -0400 removed display of circle members in left ID list
cfeed5c csoler Wed, 25 May 2016 18:47:06 -0400 fixed column width and titles in circles
605763d csoler Wed, 25 May 2016 18:34:12 -0400 added all IDs in circle to display tree
219dd01 csoler Wed, 25 May 2016 17:51:23 -0400 improved GUI display in circle list
5b69fa0 csoler Tue, 24 May 2016 21:23:35 -0400 fixed re-draw of subitem in circle tree when flags changed
2e91ab6 csoler Tue, 24 May 2016 21:07:50 -0400 added proper notify for subscription message reception in circles
5bc83d9 csoler Mon, 23 May 2016 21:09:06 -0400 fixed unsubscription of external circles
1b5d31f csoler Sun, 22 May 2016 21:15:18 -0400 attempt to fix the wrong display of uploaded size for files > 4Gb (to be confirmed)
55cb15c csoler Sun, 22 May 2016 20:35:51 -0400 fixed updating of membership when loading circle cache entry
fac1fb8 csoler Sun, 22 May 2016 18:50:18 -0400 enabled message publish for circle subscription requests
69573d1 csoler Sun, 22 May 2016 18:49:54 -0400 fixed serialisation of circle subscription requests
68e618b csoler Sun, 22 May 2016 18:21:48 -0400 fixed GUI for circle invites
6554832 csoler Sun, 22 May 2016 18:21:26 -0400 added isOwnId handle in rsidentity
be3be9f csoler Sun, 22 May 2016 18:21:00 -0400 put loading circles in cache as soon as we get the data for them. The cache entry might be incomplete.
d60e99e csoler Sat, 21 May 2016 16:50:50 -0400 added subwidgets for invited GXS ids in circles
82ad7d6 csoler Sat, 21 May 2016 15:51:49 -0400 improved debugoutput in p3gxscircles
4c5c09c csoler Thu, 19 May 2016 10:11:15 -0400 Merge pull request #390 from PhenomRetroShare/Fix_MutexInPqiPersonGrp
3a2b9e8 csoler Wed, 18 May 2016 21:47:34 -0400 added some debug info in new circle code
abe0e02 anon tahoe Wed, 18 May 2016 14:46:42 +0200 replaced mktemp by mkstemp (cherry-picked from anontahoe repository)
722609a csoler Wed, 18 May 2016 21:13:54 -0400 finished implementing the backend part for the subscription system
af5129c Phenom Wed, 18 May 2016 19:15:37 +0200 Fix Mutex in pqipersongrp for pqilistener by adding local Mutex.
9f56069 csoler Tue, 17 May 2016 11:21:03 -0400 Merge pull request #389 from PhenomRetroShare/Fix_ClearWebAPIWhenClearChatHistory
07191a7 Phenom Tue, 17 May 2016 16:50:59 +0200 Fix Clear WebAPI when clear chat history in GUI and server is not running.
f3aed81 csoler Tue, 17 May 2016 10:39:56 -0400 added test over signature size to avoid possible memory corruption (Anonymous source)
89472d6 csoler Tue, 17 May 2016 00:00:15 -0400 put some notes and comments in the code for what is to be done
116e742 csoler Mon, 16 May 2016 12:25:51 -0400 Merge pull request #388 from PhenomRetroShare/Fix_OpenExistingFileAsWarning
a2a0582 Phenom Mon, 16 May 2016 17:20:53 +0200 Change Open existing file link from Question to Warning.
2064870 csoler Mon, 16 May 2016 10:29:58 -0400 Merge pull request #385 from PhenomRetroShare/Fix_RsCollectionFileLoadCall
1f8f413 Phenom Mon, 16 May 2016 11:32:17 +0200 Fix RsCollectionFile::load(QString, bool) calls.
5d69072 csoler Sat, 14 May 2016 18:53:57 -0400 Merge pull request #383 from PhenomRetroShare/Fix_FreeTcpPacketIfPeersUnknown
-- Cyril Soler <csoler@users.sourceforge.net> Sat, 28 May 2016 10:00:00 -0500
retroshare06 (0.6.0-1.20160514.4dc62d0e~trusty) trusty; urgency=low
5bb570e csoler Sat, 14 May 2016 10:57:52 -0400 Merge pull request #384 from PhenomRetroShare/Fix_RsAccountsDetailPrivateInit
7fd84f2 Phenom Sat, 14 May 2016 16:50:17 +0200 Fix Initialisation of Private in RsAccountDetails
52f488c csoler Fri, 13 May 2016 11:13:07 -0400 Merge pull request #382 from PhenomRetroShare/Fix_CorrectPR378
d7efeb9 Phenom Fri, 13 May 2016 17:06:00 +0200 Move nDir->Files into condition nDir exists.
4b8a1d2 csoler Thu, 12 May 2016 14:42:31 -0400 Merge pull request #380 from PhenomRetroShare/Fix_ContentValue
1c5bcb8 csoler Thu, 12 May 2016 14:41:10 -0400 Merge pull request #379 from PhenomRetroShare/Fix_UninitializedVar
2487f3e csoler Thu, 12 May 2016 14:40:37 -0400 Merge pull request #378 from PhenomRetroShare/Fix_CasenDirResetedBefore
61e5a62 Phenom Thu, 12 May 2016 20:29:12 +0200 Fix ContentValue::ContentValue if GetAsxxx return false.
ed56707 Phenom Thu, 12 May 2016 20:14:59 +0200 Fix in case nDir was reset before
a1ece16 Phenom Thu, 12 May 2016 20:00:44 +0200 Fix uninitialized variables netsize, rsnetsize in p3netmgr.cc
1d476de csoler Thu, 12 May 2016 10:26:38 -0400 fixed initialisation of semaphores in created thread object
96012ef csoler Wed, 11 May 2016 22:18:02 -0400 new attempt to fix thread issues
383e403 csoler Wed, 11 May 2016 12:42:59 -0400 tried to improve the RsSemaphore class to avoid and display more info about the
e891e2b csoler Wed, 11 May 2016 10:00:20 -0400 added missing check for ssl_connection that would cause crash when the ssl conne
8fdf8f8 csoler Tue, 10 May 2016 09:46:33 -0400 fixed possible crash in rsnet.cc
74bb3b6 csoler Mon, 9 May 2016 20:54:58 -0400 replaced deprecated gethostbyname by getaddrinfo. Only linux was using the re-entrant
f8e6937 csoler Sun, 8 May 2016 18:36:41 -0400 Merge pull request #373 from PhenomRetroShare/Fix_LibResAPI_MacOS
4b81fb0 csoler Sun, 8 May 2016 10:42:20 -0400 Merge pull request #374 from PhenomRetroShare/Fix_MacOSVersion
ceb092c Phenom Fri, 6 May 2016 22:51:25 +0200 Fix preprocessor for MacOS version.
61d2ab5 Phenom Fri, 6 May 2016 22:12:40 +0200 Fix compilation of LibResAPI for MacOS
6a7bd90 csoler Fri, 6 May 2016 08:59:59 -0400 Merge pull request #372 from zeners/master
ae631a1 zeners Fri, 6 May 2016 10:34:13 +0200 Merge remote branch 'origin/master'
08be19f zeners Fri, 6 May 2016 10:29:03 +0200 webui: rebuild files on qmake
13dec7a zeners Fri, 6 May 2016 10:06:03 +0200 webui: reset file-date on touch to force build
48bc31e csoler Thu, 5 May 2016 23:55:16 -0400 Merge pull request #371 from csoler/v0.6-Threads
67e9760 csoler Thu, 5 May 2016 22:03:46 -0400 removed debug output from threads
b5ace40 csoler Thu, 5 May 2016 21:21:45 -0400 attempt to fix socket problem on 32bits/64bits windows, by using the proper SOCKET typ
9847a7a csoler Thu, 5 May 2016 20:52:10 -0400 implemented a new semaphore class that should be cross plateform
092345c csoler Thu, 5 May 2016 09:49:56 -0400 Merge pull request #363 from Nyfor/travis
ad2df86 csoler Thu, 5 May 2016 09:45:22 -0400 Merge pull request #370 from Nyfor/fix-segfault-on-close
dbd0418 Nyfor Wed, 4 May 2016 18:48:13 +0200 Fix segfault on shutdown.
0817aad csoler Wed, 4 May 2016 22:51:33 -0400 improved debugging output of rsthreads.cc (part 3)
bb00e39 csoler Wed, 4 May 2016 22:34:03 -0400 improved debugging output of rsthreads.cc (part 2)
2e02a89 csoler Wed, 4 May 2016 22:23:36 -0400 improved debugging output of rsthreads.cc
e50e686 csoler Wed, 4 May 2016 18:01:18 -0400 updated the debug message for incoming data with no registered tunnel
40f8313 csoler Wed, 4 May 2016 15:32:17 -0400 Merge pull request #307 from hunbernd/fix/sqlcipher-version
ca003c5 csoler Tue, 3 May 2016 20:55:36 -0400 added missing initialisation of deleted memory before calling realloc
0ff2941 csoler Tue, 3 May 2016 13:11:41 -0400 Merge pull request #365 from zeners/master
f4a4765 zeners Tue, 3 May 2016 19:04:42 +0200 Merge remote branch 'origin/master'
962dd91 zeners Tue, 3 May 2016 19:02:07 +0200 webui: include files on first clean build
aec8b4d csoler Mon, 2 May 2016 18:10:39 -0400 fixed bug in counting of incoming data size for sliced packets
f3bc978 Nyfor Wed, 27 Apr 2016 18:32:59 +0200 Updated Travis file.
-- Cyril Soler <csoler@users.sourceforge.net> Sat, 14 May 2016 16:00:00 -0500
retroshare06 (0.6.0-1.20160424.0d84a558~trusty) trusty; urgency=low
7914aeb csoler Sat, 30 Apr 2016 17:33:47 -0400 use RsTemporaryMemory in signature verification
be7e87c csoler Sat, 30 Apr 2016 17:25:24 -0400 use RsTemporaryMemory in signature verification
01605e5 csoler Sat, 30 Apr 2016 11:19:21 -0400 updated description f packet slicing in comments section of pqistreamer
1f7a94d csoler Sat, 30 Apr 2016 11:13:51 -0400 fixed bug causing crash in pqistreamer
0bd6670 csoler Sat, 30 Apr 2016 09:47:21 -0400 Merge pull request #362 from zeners/master
0a6ae55 zeners Sat, 30 Apr 2016 14:21:09 +0200 webui: redefined building webui
baf9404 csoler Fri, 29 Apr 2016 20:09:48 -0400 Merge pull request #360 from csoler/v0.6-RTT3
4bdd464 csoler Fri, 29 Apr 2016 18:53:25 -0400 removed a few debug output and timer measurement
6d2bfcf csoler Fri, 29 Apr 2016 18:52:58 -0400 restored average kicking rate to a more reasonnable value. To be tested (for to
3bc3989 csoler Fri, 29 Apr 2016 18:41:10 -0400 removed debug info for pqistreamer
5ab9aed csoler Fri, 29 Apr 2016 18:40:28 -0400 added placeholder service ID for packet slicing probe
654e0fc csoler Fri, 29 Apr 2016 17:53:21 -0400 added missing call to SSL_pending, which caused decrypted data to wait in the S
a443064 csoler Tue, 26 Apr 2016 23:42:44 -0400 various changes to measure RTTs more accurately
87764ab csoler Tue, 26 Apr 2016 21:23:19 -0400 removed debug info in pqistreamer
153db5c csoler Tue, 26 Apr 2016 09:22:24 -0400 added on/off mechanism for packet slicing to ensure packward compatibility
3b68585 csoler Mon, 25 Apr 2016 23:37:02 -0400 improved/simplified slicing protocol
dd81ce3 csoler Mon, 25 Apr 2016 22:50:41 -0400 using BinToHex to display mem blocks in pqistreamer debug
18e9e1c csoler Sun, 24 Apr 2016 21:29:55 -0400 moerged with upstream/master
f629575 csoler Sun, 24 Apr 2016 21:18:44 -0400 fixed a few bugs in packet slicing in pqiQoS
a2c11f9 csoler Sun, 24 Apr 2016 13:43:34 -0400 added packet reconstruction and deserialising
-- Cyril Soler <csoler@users.sourceforge.net> Sat, 30 Apr 2016 18:00:00 -0500
retroshare06 (0.6.0-1.20160424.0d84a558~trusty) trusty; urgency=low
0dc43c3 csoler Sat, 23 Apr 2016 08:29:53 -0400 Merge pull request #338 from Nyfor/master
5e94c77 Nyfor Mon, 4 Apr 2016 12:07:09 +0200 Fixed compilation for Clang.
d696f72 csoler Fri, 22 Apr 2016 20:38:07 -0400 fixed compilation
acd059b csoler Fri, 22 Apr 2016 18:49:42 -0400 removed potential memory leak in TransfersDialog
52cf66a csoler Fri, 22 Apr 2016 17:55:15 -0400 fixed memory leak in SubscribeToolButton menu
55e8087 csoler Fri, 22 Apr 2016 17:30:55 -0400 added missing free for public keys used in envelop encryption
10230df csoler Fri, 22 Apr 2016 16:50:43 -0400 added missing SSL shutdown when replacing existing connection
5261c3c csoler Thu, 21 Apr 2016 22:23:07 -0400 prevented turtle to not deleting a config item when it is not cast
e9fa9eb csoler Thu, 21 Apr 2016 22:07:50 -0400 removed tricky memory leak in chat lobbies due to handling of partial messages
7aea6e5 csoler Thu, 21 Apr 2016 22:07:10 -0400 removed some debug info
eca83fd csoler Thu, 21 Apr 2016 19:54:50 -0400 removed some debug info
fba3d37 csoler Thu, 21 Apr 2016 19:47:34 -0400 fixed memory leak after receiving RsNxsItem deserialised from decrypted memory
0d3ff0e csoler Thu, 21 Apr 2016 19:46:47 -0400 fixed possible uninitialised memory read in memory decryption return
0c711a4 csoler Thu, 21 Apr 2016 19:41:21 -0400 added missing calls to EVP_CIPHER_CTX_cleanup() to release memory after decryption, causing memory
3fae108 csoler Thu, 21 Apr 2016 12:58:48 -0400 removed div by zero in transfers dialog
0572492 csoler Wed, 20 Apr 2016 21:20:47 -0400 severely reduced packet grouping, which limited the effectiveness of QoS
d6ae71e csoler Wed, 20 Apr 2016 20:21:29 -0400 removed pointer to QStringList in QHash, causing memory loss
aba3d2f csoler Wed, 20 Apr 2016 18:24:02 -0400 removed memory leak due to zeroing (on purpose!) a data chunk in GRouter before deleting it
d017771 csoler Wed, 20 Apr 2016 18:08:26 -0400 fixed missing sendTime in distant chat, causing inconsistent display in GUI
80a9fec csoler Tue, 19 Apr 2016 22:18:25 -0400 Merge pull request #353 from crhode/master
39553a6 csoler Tue, 19 Apr 2016 21:58:30 -0400 removed debug info
5645e44 Manuel Davis Tue, 19 Apr 2016 11:32:56 -0500 Change regular expression(s) for identifying hotlinks in feral text.
8be53dd Manuel Davis Tue, 19 Apr 2016 11:11:58 -0500 Improve inserting placemark in ChatLobby.
26af7c9 csoler Sun, 17 Apr 2016 22:58:48 -0400 changed heart beat limit to a larger value. Apparently too tight a value causes disconnections due
c14c240 csoler Sun, 17 Apr 2016 00:51:45 -0400 fixed update of circles GUI using a timer. This is not optimal, and should be replaced by a proper
3000f94 csoler Sat, 16 Apr 2016 22:44:06 -0400 separated subscribe status from wether we are part of a circle or not. Still needs update of GUI
b861aa9 csoler Sat, 16 Apr 2016 17:10:36 -0400 Merge pull request #352 from AsamK/trailing_semicolon
e7ec204 AsamK Sat, 16 Apr 2016 20:40:24 +0200 Add trailing semi-colon to MimeType in .desktop files
fa8a585 csoler Fri, 15 Apr 2016 18:25:53 -0400 removed some debug info
d642934 csoler Fri, 15 Apr 2016 18:25:41 -0400 increased frequency of update for banned PGP nodes
-- Cyril Soler <csoler@users.sourceforge.net> Sun, 24 Apr 2016 12:00:00 -0500
retroshare06 (0.6.0-1.20160415.26574fd9~trusty) trusty; urgency=low
2552b55 defnax Fri, 15 Apr 2016 20:32:00 +0200 Merge branch 'master' of https://github.com/RetroShare/RetroShare
85942f4 defnax Fri, 15 Apr 2016 20:30:32 +0200 improving the create circle layout
cb6c2c9 csoler Thu, 14 Apr 2016 23:49:55 -0400 Merge pull request #350 from csoler/v0.6-Circles
048192e csoler Thu, 14 Apr 2016 23:47:42 -0400 added mOriginator to CircleCache entry and auto-ask for unknown GXS ids to the friend who suppl
ba1a1b2 csoler Thu, 14 Apr 2016 23:09:59 -0400 fixed auto-subscribed of circles when some IDs are unknown
47dd442 csoler Thu, 14 Apr 2016 18:26:47 -0400 merge upstream/master
971f8e0 csoler Wed, 13 Apr 2016 18:41:49 -0400 fixed potential crash due to not updating mPendingDataIterator after deleting map entry
92eb9c5 csoler Wed, 13 Apr 2016 18:15:56 -0400 Merge pull request #346 from PhenomRetroShare/Move_ChatNotifyButtonToToolBar
aad295d defnax Wed, 13 Apr 2016 21:00:07 +0200 Fixed layout margin
45f77de Phenom Wed, 13 Apr 2016 20:42:12 +0200 Change Lobby Send button tooltip.
718d6f9 Phenom Wed, 13 Apr 2016 20:26:36 +0200 Resize Chat Tool Bar Button for Hight DPI screen.
42a2b37 Phenom Wed, 13 Apr 2016 19:21:18 +0200 Move SearchBar to Tool Bar and remove Show/Hide action.
c5873f3 Phenom Sun, 10 Apr 2016 16:42:15 +0200 Move Chat notify button from search bar to tool bar.
d512c4a csoler Tue, 12 Apr 2016 22:59:12 -0400 enabled new link type for posted (patch from Fanch)
cf746f1 csoler Tue, 12 Apr 2016 10:06:01 -0400 fixed possible crash in GxsIdDetails
d5ed84e csoler Mon, 11 Apr 2016 23:43:18 -0400 allow one to change the contact author of a circle
8f9028d csoler Mon, 11 Apr 2016 23:30:42 -0400 fixed bug in GxsIdLabel due to not removign existing jobs for a given widget before setting it
6b2de05 csoler Mon, 11 Apr 2016 22:42:02 -0400 added channel admin and distribution method in channel summary page
a52bd98 csoler Mon, 11 Apr 2016 10:10:10 -0400 fixed potential div by 0 in speed estimations. To be tested.
b148239 csoler Sun, 10 Apr 2016 21:09:47 -0400 always pass data accept test in distant chat when we are on the client side of the tunnel
c97f197 csoler Sun, 10 Apr 2016 20:39:08 -0400 removed depth obfucation of search results and replaced by 0 always, effectively removing any i
123041a csoler Sun, 10 Apr 2016 18:55:05 -0400 skip circle vetting when sending message posts with no author
0d5b9ae csoler Sun, 10 Apr 2016 18:55:05 -0400 fixed last commit
b8075d6 csoler Sun, 10 Apr 2016 18:53:49 -0400 skip circle vetting when sending message posts with no author
4fe66d6 csoler Sun, 10 Apr 2016 10:53:21 -0400 removed Edit/New circles buttons, put them in context menu. Added header frame (needs a proper
c9c15e5 csoler Sun, 10 Apr 2016 09:49:31 -0400 Merge pull request #345 from PhenomRetroShare/Update_CircleGraphical
d727311 Phenom Sun, 10 Apr 2016 12:00:23 +0200 Fix Graphic Circles update.
3eb9a5e electron128 Sun, 10 Apr 2016 11:14:32 +0200 Merge pull request #344 from Phenom: Fix Escaped charaters in WebUI
-- Cyril Soler <csoler@users.sourceforge.net> Sat, 09 Apr 2016 23:00:00 -0500
retroshare06 (0.6.0-1.20160409.33d32589~trusty) trusty; urgency=low
3b45fd8 csoler Sat, 9 Apr 2016 17:50:46 -0400 create new item "My own identities" to store own ids in IdDialog
a5044bd csoler Sat, 9 Apr 2016 14:48:05 -0400 improved calculation of speed in pqistreamer (was called before only when sending bytes), and prevented situation wher
993d7d4 csoler Sat, 9 Apr 2016 14:46:12 -0400 removed debug info in rsgxsnetservice
0853773 csoler Sat, 9 Apr 2016 12:51:15 -0400 merged and removed debug output in rsgxsnetservice.cc
10a32d3 csoler Sat, 9 Apr 2016 11:38:07 -0400 Merge pull request #343 from csoler/v0.6-Circles
ca0f769 csoler Fri, 8 Apr 2016 21:08:22 -0400 removed warning that would show up too often when a GxsTunnel is down and message cannot be sent
85c8274 csoler Fri, 8 Apr 2016 20:41:12 -0400 Merge pull request #342 from PhenomRetroShare/Fix_AllowOnlyOneInst
08e5679 Phenom Fri, 8 Apr 2016 02:14:27 +0200 Fix Allow Only One Instance
554251d csoler Thu, 7 Apr 2016 19:50:02 -0400 Merge pull request #341 from PhenomRetroShare/Add_WebUIClearButton
24b3f0d Phenom Fri, 8 Apr 2016 01:31:36 +0200 Add a Clear button on WebUI
b90808d csoler Thu, 7 Apr 2016 18:26:18 -0400 changed update of server update TS in subscribeStatusChange from 0 to time(NULL)
c8cae4c csoler Thu, 7 Apr 2016 00:09:00 -0400 Merge pull request #297 from PhenomRetroShare/Add_AllowOnlyOneIntanceAndPassArg
4ad3b11 csoler Wed, 6 Apr 2016 22:27:02 -0400 fixed compiler warning
4bf9262 csoler Wed, 6 Apr 2016 22:26:34 -0400 merged with upstream/master
60ffcd2 csoler Wed, 6 Apr 2016 22:23:10 -0400 fixed double item deletion in RsGxsNetService::handleRecvItem()
c79c9ba csoler Wed, 6 Apr 2016 21:12:54 -0400 added encryption of message sync requests for external circles-restricted groups, and verification that properly encry
10bb542 Phenom Tue, 1 Mar 2016 13:08:33 +0100 Allow only one instance for useLocalServer option activated. If exists, pass to it arguments.
f26348b csoler Tue, 5 Apr 2016 18:09:02 -0400 fixed bug in grouter which caused sending of messages to some offline peers, hence wasting some routes, and causing "
7817a54 csoler Tue, 5 Apr 2016 17:55:03 -0400 merged with trunk
9871b37 csoler Mon, 4 Apr 2016 23:02:09 -0400 Merge pull request #305 from realityfabric/openssl_crypto_infinite_loop
9217ec3 csoler Mon, 4 Apr 2016 21:36:37 -0400 added circle distribution info in forum summary page
ff4c360 csoler Mon, 4 Apr 2016 21:15:49 -0400 fixed display bug in bw statistics graph
b206317 csoler Mon, 4 Apr 2016 12:17:34 -0400 Merge pull request #339 from PhenomRetroShare/Fix_UnitTests_Compilation
f2b9957 Phenom Mon, 4 Apr 2016 17:18:42 +0200 Fix UnitTests Compilation
d34b2e8 csoler Sun, 3 Apr 2016 17:11:13 -0400 allow to change the author ID of a group during update. Set proper value in group author widget
18dd7ee csoler Sun, 3 Apr 2016 11:42:45 -0400 moved "too many routing clues" message to debug output, since it can be caused by normal lobby operation
3554e48 csoler Sun, 3 Apr 2016 11:38:53 -0400 output packet error with some details (inspired by Phenom-PR289)
a3890ad csoler Sun, 3 Apr 2016 11:00:03 -0400 added gathering of routing clues from lobbies
9ced517 csoler Sat, 2 Apr 2016 16:54:30 -0400 improved tooltips in people list
53dbc52 csoler Sat, 2 Apr 2016 16:50:22 -0400 removed mention of null PGP ids in People
f8639e5 csoler Sat, 2 Apr 2016 16:44:41 -0400 fixed bug considering null PGP ids in ban list
5bbaa1e csoler Sat, 2 Apr 2016 16:14:08 -0400 added people settings page, removed debug output
9d9b790 csoler Sat, 2 Apr 2016 14:04:08 -0400 exposed un-verified PGP signatures on GXS ids in GUI. Added auto-ban of GXS ids signed by a PGP ids that has already s
9a6bcf8 csoler Sat, 2 Apr 2016 14:02:04 -0400 removed blue color for admin flag in forums, since admin flag is already indicated by position in "My Forums" list, an
7c4d85d csoler Sat, 2 Apr 2016 14:00:04 -0400 fixed compilation for ubuntu xenial
0350c1d csoler Fri, 1 Apr 2016 17:47:03 -0400 Merge pull request #335 from PhenomRetroShare/Add_ClearWebAPIWhenClearChatHistory2
c6f1cc4 Phenom Thu, 31 Mar 2016 22:52:53 +0200 Clear WebAPI when clear chat history in GUI.
ab78825 thunder2 Thu, 31 Mar 2016 10:23:23 +0200 Enabled webui build script for Windows compile
21421ab csoler Wed, 30 Mar 2016 14:03:50 -0400 Merge pull request #334 from zeners/master
8def617 zeners Wed, 30 Mar 2016 19:50:11 +0200 webui: windows build-script
741db13 csoler Wed, 30 Mar 2016 12:34:32 -0400 Merge pull request #333 from zeners/webui
f570477 zeners Wed, 30 Mar 2016 18:20:59 +0200 webui: patch init.sh like build.sh
cee3477 defnax Wed, 30 Mar 2016 17:06:34 +0200 Fixed the default splitter expanding of People Dialog
351af47 csoler Tue, 29 Mar 2016 15:42:23 -0400 Merge pull request #332 from zeners/master
aca8830 zeners Tue, 29 Mar 2016 21:22:14 +0200 compatible to g++11 / QT5
5783c59 electron128 Tue, 29 Mar 2016 20:16:44 +0200 Merge pull request #318 from realityfabric/remove_empty_file
475cb40 electron128 Tue, 29 Mar 2016 20:13:24 +0200 Merge pull request #328 from PhenomRetroShare/Fix_WebUI_MakeSrcBuild
5b5504c electron128 Tue, 29 Mar 2016 19:42:07 +0200 Merge pull request #330 from zeners/webui
be328e2 zeners Tue, 29 Mar 2016 18:57:18 +0200 webui: include files in install
f5f27ed zeners Tue, 29 Mar 2016 18:56:00 +0200 Merge branch 'master'
a53fbad thunder2 Tue, 29 Mar 2016 08:13:28 +0200 Fixed Windows compile.
7c288fc csoler Mon, 28 Mar 2016 23:24:50 -0400 added xenial as build target
-- Cyril Soler <csoler@users.sourceforge.net> Sat, 09 Apr 2016 23:00:00 -0500
retroshare06 (0.6.0-1.20160330.21421ab8~trusty) trusty; urgency=low
3701366 electron128 Mon, 28 Mar 2016 14:07:19 +0200 Merge pull request #327 from zeners/webui
dfa2cba zeners Mon, 28 Mar 2016 13:03:49 +0200 webui: menu in gui mode fixed
a11cd25 zeners Mon, 28 Mar 2016 11:35:44 +0200 Merge branch 'master'
bf374b3 zeners Mon, 28 Mar 2016 11:34:33 +0200 webui 4 windows build prepare
68b4cd8 electron128 Mon, 28 Mar 2016 10:19:10 +0200 Merge pull request #323 from zeners/webui
0482655 zeners Sun, 27 Mar 2016 20:29:48 +0200 webui: removed searchresult debug output
bbdb04f zeners Sun, 27 Mar 2016 20:13:47 +0200 webui: searchresult cross-checking with downloads
3bbd370 zeners Sun, 27 Mar 2016 18:28:32 +0200 webui: windows creating batch-files
d96a8ef zeners Sat, 26 Mar 2016 23:38:18 +0100 Merge branch 'master'
0c138d7 csoler Sat, 26 Mar 2016 18:36:52 -0400 moved discarding of banned identities from lobbies before signature checking, so as to avoid to time stamp their GXSI
215402b zeners Sat, 26 Mar 2016 23:36:02 +0100 webui: add downloads: focus fixed
922644f zeners Sat, 26 Mar 2016 23:24:29 +0100 Merge branch 'master'
502b137 csoler Sat, 26 Mar 2016 17:51:51 -0400 Merge pull request #325 from csoler/v0.6-Circles
ebf54d1 csoler Sat, 26 Mar 2016 17:25:15 -0400 fixed unit tests
a67c1d7 zeners Sat, 26 Mar 2016 18:19:33 +0100 webui: paste RS-links for download
1b8b9d4 csoler Fri, 25 Mar 2016 21:10:01 -0400 turned PeopleDialog to unix ff
6c8737c csoler Fri, 25 Mar 2016 21:09:37 -0400 merged with upstream/master
4831465 csoler Fri, 25 Mar 2016 21:03:09 -0400 fixed tiny bits in circles/people GUI
9efc29f csoler Fri, 25 Mar 2016 20:58:10 -0400 improved display of circle creator ID
d1b09b9 csoler Fri, 25 Mar 2016 18:54:13 -0400 removed some debug info
083dc62 csoler Fri, 25 Mar 2016 18:27:20 -0400 small code cleaning bits
3d45947 csoler Fri, 25 Mar 2016 18:21:37 -0400 fixed small bug in debug output; cleanup debug output
44cadc2 csoler Thu, 24 Mar 2016 19:46:08 -0400 cleaned debug info and disabled local circles before merge
7d8001b csoler Thu, 24 Mar 2016 19:23:34 -0400 fixed display of warning in posting into forums without proper credentials
9dc7328 csoler Thu, 24 Mar 2016 18:41:15 -0400 fixed async-ed circle loading in IdDialog
30193fe zeners Thu, 24 Mar 2016 18:07:21 +0100 webui: switch from react to mithril
d33a1e8 csoler Thu, 24 Mar 2016 00:05:54 -0400 added disabling of combo elements in GxsIdChooser for creating forums posts with unautorised GXS ids. Still needs a b
40d2350 csoler Wed, 23 Mar 2016 21:50:41 -0400 removed deadlock
981f81d csoler Wed, 23 Mar 2016 20:54:45 -0400 added anon ids to offline vetting
cef07ff zeners Thu, 24 Mar 2016 00:33:22 +0100 webui: integrate new webui in unix build process
57f4463 csoler Wed, 23 Mar 2016 18:23:10 -0400 fixed potential crash due to using deleted data (found by dimqua)
a19a068 zeners Wed, 23 Mar 2016 13:11:14 +0100 webui: options>settings, playing with colors
585c43b zeners Tue, 22 Mar 2016 23:19:36 +0100 webui: RS-reboot / RS-reboot-detection improved
60e9f0f zeners Tue, 22 Mar 2016 21:09:33 +0100 undo gitignore
a069db5 zeners Tue, 22 Mar 2016 16:37:48 +0100 webui: chat: display peer location
4733523 zeners Tue, 22 Mar 2016 16:33:05 +0100 webui: view / change rights per user
83ff00e zeners Tue, 22 Mar 2016 12:08:23 +0100 webui: updated mithril to v0.2.3
1fb1f3e csoler Mon, 21 Mar 2016 23:21:26 -0400 update of groups up to the latest attached circle server update TS. Should re-send groups that depend on a circle whe
51e0d83 zeners Mon, 21 Mar 2016 17:04:21 +0100 webui: options / rights (only defaults)
1c94ff7 zeners Mon, 21 Mar 2016 16:41:21 +0100 Merge branch 'master'
b153c2e csoler Sun, 20 Mar 2016 22:23:32 -0400 updated TODO
c304a3a csoler Sun, 20 Mar 2016 22:21:09 -0400 fixed display of properties in restricted groups
90347bd csoler Sun, 20 Mar 2016 12:51:30 -0400 Merge pull request #315 from dartraiden/master
c627e1b dartraiden Sun, 20 Mar 2016 19:27:28 +0300 Fix typo
c123761 csoler Sun, 20 Mar 2016 09:11:55 -0400 Merge pull request #314 from PhenomRetroShare/Fix_CppCheckerError
b13292b Phenom Sun, 20 Mar 2016 12:10:56 +0100 Fix error reported by CppChecker:
2e9d22c csoler Sat, 19 Mar 2016 18:47:46 -0400 used RsTemporaryMemory to avoid memory leak in case of error in GxsTunnels
d1bb939 csoler Sat, 19 Mar 2016 17:14:00 -0400 Merge pull request #312 from PhenomRetroShare/AddPluginsPathForApple
5061046 Phenom Sat, 19 Mar 2016 18:58:00 +0100 Add Plugins Path for Apple
12c0efb zeners Sat, 19 Mar 2016 17:39:46 +0100 webui: pgp-linked identity disabled
ecf8e7f zeners Sat, 19 Mar 2016 17:39:34 +0100 Merge remote branch 'origin/master'
24ba909 csoler Sat, 19 Mar 2016 11:39:53 -0400 fixed mixup between in/out bandwidth traffic info
526a83a csoler Fri, 18 Mar 2016 22:11:07 -0400 fixed update of circle name in the GUI
4e0ee29 csoler Thu, 17 Mar 2016 20:18:54 -0400 fixed creation/distribution of self-restricted circles
b6388d7 csoler Thu, 17 Mar 2016 18:17:58 -0400 fixed update of GUI when circles change
36edde6 csoler Wed, 16 Mar 2016 23:30:23 -0400 fixed bug causing GUI to not auto-unsubscribe in circles
a2a9079 csoler Wed, 16 Mar 2016 23:03:46 -0400 fixed qt4 compilation
31356ba csoler Wed, 16 Mar 2016 21:27:08 -0400 added reload of grp meta on update
b219295 csoler Wed, 16 Mar 2016 20:59:52 -0400 added update of GUI, instead of re-creating everything when a circle change
5b00c03 csoler Wed, 16 Mar 2016 14:17:16 -0400 Merge pull request #4 from PhenomRetroShare/Fix_PictureFlowDeletion
76fddb29 Phenom Wed, 16 Mar 2016 19:05:22 +0100 Fix delete in PictureFlow
b6e51b2 csoler Wed, 16 Mar 2016 09:56:36 -0400 Merge pull request #308 from dartraiden/master
5ba4f42 dartraiden Wed, 16 Mar 2016 16:24:06 +0300 correct path to Hidden Service configuration panel
384131a csoler Tue, 15 Mar 2016 22:41:59 -0400 added force reload of cache for circles that are modified
6466209 csoler Tue, 15 Mar 2016 22:11:36 -0400 added test to only subscribe/unsubscribe circles when needed, hence avoiding an unnecessary TS update
80aaf30 csoler Tue, 15 Mar 2016 00:00:39 -0400 fixed potential crash due to bad usage of updates
bdb326a csoler Mon, 14 Mar 2016 23:19:37 -0400 attempt at fixing circle cache loop. Renamed a few variables and fixed logic. Not yet fully working
83e39d8 csoler Sun, 13 Mar 2016 17:29:38 -0400 fixed effect of selecting known/signed IDs in circle creation dialog
4cf57d6 csoler Sun, 13 Mar 2016 17:19:14 -0400 set default value for circle distribution type
9c649aa csoler Sun, 13 Mar 2016 12:08:03 -0400 improved debugDump(), showing the subscription status of each grp
5fe390d csoler Sun, 13 Mar 2016 11:41:33 -0400 changed titles of tree root nodes in circles
0518062 csoler Sun, 13 Mar 2016 11:29:21 -0400 fixed circle auto-subscribe
1b72d2c zeners Sat, 12 Mar 2016 23:38:39 +0100 webui: unsubscribe chat-lobby
41a8e53 zeners Sat, 12 Mar 2016 23:28:27 +0100 webui: chat-layout fixed
0afa2e3 zeners Sat, 12 Mar 2016 20:20:56 +0100 webui: unread chat message counter in menu
e9af179 zeners Sat, 12 Mar 2016 19:17:37 +0100 webui: need for master
b1286f0 zeners Sat, 12 Mar 2016 17:44:43 +0100 webui: route peer location to chat-lobby
a065dba csoler Sat, 12 Mar 2016 11:05:03 -0500 cleaned code a little bit
61c7da7 csoler Sat, 12 Mar 2016 11:02:32 -0500 unselect all IDs when no circle is selected
b1da4ed zeners Sat, 12 Mar 2016 16:46:33 +0100 Merge branch 'master'
456a882 csoler Sat, 12 Mar 2016 10:41:35 -0500 added highlighting of currently selected circle members
5d2833f csoler Sat, 12 Mar 2016 09:25:28 -0500 improved one line of debug output in turtle
670fb3d csoler Sat, 12 Mar 2016 09:25:00 -0500 merged
4e2fd4e csoler Sat, 12 Mar 2016 09:22:28 -0500 Merge pull request #303 from PhenomRetroShare/Fix_CorrectColoredNameContrast
16c59af Phenom Sat, 12 Mar 2016 13:25:10 +0100 Correct Colored Name Contrast in chat, same way than text.
9e8a4cd csoler Fri, 11 Mar 2016 22:36:47 -0500 fixed auto-subscribe of circles when unsigned identities are locally owned
b97c5df csoler Fri, 11 Mar 2016 17:47:12 -0500 fixed culumn name in GR stats
692b549 csoler Fri, 11 Mar 2016 17:27:40 -0500 fixing compilation problem
232dba2 csoler Fri, 11 Mar 2016 17:21:27 -0500 allow non signature checking for GR message recepts at intermediate peers when key is missing. Should fix return rece
ecebace csoler Fri, 11 Mar 2016 14:26:27 -0500 Merge pull request #301 from PhenomRetroShare/Add_NewColumnInRsCollForPath
c0cf05c csoler Fri, 11 Mar 2016 14:25:18 -0500 Merge pull request #302 from PhenomRetroShare/Fix_RsLinkCopyForExtraFile
d62a205 Phenom Fri, 11 Mar 2016 20:08:28 +0100 Fix Paste RetroShare Link action when copy File link.
7e76e28 Phenom Fri, 11 Mar 2016 17:26:18 +0100 Add a new column in RsColl Editor to get only name in first one.
4136d09 csoler Thu, 10 Mar 2016 23:55:20 -0500 updated Circles TODO
4e4980b csoler Thu, 10 Mar 2016 22:57:04 -0500 fixed display of info for non admin circles, and added readonly system to not allow editing them
5361c85 csoler Thu, 10 Mar 2016 22:02:21 -0500 updated circles TODO
0282c2a csoler Wed, 9 Mar 2016 21:49:24 -0500 added ban menu entry to chat lobby participant list
3fc6f6b csoler Wed, 9 Mar 2016 20:53:49 -0500 updated TODO(circles), removed useless context menu, added tooltips for circle distribution options
4eebe24 csoler Wed, 9 Mar 2016 20:23:33 -0500 disabled auto-sync for messages in GXS circles, while keeping Grp auto-sync
76e7893 csoler Wed, 9 Mar 2016 20:18:19 -0500 updated circles TODO
2017f92 csoler Tue, 8 Mar 2016 23:12:27 -0500 updated circles todo
cf75983 csoler Tue, 8 Mar 2016 23:01:43 -0500 added TODO file specific to circles
7e31bda csoler Tue, 8 Mar 2016 23:00:24 -0500 fixed removal of peers from circles
cba4795 csoler Tue, 8 Mar 2016 00:02:16 -0500 improved circles GUI logic
9b92f66 csoler Mon, 7 Mar 2016 22:51:23 -0500 added edit of existing circles
49605a3 csoler Mon, 7 Mar 2016 22:10:18 -0500 fixed variable scope problem in introserver.cc
-- Cyril Soler <csoler@users.sourceforge.net> Mon, 28 Mar 2016 20:00:00 -0500
retroshare06 (0.6.0-1.20160306.ecf4a991~precise) precise; urgency=low
bb26069 csoler Wed, 2 Mar 2016 19:00:51 -0500 attempt at fixing negative bw rates in GUI that may pop up when an erro
20fcf63 electron128 Fri, 26 Feb 2016 18:13:20 +0100 Merge pull request #285 from PhenomRetroShare/Fix_SSGxsChannelGro
1a110e4 Phenom Mon, 22 Feb 2016 19:07:49 +0100 Define empty service string as a valid case.

View File

@ -3,7 +3,7 @@
configure: configure-stamp
configure-stamp:
dh_testdir
cd src && qmake-qt4 "CONFIG-=debug" "CONFIG+=release" PREFIX=/usr LIB_DIR=/usr/lib RetroShare.pro
cd src && qmake "CONFIG-=debug" "CONFIG+=release" PREFIX=/usr LIB_DIR=/usr/lib RetroShare.pro
touch $@

View File

@ -47,7 +47,7 @@ while [ ${#} -gt 0 ]; do
done
if test "${dist}" = "" ; then
dist="precise trusty vivid wily"
dist="precise trusty vivid wily xenial"
fi
echo Attempting to get revision number...
@ -133,6 +133,8 @@ for i in ${dist}; do
cp ../control.squeeze_bubba3 debian/control
elif test "${i}" = "precise" ; then
cp ../control.precise debian/control
elif test "${i}" = "xenial" ; then
cp ../control.xenial debian/control
elif test "${i}" = "stretch" ; then
cp ../control.${i} debian/control
cp ../rules.${i} debian/rules

View File

@ -2,8 +2,9 @@
Version=1.0
Name=RetroShare06
Comment=Securely share files with your friends
Exec=/usr/bin/RetroShare06
Exec=/usr/bin/RetroShare06 %U
Icon=/usr/share/pixmaps/retroshare06.xpm
Terminal=false
Type=Application
Categories=Network;P2P;
MimeType=x-scheme-handler/retroshare;

View File

@ -7,8 +7,8 @@ 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
Requires: qt5-qtbase-gui qt5-qtmultimedia qt5-qtx11extras qt5-qtbase
BuildRequires: gcc-c++ 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 qt5-qtx11extras-devel qt5-qttools-devel qt5-qtmultimedia-devel qt5-qttools-static
# This is because of sqlcipher:
BuildRequires: tcl
@ -56,7 +56,7 @@ cd lib/sqlcipher
make
cd -
cd src
qmake-qt4 "CONFIG-=debug" "CONFIG+=release" PREFIX=%{_prefix} LIB_DIR=%{_libdir} RetroShare.pro
qmake-qt5 "CONFIG-=debug" "CONFIG+=release" PREFIX=%{_prefix} LIB_DIR=%{_libdir} RetroShare.pro
make
cd -

View File

@ -221,7 +221,7 @@ Section $(Section_Main) Section_Main
; WebUI
SetOutPath "$INSTDIR\webui"
File /r "${SOURCEDIR}\libresapi\src\webfiles\*.*"
File /r "${SOURCEDIR}\libresapi\src\webui\*.*"
; License
SetOutPath "$INSTDIR\license"

View File

@ -241,7 +241,7 @@ Section $(Section_Main) Section_Main
; WebUI
SetOutPath "$INSTDIR\webui"
File /r "${SOURCEDIR}\libresapi\src\webfiles\*.*"
File /r "${SOURCEDIR}\libresapi\src\webui\*.*"
; License
SetOutPath "$INSTDIR\license"

View File

@ -3,9 +3,9 @@ Encoding=UTF-8
Version=1.0
Name=RetroShare06
Comment=Securely share files with your friends
Exec=/usr/bin/RetroShare06
Exec=/usr/bin/RetroShare06 %U
Icon=/usr/share/pixmaps/retroshare06.xpm
Terminal=false
Type=Application
Categories=Application;Network;
MimeType=x-scheme-handler/retroshare;

View File

@ -46,8 +46,6 @@ bdFilter::bdFilter(const std::string &fname, const bdNodeId *ownid, uint32_t fi
mFns = fns;
mFilename = fname ;
time_t now = time(NULL) ;
loadBannedIpFile() ;
mFilterFlags = filterFlags;
@ -92,8 +90,6 @@ void bdFilter::loadBannedIpFile()
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = PF_INET;
unsigned short port;
FILE *fd = fopen(mFilename.c_str(),"r") ;
if(fd == NULL)

View File

@ -496,10 +496,12 @@ void bdNode::checkPotentialPeer(bdId *id, bdId *src)
/* first check the filters */
if (!mFilterPeers.addrOkay(&(id->addr)))
{
#ifdef DEBUG_NODE_MSGS
std::cerr << "bdNode::checkPotentialPeer(";
mFns->bdPrintId(std::cerr, id);
std::cerr << ") BAD ADDRESS!!!! SHOULD DISCARD POTENTIAL PEER";
std::cerr << std::endl;
#endif
return;
}

View File

@ -344,6 +344,8 @@ int bdSpace::find_node(const bdNodeId *id, int number, std::list<bdId> &matchIds
std::cerr << " Number: " << number;
std::cerr << " Bucket #: " << buckno;
std::cerr << std::endl;
#else
(void)number;
#endif
bdBucket &buck = buckets[buckno];

View File

@ -29,7 +29,7 @@ debug {
################################# Linux ##########################################
linux-* {
QMAKE_CC = g++
QMAKE_CC = $${QMAKE_CXX}
}
linux-g++ {
@ -64,7 +64,7 @@ win32-x-g++ {
################################# Windows ##########################################
win32 {
QMAKE_CC = g++
QMAKE_CC = $${QMAKE_CXX}
OBJECTS_DIR = temp/obj
MOC_DIR = temp/moc
DEFINES *= STATICLIB WIN32_LEAN_AND_MEAN _USE_32BIT_TIME_T
@ -89,7 +89,7 @@ win32 {
################################# MacOSX ##########################################
mac {
QMAKE_CC = g++
QMAKE_CC = $${QMAKE_CXX}
OBJECTS_DIR = temp/obj
MOC_DIR = temp/moc
}

1
libresapi/src/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
webui/*

View File

@ -2,13 +2,13 @@ libresapi: resource_api and new webinterface
============================================
* ./api contains a C++ backend to control retroshare from webinterfaces or scripting
* ./webfiles contains compiled files for the webinterface
* ./webui contains HTML/CSS/JavaScript source files for the webinterface
* ./webui contains compiled files for the webinterface (after build)
* ./webui-src contains HTML/CSS/JavaScript source files for the webinterface (NEW, webinterface made with mithril.js)
Quickinfo for builders and packagers
====================================
* copy the files in ./webfiles to
* copy the files in ./webui to
* ./webui (Windows)
* /usr/share/RetroShare06/webui (Linux)
* other OS: see RsAccountsDetail::PathDataDirectory()
* other OS: see RsAccountsDetail::PathDataDirectory()

View File

@ -14,6 +14,7 @@
#include "StateTokenServer.h" // for the state token serialisers
#include "ApiPluginHandler.h"
#include "ChannelsHandler.h"
/*
data types in json http://json.org/
@ -226,13 +227,14 @@ class ApiServerMainModules
public:
ApiServerMainModules(ResourceRouter& router, StateTokenServer* sts, const RsPlugInInterfaces &ifaces):
mPeersHandler(sts, ifaces.mNotify, ifaces.mPeers, ifaces.mMsgs),
mIdentityHandler(ifaces.mIdentity),
mIdentityHandler(sts, ifaces.mNotify, ifaces.mIdentity),
mForumHandler(ifaces.mGxsForums),
mServiceControlHandler(ifaces.mServiceControl),
mFileSearchHandler(sts, ifaces.mNotify, ifaces.mTurtle, ifaces.mFiles),
mTransfersHandler(sts, ifaces.mFiles),
mChatHandler(sts, ifaces.mNotify, ifaces.mMsgs, ifaces.mPeers, ifaces.mIdentity, &mPeersHandler),
mApiPluginHandler(sts, ifaces)
mApiPluginHandler(sts, ifaces),
mChannelsHandler(ifaces.mGxsChannels)
{
// the dynamic cast is to not confuse the addResourceHandler template like this:
// addResourceHandler(derived class, parent class)
@ -254,6 +256,8 @@ public:
&ChatHandler::handleRequest);
router.addResourceHandler("apiplugin", dynamic_cast<ResourceRouter*>(&mApiPluginHandler),
&ChatHandler::handleRequest);
router.addResourceHandler("channels", dynamic_cast<ResourceRouter*>(&mChannelsHandler),
&ChannelsHandler::handleRequest);
}
PeersHandler mPeersHandler;
@ -264,6 +268,7 @@ public:
TransfersHandler mTransfersHandler;
ChatHandler mChatHandler;
ApiPluginHandler mApiPluginHandler;
ChannelsHandler mChannelsHandler;
};
ApiServer::ApiServer():
@ -311,7 +316,7 @@ std::string ApiServer::handleRequest(Request &request)
task = mRouter.handleRequest(request, resp);
}
time_t start = time(NULL);
//time_t start = time(NULL);
bool morework = true;
while(task && morework)
{

View File

@ -305,7 +305,7 @@ public:
// get content-type from extension
std::string ext = "";
unsigned int i = info.fname.rfind('.');
std::string::size_type i = info.fname.rfind('.');
if(i != std::string::npos)
ext = info.fname.substr(i+1);
MHD_add_response_header(resp, "Content-Type", ContentTypes::cTypeFromExt(ext).c_str());
@ -424,7 +424,7 @@ static void sendMessage(MHD_Connection *connection, unsigned int status, std::st
static std::string escape_html(std::string in)
{
std::string out;
for(int i = 0; i < in.size(); i++)
for(uint32_t i = 0; i < in.size(); i++)
{
char a = (in[i]&0xF0)>>4;
a = a < 10? a+'0': a-10+'A';

View File

@ -0,0 +1,112 @@
#include "ChannelsHandler.h"
#include <retroshare/rsgxschannels.h>
#include <util/radix64.h>
#include <algorithm>
#include "Operators.h"
namespace resource_api
{
StreamBase& operator << (StreamBase& left, RsGxsFile& file)
{
left << makeKeyValueReference("name", file.mName)
<< makeKeyValueReference("hash", file.mHash);
if(left.serialise())
{
double size = file.mSize;
left << makeKeyValueReference("size", size);
}
else
{
double size = 0;
left << makeKeyValueReference("size", size);
file.mSize = size;
}
return left;
}
ChannelsHandler::ChannelsHandler(RsGxsChannels *channels):
mChannels(channels)
{
addResourceHandler("create_post", this, &ChannelsHandler::handleCreatePost);
}
ResponseTask* ChannelsHandler::handleCreatePost(Request &req, Response &resp)
{
RsGxsChannelPost post;
req.mStream << makeKeyValueReference("group_id", post.mMeta.mGroupId);
req.mStream << makeKeyValueReference("subject", post.mMeta.mMsgName);
req.mStream << makeKeyValueReference("message", post.mMsg);
StreamBase& file_array = req.mStream.getStreamToMember("files");
while(file_array.hasMore())
{
RsGxsFile file;
file_array.getStreamToMember() << file;
post.mFiles.push_back(file);
}
std::string thumbnail_base64;
req.mStream << makeKeyValueReference("thumbnail_base64_png", thumbnail_base64);
if(post.mMeta.mGroupId.isNull())
{
resp.setFail("groupd_id is null");
return 0;
}
if(post.mMeta.mMsgName.empty())
{
resp.setFail("subject is empty");
return 0;
}
if(post.mMsg.empty())
{
resp.setFail("msg text is empty");
return 0;
}
// empty file list is ok, but files have to be valid
for(std::list<RsGxsFile>::iterator lit = post.mFiles.begin(); lit != post.mFiles.end(); ++lit)
{
if(lit->mHash.isNull())
{
resp.setFail("at least one file hash is empty");
return 0;
}
if(lit->mName.empty())
{
resp.setFail("at leats one file name is empty");
return 0;
}
if(lit->mSize == 0)
{
resp.setFail("at least one file size is empty");
return 0;
}
}
std::vector<uint8_t> png_data = Radix64::decode(thumbnail_base64);
if(!png_data.empty())
{
if(png_data.size() < 8)
{
resp.setFail("Decoded thumbnail_base64_png is smaller than 8 byte. This can't be a valid png file!");
return 0;
}
uint8_t png_magic_number[] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a};
if(!std::equal(&png_magic_number[0],&png_magic_number[8],png_data.begin()))
{
resp.setFail("Decoded thumbnail_base64_png does not seem to be a png file. (Header is missing magic number)");
return 0;
}
post.mThumbnail.copy(png_data.data(), png_data.size());
}
uint32_t token;
mChannels->createPost(token, post);
// TODO: grp creation acknowledge
return 0;
}
} // namespace resource_api

View File

@ -0,0 +1,21 @@
#pragma once
#include "ResourceRouter.h"
class RsGxsChannels;
namespace resource_api
{
class ChannelsHandler : public ResourceRouter
{
public:
ChannelsHandler(RsGxsChannels* channels);
private:
ResponseTask* handleCreatePost(Request& req, Response& resp);
RsGxsChannels* mChannels;
};
} // namespace resource_api

View File

@ -6,8 +6,10 @@
#include <retroshare/rspeers.h>
#include <retroshare/rsidentity.h>
#include <sstream>
#include <algorithm>
#include <limits>
#include <sstream>
#include <time.h>
namespace resource_api
{
@ -97,6 +99,39 @@ StreamBase& operator << (StreamBase& left, ChatHandler::ChatInfo& info)
return left;
}
class SendLobbyParticipantsTask: public GxsResponseTask
{
public:
SendLobbyParticipantsTask(RsIdentity* idservice, ChatHandler::LobbyParticipantsInfo pi):
GxsResponseTask(idservice, 0), mParticipantsInfo(pi)
{
const std::map<RsGxsId, time_t>& map = mParticipantsInfo.participants;
for(std::map<RsGxsId, time_t>::const_iterator mit = map.begin(); mit != map.end(); ++mit)
{
requestGxsId(mit->first);
}
}
private:
ChatHandler::LobbyParticipantsInfo mParticipantsInfo;
protected:
virtual void gxsDoWork(Request &/*req*/, Response &resp)
{
resp.mDataStream.getStreamToMember();
const std::map<RsGxsId, time_t>& map = mParticipantsInfo.participants;
for(std::map<RsGxsId, time_t>::const_iterator mit = map.begin(); mit != map.end(); ++mit)
{
StreamBase& stream = resp.mDataStream.getStreamToMember();
double last_active = mit->second;
stream << makeKeyValueReference("last_active", last_active);
streamGxsId(mit->first, stream.getStreamToMember("identity"));
}
resp.mStateToken = mParticipantsInfo.state_token;
resp.setOk();
done();
}
};
ChatHandler::ChatHandler(StateTokenServer *sts, RsNotify *notify, RsMsgs *msgs, RsPeers* peers, RsIdentity* identity, UnreadMsgNotify* unread):
mStateTokenServer(sts), mNotify(notify), mRsMsgs(msgs), mRsPeers(peers), mRsIdentity(identity), mUnreadMsgNotify(unread), mMtx("ChatHandler::mMtx")
{
@ -111,11 +146,13 @@ ChatHandler::ChatHandler(StateTokenServer *sts, RsNotify *notify, RsMsgs *msgs,
addResourceHandler("lobbies", this, &ChatHandler::handleLobbies);
addResourceHandler("subscribe_lobby", this, &ChatHandler::handleSubscribeLobby);
addResourceHandler("unsubscribe_lobby", this, &ChatHandler::handleUnsubscribeLobby);
addResourceHandler("clear_lobby", this, &ChatHandler::handleClearLobby);
addResourceHandler("lobby_participants", this, &ChatHandler::handleLobbyParticipants);
addResourceHandler("messages", this, &ChatHandler::handleMessages);
addResourceHandler("send_message", this, &ChatHandler::handleSendMessage);
addResourceHandler("mark_chat_as_read", this, &ChatHandler::handleMarkChatAsRead);
addResourceHandler("info", this, &ChatHandler::handleInfo);
addResourceHandler("typing_label", this, &ChatHandler::handleTypingLabel);
addResourceHandler("receive_status", this, &ChatHandler::handleReceiveStatus);
addResourceHandler("send_status", this, &ChatHandler::handleSendStatus);
addResourceHandler("unread_msgs", this, &ChatHandler::handleUnreadMsgs);
}
@ -132,20 +169,40 @@ void ChatHandler::notifyChatMessage(const ChatMessage &msg)
mRawMsgs.push_back(msg);
}
// to be removed
/*
ChatHandler::Lobby ChatHandler::getLobbyInfo(ChatLobbyId id)
void ChatHandler::notifyChatCleared(const ChatId &chat_id)
{
tick();
RS_STACK_MUTEX(mMtx); // ********* LOCKED **********
for(std::vector<Lobby>::iterator vit = mLobbies.begin(); vit != mLobbies.end(); ++vit)
if(vit->id == id)
return *vit;
std::cerr << "ChatHandler::getLobbyInfo Error: Lobby not found" << std::endl;
return Lobby();
RS_STACK_MUTEX(mMtx); /********** LOCKED **********/
//Remove processed messages
std::list<Msg>& msgs = mMsgs[chat_id];
msgs.clear();
//Remove unprocessed messages
for(std::list<ChatMessage>::iterator lit = mRawMsgs.begin(); lit != mRawMsgs.end();)
{
ChatMessage& msg = *lit;
if (msg.chat_id == chat_id)
{
lit = mRawMsgs.erase(lit);
} else {
++lit;
}
}
}
void ChatHandler::notifyChatStatus(const ChatId &chat_id, const std::string &status)
{
RS_STACK_MUTEX(mMtx); /********** LOCKED **********/
locked_storeTypingInfo(chat_id, status);
}
void ChatHandler::notifyChatLobbyEvent(uint64_t lobby_id, uint32_t event_type,
const RsGxsId &nickname, const std::string& any_string)
{
RS_STACK_MUTEX(mMtx); /********** LOCKED **********/
if(event_type == RS_CHAT_LOBBY_EVENT_PEER_STATUS)
{
locked_storeTypingInfo(ChatId(lobby_id), any_string, nickname);
}
}
*/
void ChatHandler::tick()
{
@ -170,9 +227,46 @@ void ChatHandler::tick()
l.is_broadcast = false;
l.gxs_id = info.gxs_id;
lobbies.push_back(l);
// update the lobby participants list
// maybe it causes to much traffic to do this in every tick,
// because the client would get the whole list every time a message was received
// we could reduce the checking frequency
std::map<ChatLobbyId, LobbyParticipantsInfo>::iterator mit = mLobbyParticipantsInfos.find(*lit);
if(mit == mLobbyParticipantsInfos.end())
{
mLobbyParticipantsInfos[*lit].participants = info.gxs_ids;
mLobbyParticipantsInfos[*lit].state_token = mStateTokenServer->getNewToken();
}
else
{
LobbyParticipantsInfo& pi = mit->second;
if(!std::equal(pi.participants.begin(), pi.participants.end(), info.gxs_ids.begin()))
{
pi.participants = info.gxs_ids;
mStateTokenServer->replaceToken(pi.state_token);
}
}
}
}
// remove participants info of old lobbies
std::vector<ChatLobbyId> participants_info_to_delete;
for(std::map<ChatLobbyId, LobbyParticipantsInfo>::iterator mit = mLobbyParticipantsInfos.begin();
mit != mLobbyParticipantsInfos.end(); ++mit)
{
if(std::find(subscribed_ids.begin(), subscribed_ids.end(), mit->first) == subscribed_ids.end())
{
participants_info_to_delete.push_back(mit->first);
}
}
for(std::vector<ChatLobbyId>::iterator vit = participants_info_to_delete.begin(); vit != participants_info_to_delete.end(); ++vit)
{
LobbyParticipantsInfo& pi = mLobbyParticipantsInfos[*vit];
mStateTokenServer->discardToken(pi.state_token);
mLobbyParticipantsInfos.erase(*vit);
}
{
Lobby l;
l.name = "BroadCast";
@ -369,6 +463,46 @@ void ChatHandler::tick()
}
}
static void writeUTF8 ( std::ostream & Out, unsigned int Ch )
/* writes Ch in UTF-8 encoding to Out. Note this version only deals
with characters up to 16 bits.
From: http://www.codecodex.com/wiki/Unescape_HTML_special_characters_from_a_String*/
{
if (Ch >= 0x800)
{
Out.put(0xE0 | ((Ch >> 12) & 0x0F));
Out.put(0x80 | ((Ch >> 6) & 0x3F));
Out.put(0x80 | ((Ch ) & 0x3F));
}
else if (Ch >= 0x80)
{
Out.put(0xC0 | ((Ch >> 6) & 0x1F));
Out.put(0x80 | ((Ch ) & 0x3F));
}
else
{
Out.put(Ch);
}
}
static unsigned int stringToDecUInt ( std::string str)
{
unsigned int out = 0;
unsigned int max = std::numeric_limits<int>::max() / 10;
int lenght = str.length();
for (int curs = 0; curs < lenght; ++curs) {
char c = str[curs];
if ( (c >= '0')
&& (c <= '9')
&& (out < max)
) {
out *= 10;
out += (int)( c - '0');
} else return 0;
}
return out;
}
void ChatHandler::getPlainText(const std::string& in, std::string &out, std::vector<Triple> &links)
{
if (in.size() == 0)
@ -386,6 +520,9 @@ void ChatHandler::getPlainText(const std::string& in, std::string &out, std::vec
std::string last_six_chars;
unsigned int tag_start_index = 0;
Triple current_link;
bool onEscapeChar = false;
unsigned int escapeCharIndexStart = -1;
for(unsigned int i = 0; i < in.size(); ++i)
{
if(keep_link && in[i] == '"')
@ -408,10 +545,12 @@ void ChatHandler::getPlainText(const std::string& in, std::string &out, std::vec
if(!ignore || keep_link)
out += in[i];
// "falling edge" resets mode to keep
if(in[i] == '>') {
if(in[i] == '>' && ignore) {
// leave ignore mode on, if it's a style tag
if (tag_start_index == 0 || tag_start_index + 6 > i || in.substr(tag_start_index, 6) != "<style")
if (tag_start_index == 0 || tag_start_index + 6 > i || in.substr(tag_start_index, 6) != "<style") {
ignore = false;
tag_start_index = 0;
}
}
last_six_chars += in[i];
@ -436,9 +575,250 @@ void ChatHandler::getPlainText(const std::string& in, std::string &out, std::vec
}
current_link = Triple();
}
std::string br = "<br/>";
if(last_six_chars.size() >= br.size()
&& last_six_chars.substr(last_six_chars.size()-br.size()) == br)
{
out += "\n";
}
if (in[i] == '&') {
onEscapeChar = true;
escapeCharIndexStart = out.length();
}
if (ignore || keep_link) {
onEscapeChar = false;
escapeCharIndexStart = -1;
}
if ((in[i] == ';') && onEscapeChar) {
onEscapeChar = false;
bool escapeFound = true;
std::string escapeReplace = "";
//Keep only escape value to replace it
std::string escapeCharValue = out.substr(escapeCharIndexStart,
out.length() - escapeCharIndexStart - 1);
if (escapeCharValue[0] == '#') {
int escapedCharUTF8 = stringToDecUInt(escapeCharValue.substr(1));
std::ostringstream escapedSStream;
writeUTF8( escapedSStream, escapedCharUTF8);
escapeReplace = escapedSStream.str();
} else if (escapeCharValue == "euro") {
escapeReplace = "";
} else if (escapeCharValue == "nbsp") {
escapeReplace = " ";
} else if (escapeCharValue == "quot") {
escapeReplace = "\"";
} else if (escapeCharValue == "amp") {
escapeReplace = "&";
} else if (escapeCharValue == "lt") {
escapeReplace = "<";
} else if (escapeCharValue == "gt") {
escapeReplace = ">";
} else if (escapeCharValue == "iexcl") {
escapeReplace = "¡";
} else if (escapeCharValue == "cent") {
escapeReplace = "¢";
} else if (escapeCharValue == "pound") {
escapeReplace = "£";
} else if (escapeCharValue == "curren") {
escapeReplace = "¤";
} else if (escapeCharValue == "yen") {
escapeReplace = "¥";
} else if (escapeCharValue == "brvbar") {
escapeReplace = "¦";
} else if (escapeCharValue == "sect") {
escapeReplace = "§";
} else if (escapeCharValue == "uml") {
escapeReplace = "¨";
} else if (escapeCharValue == "copy") {
escapeReplace = "©";
} else if (escapeCharValue == "ordf") {
escapeReplace = "ª";
} else if (escapeCharValue == "not") {
escapeReplace = "¬";
} else if (escapeCharValue == "shy") {
escapeReplace = " ";//?
} else if (escapeCharValue == "reg") {
escapeReplace = "®";
} else if (escapeCharValue == "macr") {
escapeReplace = "¯";
} else if (escapeCharValue == "deg") {
escapeReplace = "°";
} else if (escapeCharValue == "plusmn") {
escapeReplace = "±";
} else if (escapeCharValue == "sup2") {
escapeReplace = "²";
} else if (escapeCharValue == "sup3") {
escapeReplace = "³";
} else if (escapeCharValue == "acute") {
escapeReplace = "´";
} else if (escapeCharValue == "micro") {
escapeReplace = "µ";
} else if (escapeCharValue == "para") {
escapeReplace = "";
} else if (escapeCharValue == "middot") {
escapeReplace = "·";
} else if (escapeCharValue == "cedil") {
escapeReplace = "¸";
} else if (escapeCharValue == "sup1") {
escapeReplace = "¹";
} else if (escapeCharValue == "ordm") {
escapeReplace = "º";
} else if (escapeCharValue == "raquo") {
escapeReplace = "»";
} else if (escapeCharValue == "frac14") {
escapeReplace = "¼";
} else if (escapeCharValue == "frac12") {
escapeReplace = "½";
} else if (escapeCharValue == "frac34") {
escapeReplace = "¾";
} else if (escapeCharValue == "iquest") {
escapeReplace = "¿";
} else if (escapeCharValue == "Agrave") {
escapeReplace = "À";
} else if (escapeCharValue == "Aacute") {
escapeReplace = "Á";
} else if (escapeCharValue == "Acirc") {
escapeReplace = "Â";
} else if (escapeCharValue == "Atilde") {
escapeReplace = "Ã";
} else if (escapeCharValue == "Auml") {
escapeReplace = "Ä";
} else if (escapeCharValue == "Aring") {
escapeReplace = "Å";
} else if (escapeCharValue == "AElig") {
escapeReplace = "Æ";
} else if (escapeCharValue == "Ccedil") {
escapeReplace = "Ç";
} else if (escapeCharValue == "Egrave") {
escapeReplace = "È";
} else if (escapeCharValue == "Eacute") {
escapeReplace = "É";
} else if (escapeCharValue == "Ecirc") {
escapeReplace = "Ê";
} else if (escapeCharValue == "Euml") {
escapeReplace = "Ë";
} else if (escapeCharValue == "Igrave") {
escapeReplace = "Ì";
} else if (escapeCharValue == "Iacute") {
escapeReplace = "Í";
} else if (escapeCharValue == "Icirc") {
escapeReplace = "Î";
} else if (escapeCharValue == "Iuml") {
escapeReplace = "Ï";
} else if (escapeCharValue == "ETH") {
escapeReplace = "Ð";
} else if (escapeCharValue == "Ntilde") {
escapeReplace = "Ñ";
} else if (escapeCharValue == "Ograve") {
escapeReplace = "Ò";
} else if (escapeCharValue == "Oacute") {
escapeReplace = "Ó";
} else if (escapeCharValue == "Ocirc") {
escapeReplace = "Ô";
} else if (escapeCharValue == "Otilde") {
escapeReplace = "Õ";
} else if (escapeCharValue == "Ouml") {
escapeReplace = "Ö";
} else if (escapeCharValue == "times") {
escapeReplace = "×";
} else if (escapeCharValue == "Oslash") {
escapeReplace = "Ø";
} else if (escapeCharValue == "Ugrave") {
escapeReplace = "Ù";
} else if (escapeCharValue == "Uacute") {
escapeReplace = "Ú";
} else if (escapeCharValue == "Ucirc") {
escapeReplace = "Û";
} else if (escapeCharValue == "Uuml") {
escapeReplace = "Ü";
} else if (escapeCharValue == "Yacute") {
escapeReplace = "Ý";
} else if (escapeCharValue == "THORN") {
escapeReplace = "Þ";
} else if (escapeCharValue == "szlig") {
escapeReplace = "ß";
} else if (escapeCharValue == "agrave") {
escapeReplace = "à";
} else if (escapeCharValue == "aacute") {
escapeReplace = "á";
} else if (escapeCharValue == "acirc") {
escapeReplace = "â";
} else if (escapeCharValue == "atilde") {
escapeReplace = "ã";
} else if (escapeCharValue == "auml") {
escapeReplace = "ä";
} else if (escapeCharValue == "aring") {
escapeReplace = "å";
} else if (escapeCharValue == "aelig") {
escapeReplace = "æ";
} else if (escapeCharValue == "ccedil") {
escapeReplace = "ç";
} else if (escapeCharValue == "egrave") {
escapeReplace = "è";
} else if (escapeCharValue == "eacute") {
escapeReplace = "é";
} else if (escapeCharValue == "ecirc") {
escapeReplace = "ê";
} else if (escapeCharValue == "euml") {
escapeReplace = "ë";
} else if (escapeCharValue == "igrave") {
escapeReplace = "ì";
} else if (escapeCharValue == "iacute") {
escapeReplace = "í";
} else if (escapeCharValue == "icirc") {
escapeReplace = "î";
} else if (escapeCharValue == "iuml") {
escapeReplace = "ï";
} else if (escapeCharValue == "eth") {
escapeReplace = "ð";
} else if (escapeCharValue == "ntilde") {
escapeReplace = "ñ";
} else if (escapeCharValue == "ograve") {
escapeReplace = "ò";
} else if (escapeCharValue == "oacute") {
escapeReplace = "ó";
} else if (escapeCharValue == "ocirc") {
escapeReplace = "ô";
} else if (escapeCharValue == "otilde") {
escapeReplace = "õ";
} else if (escapeCharValue == "ouml") {
escapeReplace = "ö";
} else if (escapeCharValue == "divide") {
escapeReplace = "÷";
} else if (escapeCharValue == "oslash") {
escapeReplace = "ø";
} else if (escapeCharValue == "ugrave") {
escapeReplace = "ù";
} else if (escapeCharValue == "uacute") {
escapeReplace = "ú";
} else if (escapeCharValue == "ucirc") {
escapeReplace = "û";
} else if (escapeCharValue == "uuml") {
escapeReplace = "ü";
} else if (escapeCharValue == "yacute") {
escapeReplace = "ý";
} else if (escapeCharValue == "thorn") {
escapeReplace = "þ";
} else {
escapeFound = false;
}
if (escapeFound) {
out = out.substr(0, escapeCharIndexStart-1);
out += escapeReplace;
}
}
}
}
void ChatHandler::locked_storeTypingInfo(const ChatId &chat_id, std::string status, RsGxsId lobby_gxs_id)
{
TypingLabelInfo& info = mTypingLabelInfo[chat_id];
info.timestamp = time(0);
info.status = status;
mStateTokenServer->replaceToken(info.state_token);
info.author_id = lobby_gxs_id;
}
void ChatHandler::handleWildcard(Request &/*req*/, Response &resp)
{
RS_STACK_MUTEX(mMtx); /********** LOCKED **********/
@ -496,11 +876,44 @@ void ChatHandler::handleSubscribeLobby(Request &req, Response &resp)
resp.setFail("lobby join failed. (See console for more info)");
}
void ChatHandler::handleUnsubscribeLobby(Request &req, Response &/*resp*/)
void ChatHandler::handleUnsubscribeLobby(Request &req, Response &resp)
{
ChatLobbyId id = 0;
req.mStream << makeKeyValueReference("id", id);
mRsMsgs->unsubscribeChatLobby(id);
resp.setOk();
}
void ChatHandler::handleClearLobby(Request &req, Response &resp)
{
ChatLobbyId id = 0;
req.mStream << makeKeyValueReference("id", id);
if (id !=0) {
notifyChatCleared(ChatId(id));
} else {
//Is BroadCast
notifyChatCleared(ChatId("B"));
}
resp.setOk();
}
ResponseTask* ChatHandler::handleLobbyParticipants(Request &req, Response &resp)
{
RS_STACK_MUTEX(mMtx); /********** LOCKED **********/
ChatId id(req.mPath.top());
if(!id.isLobbyId())
{
resp.setFail("Path element \""+req.mPath.top()+"\" is not a ChatLobbyId.");
return 0;
}
std::map<ChatLobbyId, LobbyParticipantsInfo>::const_iterator mit = mLobbyParticipantsInfos.find(id.toLobbyId());
if(mit == mLobbyParticipantsInfos.end())
{
resp.setFail("lobby not found");
return 0;
}
return new SendLobbyParticipantsTask(mRsIdentity, mit->second);
}
void ChatHandler::handleMessages(Request &req, Response &resp)
@ -573,89 +986,6 @@ void ChatHandler::handleMarkChatAsRead(Request &req, Response &resp)
mStateTokenServer->replaceToken(mUnreadMsgsStateToken);
}
// to be removed
// we do now cache chat info, to be able to include it in new message notify easily
/*
class InfoResponseTask: public GxsResponseTask
{
public:
InfoResponseTask(ChatHandler* ch, RsPeers* peers, RsIdentity* identity): GxsResponseTask(identity, 0), mChatHandler(ch), mRsPeers(peers), mState(BEGIN){}
enum State {BEGIN, WAITING};
ChatHandler* mChatHandler;
RsPeers* mRsPeers;
State mState;
bool is_broadcast;
bool is_gxs_id;
bool is_lobby;
bool is_peer;
std::string remote_author_id;
std::string remote_author_name;
virtual void gxsDoWork(Request& req, Response& resp)
{
ChatId id(req.mPath.top());
if(id.isNotSet())
{
resp.setFail("not a valid chat id");
done();
return;
}
if(mState == BEGIN)
{
is_broadcast = false;
is_gxs_id = false;
is_lobby = false;
is_peer = false;
if(id.isBroadcast())
{
is_broadcast = true;
}
else if(id.isGxsId())
{
is_gxs_id = true;
remote_author_id = id.toGxsId().toStdString();
requestGxsId(id.toGxsId());
}
else if(id.isLobbyId())
{
is_lobby = true;
remote_author_id = "";
remote_author_name = mChatHandler->getLobbyInfo(id.toLobbyId()).name;
}
else if(id.isPeerId())
{
is_peer = true;
remote_author_id = id.toPeerId().toStdString();
remote_author_name = mRsPeers->getPeerName(id.toPeerId());
}
else
{
std::cerr << "Error in InfoResponseTask::gxsDoWork(): unhandled chat_id=" << id.toStdString() << std::endl;
}
mState = WAITING;
}
else
{
if(is_gxs_id)
remote_author_name = getName(id.toGxsId());
resp.mDataStream << makeKeyValueReference("remote_author_id", remote_author_id)
<< makeKeyValueReference("remote_author_name", remote_author_name)
<< makeKeyValueReference("is_broadcast", is_broadcast)
<< makeKeyValueReference("is_gxs_id", is_gxs_id)
<< makeKeyValueReference("is_lobby", is_lobby)
<< makeKeyValueReference("is_peer", is_peer);
resp.setOk();
done();
}
}
};
ResponseTask *ChatHandler::handleInfo(Request &req, Response &resp)
{
return new InfoResponseTask(this, mRsPeers, mRsIdentity);
}
*/
void ChatHandler::handleInfo(Request &req, Response &resp)
{
RS_STACK_MUTEX(mMtx); /********** LOCKED **********/
@ -675,14 +1005,99 @@ void ChatHandler::handleInfo(Request &req, Response &resp)
resp.setOk();
}
void ChatHandler::handleTypingLabel(Request &/*req*/, Response &/*resp*/)
class SendTypingLabelInfo: public GxsResponseTask
{
public:
SendTypingLabelInfo(RsIdentity* identity, RsPeers* peers, ChatId id, const ChatHandler::TypingLabelInfo& info):
GxsResponseTask(identity), mState(BEGIN), mPeers(peers),mId(id), mInfo(info) {}
private:
enum State {BEGIN, WAITING_ID};
State mState;
RsPeers* mPeers;
ChatId mId;
ChatHandler::TypingLabelInfo mInfo;
protected:
void gxsDoWork(Request& /*req*/, Response& resp)
{
if(mState == BEGIN)
{
// lobby and distant require to fetch a gxs_id
if(mId.isLobbyId())
{
requestGxsId(mInfo.author_id);
}
else if(mId.isDistantChatId())
{
DistantChatPeerInfo dcpinfo ;
rsMsgs->getDistantChatStatus(mId.toDistantChatId(), dcpinfo);
requestGxsId(dcpinfo.to_id);
}
mState = WAITING_ID;
}
else
{
std::string name = "BUG: case not handled in SendTypingLabelInfo";
if(mId.isPeerId())
{
name = mPeers->getPeerName(mId.toPeerId());
}
else if(mId.isDistantChatId())
{
DistantChatPeerInfo dcpinfo ;
rsMsgs->getDistantChatStatus(mId.toDistantChatId(), dcpinfo);
name = getName(dcpinfo.to_id);
}
else if(mId.isLobbyId())
{
name = getName(mInfo.author_id);
}
else if(mId.isBroadcast())
{
name = mPeers->getPeerName(mId.broadcast_status_peer_id);
}
uint32_t ts = mInfo.timestamp;
resp.mDataStream << makeKeyValueReference("author_name", name)
<< makeKeyValueReference("timestamp", ts)
<< makeKeyValueReference("status_string", mInfo.status);
resp.mStateToken = mInfo.state_token;
resp.setOk();
done();
}
}
};
ResponseTask* ChatHandler::handleReceiveStatus(Request &req, Response &resp)
{
RS_STACK_MUTEX(mMtx); /********** LOCKED **********/
ChatId id(req.mPath.top());
if(id.isNotSet())
{
resp.setFail("\""+req.mPath.top()+"\" is not a valid chat id");
return 0;
}
std::map<ChatId, TypingLabelInfo>::iterator mit = mTypingLabelInfo.find(id);
if(mit == mTypingLabelInfo.end())
{
locked_storeTypingInfo(id, "");
mit = mTypingLabelInfo.find(id);
}
return new SendTypingLabelInfo(mRsIdentity, mRsPeers, id, mit->second);
}
void ChatHandler::handleSendStatus(Request &/*req*/, Response &/*resp*/)
void ChatHandler::handleSendStatus(Request &req, Response &resp)
{
std::string chat_id;
std::string status;
req.mStream << makeKeyValueReference("chat_id", chat_id)
<< makeKeyValueReference("status", status);
ChatId id(chat_id);
if(id.isNotSet())
{
resp.setFail("chat_id is invalid");
return;
}
mRsMsgs->sendStatusString(id, status);
resp.setOk();
}
void ChatHandler::handleUnreadMsgs(Request &/*req*/, Response &resp)

View File

@ -25,6 +25,14 @@ public:
// from NotifyClient
// note: this may get called from the own and from foreign threads
virtual void notifyChatMessage(const ChatMessage& msg);
virtual void notifyChatCleared(const ChatId& chat_id);
// typing label for peer, broadcast and distant chat
virtual void notifyChatStatus (const ChatId& /* chat_id */, const std::string& /* status_string */);
//typing label for lobby chat, peer join and leave messages
virtual void notifyChatLobbyEvent (uint64_t /* lobby id */, uint32_t /* event type */ ,
const RsGxsId& /* nickname */,const std::string& /* any string */);
// from tickable
virtual void tick();
@ -81,6 +89,12 @@ public:
}
};
class LobbyParticipantsInfo{
public:
StateToken state_token;
std::map<RsGxsId, time_t> participants;
};
class ChatInfo{
public:
bool is_broadcast;
@ -91,20 +105,33 @@ public:
std::string remote_author_name;
};
class TypingLabelInfo{
public:
time_t timestamp;
std::string status;
StateToken state_token;
// only for lobbies
RsGxsId author_id;
};
private:
void handleWildcard(Request& req, Response& resp);
void handleLobbies(Request& req, Response& resp);
void handleSubscribeLobby(Request& req, Response& resp);
void handleUnsubscribeLobby(Request& req, Response& resp);
void handleClearLobby(Request& req, Response& resp);
ResponseTask* handleLobbyParticipants(Request& req, Response& resp);
void handleMessages(Request& req, Response& resp);
void handleSendMessage(Request& req, Response& resp);
void handleMarkChatAsRead(Request& req, Response& resp);
void handleInfo(Request& req, Response& resp);
void handleTypingLabel(Request& req, Response& resp);
ResponseTask *handleReceiveStatus(Request& req, Response& resp);
void handleSendStatus(Request& req, Response& resp);
void handleUnreadMsgs(Request& req, Response& resp);
void getPlainText(const std::string& in, std::string &out, std::vector<Triple> &links);
// last parameter is only used for lobbies!
void locked_storeTypingInfo(const ChatId& chat_id, std::string status, RsGxsId lobby_gxs_id = RsGxsId());
StateTokenServer* mStateTokenServer;
RsNotify* mNotify;
@ -121,9 +148,13 @@ private:
std::map<ChatId, ChatInfo> mChatInfo;
std::map<ChatId, TypingLabelInfo> mTypingLabelInfo;
StateToken mLobbiesStateToken;
std::vector<Lobby> mLobbies;
std::map<ChatLobbyId, LobbyParticipantsInfo> mLobbyParticipantsInfos;
StateToken mUnreadMsgsStateToken;
};

View File

@ -4,6 +4,7 @@ class RsPlugInInterfaces;
namespace resource_api{
// populates the given RsPlugInInterfaces object with pointers from gloabl variables like rsPeers, rsMsgs, rsFiles...
bool getPluginInterfaces(RsPlugInInterfaces& interfaces);
} // namespace resource_api

View File

@ -62,6 +62,7 @@ bool GxsResponseTask::doWork(Request &req, Response &resp)
{
more = false; // pause when an id failed, to give the service time tim fetch the data
ready = false;
// TODO: remove identities which failed many times from list, to avoid blocking when ids fail
}
}
if(!ready)

View File

@ -15,7 +15,7 @@ class GxsResponseTask: public ResponseTask
{
public:
// token service is allowed to be null if no token functions are wanted
GxsResponseTask(RsIdentity* id_service, RsTokenService* token_service);
GxsResponseTask(RsIdentity* id_service, RsTokenService* token_service = 0);
virtual bool doWork(Request &req, Response& resp);
protected:

View File

@ -16,17 +16,18 @@ namespace resource_api
class SendIdentitiesListTask: public GxsResponseTask
{
public:
SendIdentitiesListTask(RsIdentity* idservice, std::list<RsGxsId> ids):
GxsResponseTask(idservice, 0)
SendIdentitiesListTask(RsIdentity* idservice, std::list<RsGxsId> ids, StateToken state):
GxsResponseTask(idservice, 0), mStateToken(state)
{
for(std::list<RsGxsId>::iterator vit = ids.begin(); vit != ids.end(); ++vit)
{
requestGxsId(*vit);
mIds.push_back(*vit);// convert fro list to vector
mIds.push_back(*vit);// convert from list to vector
}
}
private:
std::vector<RsGxsId> mIds;
StateToken mStateToken;
protected:
virtual void gxsDoWork(Request &req, Response &resp)
{
@ -35,17 +36,89 @@ protected:
{
streamGxsId(*vit, resp.mDataStream.getStreamToMember());
}
resp.mStateToken = mStateToken;
resp.setOk();
done();
}
};
IdentityHandler::IdentityHandler(RsIdentity *identity):
mRsIdentity(identity)
class CreateIdentityTask: public GxsResponseTask
{
public:
CreateIdentityTask(RsIdentity* idservice):
GxsResponseTask(idservice, idservice->getTokenService()), mState(BEGIN), mToken(0), mRsIdentity(idservice){}
private:
enum State {BEGIN, WAIT_ACKN, WAIT_ID};
State mState;
uint32_t mToken;
RsIdentity* mRsIdentity;
RsGxsId mId;
protected:
virtual void gxsDoWork(Request &req, Response &resp)
{
switch(mState)
{
case BEGIN:{
RsIdentityParameters params;
req.mStream << makeKeyValueReference("name", params.nickname) << makeKeyValueReference("pgp_linked", params.isPgpLinked);
if(params.nickname == "")
{
resp.setFail("name can't be empty");
done();
return;
}
mRsIdentity->createIdentity(mToken, params);
addWaitingToken(mToken);
mState = WAIT_ACKN;
break;
}
case WAIT_ACKN:{
RsGxsGroupId grpId;
if(!mRsIdentity->acknowledgeGrp(mToken, grpId))
{
resp.setFail("acknowledge of group id failed");
done();
return;
}
mId = RsGxsId(grpId);
requestGxsId(mId);
mState = WAIT_ID;
break;
}
case WAIT_ID:
streamGxsId(mId, resp.mDataStream);
resp.setOk();
done();
}
}
};
IdentityHandler::IdentityHandler(StateTokenServer *sts, RsNotify *notify, RsIdentity *identity):
mStateTokenServer(sts), mNotify(notify), mRsIdentity(identity),
mMtx("IdentityHandler Mtx"), mStateToken(sts->getNewToken())
{
mNotify->registerNotifyClient(this);
addResourceHandler("*", this, &IdentityHandler::handleWildcard);
addResourceHandler("own", this, &IdentityHandler::handleOwn);
addResourceHandler("create_identity", this, &IdentityHandler::handleCreateIdentity);
}
IdentityHandler::~IdentityHandler()
{
mNotify->unregisterNotifyClient(this);
}
void IdentityHandler::notifyGxsChange(const RsGxsChanges &changes)
{
RS_STACK_MUTEX(mMtx); // ********** LOCKED **********
// if changes come from identity service, invalidate own state token
if(changes.mService == mRsIdentity->getTokenService())
{
mStateTokenServer->replaceToken(mStateToken);
}
}
void IdentityHandler::handleWildcard(Request &req, Response &resp)
@ -54,6 +127,7 @@ void IdentityHandler::handleWildcard(Request &req, Response &resp)
if(req.isPut())
{
#ifdef REMOVE
RsIdentityParameters params;
req.mStream << makeKeyValueReference("name", params.nickname);
if(req.mStream.isOK())
@ -67,9 +141,14 @@ void IdentityHandler::handleWildcard(Request &req, Response &resp)
{
ok = false;
}
#endif
}
else
{
{
RS_STACK_MUTEX(mMtx); // ********** LOCKED **********
resp.mStateToken = mStateToken;
}
RsTokReqOptions opts;
opts.mReqType = GXS_REQUEST_TYPE_GROUP_DATA;
uint32_t token;
@ -124,14 +203,24 @@ void IdentityHandler::handleWildcard(Request &req, Response &resp)
}
}
ResponseTask* IdentityHandler::handleOwn(Request &req, Response &resp)
ResponseTask* IdentityHandler::handleOwn(Request & /* req */, Response &resp)
{
StateToken state;
{
RS_STACK_MUTEX(mMtx); // ********** LOCKED **********
state = mStateToken;
}
std::list<RsGxsId> ids;
if(mRsIdentity->getOwnIds(ids))
return new SendIdentitiesListTask(mRsIdentity, ids);
return new SendIdentitiesListTask(mRsIdentity, ids, state);
resp.mDataStream.getStreamToMember();
resp.setWarning("identities not loaded yet");
return 0;
}
ResponseTask* IdentityHandler::handleCreateIdentity(Request & /* req */, Response & /* resp */)
{
return new CreateIdentityTask(mRsIdentity);
}
} // namespace resource_api

View File

@ -1,19 +1,36 @@
#pragma once
#include <retroshare/rsnotify.h>
#include <util/rsthreads.h>
#include "ResourceRouter.h"
#include "StateTokenServer.h"
class RsIdentity;
namespace resource_api
{
class IdentityHandler: public ResourceRouter
class IdentityHandler: public ResourceRouter, NotifyClient
{
public:
IdentityHandler(RsIdentity* identity);
IdentityHandler(StateTokenServer* sts, RsNotify* notify, RsIdentity* identity);
virtual ~IdentityHandler();
// from NotifyClient
// note: this may get called from foreign threads
virtual void notifyGxsChange(const RsGxsChanges &changes);
private:
RsIdentity* mRsIdentity;
void handleWildcard(Request& req, Response& resp);
ResponseTask *handleOwn(Request& req, Response& resp);
ResponseTask *handleCreateIdentity(Request& req, Response& resp);
StateTokenServer* mStateTokenServer;
RsNotify* mNotify;
RsIdentity* mRsIdentity;
RsMutex mMtx;
StateToken mStateToken; // mutex protected
};
} // namespace resource_api

View File

@ -24,6 +24,7 @@ void handlePaginationRequest(Request& req, Response& resp, C& data)
// set result type to list
resp.mDataStream.getStreamToMember();
resp.mDebug << "note: list is empty" << std::endl;
resp.setOk();
return;
}

View File

@ -72,7 +72,7 @@ PeersHandler::~PeersHandler()
mStateTokenServer->unregisterTickClient(this);
}
void PeersHandler::notifyListChange(int list, int type)
void PeersHandler::notifyListChange(int list, int /* type */)
{
RsStackMutex stack(mMtx); /********** STACK LOCKED MTX ******/
if(list == NOTIFY_LIST_FRIENDS)
@ -193,6 +193,8 @@ void PeersHandler::handleWildcard(Request &req, Response &resp)
ok &= mRsPeers->getPeerDetails(*lit, details);
detailsVec.push_back(details);
}
// mark response as list, in case it is empty
resp.mDataStream.getStreamToMember();
for(std::list<RsPgpId>::iterator lit = identities.begin(); lit != identities.end(); ++lit)
{
// if no own ssl id is known, then hide the own id from the friendslist

View File

@ -12,7 +12,7 @@ public:
{
addResourceHandler("eins", this, &TestResource::eins);
}
ResponseTask* eins(Request& req, Response& resp)
ResponseTask* eins(Request& /* req */, Response& /* resp */)
{
return 0;
}

View File

@ -30,7 +30,7 @@ RsControlModule::RsControlModule(int argc, char **argv, StateTokenServer* sts, A
this->argv = argv;
// start worker thread
if(full_control)
start();
start("resapi ctrl mod");
else
mRunState = RUNNING_OK_NO_FULL_CONTROL;
@ -55,7 +55,7 @@ bool RsControlModule::processShouldExit()
return mProcessShouldExit;
}
bool RsControlModule::askForPassword(const std::string &key_details, bool prev_is_bad, std::string &password, bool& cancelled)
bool RsControlModule::askForPassword(const std::string &key_details, bool /* prev_is_bad */, std::string &password, bool& cancelled)
{
cancelled = false ;
{

View File

@ -4,6 +4,8 @@
#include "Operators.h"
#include <stdlib.h>
namespace resource_api
{
// maybe move to another place later
@ -44,6 +46,7 @@ ServiceControlHandler::ServiceControlHandler(RsServiceControl* control):
mRsServiceControl(control)
{
addResourceHandler("*", this, &ServiceControlHandler::handleWildcard);
addResourceHandler("user", this, &ServiceControlHandler::handleUser);
}
void ServiceControlHandler::handleWildcard(Request &req, Response &resp)
@ -73,7 +76,42 @@ void ServiceControlHandler::handleWildcard(Request &req, Response &resp)
}
else if(req.isPut())
{
// change service default
std::string serviceidtext;
bool enabled;
req.mStream << makeKeyValueReference("service_id", serviceidtext)
<< makeKeyValueReference("default_allowed", enabled);
RsServicePermissions serv_perms ;
//uint32_t serviceid = fromString<uint32_t>(serviceidtext);
uint32_t serviceid = atoi(serviceidtext.c_str());
if (serviceid == 0) {
resp.setFail("service_id missed");
return;
}
if(!rsServiceControl->getServicePermissions(serviceid, serv_perms)){
resp.setFail("service_id " + serviceidtext + " is invalid");
return;
}
serv_perms.mDefaultAllowed = enabled;
if(serv_perms.mDefaultAllowed)
{
serv_perms.mPeersDenied.clear() ;
}
else
{
serv_perms.mPeersAllowed.clear() ;
}
ok = rsServiceControl->updateServicePermissions(serviceid,serv_perms);
if (!ok) {
resp.setFail("updateServicePermissions failed");
return;
}
}
}
if(ok)
@ -86,4 +124,62 @@ void ServiceControlHandler::handleWildcard(Request &req, Response &resp)
}
}
void ServiceControlHandler::handleUser(Request& req, Response& resp){
// no get, only put (post) to allow user or delete to remove user
std::string serviceidtext;
std::string peeridtext;
bool enabled;
bool ok;
req.mStream << makeKeyValueReference("service_id", serviceidtext)
<< makeKeyValueReference("peer_id", peeridtext)
<< makeKeyValueReference("enabled", enabled);
RsPeerId peer_id(peeridtext);
if (peer_id.isNull()) {
resp.setFail("peer_id missing or not found");
return;
}
RsServicePermissions serv_perms ;
uint32_t serviceid = atoi(serviceidtext.c_str());
if (serviceid == 0) {
resp.setFail("service_id missed");
return;
}
if(!rsServiceControl->getServicePermissions(serviceid, serv_perms)){
resp.setFail("service_id " + serviceidtext + " is invalid");
return;
}
if(req.isPut())
{
if (enabled && !serv_perms.peerHasPermission(peer_id))
{
serv_perms.setPermission(peer_id);
} else if (!enabled && serv_perms.peerHasPermission(peer_id)){
serv_perms.resetPermission(peer_id);
} else {
//nothing todo
resp.setOk();
return;
}
} else {
resp.setFail("only POST supported.");
return;
}
ok = rsServiceControl->updateServicePermissions(serviceid,serv_perms);
if (!ok) {
resp.setFail("updateServicePermissions failed");
return;
}
resp.setOk();
}
} // namespace resource_api

View File

@ -16,5 +16,6 @@ public:
private:
RsServiceControl* mRsServiceControl;
void handleWildcard(Request& req, Response& resp);
void handleUser(Request& req, Response& resp);
};
} // namespace resource_api

View File

@ -114,6 +114,7 @@ void StateTokenServer::handleWildcard(Request &req, Response &resp)
RsStackMutex stack(mMtx); /********** STACK LOCKED MTX ******/
// want to lookpup many tokens at once, return a list of invalid tokens
// TODO: make generic list serialiser/deserialiser
resp.mDataStream.getStreamToMember();
while(req.mStream.hasMore())
{
StateToken token;

View File

@ -42,7 +42,7 @@ void TransfersHandler::tick()
}
}
void TransfersHandler::handleWildcard(Request &req, Response &resp)
void TransfersHandler::handleWildcard(Request & /*req*/, Response & /*resp*/)
{
}
@ -108,7 +108,7 @@ void TransfersHandler::handleControlDownload(Request &req, Response &resp)
resp.setFail("error: action not handled");
}
void TransfersHandler::handleDownloads(Request &req, Response &resp)
void TransfersHandler::handleDownloads(Request & /* req */, Response &resp)
{
tick();
resp.mStateToken = mStateToken;

View File

@ -525,7 +525,7 @@ std::string SerializeValue(const Value& v)
// json expets decimal points, so replace all commas with decimal points
if(v.GetType() == FloatVal || v.GetType() == DoubleVal)
{
for(int i = 0; i < str.size(); i++)
for(unsigned int i = 0; i < str.size(); i++)
if(str[i] == ',')
str[i] = '.';
}

View File

@ -13,18 +13,97 @@ 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
webui_files.path = "$${DATA_DIR}/webui"
webui_files.files = webui/app.js webui/app.css webui/index.html
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
# create dummy files, we need it to include files on first try
system(webui-src/make-src/build.sh .)
WEBUI_SRC_SCRIPT = webui-src/make-src/build.sh
WEBUI_SRC_HTML = $$WEBUI_SRC_SCRIPT
WEBUI_SRC_HTML += webui-src/app/assets/index.html
WEBUI_SRC_JS = $$WEBUI_SRC_SCRIPT
WEBUI_SRC_JS += webui-src/app/accountselect.js
WEBUI_SRC_JS += webui-src/app/adddownloads.js
WEBUI_SRC_JS += webui-src/app/addidentity.js
WEBUI_SRC_JS += webui-src/app/addpeer.js
WEBUI_SRC_JS += webui-src/app/chat.js
WEBUI_SRC_JS += webui-src/app/createlogin.js
WEBUI_SRC_JS += webui-src/app/downloads.js
WEBUI_SRC_JS += webui-src/app/forums.js
WEBUI_SRC_JS += webui-src/app/home.js
WEBUI_SRC_JS += webui-src/app/identities.js
WEBUI_SRC_JS += webui-src/app/main.js
WEBUI_SRC_JS += webui-src/app/menudef.js
WEBUI_SRC_JS += webui-src/app/menu.js
WEBUI_SRC_JS += webui-src/app/mithril.js
WEBUI_SRC_JS += webui-src/app/mithril.min.js
WEBUI_SRC_JS += webui-src/app/peers.js
WEBUI_SRC_JS += webui-src/app/retroshare.js
WEBUI_SRC_JS += webui-src/app/search.js
WEBUI_SRC_JS += webui-src/app/searchresult.js
WEBUI_SRC_JS += webui-src/app/servicecontrol.js
WEBUI_SRC_JS += webui-src/app/settings.js
WEBUI_SRC_JS += webui-src/app/waiting.js
WEBUI_SRC_CSS = $$WEBUI_SRC_SCRIPT
WEBUI_SRC_CSS += webui-src/app/green-black.scss
WEBUI_SRC_CSS += webui-src/app/_reset.scss
WEBUI_SRC_CSS += webui-src/app/_chat.sass
WEBUI_SRC_CSS += webui-src/app/main.sass
create_webfiles_html.output = webui/index.html
create_webfiles_html.input = WEBUI_SRC_HTML
create_webfiles_html.commands = sh $$_PRO_FILE_PWD_/webui-src/make-src/build.sh $$_PRO_FILE_PWD_ index.html .
create_webfiles_html.variable_out = JUNK
create_webfiles_html.CONFIG = combine no_link
create_webfiles_js.output = webui/app.js
create_webfiles_js.input = WEBUI_SRC_JS
create_webfiles_js.commands = sh $$_PRO_FILE_PWD_/webui-src/make-src/build.sh $$_PRO_FILE_PWD_ app.js .
create_webfiles_js.variable_out = JUNK
create_webfiles_js.CONFIG = combine no_link
create_webfiles_css.output = webui/app.css
create_webfiles_css.input = WEBUI_SRC_CSS
create_webfiles_css.commands = sh $$_PRO_FILE_PWD_/webui-src/make-src/build.sh $$_PRO_FILE_PWD_ app.css .
create_webfiles_css.variable_out = JUNK
create_webfiles_css.CONFIG = combine no_link
QMAKE_EXTRA_COMPILERS += create_webfiles_html create_webfiles_js create_webfiles_css
}
win32{
DEFINES *= WINDOWS_SYS
INCLUDEPATH += . $$INC_DIR
greaterThan(QT_MAJOR_VERSION, 4) {
# Qt 5
PRO_PATH=$$shell_path($$_PRO_FILE_PWD_)
MAKE_SRC=$$shell_path($$PRO_PATH/webui-src/make-src)
} else {
# Qt 4
PRO_PATH=$$replace(_PRO_FILE_PWD_, /, \\)
MAKE_SRC=$$PRO_PATH\\webui-src\\make-src
}
#create_webfiles.commands = $$MAKE_SRC\\build.bat $$PRO_PATH
#QMAKE_EXTRA_TARGETS += create_webfiles
#PRE_TARGETDEPS += create_webfiles
QMAKE_POST_LINK=$$MAKE_SRC\\build.bat $$PRO_PATH
# create dummy files
system($$MAKE_SRC\\init.bat .)
}
libmicrohttpd{
@ -66,7 +145,8 @@ SOURCES += \
api/LivereloadHandler.cpp \
api/TmpBlobStore.cpp \
util/ContentTypes.cpp \
api/ApiPluginHandler.cpp
api/ApiPluginHandler.cpp \
api/ChannelsHandler.cpp
HEADERS += \
api/ApiServer.h \
@ -91,4 +171,5 @@ HEADERS += \
api/LivereloadHandler.h \
api/TmpBlobStore.h \
util/ContentTypes.h \
api/ApiPluginHandler.h
api/ApiPluginHandler.h \
api/ChannelsHandler.h

File diff suppressed because one or more lines are too long

View File

@ -1,109 +0,0 @@
/**
* JS Api for Retroshare
* @constructor
* @param {object} connection - an object which implements a request() function.
* The request function should take two parameters: an object to be send as request and a callback.
* The callback should get called with an response object on success.
*/
function RsApi(connection)
{
var runnign = true;
/**
* Send a request to the server
* @param req - the request so send
* @param {Function} cb - callback function which takes the response as parameter
*/
this.request = function(req, cb)
{
connection.request(req, cb);
};
var tokenlisteners = [];
/**
* Register a callback to be called when the state token expired.
* @param {Function} listener - the callback function, which does not take arguments
* @param token - the state token to listen for
*/
this.register_token_listener = function(listener, token)
{
tokenlisteners.push({listener:listener, token:token});
};
/**
* Unregister a previously registered callback.
*/
this.unregister_token_listener = function(listener) // no token as parameter, assuming unregister from all listening tokens
{
var to_delete = [];
for(var i=0; i<tokenlisteners.length; i++){
if(tokenlisteners[i].listener === listener){
to_delete.push(i);
}
}
for(var i=0; i<to_delete.length; i++){
// copy the last element to the current index
var index = to_delete[i];
tokenlisteners[index] = tokenlisteners[tokenlisteners.length-1];
// remove last element
tokenlisteners.pop();
}
};
/**
* start polling for state changes
*/
this.start = function(){
running = true;
setTimeout(tick, TICK_INTERVAL);
}
/**
* stop polling for state changes
*/
this.stop = function(){
running = false;
}
// ************** interal stuff **************
var TICK_INTERVAL = 3000;
function received_tokenstates(resp)
{
if(resp.data){
for(var i=0; i<resp.data.length; i++){
var token = resp.data[i];
// search the listener for this token
for(var j=0; j<tokenlisteners.length; j++){
if(tokenlisteners[j].token === token){
// call the listener
tokenlisteners[j].listener();
}
}
}
}
// schedule new update
if(running)
setTimeout(tick, TICK_INTERVAL);
};
function received_error()
{
// try again, maybe want a better logic later
if(running)
setTimeout(tick, TICK_INTERVAL);
};
function tick()
{
var data = [];
// maybe cache the token list?
// profiler will tell us if we should
for(var i=0; i<tokenlisteners.length; i++){
data.push(tokenlisteners[i].token);
}
connection.request({
path: "statetokenservice",
data: data,
}, received_tokenstates, received_error);
};
};
// with this trick, we should be able to run in browser or nodejs
if(typeof window === 'undefined')
{
// we are running in nodejs, so have to add to export
module.exports = RsApi;
}

View File

@ -1,123 +0,0 @@
/**
* Connection to the RS backend using XHR
* (could add other connections later, for example WebSockets)
* @constructor
*/
function RsXHRConnection(server_hostname, server_port)
{
var debug;
//debug = function(str){console.log(str);};
debug = function(str){};
//server_hostname = "localhost";
//server_port = "9090";
var api_root_path = "/api/v2/";
var status_listeners = [];
function notify_status(status)
{
for(var i = 0; i < status_listeners.length; i++)
{
status_listeners[i](status);
}
}
/**
* Register a callback to be called when the state of the connection changes.
* @param {function} cb - callback which receives a single argument. The arguments value is "connected" or "not_connected".
*/
this.register_status_listener = function(cb)
{
status_listeners.push(cb);
};
/**
* Unregister a status callback function.
* @param {function} cb - a privously registered callback function
*/
this.unregister_status_listener = function(cb)
{
var to_delete = [];
for(var i = 0; i < status_listeners.length; i++)
{
if(status_listeners[i] === cb){
to_delete.push(i);
}
}
for(var i = 0; i < to_delete.length; i++)
{
// copy the last element to the current index
var index = to_delete[i];
status_listeners[i] = status_listeners[status_listeners.length-1];
// remove the last element
status_listeners.pop();
}
};
/**
* Send a request to the backend
* automatically encodes the request as JSON before sending it to the server
* @param {object} req - the request to send to the server
* @param {function} cb - callback function to be called to handle the response. The callback takes one object as parameter. Can be left undefined.
* @param {function} err_cb - callback function to signal a failed request. Can be undefined.
*/
this.request = function(req, cb, err_cb)
{
//var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
// TODO: window is not available in QML
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
//console.log("onreadystatechanged state"+xhr.readyState);
// TODO: figure out how to catch errors like connection refused
// maybe want to have to set a state variable like ok=false
// the gui could then display: "no connection to server"
if (xhr.readyState === 4) {
if(xhr.status !== 200)
{
console.log("RsXHRConnection: request failed with status: "+xhr.status);
console.log("request was:");
console.log(req);
notify_status("not_connected");
if(err_cb !== undefined)
err_cb();
return;
}
// received response
notify_status("connected");
debug("RsXHRConnection received response:");
debug(xhr.responseText);
if(false)//if(xhr.responseText === "")
{
debug("Warning: response is empty");
return;
}
try
{
var respObj = JSON.parse(xhr.responseText);
}
catch(e)
{
debug("Exception during response handling: "+e);
}
if(cb === undefined)
debug("No callback function specified");
else
cb(respObj);
}
}
// post is required for sending data
var method;
if(req.data){
method = "POST";
} else {
method = "GET";
}
xhr.open(method, "http://"+server_hostname+":"+server_port+api_root_path+req.path);
var data = JSON.stringify(req.data);
debug("RsXHRConnection sending data:");
debug(data);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(data);
};
};

View File

@ -1,134 +0,0 @@
body {
background-color: black;
color: lime;
font-family: monospace;
margin: 0em;
/*padding: 1.5em;*/
padding: 2mm;
font-size: 1.1em;
}
#overlay{
z-index: 10;
position: fixed;
top:0;
left:0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.8);
}
.paddingbox{
padding:2mm;
}
.nav{
list-style-type: none;
padding: 0em;
margin: 0em;
}
.nav li{
display: inline;
padding: 0.1em;
margin-right: 1em;
border-width: 0.1em;
border-color: blue;
border-bottom-style: solid;
cursor: pointer;
}
td{
padding: 0.3em;
border-style: solid;
border-width: 0.1em;
border-color: lime;
}
.btn{
border-style: solid;
border-color: lime;
border-width: 0.1em;
cursor: pointer;
padding: 0.1em;
}
.btn2, .box{
border-style: solid;
/*border-color: lime;*/
border-color: limeGreen;
/*border-width: 1px;*/
border-radius: 3mm;
padding: 2mm;
font-size: 10mm;
cursor: pointer;
margin-bottom: 2mm;
}
.btn2:hover{
background-color: midnightblue;
}
.filelink{
color: inherit;
}
input, textarea{
color: lime;
font-family: monospace;
background-color: black;
border-color: lime;
font-size: 10mm;
border-radius: 3mm;
border-width: 1mm;
padding: 2mm;
margin-bottom: 2mm;
margin-right: 2mm;
/* make the button the whole screen width */
width: 100%;
/* make the text input fit small screens*/
box-sizing: border-box;
}
input:hover{
background-color: midnightblue;
}
.checkbox {
width: auto;
}
.flexbox{
display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */
display: -moz-box; /* OLD - Firefox 19- (buggy but mostly works) */
display: -ms-flexbox; /* TWEENER - IE 10 */
display: -webkit-flex; /* NEW - Chrome */
display: flex; /* NEW, Spec - Opera 12.1, Firefox 20+ */
}
.flexwidemember{
-webkit-box-flex: 1; /* OLD - iOS 6-, Safari 3.1-6 */
-moz-box-flex: 1; /* OLD - Firefox 19- */
width: 20%; /* For old syntax, otherwise collapses. */
-webkit-flex: 1; /* Chrome */
-ms-flex: 1; /* IE 10 */
flex: 1; /* NEW, Spec - Opera 12.1, Firefox 20+ */
}
#logo_splash{
-webkit-animation-fill-mode: forwards; /* Chrome, Safari, Opera */
animation-fill-mode: forwards;
-webkit-animation-name: logo_splash; /* Chrome, Safari, Opera */
-webkit-animation-duration: 3s; /* Chrome, Safari, Opera */
animation-name: logo_splash;
animation-duration: 3s;
text-align: center;
}
/* Chrome, Safari, Opera */
@-webkit-keyframes logo_splash {
from {opacity: 0;}
to {opacity: 1;}
}
/* Standard syntax */
@keyframes logo_splash {
from {opacity: 0;}
to {opacity: 1;}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,29 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>New webinterface for Retroshare</title>
<script src="RsXHRConnection.js"></script>
<script src="RsApi.js"></script>
<!-- it seems to work more reliable, if the jsx file is loaded before react -->
<script type="text/jsx" src="gui.jsx"></script>
<script src="react.js"></script>
<script src="JSXTransformer.js"></script>
<link href="green-black.css" rel="stylesheet">
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1">
</head>
<body>
<script>
document.write("<p>loading lots of stuff...</p>");
</script>
<p><noscript>The Retroshare web interface requires JavaScript. Please enable JavaScript in your browser.</noscript></p>
<!--<div id="logo_splash">
<img src="img/logo_splash.png"></img>
</div>-->
</body>
</html>

File diff suppressed because it is too large Load Diff

2
libresapi/src/webui-src/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
node_modules/*
public/*

View File

@ -0,0 +1,78 @@
A new approach to build a webinterface for RS
=============================================
1. get JSON encoded data from the backend, data contains a state token
2. render data with mithril.js
3. ask the backend if the state token from step 1 expired. If yes, then start again with step 1.
Steps 1. and 3. are common for most things, only Step 2. differs. This allows to re-use code for steps 1. and 3.
BUILD / DEVELOPMENT
------------
- install tools
sudo apt-get install TODO (insert package names for nodejs, ruby, sass here)
- run this once in webui-src directory, to install more tools
npm install
- start build
npm run watch
- the build process watches files for changes, and rebuilds and reloads the page. Build output is in ./public
- use the --webinterface 9090 command line parameter to enable webui in retroshare-nogui
- set the --docroot parameter of retroshare-nogui to point to the "libresapi/src/webui-src/public" directory
(or symlink from /usr/share/RetroShare06/webui on Linux, ./webui on Windows)
- retroshare-gui does not have a --docroot parameter. Use symlinks then.
CONTRIBUTE
----------
- if you are a web developer or want to become one
get in contact!
- lots of work to do, i need you!
TODO
----
[ ] make stylesheets or find reusable sass/css components
google material design has nice rules for color, spacing and everything: https://www.google.de/design/spec/material-design/introduction.html
[ ] find icons, maybe use google material design iconfont
[X] use urls/mithril routing for the menu. urls could replace state stored in rs.content
[X] drag and drop private key upload and import
[X] link from peer location to chat (use urls and mithril routing)
[X] add/remove friend, own cert
[X] downloads, search
[ ] make reusable infinite list controller, the js part to load data from Pagination.h (tweak Pagination.h to make everything work)
should provide forward, backward and follow-list-end
[ ] backend: view/create identities
[ ] backend: chat lobby participants list
[X] chat: send_message
[ ] backend: chat typing notifications
[ ] make routines to handle retroshare links
[ ] backend: edit shared folders
[ ] backend: view shared files
[ ] redirect if a url is not usable in the current runstate (e.g. redirect from login page to home page, after login)
[X] sort friendslist
need 4 master
-------------
[X] unsubscribe lobby
[X] unread chat message counter in menu
[X] list chat-lobby participants
[X] creating app.js on build (no need for npm on regulary build)
url-handling (brainstorming)
----------------------------
* normal weblinks (bbcode? => only with gui support)
* rslinks
- files
- (chatrooms)
- forum retroshare://forum?name=Developers%27%20Discussions&id=8fd22bd8f99754461e7ba1ca8a727995
- own cert link (paste)
- cert-links
- searches
- [X] downloads pasten
- uploads?
* enter / display urls
- use urls in href like used for input (so it can be copy-link)
- handle RS-urls with javascript, other with target _blank
* smilies
* Bilder
* KEEP IT SIMPLE

View File

@ -0,0 +1,81 @@
.chat
$color: black
$header_height: 50px
$left_width: 200px
$right_width: 200px
$input_height: 100px
padding: 15px
&.container
height: 100%
padding: 0px
position: relative
box-sizing: border-box
&.header
position: absolute
top: 0px
left: 0px
right: 0px
height: $header_height
background-color: $color
border-bottom: solid 1px gray
box-sizing: border-box
&.left
position: absolute
top: $header_height
bottom: 0px
left: 0px
width: $left_width
//border-right: solid 1px gray
box-sizing: border-box
background-color: black
&.right
position: absolute
top: $header_height
right: 0px
bottom: 0px
width: $right_width
box-sizing: border-box
//border-left: solid 1px gray
&.middle
//background-color: blue
position: absolute
top: 0px
margin-top: $header_height
left: $left_width
right: $right_width
box-sizing: border-box
padding: 0px
height: 100%
overflow-y: scroll
&.bottom
position: absolute
bottom: 0px
right: $right_width
left: $left_width
padding: 5px
&.msg
padding: 0px
$author_width: 100px
&.container
position: relative
border-bottom: solid 1px lightgray
padding: 10px
height: unset
//background-color: lime
&.from
position: absolute
width: $author_width
top: 10px
left: 0px
color: white
text-align: right
&.when
float: right
color: lightgray
margin-bottom: 10px
&.text
padding-left: $author_width
top: 0px
left: $author_width
white-space: pre-wrap
height: initial

View File

@ -0,0 +1,48 @@
/* http://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain)
*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}

View File

@ -0,0 +1,68 @@
"use strict";
var m = require("mithril");
var rs = require("retroshare");
function cancel(){
rs.memory("control/locations").curraccount=null;
m.redraw();
}
function selAccount(account){
rs.memory("control/locations").curraccount=account;
m.redraw();
rs.request("control/login", {id: account.id}, function(){
console.log("login sent");
});
}
function curraccount() {
var mem;
mem = rs.memory("control/locations");
if (mem.curraccount === undefined) {
return null;
}
return mem.curraccount;
}
module.exports = {view: function(){
var accounts = rs("control/locations");
if(accounts === undefined || accounts == null){
return m("div", "accounts: waiting_server");
}
if (curraccount() == null) {
return m("div", [
m("h2","login:"),
m("hr"),
accounts.map(function(account){
return [
m("div.btn2", {
onclick: function(){
selAccount(account)
}
},
account.location + " (" + account.name + ")"),
m("br")
]
})
]);
} else {
// rs.untoken("control/password");
return m("div", [
m("div", [
"logging in ...",
m("br"),
"(waiting for password-request)",
]),
/*
m("hr"),
m(".btn2", {
onclick: function() {
cancel();
}
},"Cancel " + curraccount().name + " login "),
*/
]);
}
}
};

View File

@ -0,0 +1,299 @@
var m = require("mithril");
var rs = require("retroshare");
var me = {
toParse: [], // links to parse ( = pasted content)
toConfirm: [], // links to confirm
toAdd: [], // links to add
toResult: [], // Result to show
index: 0,
view: function(){
return m("div", {
style: {
height:"100%",
boxSizing: "border-box",
paddingBottom: "130px",
}
},[
m("h2","add downloads"),
m("hr"),
this.toParse.length
? step2()
: this.toConfirm.length
? step3()
: this.toAdd.length
? step4()
: this.toResult.length
? step5()
: step1()
,
]);
},
parseOne: function(){
if (me.index == null) {
return null;
}
var startindex = me.index;
while (me.toParse.length > me.index && me.index - startindex < 10) {
var src = me.toParse[me.index].split("?",2);
console.log(src);
if (src[0] == "retroshare://file" && src.length == 2) {
var target = {action: "begin"};
var errText = "Error: link missing name and/or hash"
src[1].split("&").map(function(parm){
var pos = parm.indexOf("=");
if (pos >0){
if (parm.substr(0,pos) == "name") {
var sname=decodeURIComponent(parm.substr(pos+1))
if (sname.match("[\\\\/]")) {
errText="name contains illegal char "
+ sname.match("[\\\\/]");
} else {
target.name=sname;
}
} else if (parm.substr(0,pos) == "size") {
target.size=parseFloat(parm.substr(pos+1));
} else if (parm.substr(0,pos) == "hash") {
target.hash=parm.substr(pos+1);
}
}
});
if (target['name'] && target['hash']){
me.toConfirm.push({
text: target.name,
target: target,
confirmed: true,
});
} else {
me.toConfirm.push({
text:errText,
});
}
} else {
me.toConfirm.push({ text: "Error: no Retroshare-file link"})
}
me.index++;
}
if (me.toParse.length > me.index) {
window.setTimeout("require(\"adddownloads\").parseOne()",1);
} else {
me.toParse = [];
console.log(me.toConfirm.length);
}
refresh();
},
addOne: function(){
if (me.index == null) {
cancel();
} else if (me.index >= me.toAdd.length) {
me.toResult=me.toAdd;
me.toAdd=[];
refresh();
} else {
console.log([
me.toAdd[me.index].action,
me.toAdd[me.index].name,
me.toAdd[me.index].size,
me.toAdd[me.index].hash,
]);
refresh();
rs.request("transfers/control_download", me.toAdd[me.index],
function(data,statetoken){
if (me.index != null) {
me.toAdd[me.index].ok=true;
me.index++;
me.addOne();
}
}, {
onfail: function(value){
me.toAdd[me.index].ok=false;
me.toAdd[me.index].debug_msg=value;
me.index++;
me.addOne();
},
onmismatch: function(response){
me.toAdd[me.index].ok=false;
me.toAdd[me.index].debug_msg=response.debug_msg;
me.index++;
me.addOne();
},
}
);
}
}
};
function cancel() {
me.toAdd=[];
me.toConfirm=[];
me.toParse=[];
me.toResult=[];
me.index=null;
refresh();
}
function parseDownloads(){
me.toParse = document.getElementById("txtInput").value.replace("\r\n","\n").split("\n");
var pos;
while ((pos=me.toParse.indexOf(""))>=0) {
me.toParse.splice(pos,1);
}
var parser = document.createElement('a');
me.toConfirm = [];
me.index = 0;
if (me.toParse.length > me.index){
window.setTimeout("require(\"adddownloads\").parseOne()",1);
}
}
function addDownloads(){
me.toConfirm.map(function(item){
if (item.confirmed) {
item.debug_msg="";
me.toAdd.push(item.target);
}
});
me.toConfirm=[];
if (me.toAdd.length > 0){
me.index=0;
window.setTimeout("require(\"adddownloads\").addOne()",1);
} else {
cancel();
}
refresh();
}
function refresh(){
m.startComputation();
m.endComputation();
}
function cancelBtn(){
return m("div.btn2", {
style:{
textAlign: "center",
color: "red",
borderColor: "red",
},
onclick:cancel,
},"cancel");
}
// paste links
function step1(){
m.initControl = "txtInput";
return [
m("h3","step 1 / 5: paste retroshare-links:"),
m("textarea[id=txtInput]", {
style: {
height:"100%",
},
onkeydown: function(event){
if (event.keyCode == 13){
parseDownloads();
}
}
}),
m("div.btn2", {
style:{
textAlign:"center",
},
onclick:parseDownloads,
},"add downloads")
]
}
// parsing links
function step2(){
return [
m("h3","step 2 / 5: parsing input ..."),
m("p",
"parsing " + (me.index) + " / " + me.toParse.length),
cancelBtn(),
]
}
// parsing confirm
function step3(){
return [
m("h3","step 3 / 5: confirm-links:"),
m("ul",
me.toConfirm.map(function(item){
return m("li", {
style:{
color: item.confirmed
? "lime"
: "red"
},
}, item.text);
})
),
m("div.btn2", {
style:{
textAlign:"center",
},
onclick:addDownloads,
},"add green listed downloads"),
cancelBtn(),
]
}
// adding links
function step4(){
return [
m("h3","step 4 / 5: adding downloads:"),
m("p",
"adding " + (me.index) + " / " + me.toParse.length),
m("ul",
me.toAdd.map(function(item){
return m("li", {
style:{
color: item.ok === undefined
? "white"
: item.ok == null
? "grey"
: item.ok
? "lime"
: "red"
},
}, (item.debug_msg ? item.debug_msg + ": " : "") + item.name
+ " " + item.size + " " + item.hash);
})
),
cancelBtn(),
]
}
// show result
function step5(){
return [
m("h3","step 5 / 5: Result:"),
m("p",
"verarbeitet: " + me.toResult.length),
m("ul",
me.toResult.map(function(item){
return m("li", {
style:{
color: item.ok === undefined
? "white"
: item.ok == null
? "grey"
: item.ok
? "lime"
: "red"
},
}, (item.debug_msg ? item.debug_msg + ": " : "") + item.name);
})
),
m("div.btn2", {
style:{
textAlign: "center",
},
onclick: cancel,
},"ok"),
]
}
module.exports = me;

View File

@ -0,0 +1,54 @@
"use strict";
var m = require("mithril");
var rs = require("retroshare");
function createidentity(){
var data = {
name: document.getElementById("txtname").value,
pgp_linked: false,
//document.getElementById("chklinked").checked,
};
m.route("/waiting");
rs.request("identity/create_identity",data, function(){
m.route("/identities");
})
}
module.exports = {view: function(){
m.initControl = "txtname";
return m("div",
m("h2","create identity"),
m("hr"),
m("h3","name"),
m("input", {
type: "text",
id: "txtname",
/*
onkeydown: function(event){
if (event.keyCode == 13){
setPasswd(this.value);
sendPassword(needpasswd);
}
}
*/
}),
/*
m("b","linked with pgp-id: "),
m("input", {
type: "checkbox",
id: "chklinked",
style: {
fontweight:"bold",
width: "0%",
}
}),
*/
m("p"," "),
m("input.btn2", {
onclick: createidentity,
type: "button",
value: "create new identity",
})
)
}}

View File

@ -0,0 +1,151 @@
"use strict";
var m = require("mithril");
var rs = require("retroshare");
var newkey = "";
var remote = "";
module.exports = {
view: function(){
var key = m.route.param("radix");
var pgp = m.route.param("pgp_id");
var peer_id =m.route.param("peer_id");
if (key===undefined && pgp === undefined) {
var owncert = rs("peers/self/certificate");
if (owncert === undefined ) {
owncert = {cert_string:"< waiting for server ... >"}
}
return m("div", [
m("h2","add new friend (Step 1/3)"),
m("p","Your own key, give it to your friends"),
m("pre", owncert.cert_string),
m("p","paste your friends key below"),
m("textarea", {
ref:"cert",
cols:"70",
rows:"16",
onchange: m.withAttr("value", function(value){newkey=value;})
}),
m("br"),
m("input.btn2",{
type:"button",
value:"read",
onclick: function (){
m.route("/addpeer",{radix:newkey})
},
})
]);
} else if (pgp === undefined) {
rs.request("peers/examine_cert",{cert_string:key},
function(data,responsetoken){
data.radix=key;
m.route("/addpeer", data);
}
);
return m("div", [
m("h2","add new friend (Step 2/3)"),
m("div", "analyse cert, please wait for server ...")
// { data: null, debug_msg: "failed to load certificate ", returncode: "fail" }
]);
} else {
var result = {
cert_string:key ,
flags:{
allow_direct_download:false,
allow_push:false,
// set to false, until the webinterface supports managment of the blacklist/whitelist
require_whitelist: false,
}
};
return m("div",[
m("h2","add new friend (Step 3/3)"),
m("p","Do you want to add "
+ m.route.param("name")
+ " (" + m.route.param("location") + ")"
+ " to your friendslist?"),
m("input.checkbox[type=checkbox]", {
onchange: m.withAttr("checked", function(checked){
result.flags.allow_direct_download=checked;
})
}), "Allow direct downloads from this node",
m("br"),
m("input.checkbox[type=checkbox]", {
onchange: m.withAttr("checked", function(checked){
result.flags.allow_push=checked;
})
}), "Auto download recommended files from this node",
m("div.btn2",{
onclick: function(){
m.route("/waiting");
rs.request("peers",result,function(data, responsetoken){
m.route("/peers");
})
}
},"add to friendslist")
])
}
}
};
/*
return "peers/self/certificate"
RS.request({path: "peers/examine_cert", data: {cert_string: cert_string}}, this.examine_cert_callback);
this.setState({page:"waiting", cert_string: cert_string});
RS.request(
{
path: "peers",
data: {
cert_string: this.state.cert_string,
flags:{
allow_direct_download: this.refs.cb_direct_dl.getDOMNode().checked,
allow_push: this.refs.cb_push.getDOMNode().checked,
// set to false, until the webinterface supports managment of the blacklist/whitelist
require_whitelist: false,
}
}
});
render: function(){
if(this.state.page === "start")
return(
<div>
<p>Your own key, give it to your friends</p>
<OwnCert/>
<p>paste your friends key below</p>
<textarea ref="cert" cols="70" rows="16"></textarea><br/>
<input
type="button"
value="read key"
onClick={this.add_friend_handler}
/>
</div>
);
if(this.state.page === "waiting")
return(
<div>
waiting for response from server...
</div>
);
if(this.state.page === "peer")
return(
<div>
<p>Do you want to add {this.state.data.name} to your friendslist?</p>
<input className="checkbox" type="checkbox" ref="cb_direct_dl"/> Allow direct downloads from this node<br/>
<input className="checkbox" type="checkbox" ref="cb_push"/> Auto download recommended files from this node<br/>
<div onClick={this.final_add_handler} className="btn2">add to friendslist</div>
</div>
);
},
*/

View File

@ -0,0 +1,23 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>rswebui6</title>
<link rel="stylesheet" href="app.css">
<script src="app.js"></script>
</head>
<body onload="load_ui();">
<div id="main">if app does not load, enable JavaScript!</div>
<script type="text/javascript">
function load_ui(){
var m = require("mithril");
var ui = require("main");
var main = document.getElementById("main");
ui.init(main);
if (m.initControl != undefined) {
m.initControl.focus();
}
}
</script>
</body>
</html>

View File

@ -0,0 +1,298 @@
"use strict";
var m = require("mithril");
var rs = require("retroshare");
var msg = null;
var particips = [];
function dspmsg(from, when, text){
return m(".chat.msg.container",[
m(".chat.msg.from", from),
m(".chat.msg.when", when),
m(".chat.msg.text", text),
]);
}
function lobbies(){
return [
rs.list("chat/lobbies",function(lobby){
return m("div.btn",{
title: "topic: " + lobby.topic + "\n"
+ "subscribed: " + lobby.subscribed,
style: {
backgroundColor: lobby.subscribed ? 'blue' : 'darkred',
},
onclick: function(){
m.route("/chat?lobby=" + lobby.chat_id);
}
},
lobby.name + (
lobby.unread_msg_count > 0
? ("(" + lobby.unread_msg_count + ")")
: "")
);
},
rs.sort.bool("is_broadcast",
rs.sort.bool("subscribed",
rs.sort("name")))
),
m("br"),
m("h3","peers:"),
rs.list("peers",function(peer){
return peer.locations.map(function(loc){
if (loc.location == "") {
return [];
};
return m("div.btn",{
style: {
backgroundColor: loc.is_online ? 'blue' : 'darkred',
},
onclick: function(){
m.route("/chat?lobby=" + loc.chat_id);
}
},
peer.name + " / " + loc.location + (
loc.unread_msgs > 0
? ("(" + loc.unread_msgs + ")")
: "")
);
})
})
];
}
function getLobbyDetails(lobbyid){
var lobs = rs("chat/lobbies");
if (lobs === undefined) {
return null;
};
for(var i = 0, l = lobs.length; i < l; ++i) {
if (lobs[i].chat_id == lobbyid) {
return lobs[i];
}
}
var peers = rs("peers");
if (peers === undefined) {
return null;
};
for(var i = 0, l = peers.length; i < l; ++i) {
var peer = peers[i];
for(var i1 = 0, l1 = peer.locations.length; i1 < l1; ++i1) {
if (peer.locations[i1].chat_id == lobbyid) {
return peer.locations[i1];
}
}
}
return null;
}
function sendmsg(msgid){
var txtmsg = document.getElementById("txtNewMsg");
rs.request("chat/send_message", {
chat_id: msgid,
msg: txtmsg.value
});
txtmsg.value="";
}
function lobby(lobbyid){
var msgs;
var lobdt = getLobbyDetails(lobbyid);
var info = rs("chat/info/" + lobbyid);
if (lobdt == null || info === undefined) {
return m("div","waiting ...");
}
var mem = rs.memory("chat/info/" + lobbyid);
if (mem.msg === undefined) {
mem.msg = [];
};
var reqData = {};
if (mem.lastKnownMsg != undefined) {
reqData.begin_after = mem.lastKnownMsg;
}
rs.request("chat/messages/" + lobbyid, reqData, function (data) {
if (data.length > 0 ) {
mem.msg = mem.msg.concat(data);
if (mem.msg.length > 0) {
mem.lastKnownMsg = mem.msg[mem.msg.length -1].id;
}
rs.request("chat/mark_chat_as_read/" + lobbyid,{}, null,
{allow: "ok|not_set"});
} else {
mem.msg = [];
}
}, {
onmismatch: function (){},
log:function(){} //no logging (pulling)
});
var intro = [
m("h2",lobdt.name),
m("p",lobdt.topic ? lobdt.topic: lobdt.location),
m("hr")
]
if (lobdt.subscribed != undefined && !lobdt.subscribed) {
return [
intro,
m("b","select subscribe identity:"),
m("p"),
rs.list("identity/own", function(item){
return m("div.btn2",{
onclick:function(){
console.log("subscribe - id:" + lobdt.id +", "
+ "gxs_id:" + item.gxs_id)
rs.request("chat/subscribe_lobby",{
id:lobdt.id,
gxs_id:item.gxs_id
})
}
},"subscribe as " + item.name);
}),
];
} else {
msg = m(".chat.bottom",[
m("div","enter new message:"),
m("input",{
id:"txtNewMsg",
onkeydown: function(event){
if (event.keyCode == 13){
sendmsg(lobbyid);
}
}
}),
m("div.btn2", {
style: {textAlign:"center"},
onclick: function(){
sendmsg(lobbyid);
}
},"submit")
]);
}
if (lobdt.subscribed != undefined
&& lobdt.subscribed
&& !lobdt.is_broadcast
) {
//set participants
particips = [
m("div.btn", {
style: {
"text-align":"center"
},
onclick: function (){
rs.request("chat/unsubscribe_lobby",{
id:lobdt.id,
});
m.route("/chat");
}
},"unsubscribe"),
m("div.btn", {
style: {
"text-align":"center"
},
onclick: function (){
rs.request("chat/clear_lobby",{
id:lobdt.id,
});
m.route("/chat?lobby=" + lobbyid);
}
},"clear"),
m("h3","participants:"),
rs.list(
"chat/lobby_participants/" + lobbyid,
function(item) {
return m("div",item.identity.name);
},
function (a,b){
return rs.stringSort(a.identity.name,b.identity.name);
}
)
]
} else {
if (lobdt.subscribed != undefined
&& lobdt.subscribed
&& lobdt.is_broadcast
) {
//set participants
particips = [
m("div.btn", {
style: {
"text-align":"center"
},
onclick: function (){
rs.request("chat/clear_lobby",{
lobbyid,
});
m.route("/chat?lobby=" + lobbyid);
}
},"clear"),
]
}
}
return [
intro,
mem.msg.map(function(item){
var d = new Date(new Number(item.send_time)*1000);
return dspmsg(
item.author_name,
d.toLocaleDateString() + " " + d.toLocaleTimeString(),
item.msg
);
})
];
}
module.exports = {
frame: function(content, right){
return m("div", {
style: {
"height": "100%",
"box-sizing": "border-box",
"padding-bottom": "170px",
}
},[
m(".chat.container", [
m(".chat.header", [
m(
"h2",
{style:{margin:"0px"}},
"chat"
)
]),
m(".chat.left", [
m("div.chat.header[style=position:relative]","lobbies:"),
m("br"),
lobbies(),
]),
m(".chat.right", right),
m(".chat.middle", content),
m(".chat.clear", ""),
]),
msg != null
? msg
: [],
]);
},
view: function(){
var lobbyid = m.route.param("lobby");
msg = null;
if (lobbyid != undefined ) {
particips = [];
return this.frame(
lobby(lobbyid),
particips
);
};
return this.frame(
m(
"div",
{style: {margin:"10px"}},
"please select lobby"
),
m("div","")
);
}
}

View File

@ -0,0 +1,254 @@
var m = require("mithril");
var rs = require("retroshare");
var locationName = "";
var password ="";
var ssl_name = "";
var newName = "";
function listprofiles(){
var locations = rs("control/locations");
var knownProfileIds = [];
var result = [];
if(locations === undefined || locations == null){
return m("div", "profiles: waiting_server");
}
locations.map(function(location) {
if (knownProfileIds.indexOf(location.pgp_id)<0){
knownProfileIds.push(location.pgp_id);
result.push(m(
"div.btn2",{
onclick: function(){
m.route("/createlogin",{
id: location.pgp_id,
name: location.name,
})
}
},
location.name
));
}
});
return result;
}
function setLocationName(location) {
locationName = location;
}
function setPasswd(passwd) {
password = passwd;
}
function setSslName(ssl) {
ssl_name = ssl;
}
function setNewName(name) {
newName = name;
}
function checkpasswd(){
var status = "";
var color = "red";
var lbl = document.getElementById("lblpwdinfo");
var passwd2 = document.getElementById("txtpasswd2").value;
if (passwd2 == password && passwd2 != "") {
color = "lime";
status = "password ok";
} else if (passwd2 == "") {
color = "yellow";
status = "password required";
} else {
color = "red";
status = "passwords don't match";
}
lbl.textContent = status;
lbl.style.color=color;
}
function createLocation() {
var profile = m.route.param("id");
var profname = m.route.param("name");
var loc ={
ssl_name: document.getElementById("txtlocation").value,
pgp_password: password,
};
if (profile != undefined) {
loc.pgp_id= profile;
} else {
loc.pgp_name = newName;
};
rs.request("control/create_location",loc,function(data){
m.route("/accountselect", {});
});
m.route("/createlogin",{state:wait});
}
function certDrop(event)
{
console.log("onDrop()");
console.log(event.dataTransfer.files);
event.preventDefault();
var reader = new FileReader();
var widget = this;
reader.onload = function(evt) {
console.log("onDrop(): file loaded");
rs.request(
"control/import_pgp",{
key_string:evt.target.result,
}, importCallback);
};
reader.readAsText(event.dataTransfer.files[0]);
m.route("/createlogin",{state:"waiting"});
}
function importCallback(resp)
{
console.log("importCallback()" + resp);
m.route("/createlogin",{
id:resp.pgp_id,
name:"",
});
}
module.exports = {
view: function(){
var profile = m.route.param("id");
var state = m.route.param("state");
var profname = m.route.param("name");
var hidden = m.route.param("hidden");
if (state == "wait"){
return m("div","waiting ...");
} if (state == "newid"){
m.initControl = "txtnewname";
return m("div",[
m("h2","create login - Step 2 / 2: create location"),
m("h3","- for new profile "),
m("hr"),
m("h2","PGP-profile name:"),
m("input",{
id: "txtnewname",
type:"text",
onchange:m.withAttr("value", setNewName),
onkeydown: function(event){
if (event.keyCode == 13){
document.getElementById("txtpasswd").focus();
}
},
}),
m("h2","enter password:"),
m("input", {
id: "txtpasswd",
type:"password",
onchange: m.withAttr("value",setPasswd),
onkeydown: function(event){
if (event.keyCode == 13){
setPasswd(this.value);
document.getElementById("txtpasswd2").focus();
};
checkpasswd;
}
}),
m("h2", "re-enter password:"),
m("input", {
id: "txtpasswd2",
type:"password",
onfocus: checkpasswd,
onchange: checkpasswd,
onkeyup: function(event){
if (event.keyCode == 13){
document.getElementById("txtlocation").focus();
}
checkpasswd();
}
}),
m("h3",{
id: "lblpwdinfo",
style:"color:yellow",
}, "password required"),
m("h2","location name:"),
m("input",{
id: "txtlocation",
type:"text",
onchange:m.withAttr("value", setLocationName),
onkeydown: function(event){
if (event.keyCode == 13){
setSslName(this.value);
createLocation();
}
},
}),
m("br"),
m("input",{
type: "button",
onclick: createLocation,
value: "create location",
}),
]);
} else if (profile != undefined) {
m.initControl = "txtpasswd";
return m("div",[
m("h2","create login - Step 2 / 2: create location"),
m("h3","- for " + profname + " (" +profile + ")"),
m("hr"),
m("h2","enter password:"),
m("input", {
id: "txtpasswd",
type:"password",
onchange: m.withAttr("value",setPasswd),
onkeydown: function(event){
if (event.keyCode == 13){
setPasswd(this.value);
document.getElementById("txtlocation").focus();
}
}
}),
m("h2","location name:"),
m("input",{
id: "txtlocation",
type:"text",
onchange:m.withAttr("value", setLocationName),
onkeydown: function(event){
if (event.keyCode == 13){
setSslName(this.value);
createLocation();
}
},
}),
m("br"),
m("input",{
type: "button",
onclick: createLocation,
value: "create location",
}),
]);
} else {
return m("div",[
m("h2","create login - Step 1 / 2: select profile(PGP-ID)"),
m("hr"),
m("div.btn2",{
onclick: function(){
m.route("/createlogin", {state: "newid"});
},
} ,"<create new profile>"),
m("div.btn2",{
ondragover:function(event){
/*important: block default event*/
event.preventDefault();
},
ondrop: certDrop,
} ,"<import profile (drag and drop a profile here)>"),
listprofiles()
]);
};
}
}

View File

@ -0,0 +1,96 @@
var m = require("mithril");
var rs = require("retroshare");
function makeFriendlyUnit(bytes)
{
if(bytes < 1e3)
return bytes.toFixed(1) + "B";
if(bytes < 1e6)
return (bytes/1e3).toFixed(1) + "kB";
if(bytes < 1e9)
return (bytes/1e6).toFixed(1) + "MB";
if(bytes < 1e12)
return (bytes/1e9).toFixed(1) + "GB";
return (bytes/1e12).toFixed(1) + "TB";
}
function progressBar(file){
return m("div[style=border:5px solid lime;"
+ 'border-radius:3mm;'
+ 'padding:2mm;'
+ 'height:5mm'
+ "]", [
m("div[style="
+ 'background-color:lime;'
+ 'height:100%;'
+ 'width:' + (file.transfered / file.size * 100)+'%'
+ ']'
,"")
]);
};
function cntrlBtn(file, act) {
return(
m("div.btn",{
onclick: function(){
rs.request("transfers/control_download",{action: act, id: file.id});
}
},
act)
)
}
module.exports = {
view: function(){
var paths = rs("transfers/downloads");
var filestreamer_url = "/fstream/";
if (paths === undefined) {
return m("div", "Downloads ... please wait ...");
}
return m("div", [
m("h2","Downloads (" + paths.length +")"),
m("div.btn2", {
onclick: function(){
m.route("/downloads/add");
}
}, "add retrohare downloads"),
m("hr"),
m('table', [
m("tr",[
m("th","name"),
m("th","size"),
m("th","progress"),
m("th","transfer rate"),
m("th","status"),
m("th","progress"),
m("th","action")
]),
paths.map(function (file){
var ctrlBtn = m("div","");
var progress = file.transfered / file.size * 100;
return m("tr",[
m("td",[
m("a.filelink",
{
target: "blank",
href: filestreamer_url + file.hash + "/" + encodeURIComponent(file.name)
},
file.name
)
]),
m("td", makeFriendlyUnit(file.size)),
m("td", progress.toPrecision(3) + "%"),
m("td", makeFriendlyUnit(file.transfer_rate*1e3)+"/s"),
m("td", file.download_status),
m("td", progressBar(file)),
m("td", [
cntrlBtn(file, file.download_status==="paused"?"start":"pause"),
cntrlBtn(file, "cancel")]
)
])
})
])
]);
}
};

View File

@ -0,0 +1,65 @@
"use strict";
var m = require("mithril");
var rs = require("retroshare");
module.exports = {view: function(){
return m("div",[
m("h2","forums"),
m("p","(work in progress, currently only listing)"),
m("hr"),
/*
m("div.btn2", {
onclick: function (){
m.route("/addforum");
}
},"< create new forum >"),
*/
m("ul",
rs.list("forums",
function(item){
return m("li",[
m("h2",item.name),
m("div",{style:{margin:"10px"}},
[
item.description != ""
? [
m("span", "Description: "
+ item.description),
m("br")]
: [],
m("span","messages visible: "
+ item.visible_msg_count),
]
),
/*
item.subscribed
? [
m(
"span.btn2",
{style:{padding:"0px"}},
"unsubscribe"
),
" ",
m(
"span.btn2",
{style:{padding:"0px", margin:"10px"}},
"enter"
),
m("hr", {style: {color:"silver"}}),
]
: [
m(
"span.btn2",
{style:{padding:"0px", margin:"10px"}},
"subscribe"
),
]
*/
]);
},
rs.sort("name")
)
)
]);
}}

View File

@ -0,0 +1,145 @@
body {
background-color: black;
color: lime;
font-family: monospace;
margin: 0em;
/*padding: 1.5em;*/
padding: 2mm;
font-size: 1.1em;
box-sizing: border-box;
}
#overlay{
z-index: 10;
position: fixed;
top:0;
left:0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.8);
}
.paddingbox{
padding:2mm;
}
.nav{
list-style-type: none;
padding: 0em;
margin: 0em;
}
.nav li{
display: inline;
padding: 0.1em;
margin-right: 1em;
border-width: 0.1em;
border-color: blue;
border-bottom-style: solid;
cursor: pointer;
}
td{
padding: 0.3em;
border-style: solid;
border-width: 0.1em;
border-color: lime;
}
hr {
color: lime;
}
.menu{
border-style: solid;
border-color: lime;
border-width: 0.1em;
cursor: pointer;
padding: 0.0em;
}
.btn{
border-style: solid;
border-color: lime;
border-width: 0.1em;
cursor: pointer;
padding: 0.1em;
}
.btn2, .box{
border-style: solid;
/*border-color: lime;*/
border-color: limeGreen;
/*border-width: 1px;*/
border-radius: 3mm;
padding: 2mm;
font-size: 10mm;
cursor: pointer;
margin-bottom: 2mm;
}
.btn2:hover{
background-color: midnightblue;
}
.filelink{
color: inherit;
}
input, textarea{
color: lime;
font-family: monospace;
background-color: black;
border-color: lime;
font-size: 10mm;
border-radius: 3mm;
border-width: 1mm;
padding: 2mm;
margin-bottom: 2mm;
margin-right: 2mm;
/* make the button the whole screen width */
width: 100%;
/* make the text input fit small screens*/
box-sizing: border-box;
}
input:hover{
background-color: midnightblue;
}
.checkbox {
width: auto;
}
.flexbox{
display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */
display: -moz-box; /* OLD - Firefox 19- (buggy but mostly works) */
display: -ms-flexbox; /* TWEENER - IE 10 */
display: -webkit-flex; /* NEW - Chrome */
display: flex; /* NEW, Spec - Opera 12.1, Firefox 20+ */
}
.flexwidemember{
-webkit-box-flex: 1; /* OLD - iOS 6-, Safari 3.1-6 */
-moz-box-flex: 1; /* OLD - Firefox 19- */
width: 20%; /* For old syntax, otherwise collapses. */
-webkit-flex: 1; /* Chrome */
-ms-flex: 1; /* IE 10 */
flex: 1; /* NEW, Spec - Opera 12.1, Firefox 20+ */
}
#logo_splash{
-webkit-animation-fill-mode: forwards; /* Chrome, Safari, Opera */
animation-fill-mode: forwards;
-webkit-animation-name: logo_splash; /* Chrome, Safari, Opera */
-webkit-animation-duration: 3s; /* Chrome, Safari, Opera */
animation-name: logo_splash;
animation-duration: 3s;
text-align: center;
}
/* Chrome, Safari, Opera */
@-webkit-keyframes logo_splash {
from {opacity: 0;}
to {opacity: 1;}
}
/* Standard syntax */
@keyframes logo_splash {
from {opacity: 0;}
to {opacity: 1;}
}

View File

@ -0,0 +1,6 @@
var m = require("mithril");
module.exports = {view: function(){
return m("div","RetroShare - WebClient - Welcome");
}
};

View File

@ -0,0 +1,22 @@
"use strict";
var m = require("mithril");
var rs = require("retroshare");
module.exports = {view: function(){
return m("div",[
m("h2","identities"),
m("hr"),
m("div.btn2", {
onclick: function (){
m.route("/addidentity");
}
},"< create new identity >"),
m("ul",
rs.list("identity/own", function(item){
return m("li",[m("h2",item.name)]);
},
rs.sort("name"))
)
]);
}}

View File

@ -0,0 +1,122 @@
"use strict";
var m = require("mithril");
var rs = require("retroshare");
var menu =require("menu");
var currentpasswd = null;
function setPasswd(password) {
currentpasswd = password
}
function sendPassword(data) {
console.log("sending pwd for " + data.key_name + "...");
rs.request("control/password", {password: currentpasswd}, function(){
m.redraw();
});
}
function Page(menu){
this.menu = menu;
this.module = (menu.module != undefined) ? menu.module : menu.name;
this.path = menu.path != undefined ? menu.path : ("/" + menu.name);
var runst = menu.runstate;
var content = require(this.module);
var mm = require("menu");
this.view = function(){
var runstate = rs("control/runstate");
var needpasswd = rs("control/password");
//console.log("runstate: " + (runstate === undefined ? runstate : runstate.runstate));
if(runstate === undefined){
return m("h2", "waiting_server ... ");
} else if (runstate.runstate == null){
// try clean reboot ...
rs.clearCache();
rs("control/runstate"); //reboot detector
console.log("i'm down");
return m("h2", "server down");
} else if (needpasswd != undefined && needpasswd.want_password === true){
m.initControl = "txtpasswd";
return m("div",[
m("h2","password required"),
m("h3",needpasswd.key_name),
m("input",{
id: "txtpasswd",
type:"password",
onchange:m.withAttr("value", setPasswd),
onkeydown: function(event){
if (event.keyCode == 13){
setPasswd(this.value);
sendPassword(needpasswd);
}
}
}),
m("br"),
m("input[type=button][value=send password]",{
onclick: function(){
sendPassword(needpasswd);
}
}),
]);
} else {
if (runstate.runstate.match("waiting_init|waiting_startup")) {
return m("h2","server starting ...")
} else if(runstate.runstate.match("waiting_account_select|running_ok.*")) {
if (runst === undefined || runstate.runstate.match(runst)) {
return m("div", {
style: {
height: "100%",
"box-sizing": "border-box",
"padding-bottom": "40px"
}
}, [
m("div", mm.view()),
m("hr"),
m("div", {
style: {
height: "100%",
"box-sizing": "border-box",
"padding-bottom":"40px"
}
}, content)
]);
} else {
// funktion currently not available
m.route("/");
return m("div", [
m("div", mm.view()),
m("hr"),
m("div", require("home").view())
]);
};
} else {
return m("div", "unknown runstate: " + runstate.runstate);
}
}
}
};
module.exports = {
init:function(main){
console.log("start init ...");
var menudef = require("menudef");
var maps = {};
var m = require("mithril");
menudef.nodes.map(function(menu){
if (menu.action === undefined) {
var p = new Page(menu)
console.log("adding route " + menu.name + " for " + p.path + " with module " + p.module);
maps[p.path] = p;
}
});
m.route.mode = "hash";
m.route(main,"/",maps);
console.log("init done.");
}
};

View File

@ -0,0 +1,12 @@
/*@import "reset" */
html, body, #main
height: 100%
/*body */
/* font-family: "Sans-serif" */
@import "chat"
@import "green-black"

View File

@ -0,0 +1,65 @@
"use strict";
var m = require("mithril");
var rs = require("retroshare");
var mnodes = require("menudef");
function goback(){
rs.content=null;
m.redraw();
}
function buildmenu(menu, tagname, runstate, ignore){
if (
(menu.runstate === undefined
|| runstate.match("^(" + menu.runstate + ")$")!=null)
&& (!menu.name.match(ignore))
&& (menu.path === undefined || menu.path.match(":")==null)
&& (menu.show === undefined || menu.show)
) {
var name = menu.name;
if (menu.counter != undefined) {
name += menu.counter();
}
if (menu.action === undefined) {
return m(tagname , {
onclick: function(){
m.route(
menu.path != undefined ? menu.path : "/" + menu.name
)
}
}, name);
} else {
return m(tagname, {onclick: function(){menu.action(m)}}, name);
}
}
}
module.exports = {view: function(){
var runstate = rs("control/runstate");
if (runstate === undefined
|| runstate.runstate === undefined
|| runstate.runstate == null)
return m("div.nav","menu: waiting for server ...");
if (m.route() != "/")
return m("span",[
m("span"," | "),
mnodes.nodes.map(function(menu){
var item = buildmenu(menu,"span.menu", runstate.runstate, "-");
if (item != null){
return [
item,
m("span"," | ")
]
}
})
]);
return m("div", [
m("h2","home"),
m("hr"),
mnodes.nodes.map(function(menu){
return buildmenu(menu,"div.btn2", runstate.runstate, "home");
})
]);
}
};

View File

@ -0,0 +1,119 @@
var rs=require("retroshare");
module.exports = { nodes: [
{
name: "home",
path: "/"
},
{
name: "login",
module: "accountselect",
runstate: "waiting_account_select",
counter: rs.counting("control/locations"),
},
{
name: "create login",
path: "/createlogin",
module: "createlogin",
runstate: "waiting_account_select",
},
{
name: "peers",
runstate: "running_ok.*",
counter: rs.counting("peers", function(data){
var onlinecount = 0;
data.map(function(peer) {
var is_online = false;
peer.locations.map(function (location){
if (location.is_online) {
is_online=true;
}
});
if (is_online) {
onlinecount +=1;
}
});
return onlinecount + "/" + data.length;
})
},
{
name: "addpeer",
runstate: "running_ok.*",
show: false,
},
{
name: "identities",
runstate: "running_ok.*",
counter: rs.counting("identity/own"),
},
{
name: "addidentity",
runstate: "running_ok.*",
show: false,
},
{
name:"searchresult",
path: "/search/:id",
runstate: "running_ok.*",
},
{
name: "search",
runstate: "running_ok.*",
},
{
name: "downloads",
runstate: "running_ok.*",
counter: rs.counting("transfers/downloads")
},
{
name: "adddownloads",
runstate: "running_ok.*",
path: "/downloads/add",
show: false,
},
{
name: "forums",
runstate: "running_ok.*",
},
{
name: "chat",
runstate: "running_ok.*",
counter: rs.counting2({
"peers": function(peer) {
var sum = 0;
peer.locations.map(function (loc) {
sum += parseInt(loc.unread_msgs);
});
return sum;
},
"chat/lobbies": function(lobby) {
return lobby.unread_msg_count;
}
})
},
{
name:"settings",
runstate: "running_ok.*",
},
{
name:"servicecontrol",
runstate: "running_ok.*",
path:"/settings/servicecontrol",
show: false,
},
{
name: "shutdown",
runstate: "running_ok|waiting_account_select",
action: function(m){
rs.request("control/shutdown",null,function(){
rs("control/runstate").runstate=null;
rs.forceUpdate("control/runstate");
m.redraw();
});
}
},
{
name: "waiting",
show: false,
},
]
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,89 @@
"use strict";
var m = require("mithril");
var rs = require("retroshare");
module.exports = {view: function(){
var peers = rs("peers");
//console.log("peers:" + peers);
//waiting for peerlist ...
if(peers === undefined || peers == null){
return m("div",[
m("h2","peers"),
m("h3","waiting_server"),
]);
};
peers = peers.sort(rs.sort("name"));
//building peerlist (prebuild for counting)
var online = 0;
var peerlist = peers.map(function(peer){
var isonline = false;
var avatar_address ="";
//building location list (prebuild for state + icon)
var loclist = peer.locations.map(function(location){
if (location.is_online && ! isonline){
online +=1;
isonline = true;
}
if (location.avatar_address != "" && avatar_address =="") {
avatar_address=location.avatar_address;
}
return m("li",{
style:"color:" + (location.is_online ? "lime": "grey")
+ ";cursor:pointer",
onclick: function(){
m.route("/chat?lobby=" + location.chat_id)
}
}, location.location);
});
//return friend (peer + locations)
return m("div.flexbox[style=color:lime]",[
// avatar-icon
m("div", [
avatar_address == "" ? "" : (
m("img",{
src: rs.apiurl("peers" + avatar_address),
style:"border-radius:3mm;margin:2mm;",
})
)
]),
//peername + locations
m("div.flexwidemember",[
m("h1[style=margin-bottom:1mm;]",
{style:"color:" + (isonline ? "lime": "grey")} ,
peer.name
),
m("ul", loclist ),
]),
//remove-button
m("div", {
style: "color:red;" +
"font-size:1.5em;" +
"padding:0.2em;" +
"cursor:pointer",
onclick: function (){
var yes = window.confirm(
"Remove " + peer.name + " from friendslist?");
if(yes){
rs.request("peers/" + peer.pgp_id +"/delete");
}
}
}, "X")
]);
});
// return add-peer-button + peerlist
return m("div",[
m("div.btn2",{onclick: function(){m.route("/addpeer")}},"add new friend"),
m("h2","peers (online: " + online +" / " + peers.length + "):"),
m("div", [
peerlist,
]),
]);
}
};

View File

@ -0,0 +1,410 @@
/*
var rs = requires("rs");
var m = require("mithril");
function main(){
var state = rs("runstate");
if(state=== undefined){
return m("div", "waiting for server");
}
if(state === "waiting_login"){
return require("login")();
}
if(state === "running_ok"){
return require("mainwindow")();
}
}
*/
/*
idea: statetokenservice could just send the date instead of the token
*/
"use strict";
var m = require("mithril");
var api_url = window.location.protocol + "//" + window.location.hostname + ":" + window.location.port + "/api/v2/";
var filestreamer_url = window.location.protocol + "//" +window.location.hostname + ":" + window.location.port + "/fstream/";
var upload_url = window.location.protocol + "//" + window.location.hostname + ":" + window.location.port + "/upload/";
function for_key_in_obj(obj, callback){
var key;
for(key in obj){
callback(key, obj[key]);
}
}
var cache = {};
var last_update_ts = 0;
function check_for_changes(){
var tokens = [];
var paths_to_fetch = [];
// console.log("start-check " + Object.keys(cache));
for_key_in_obj(cache, function(path, item){
var token = item.statetoken;
if(token === undefined || token== null) {
paths_to_fetch.push(path)
} else if (tokens.indexOf(token)<0) {
tokens.push(token);
}
});
// console.log("tokens found: " + tokens);
var req = m.request({
method: "POST",
url: api_url + "statetokenservice",
background: true,
data: tokens,
});
req.then(function handle_statetoken_response(response){
// console.log("checking result " + response.data ? Object.keys(response.data) : "<null>") ;
for_key_in_obj(cache, function(path, item){
var found = false;
for(var i = 0; i < response.data.length; i++){
if(response.data[i] === item.statetoken){
found = true;
}
}
if(found){
paths_to_fetch.push(path);
}
});
// console.log("generating Results for paths " + paths_to_fetch);
var requests = [];
paths_to_fetch.map(function request_it(path){
var req2 = m.request({
method: "GET",
url: api_url + path,
background: true,
});
req2 = req2.then(function fill_in_result(response){
cache[path].data = response.data;
cache[path].statetoken = response.statetoken;
});
requests.push(req2);
});
if(requests.length > 0){
// console.log("requesting " + requests.length + " requests");
m.sync(requests).then(function trigger_render(){
m.startComputation();
m.endComputation();
checkFocus();
setTimeout(check_for_changes, 500);
});
}
else{
// console.log("no requests");
setTimeout(check_for_changes, 500);
}
}, function errhandling(value){
// console.log("server disconnected " + value);
setTimeout(check_for_changes, 500);
});
}
check_for_changes();
var update_scheduled = false;
function schedule_request_missing(){
if(update_scheduled)
return;
update_scheduled = true;
// place update logic outside of render loop, this way we can fetch multiple things at once
// (because after the render loop everything we should fetch is in the list)
// if we fetch multiple things at once, we can delay a re-rende runtil everything is done
// so we need only one re-render for multiple updates
setTimeout(function request_missing(){
update_scheduled = false;
var requests = [];
for_key_in_obj(cache, function(path, item){
if(!item.requested){
var req = m.request({
method: "GET",
url: api_url + path,
background: true,
});
req.then(function fill_data(response){
// TODO: add errorhandling
item.data = response.data;
item.statetoken = response.statetoken;
if (item.then != undefined && item.then != null) {
try {
item.then(response);
} catch (ex) {
if (item.errorCallback != undefined && item.errorCallback != null) {
item.errorCallback(ex);
};
}
};
}, function errhandling(value){
if (item.errorCallback != undefined && item.errorCallback != null) {
item.errorCallback(value);
}
});
requests.push(req);
}
item.requested = true;
});
m.sync(requests).then(function trigger_render(){
m.startComputation();
m.endComputation();
checkFocus();
});
});
}
function checkFocus(){
if (m.initControl != undefined) {
var ctrl = document.getElementById(m.initControl);
if (ctrl!= null) {
ctrl.focus();
m.initControl = undefined;
} else {
console.log("focus-control '" + m.initControl + "' not found!");
m.initControl = undefined;
}
}
}
// called every time, rs or rs.request failed, only response or value is set
function requestFail(path, response, value) {
rs.error = "error on " + path;
console.log("Error on " + path +
(response == null ? ", value: " + value : (", response: " +
(response.debug_msg === undefined ? response : response.debug_msg)
))
);
}
function rs(path, args, callback, options){
if(cache[path] === undefined){
options=optionsPrep(options,path);
var req = {
data: args,
statetoken: undefined,
requested: false,
allow: options.allow,
then: function(response){
options.log(path + ": response: " + response.returncode);
if (!this.allow.match(response.returncode)) {
options.onmismatch(response);
} else if (callback != undefined && callback != null) {
callback(response.data, response.statetoken);
}
},
errorCallback: options.onfail
};
cache[path] = req;
schedule_request_missing();
}
return cache[path].data;
}
module.exports = rs;
rs.for_key_in_obj = for_key_in_obj;
// single request for action
rs.request=function(path, args, callback, options){
options = optionsPrep(options, path);
var req = m.request({
method: options.method === undefined ? "POST" : options.method,
url: api_url + path,
data: args,
background: true
});
req.then(function checkResponseAndCallback(response){
options.log(path + ": response: " + response.returncode);
if (!options.allow.match(response.returncode)) {
options.onmismatch(response);
} else if (callback != undefined && callback != null) {
callback(response.data, response.statetoken);
}
}, options.onfail);
return req;
};
//set default-values for shared options in rs() and rs.request()
function optionsPrep(options, path) {
if (options === undefined) {
options = {};
}
if (options.onfail === undefined) {
options.onfail = function errhandling(value){
requestFail(path, null, value);
}
};
if (options.onmismatch === undefined) {
options.onmismatch = function errhandling(response){
requestFail(path, response,null);
}
};
if (options.log === undefined) {
options.log = function(message) {
console.log(message);
}
}
if (options.allow === undefined) {
options.allow = "ok";
};
return options;
}
// force reload for path
rs.forceUpdate = function(path, removeCache){
if (removeCache === undefined || !removeCache) {
cache[path].requested=false;
} else {
delete cache[path];
}
}
// force reload for all
rs.clearCache = function(path, removeCache){
console.log("clearing Cache ...")
cache = {};
console.log("update_scheduled: " + update_scheduled);
update_scheduled = false;
check_for_changes();
console.log("Cache cleared.")
}
// dismiss statetoken (= force reload)
rs.untoken = function(path) {
cache[path].statetoken = null;
}
//return api-path
rs.apiurl = function(path) {
if (path === undefined) {
path="";
}
if (path.length > 0 && "^\\\\|\\/".match(path)) {
path=path.substr(1);
}
return api_url + path;
}
// counting in menu
rs.counting = function(path, counterfnkt) {
return function () {
var data=rs(path);
if (data != undefined) {
if (counterfnkt === undefined) {
return " (" + data.length + ")";
}
return " (" + counterfnkt(data) + ")";
}
return "";
}
};
// counting in menu
rs.counting2 = function(targets) {
return function () {
var sum = 0;
for (var path in targets) {
var data=rs(path);
if (data != undefined) {
data.map(function(item){
sum += parseInt(targets[path](item));
});
};
};
if (sum > 0) {
return " (" + sum + ")";
}
return "";
}
};
// listing data-elements
rs.list = function(path, buildfktn, sortfktn){
var list = rs(path);
if (list === undefined|| list == null) {
return "< waiting for server ... >"
};
if (sortfktn != undefined && sortfktn != null) {
list=list.sort(sortfktn);
}
return list.map(buildfktn);
};
//remember additional data (feature of last resort)
rs.memory = function(path, args){
var item = cache[path];
if (item === undefined) {
rs(path, args);
item = cache[path];
}
if (item.memory === undefined) {
item.memory = {};
}
return item.memory;
};
// Sortierfunktion für Texte von Objekten,
// falls einfache Namen nicht funktionieren
rs.stringSort = function(textA,textB, innersort, objectA, objectB){
if (textA.toLowerCase() == textB.toLowerCase()) {
if (innersort === undefined) {
return 0
}
return innersort(objectA,objectB);
} else if (textA.toLowerCase() < textB.toLowerCase()) {
return -1
} else {
return 1
}
}
//return sorting-function for string, based on property name
//using: list.sort(rs.sort("name"));
// -----
//innersort: cascading sorting - using:
//list.sort(rs.sort("type",rs.sort("name")))
rs.sort = function(name, innersort){
return function(a,b) {
return rs.stringSort(a[name],b[name],innersort,a,b);
}
}
//return sorting-function for boolean, based on property name
rs.sort.bool = function(name, innersort){
return function(a,b){
if (a[name] == b[name]) {
if (innersort === undefined) {
return 0
}
return innersort(a,b);
} else if (a[name]) {
return -1
} else {
return 1
}
}
}
// searching a element in a list
// items: list to search in
// name: name of attribute to lookup
// value: attribute's value to compare
rs.find = function(items, name, value) {
if (items === undefined||items == null) {
return null;
};
for(var i = 0, l = items.length; i < l; ++i) {
if (items[i][name] == value) {
return items[i];
}
}
return null;
}

View File

@ -0,0 +1,54 @@
var m = require("mithril");
var rs = require("retroshare");
var state = {};
var searchText = "";
function updateText(newText) {
searchText = newText;
}
function dosearch(){
console.log("searching for: "+searchText);
rs.request(
"filesearch/create_search", {
distant: true,
search_string: searchText
},
function(resp){
m.route("/search/" + resp.search_id);
}
);
}
module.exports = {
view: function(){
var results = rs("filesearch");
if (results === undefined||results == null) {
results = [];
};
return m("div",[
m("h2","turtle file search"),
m("div", [
m("input[type=text]", {onchange:m.withAttr("value", updateText)}),
m("input[type=button][value=search]",{onclick:dosearch})
]),
m("hr"),
m("h2","previous searches:"),
m("div", [
results.map(function(item){
var res = rs("filesearch/" + item.id,{},null,{allow:"not_set|ok"});
if (res === undefined) {
res =[];
};
return m("div.btn2",{
onclick:function(){
m.route("/search/" + item.id);
}
}, item.search_string + " (" + res.length + ")");
})
])
])
}
}

View File

@ -0,0 +1,71 @@
var m = require("mithril");
var rs = require("retroshare");
module.exports = {
view: function(){
var id=m.route.param("id");
var results = rs("filesearch/" + id ,{},null,{allow:"not_set|ok"});
if (results === undefined || results.length == undefined) {
results = [];
}
var searches = rs("filesearch");
var searchdetail = "<unknown>";
if (!(searches === undefined) && !(searches.length === undefined)) {
searches.forEach(function(s){
if (s.id == id) {
searchdetail = s.search_string;
}
});
}
var dl_ids = [];
var downloads =rs("transfers/downloads");
if (downloads !== undefined) {
downloads.map(function(item){
dl_ids.push(item.hash);
})
}
return m("div",[
m("h2","turtle file search results"),
m("h3", "searchtext: " + searchdetail + " (" + results.length + ")"),
m("hr"),
m("table", [
m("tr" ,[
m("th","name"),
m("th","size"),
m("th",""),
]),
results.map(function(file){
if (dl_ids.indexOf(file.hash)>=0) {
file.state="in download queue"
}
return m("tr",[
m("th",file.name),
m("th",file.size),
m("th",[
file.state === undefined
? m("span.btn", {
onclick:function(){
rs.request("transfers/control_download", {
action: "begin",
name: file.name,
size: file.size,
hash: file.hash,
}, function(){
result="added";
});
m.startComputation();
m.endComputation();
}
}, "download")
: file.state
]),
])
})
])
])
}
}

View File

@ -0,0 +1,264 @@
"use strict";
var m = require("mithril");
var rs = require("retroshare");
function setOption(id,value) {
return function(){
rs.request("servicecontrol", {
service_id: id,
default_allowed: value,
});
rs.forceUpdate("servicecontrol", true);
}
}
function setUserOption(serviceid, userid, value) {
return function(){
rs.request("servicecontrol/user", {
service_id: serviceid,
peer_id: userid,
enabled: value
}, function(){
rs.forceUpdate("servicecontrol", true)
});
}
}
function createSwitch(isOn, width) {
if (width === undefined) {
width = "2.1em";
}
return [
m("div.menu", {
style: {
float:"left",
width: width,
textAlign: "center",
color: "#303030",
borderColor: isOn
? "lime"
: "red",
backgroundColor: !isOn
? "black"
: "lime",
}
}, "ON"),
m("div.menu",{
style: {
float:"left",
width: width,
textAlign: "center",
marginRight:"5px",
color: "#303030",
borderColor: isOn
? "lime"
: "red",
backgroundColor: isOn
? "black"
: "red",
}
}, "OFF"),
];
}
function breadcrums(name, parts){
var result = [];
rs.for_key_in_obj(parts, function(partname,item){
result.push(
m("span.btn",{
onclick: function(){
m.route(item)
}
},partname)
);
result.push(" / ");
});
result.push(name);
return result;
}
function serviceView(serviceid) {
var service, liste;
service = rs.find(rs("servicecontrol"),"service_id",serviceid);
if (service == null) {
return m("h3","<please wait ... >");
}
liste = service.default_allowed
? service.peers_denied
: service.peers_allowed;
return m("div", [
m("h2", breadcrums(service.service_name, {
settings:"/settings",
rights: "/settings/servicecontrol",
})),
m("hr"),
m("h2",{
style:{
float:"left",
}
},[
m("div",{
style:{
float:"left",
}
},"user rights for: " + service.service_name + ", default: "),
m("div", {
onclick: setOption(
serviceid,
!service.default_allowed
),
style: {
float:"left",
marginLeft: "0.4em",
marginRight: "0.4em",
}
},createSwitch(service.default_allowed)),
]),
m("div", {
style: {
clear:"left",
}
}),
m("ul", rs.list("peers",function(peer){
var locs;
locs = peer.locations;
locs.sort(rs.sort("location"));
return peer.locations.map(function(location){
var isExcept, isOn;
isExcept = liste != null
&& liste.indexOf(location.peer_id)>=0;
isOn = service.default_allowed ? !isExcept: isExcept;
return m("li", {
style: {
margin: "5px",
color: isOn ? "lime" :"red",
}
}, [
m("div"),
m("div", {
onclick: setUserOption(
serviceid,
location.peer_id,
!isOn
),
style: {
float:"left",
},
},createSwitch(isOn)),
m("div",
{
style: {
//color: "lime",
float:"left",
marginLeft: "5px",
marginRight: "5px",
fontWeight: "bold",
}
},
peer.name + (location.location
? " (" + location.location + ")"
: "")
),
m("div", {
style: {
clear: "left"
}
}),
]);
})
}, rs.sort("name")))
]);
}
module.exports = {
view: function(){
if (m.route.param("service_id")) {
return serviceView(m.route.param("service_id"));
}
return m("div", [
m("h2", breadcrums("rights", {
settings:"/settings",
})),
m("hr"),
m("ul", rs.list("servicecontrol", function(item){
return m("li", {
style: {
margin: "5px",
color: item.default_allowed ? "lime" :"red",
}
}, [
m("div"),
m("div", {
onclick: setOption(
item.service_id,
!item.default_allowed
),
style: {
float:"left",
}
},createSwitch(item.default_allowed)),
m("div.menu",
{
style: {
// color: "lime",
borderColor: item.default_allowed
? "lime"
: "red",
float: "left",
marginLeft: "5px",
marginRight: "5px",
paddingLeft: "2px",
paddingRight: "2px",
},
onclick: function(){
m.route("/settings/servicecontrol/", {
service_id: item.service_id,
})
}
}, "more"
),
m("div",
{
style: {
// color: "lime",
float:"left",
marginLeft: "5px",
marginRight: "5px",
fontWeight: "bold",
}
},
item.service_name
),
m("div",
{
style: {
color: "lime",
float:"left",
marginLeft: "5px",
marginRight: "5px",
}
},
(
item.default_allowed
? ( item.peers_denied != null
? "(" + item.peers_denied.length + " denied)"
: "")
: ( item.peers_allowed != null
? "(" + item.peers_allowed.length + " allowed)"
: "")
)
),
m("div", {
style: {
clear: "left"
}
}),
]);
})
)
]);
}
}

View File

@ -0,0 +1,19 @@
"use strict";
var m = require("mithril");
var rs = require("retroshare");
module.exports = {
view: function(){
return m("div", [
m("h2","settings"),
m("hr"),
m("div.btn2",{
onclick: function(){
m.route("/settings/servicecontrol");
},
}, "rights")
]);
}
}

View File

@ -0,0 +1,8 @@
"use strict";
var m = require("mithril");
var rs = require("retroshare");
module.exports = {view: function(){
return m("h2","please wait ...");
}}

View File

@ -0,0 +1,12 @@
module.exports = {
config:{
files:{
javascripts:{
joinTo: 'app.js'
},
stylesheets:{
joinTo: 'app.css'
}
}
}
};

View File

@ -0,0 +1,41 @@
@echo off
REM create webfiles from sources at compile time (works without npm/node.js)
set publicdest=%1\webui
set src=%1\webui-src
if "%1" == "" set publicdest=..\..\webui&&set src=..
if exist "%publicdest%" echo remove existing %publicdest%&&rd %publicdest% /S /Q
echo mkdir %publicdest%
md %publicdest%
echo building app.js
echo - copy template.js ...
copy %src%\make-src\template.js %publicdest%\app.js
for %%F in (%src%\app\*.js) DO (set "fname=%%~nF" && CALL :addfile)
echo building app.css
type %src%\app\green-black.scss >> %publicdest%\app.css
type %src%\make-src\main.css >> %publicdest%\app.css
type %src%\make-src\chat.css >> %publicdest%\app.css
echo copy index.html
copy %src%\app\assets\index.html %publicdest%\index.html
echo build.bat complete
goto :EOF
:addfile
echo - adding %fname% ...
echo require.register("%fname%", function(exports, require, module) { >> %publicdest%\app.js
echo %src%\app\%fname%.js
type %src%\app\%fname%.js >> %publicdest%\app.js
echo. >> %publicdest%\app.js
echo }); >> %publicdest%\app.js
:EOF

View File

@ -0,0 +1,62 @@
#!/usr/bin/env sh
# create webfiles from sources at compile time (works without npm/node.js)
if [ "$1" = "" ]; then
publicdest=../../webui
src=..
else
publicdest=$1/webui
src=$1/webui-src
fi
if [ "$2" = "" ]; then
if [ -d "$publicdest" ]; then
echo remove existing $publicdest
rm $publicdest -R
fi
fi
if [ ! -d "$publicdest" ]; then
echo mkdir $publicdest
mkdir $publicdest
fi
if [ "$2" = "" ]||[ "$2" = "app.js" ]; then
echo building app.js
echo - copy template.js ...
cp $src/make-src/template.js $publicdest/app.js
for filename in $src/app/*.js; do
fname=$(basename "$filename")
fname="${fname%.*}"
echo - adding $fname ...
echo require.register\(\"$fname\", function\(exports, require, module\) { >> $publicdest/app.js
cat $filename >> $publicdest/app.js
echo >> $publicdest/app.js
echo }\)\; >> $publicdest/app.js
done
fi
if [ "$2" = "" ]||[ "$2" = "app.css" ]; then
echo building app.css
cat $src/app/green-black.scss >> $publicdest/app.css
cat $src/make-src/main.css >> $publicdest/app.css
cat $src/make-src/chat.css >> $publicdest/app.css
fi
if [ "$2" = "" ]||[ "$2" = "index.html" ]; then
echo copy index.html
cp $src/app/assets/index.html $publicdest/index.html
fi
if [ "$2" != "" ]&&[ "$3" != "" ]; then
if [ ! -d "$3/webui" ]; then
echo mkdir $3/webui
mkdir $3/webui
fi
echo copy $2 nach $3/webui/$2
cp $publicdest/$2 $3/webui/$2
fi
echo build.sh complete

View File

@ -0,0 +1,72 @@
.chat {
padding: 15px; }
.chat.container {
height: 100%;
padding: 0px;
position: relative;
box-sizing: border-box; }
.chat.header {
position: absolute;
top: 0px;
left: 0px;
right: 0px;
height: 50px;
background-color: black;
border-bottom: solid 1px gray;
box-sizing: border-box; }
.chat.left {
position: absolute;
top: 50px;
bottom: 0px;
left: 0px;
width: 200px;
box-sizing: border-box;
background-color: black; }
.chat.right {
position: absolute;
top: 50px;
right: 0px;
bottom: 0px;
width: 200px;
box-sizing: border-box; }
.chat.middle {
position: absolute;
top: 0px;
margin-top: 50px;
left: 200px;
right: 200px;
box-sizing: border-box;
padding: 0px;
height: 100%;
overflow-y: scroll; }
.chat.bottom {
position: absolute;
bottom: 0px;
right: 200px;
left: 200px;
padding: 5px; }
.chat.msg {
padding: 0px; }
.chat.msg.container {
position: relative;
border-bottom: solid 1px lightgray;
padding: 10px;
height: unset; }
.chat.msg.from {
position: absolute;
width: 100px;
top: 10px;
left: 0px;
color: white;
text-align: right; }
.chat.msg.when {
float: right;
color: lightgray;
margin-bottom: 10px; }
.chat.msg.text {
padding-left: 100px;
top: 0px;
left: 100px;
white-space: pre-wrap;
height: initial; }

View File

@ -0,0 +1,15 @@
@echo off
REM create dummy webfiles at qmake run
set publicdest=%1\webui
if "%1" == "" set publicdest=..\..\webui
if exist %publicdest% echo remove %publicdest%&&rd %publicdest% /S /Q
echo create %publicdest%
md %publicdest%
echo create %publicdest%\app.js, %publicdest%\app.css, %publicdest%\index.html
echo. > %publicdest%\app.js
echo. > %publicdest%\app.css
echo. > %publicdest%\index.html

View File

@ -0,0 +1,22 @@
#!/usr/bin/env sh
# create dummy webfiles at qmake run
if [ "$1" = "" ];then
publicdest=../../webui
else
publicdest=$1/webui
fi
if [ -d "$publicdest" ]; then
echo remove $publicdest
rm $publicdest -R
fi
echo create $publicdest
mkdir $publicdest
echo touch $publicdest/app.js, $publicdest/app.css, $publicdest/index.html
touch $publicdest/app.js -d 1970-01-01
touch $publicdest/app.css -d 1970-01-01
touch $publicdest/index.html -d 1970-01-01

View File

@ -0,0 +1,2 @@
html, body, #main {
height: 100%; }

View File

@ -0,0 +1,7 @@
this folder contains files needed to create webfiles at compile-time and qmake
* init.sh creates dummy files at qmake
* build.sh creates files at compile time
* chat.css compiled version of _chat.sass (.sass should replaced by .scss)
* main.css simple template extracted from main.sass
* template.js start of compiled app.js, containing additional created content

View File

@ -0,0 +1,112 @@
(function() {
'use strict';
var globals = typeof window === 'undefined' ? global : window;
if (typeof globals.require === 'function') return;
var modules = {};
var cache = {};
var aliases = {};
var has = ({}).hasOwnProperty;
var endsWith = function(str, suffix) {
return str.indexOf(suffix, str.length - suffix.length) !== -1;
};
var _cmp = 'components/';
var unalias = function(alias, loaderPath) {
var start = 0;
if (loaderPath) {
if (loaderPath.indexOf(_cmp) === 0) {
start = _cmp.length;
}
if (loaderPath.indexOf('/', start) > 0) {
loaderPath = loaderPath.substring(start, loaderPath.indexOf('/', start));
}
}
var result = aliases[alias + '/index.js'] || aliases[loaderPath + '/deps/' + alias + '/index.js'];
if (result) {
return _cmp + result.substring(0, result.length - '.js'.length);
}
return alias;
};
var _reg = /^\.\.?(\/|$)/;
var expand = function(root, name) {
var results = [], part;
var parts = (_reg.test(name) ? root + '/' + name : name).split('/');
for (var i = 0, length = parts.length; i < length; i++) {
part = parts[i];
if (part === '..') {
results.pop();
} else if (part !== '.' && part !== '') {
results.push(part);
}
}
return results.join('/');
};
var dirname = function(path) {
return path.split('/').slice(0, -1).join('/');
};
var localRequire = function(path) {
return function expanded(name) {
var absolute = expand(dirname(path), name);
return globals.require(absolute, path);
};
};
var initModule = function(name, definition) {
var module = {id: name, exports: {}};
cache[name] = module;
definition(module.exports, localRequire(name), module);
return module.exports;
};
var require = function(name, loaderPath) {
var path = expand(name, '.');
if (loaderPath == null) loaderPath = '/';
path = unalias(name, loaderPath);
if (has.call(cache, path)) return cache[path].exports;
if (has.call(modules, path)) return initModule(path, modules[path]);
var dirIndex = expand(path, './index');
if (has.call(cache, dirIndex)) return cache[dirIndex].exports;
if (has.call(modules, dirIndex)) return initModule(dirIndex, modules[dirIndex]);
throw new Error('Cannot find module "' + name + '" from '+ '"' + loaderPath + '"');
};
require.alias = function(from, to) {
aliases[to] = from;
};
require.register = require.define = function(bundle, fn) {
if (typeof bundle === 'object') {
for (var key in bundle) {
if (has.call(bundle, key)) {
modules[key] = bundle[key];
}
}
} else {
modules[bundle] = fn;
}
};
require.list = function() {
var result = [];
for (var item in modules) {
if (has.call(modules, item)) {
result.push(item);
}
}
return result;
};
require.brunch = true;
require._cache = cache;
globals.require = require;
})();

View File

@ -0,0 +1,11 @@
{
"name": "webui_neu",
"scripts": {
"watch": "brunch watch --server"
},
"devDependencies": {
"auto-reload-brunch": "^1.8.0",
"brunch": "^1.8.5",
"sass-brunch": "^1.9.1"
}
}

View File

@ -1,36 +0,0 @@
REACT_VERSION = 0.13.1
DISTDIR = ../webfiles
JSEXTLIBS = $(DISTDIR)/react.js $(DISTDIR)/JSXTransformer.js
JSLIBS = RsXHRConnection.js RsApi.js
HTML = index.html
JSGUI = gui.jsx
CSS = green-black.css
all: $(DISTDIR) $(JSEXTLIBS) $(addprefix $(DISTDIR)/, $(JSLIBS)) $(addprefix $(DISTDIR)/, $(HTML)) $(addprefix $(DISTDIR)/, $(JSGUI)) $(addprefix $(DISTDIR)/, $(CSS))
.PHONY: all
$(DISTDIR)/livereload: $(DISTDIR) $(JSEXTLIBS) $(addprefix $(DISTDIR)/, $(JSLIBS)) $(addprefix $(DISTDIR)/, $(HTML)) $(addprefix $(DISTDIR)/, $(JSGUI)) $(addprefix $(DISTDIR)/, $(CSS))
wget -qO- http://localhost:9090/api/v2/livereload/trigger
touch $(DISTDIR)/livereload
$(DISTDIR)/react.js:
cd $(DISTDIR) && wget --no-check-certificate --output-document react.js http://fb.me/react-$(REACT_VERSION).js
$(DISTDIR)/JSXTransformer.js:
cd $(DISTDIR) && wget --no-check-certificate --output-document JSXTransformer.js http://fb.me/JSXTransformer-$(REACT_VERSION).js
$(addprefix $(DISTDIR)/, $(JSLIBS)): $(DISTDIR)/%: %
cp $< $@
$(addprefix $(DISTDIR)/, $(HTML)): $(DISTDIR)/%: %
cp $< $@
$(addprefix $(DISTDIR)/, $(JSGUI)): $(DISTDIR)/%: %
cp $< $@
$(addprefix $(DISTDIR)/, $(CSS)): $(DISTDIR)/%: %
cp $< $@
$(DISTDIR):
mkdir $(DISTDIR)

View File

@ -1,142 +0,0 @@
var TypesMod = require("./Types.js");
var Type = TypesMod.Type;
var string = TypesMod.string;
var bool = TypesMod.bool;
var any = TypesMod.any;
if(require.main === module)
{
var RsNodeHttpConnection = require("./RsNodeHttpConnection.js");
debugger;
var connection = new RsNodeHttpConnection();
var RsApi = require("./RsApi.js");
var RS = new RsApi(connection);
var tests = [];
var doc = {
counter: 0,
toc: [],
content: [],
header: function(h){
this.toc.push(h);
this.content.push("<a name=\""+this.counter+"\"><h1>"+h+"</h1></a>");
this.counter += 1;
},
paragraph: function(p){
this.content.push("<p>"+p+"</p>");
},
};
PeersTest(tests, doc);
var docstr = "<!DOCTYPE html><html><body>";
docstr += "<h1>Table of Contents</h1>";
docstr += "<ul>";
for(var i in doc.toc)
{
docstr += "<li><a href=\"#"+i+"\">"+doc.toc[i]+"</a></li>";
}
docstr += "</ul>";
for(var i in doc.content)
{
docstr += doc.content[i];
}
docstr += "</body></html>";
var fs = require('fs');
fs.writeFile("dist/api_documentation.html", docstr);
tests.map(function(test){
test(RS);
});
}
function PeersTest(tests, doc)
{
// compound types
var location = new Type("location",
{
avatar_address: string,
groups: any,
is_online: bool,
location: string,
peer_id: any,
});
var peer_info = new Type("peer_info",
{
name: string,
pgp_id: any,
locations: [location],
});
var peers_list = new Type("peers_list",[peer_info]);
doc.header("peers");
doc.paragraph("<pre>"+graphToText(peers_list)+"</pre>");
tests.push(function(RS){
console.log("testing peers module...");
console.log("expected schema is:")
console.log(graphToText(peers_list));
RS.request({path: "peers"}, function(resp){
//console.log("got response:"+JSON.stringify(resp));
var ok = peers_list.check(function(str){console.log(str);}, resp.data, [])
if(ok)
console.log("success");
else
console.log("fail");
});
});
function graphToText(top_node)
{
//var dbg = function(str){console.log(str);};
var dbg = function(str){};
dbg("called graphToText with " + top_node);
var res = "";
_visit(top_node.getObj(), 0);
return res;
function _indent(count)
{
var str = "";
for(var i = 0; i < count; i++)
{
str = str + " ";
}
return str;
}
function _visit(node, indent)
{
dbg("_visit");
if(node instanceof Array)
{
dbg("is instanceof Array");
//res = res + "[";
res = res + "array\n";
_visit(node[0], indent);
//res = res + _indent(indent) + "]\n";
}
else if(node instanceof Type && node.isLeaf())
{
dbg("is instanceof Type");
res = res + node.getName() + "\n";
}
else // Object, have to check all children
{
dbg("is Object");
//res = res + "{\n";
for(m in node.getObj())
{
res = res + _indent(indent+1) + m + ": ";
_visit(node.getObj()[m], indent+1);
}
//res = res + _indent(indent) + "}\n";
}
}
}
}

View File

@ -1,48 +0,0 @@
A new approach to build a webinterface for RS
=============================================
1. get JSON encoded data from the backend, data contains a state token
2. render data with react.js
3. ask the backend if the state token from step 1 expired. If yes, then start again with step 1.
Steps 1. and 3. are common for most things, only Step 2. differs. This allows to re-use code for steps 1. and 3.
BUILD / INSTALLATION
------------
- run (requires wget, use MinGW shell on Windows)
make
- all output files are now in libresapi/src/webfiles
- use the --webinterface 9090 command line parameter to enable webui in retroshare-nogui
- set the --docroot parameter of retroshare-nogui to point to the "libresapi/src/webfiles" directory
(or symlink from /usr/share/RetroShare06/webui on Linux, ./webui on Windows)
- retroshare-gui does not have a --docroot parameter. Use symlinks then.
DEVELOPMENT
-----------
- Ubuntu: install nodejs package
sudo apt-get install nodejs
- Windows: download and install nodejs from http://nodejs.org
- Download development tools with the nodejs package manager (short npm)
npm install
- run Retroshare with webinterface on port 9090
- during development, run this command (use MinGW shell on Windows)
while true; do make ../webfiles/livereload --silent; sleep 1; done
- the command will copy the source files to libresapi/src/webfiles if they change
- it will trigger livereload at http://localhost:9090/api/v2/livereload/trigger
API DOCUMENTATION
-----------------
- run
node PeersTest.js
- this will print the expected schema of the api output, and it will try to test it with real data
- run retroshare-nogui with webinterface enabled on port 9090, to test if the real output of the api matches the expected schema
CONTRIBUTE
----------
- if you are a web developer or want to become one
get in contact!
- lots of work to do, i need you!

View File

@ -1,109 +0,0 @@
/**
* JS Api for Retroshare
* @constructor
* @param {object} connection - an object which implements a request() function.
* The request function should take two parameters: an object to be send as request and a callback.
* The callback should get called with an response object on success.
*/
function RsApi(connection)
{
var runnign = true;
/**
* Send a request to the server
* @param req - the request so send
* @param {Function} cb - callback function which takes the response as parameter
*/
this.request = function(req, cb)
{
connection.request(req, cb);
};
var tokenlisteners = [];
/**
* Register a callback to be called when the state token expired.
* @param {Function} listener - the callback function, which does not take arguments
* @param token - the state token to listen for
*/
this.register_token_listener = function(listener, token)
{
tokenlisteners.push({listener:listener, token:token});
};
/**
* Unregister a previously registered callback.
*/
this.unregister_token_listener = function(listener) // no token as parameter, assuming unregister from all listening tokens
{
var to_delete = [];
for(var i=0; i<tokenlisteners.length; i++){
if(tokenlisteners[i].listener === listener){
to_delete.push(i);
}
}
for(var i=0; i<to_delete.length; i++){
// copy the last element to the current index
var index = to_delete[i];
tokenlisteners[index] = tokenlisteners[tokenlisteners.length-1];
// remove last element
tokenlisteners.pop();
}
};
/**
* start polling for state changes
*/
this.start = function(){
running = true;
setTimeout(tick, TICK_INTERVAL);
}
/**
* stop polling for state changes
*/
this.stop = function(){
running = false;
}
// ************** interal stuff **************
var TICK_INTERVAL = 3000;
function received_tokenstates(resp)
{
if(resp.data){
for(var i=0; i<resp.data.length; i++){
var token = resp.data[i];
// search the listener for this token
for(var j=0; j<tokenlisteners.length; j++){
if(tokenlisteners[j].token === token){
// call the listener
tokenlisteners[j].listener();
}
}
}
}
// schedule new update
if(running)
setTimeout(tick, TICK_INTERVAL);
};
function received_error()
{
// try again, maybe want a better logic later
if(running)
setTimeout(tick, TICK_INTERVAL);
};
function tick()
{
var data = [];
// maybe cache the token list?
// profiler will tell us if we should
for(var i=0; i<tokenlisteners.length; i++){
data.push(tokenlisteners[i].token);
}
connection.request({
path: "statetokenservice",
data: data,
}, received_tokenstates, received_error);
};
};
// with this trick, we should be able to run in browser or nodejs
if(typeof window === 'undefined')
{
// we are running in nodejs, so have to add to export
module.exports = RsApi;
}

View File

@ -1,51 +0,0 @@
var http = require('http');
/**
* Connection to the RS backend using http for running under node.js
* Mainly for testing, but could also use it for general purpose scripting.
* @constructor
*/
module.exports = function()
{
var server_hostname = "localhost";
var server_port = "9090";
var api_root_path = "/api/v2/";
this.request = function(request, callback)
{
var data;
if(request.data)
data = JSON.stringify(request.data);
else
data = "";
// NODEJS specific
var req = http.request({
host: server_hostname,
port: server_port,
path: api_root_path + request.path,
headers: {
"Content-Type": "application/json",
"Content-Length": data.length, // content length is required, else Wt will not provide the data (maybe WT does not like chunked encoding?)
}
//method: "POST",
}, function(response){
var databuffer = [];
response.on("data", function(chunk){
//console.log("got some data");
databuffer = databuffer + chunk;
})
response.on("end", function(){
//console.log("finished receiving data");
//console.log("data:"+databuffer);
callback(JSON.parse(databuffer));
})
});
//console.log("uploading data:");
//console.log(data);
req.write(data);
req.end();
}
}

View File

@ -1,123 +0,0 @@
/**
* Connection to the RS backend using XHR
* (could add other connections later, for example WebSockets)
* @constructor
*/
function RsXHRConnection(server_hostname, server_port)
{
var debug;
//debug = function(str){console.log(str);};
debug = function(str){};
//server_hostname = "localhost";
//server_port = "9090";
var api_root_path = "/api/v2/";
var status_listeners = [];
function notify_status(status)
{
for(var i = 0; i < status_listeners.length; i++)
{
status_listeners[i](status);
}
}
/**
* Register a callback to be called when the state of the connection changes.
* @param {function} cb - callback which receives a single argument. The arguments value is "connected" or "not_connected".
*/
this.register_status_listener = function(cb)
{
status_listeners.push(cb);
};
/**
* Unregister a status callback function.
* @param {function} cb - a privously registered callback function
*/
this.unregister_status_listener = function(cb)
{
var to_delete = [];
for(var i = 0; i < status_listeners.length; i++)
{
if(status_listeners[i] === cb){
to_delete.push(i);
}
}
for(var i = 0; i < to_delete.length; i++)
{
// copy the last element to the current index
var index = to_delete[i];
status_listeners[i] = status_listeners[status_listeners.length-1];
// remove the last element
status_listeners.pop();
}
};
/**
* Send a request to the backend
* automatically encodes the request as JSON before sending it to the server
* @param {object} req - the request to send to the server
* @param {function} cb - callback function to be called to handle the response. The callback takes one object as parameter. Can be left undefined.
* @param {function} err_cb - callback function to signal a failed request. Can be undefined.
*/
this.request = function(req, cb, err_cb)
{
//var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
// TODO: window is not available in QML
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
//console.log("onreadystatechanged state"+xhr.readyState);
// TODO: figure out how to catch errors like connection refused
// maybe want to have to set a state variable like ok=false
// the gui could then display: "no connection to server"
if (xhr.readyState === 4) {
if(xhr.status !== 200)
{
console.log("RsXHRConnection: request failed with status: "+xhr.status);
console.log("request was:");
console.log(req);
notify_status("not_connected");
if(err_cb !== undefined)
err_cb();
return;
}
// received response
notify_status("connected");
debug("RsXHRConnection received response:");
debug(xhr.responseText);
if(false)//if(xhr.responseText === "")
{
debug("Warning: response is empty");
return;
}
try
{
var respObj = JSON.parse(xhr.responseText);
}
catch(e)
{
debug("Exception during response handling: "+e);
}
if(cb === undefined)
debug("No callback function specified");
else
cb(respObj);
}
}
// post is required for sending data
var method;
if(req.data){
method = "POST";
} else {
method = "GET";
}
xhr.open(method, "http://"+server_hostname+":"+server_port+api_root_path+req.path);
var data = JSON.stringify(req.data);
debug("RsXHRConnection sending data:");
debug(data);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(data);
};
};

View File

@ -1,146 +0,0 @@
/**
* Construct a new type from an array, object or function.
* Use instances of this class to build a schema graph.
* The schema graph must not contain data other than arrays and instances of this class.
* Use the check function to check if arbitrary JS objects matches the schema.
* @constructor
* @param {String} name - name for the new type
* @param obj - array, object or function
* array: array should contain one instance of class "Type"
* object: object members can be arrays or instances of class "Type".
* Can also have child objects, but the leaf members have to be instances of class "Type"
* function: a function which takes three parameters: log, other, stack
* must return true if other matches the type, can report errors using the function passed in log.
*/
function Type(name, obj)
{
//var dbg = function(str){console.log(str);};
var dbg = function(str){};
this.getName = function(){
return name;
}
this.isLeaf = function(){
return typeof(obj) === "function";
}
this.getObj = function(){
return obj;
}
this.check = function(log, other, stack)
{
if(typeof(obj) === "object")
{
stack.push("<"+name+">");
var ok = _check(log, obj, other, stack);
stack.pop;
return ok;
}
if(typeof(obj) === "function")
return obj(log, other, stack);
log("FATAL Error: wrong usage of new Type(), second parameter should be an object or checker function");
return false;
}
function _check(log, ref, other, stack)
{
dbg("_check");
dbg("ref=" + ref);
dbg("other=" + other);
dbg("stack=[" + stack + "]");
if(ref instanceof Array)
{
dbg("is instanceof Array");
if(other instanceof Array)
{
if(other.length > 0)
{
return _check(log, ref[0], other[0], stack);
}
else
{
log("Warning: can't check array of length 0 in ["+stack+"]");
return true;
}
}
else
{
log("Error: not an Array ["+stack+"]");
return false;
}
}
if(ref instanceof Type)
{
dbg("is instanceof Type");
return ref.check(log, other, stack);
}
else // Object, have to check all children
{
dbg("is Object");
var ok = true;
for(m in ref)
{
if(m in other)
{
stack.push(m);
ok = ok && _check(log, ref[m], other[m], stack);
stack.pop();
}
else
{
log("Error: missing member \""+m+"\" in ["+stack+"]");
ok = false;
}
}
// check for additionally undocumented members
for(m in other)
{
if(!(m in ref))
{
log("Warning: found additional member \""+m+"\" in ["+stack+"]");
}
}
return ok;
}
}
};
// basic data types
// - string
// - bool
// - any (placeholder for unknown type)
var string = new Type("string",
function(log, other, stack)
{
if(typeof(other) !== "string")
{
log("Error: not a string ["+stack+"]");
return false;
}
else
return true;
}
);
var bool = new Type("bool",
function(log, other, stack)
{
if(typeof(other) !== "boolean")
{
log("Error: not a bool ["+stack+"]");
return false;
}
else
return true;
}
);
var any = new Type("any",
function(log, other, stack)
{
return true;
}
);
exports.Type = Type;
exports.string = string;
exports.bool = bool;
exports.any = any;

View File

@ -1,134 +0,0 @@
body {
background-color: black;
color: lime;
font-family: monospace;
margin: 0em;
/*padding: 1.5em;*/
padding: 2mm;
font-size: 1.1em;
}
#overlay{
z-index: 10;
position: fixed;
top:0;
left:0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.8);
}
.paddingbox{
padding:2mm;
}
.nav{
list-style-type: none;
padding: 0em;
margin: 0em;
}
.nav li{
display: inline;
padding: 0.1em;
margin-right: 1em;
border-width: 0.1em;
border-color: blue;
border-bottom-style: solid;
cursor: pointer;
}
td{
padding: 0.3em;
border-style: solid;
border-width: 0.1em;
border-color: lime;
}
.btn{
border-style: solid;
border-color: lime;
border-width: 0.1em;
cursor: pointer;
padding: 0.1em;
}
.btn2, .box{
border-style: solid;
/*border-color: lime;*/
border-color: limeGreen;
/*border-width: 1px;*/
border-radius: 3mm;
padding: 2mm;
font-size: 10mm;
cursor: pointer;
margin-bottom: 2mm;
}
.btn2:hover{
background-color: midnightblue;
}
.filelink{
color: inherit;
}
input, textarea{
color: lime;
font-family: monospace;
background-color: black;
border-color: lime;
font-size: 10mm;
border-radius: 3mm;
border-width: 1mm;
padding: 2mm;
margin-bottom: 2mm;
margin-right: 2mm;
/* make the button the whole screen width */
width: 100%;
/* make the text input fit small screens*/
box-sizing: border-box;
}
input:hover{
background-color: midnightblue;
}
.checkbox {
width: auto;
}
.flexbox{
display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */
display: -moz-box; /* OLD - Firefox 19- (buggy but mostly works) */
display: -ms-flexbox; /* TWEENER - IE 10 */
display: -webkit-flex; /* NEW - Chrome */
display: flex; /* NEW, Spec - Opera 12.1, Firefox 20+ */
}
.flexwidemember{
-webkit-box-flex: 1; /* OLD - iOS 6-, Safari 3.1-6 */
-moz-box-flex: 1; /* OLD - Firefox 19- */
width: 20%; /* For old syntax, otherwise collapses. */
-webkit-flex: 1; /* Chrome */
-ms-flex: 1; /* IE 10 */
flex: 1; /* NEW, Spec - Opera 12.1, Firefox 20+ */
}
#logo_splash{
-webkit-animation-fill-mode: forwards; /* Chrome, Safari, Opera */
animation-fill-mode: forwards;
-webkit-animation-name: logo_splash; /* Chrome, Safari, Opera */
-webkit-animation-duration: 3s; /* Chrome, Safari, Opera */
animation-name: logo_splash;
animation-duration: 3s;
text-align: center;
}
/* Chrome, Safari, Opera */
@-webkit-keyframes logo_splash {
from {opacity: 0;}
to {opacity: 1;}
}
/* Standard syntax */
@keyframes logo_splash {
from {opacity: 0;}
to {opacity: 1;}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,29 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>New webinterface for Retroshare</title>
<script src="RsXHRConnection.js"></script>
<script src="RsApi.js"></script>
<!-- it seems to work more reliable, if the jsx file is loaded before react -->
<script type="text/jsx" src="gui.jsx"></script>
<script src="react.js"></script>
<script src="JSXTransformer.js"></script>
<link href="green-black.css" rel="stylesheet">
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1">
</head>
<body>
<script>
document.write("<p>loading lots of stuff...</p>");
</script>
<p><noscript>The Retroshare web interface requires JavaScript. Please enable JavaScript in your browser.</noscript></p>
<!--<div id="logo_splash">
<img src="img/logo_splash.png"></img>
</div>-->
</body>
</html>

View File

@ -1,10 +0,0 @@
{
"name": "rswebui",
"version": "0.0.0",
"dependencies": {
},
"devDependencies": {
},
"scripts": {
}
}

View File

@ -1,11 +0,0 @@
This is the list of known BUGS:
-------------------------------
* None!

View File

@ -124,10 +124,13 @@ void DistantChatService::handleRecvChatStatusItem(RsChatStatusItem *cs)
std::cerr << "DistantChatService::handleRecvChatStatusItem(): received keep alive packet for inactive chat! peerId=" << cs->PeerId() << std::endl;
}
bool DistantChatService::acceptDataFromPeer(const RsGxsId& gxs_id,const RsGxsTunnelId& tunnel_id)
bool DistantChatService::acceptDataFromPeer(const RsGxsId& gxs_id,const RsGxsTunnelId& tunnel_id,bool is_client_side)
{
bool res = true ;
if(is_client_side) // always accept distant chat when we're the client side.
return true ;
if(mDistantChatPermissions & RS_DISTANT_CHAT_CONTACT_PERMISSION_FLAG_FILTER_NON_CONTACTS)
res = (rsIdentity!=NULL) && rsIdentity->isARegularContact(gxs_id) ;
@ -261,9 +264,12 @@ bool DistantChatService::initiateDistantChatConnexion(const RsGxsId& to_gxs_id,
RsChatMsgItem *item = new RsChatMsgItem;
item->message = "[Starting distant chat. Please wait for secure tunnel to be established]" ;
item->chatFlags = RS_CHAT_FLAG_PRIVATE ;
item->sendTime = time(NULL) ;
item->PeerId(RsPeerId(tunnel_id)) ;
handleRecvChatMsgItem(item) ;
delete item ; // item is replaced by NULL if partial, but this is not the case here.
return true ;
}

View File

@ -63,7 +63,7 @@ public:
// derived in p3ChatService, so as to pass down some info
virtual void handleIncomingItem(RsItem *) = 0;
virtual bool handleRecvChatMsgItem(RsChatMsgItem *ci)=0 ;
virtual bool handleRecvChatMsgItem(RsChatMsgItem *& ci)=0 ;
bool handleOutgoingItem(RsChatItem *) ;
bool handleRecvItem(RsChatItem *) ;
@ -89,7 +89,7 @@ public:
virtual void connectToGxsTunnelService(RsGxsTunnelService *tunnel_service) ;
private:
virtual bool acceptDataFromPeer(const RsGxsId& gxs_id,const RsGxsTunnelService::RsGxsTunnelId& tunnel_id) ;
virtual bool acceptDataFromPeer(const RsGxsId& gxs_id, const RsGxsTunnelService::RsGxsTunnelId& tunnel_id, bool is_client_side) ;
virtual void notifyTunnelStatus(const RsGxsTunnelService::RsGxsTunnelId& tunnel_id,uint32_t tunnel_status) ;
virtual void receiveData(const RsGxsTunnelService::RsGxsTunnelId& id,unsigned char *data,uint32_t data_size) ;

View File

@ -152,6 +152,10 @@ bool DistributedChatService::handleRecvChatLobbyMsgItem(RsChatMsgItem *ci)
return false;
}
// add a routing clue for this peer/GXSid combination. This is quite reliable since the lobby transport is almost instantaneous
rsGRouter->addRoutingClue(GRouterKeyId(cli->signature.keyId),cli->PeerId()) ;
ChatLobbyFlags fl ;
// delete items that are not for us, as early as possible.
@ -420,11 +424,6 @@ void DistributedChatService::checkSizeAndSendLobbyMessage(RsChatItem *msg)
sendChatItem(msg) ;
}
bool DistributedChatService::locked_checkAndRebuildPartialLobbyMessage(RsChatLobbyMsgItem *ci)
{
return true ;
}
bool DistributedChatService::handleRecvItem(RsChatItem *item)
{
switch(item->PacketSubType())
@ -699,6 +698,9 @@ void DistributedChatService::handleRecvChatLobbyEventItem(RsChatLobbyEventItem *
std::cerr << std::endl;
return ;
}
// add a routing clue for this peer/GXSid combination. This is quite reliable since the lobby transport is almost instantaneous
rsGRouter->addRoutingClue(GRouterKeyId(item->signature.keyId),item->PeerId()) ;
if(! bounceLobbyObject(item,item->PeerId()))
return ;

Some files were not shown because too many files have changed in this diff Show More