mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-12-28 08:59:37 -05:00
fixed conflicts with upstream/master
This commit is contained in:
commit
4a76fddaa9
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -17,3 +17,6 @@
|
||||
[submodule "supportlibs/libsam3"]
|
||||
path = supportlibs/libsam3
|
||||
url = https://github.com/i2p/libsam3.git
|
||||
[submodule "supportlibs/jni.hpp"]
|
||||
path = supportlibs/jni.hpp
|
||||
url = https://github.com/RetroShare/jni.hpp.git
|
||||
|
@ -2,7 +2,7 @@
|
||||
## image name must match gitlab repository name, you can play just with the tag
|
||||
## the part after :
|
||||
# export CI_IMAGE_NAME="registry.gitlab.com/retroshare/retroshare:android_arm_base"
|
||||
# docker build --squash -t "${CI_REGISTRY_IMAGE}" \
|
||||
# docker build --squash --tag "${CI_IMAGE_NAME}" \
|
||||
# --build-arg QT_INSTALLER_JWT_TOKEN="your qt JWT token goes here" .
|
||||
#
|
||||
# To build Android ARMv8 (64 bit) package pass also
|
||||
@ -25,14 +25,16 @@
|
||||
FROM ubuntu:20.04
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
ENV APT_UNAT="--assume-yes --quiet"
|
||||
|
||||
RUN apt-get update && apt-get clean
|
||||
RUN apt-get install -y -qq \
|
||||
RUN apt-get update $APT_UNAT && apt-get upgrade --show-upgraded $APT_UNAT && \
|
||||
apt-get clean $APT_UNAT
|
||||
RUN apt-get install --no-install-recommends $APT_UNAT \
|
||||
bash build-essential bzip2 cmake curl chrpath doxygen \
|
||||
git p7zip python qt5-default qttools5-dev tclsh unzip wget zip
|
||||
|
||||
# Dependencies to create Android pkg
|
||||
RUN apt-get install -y -qq \
|
||||
RUN apt-get install --no-install-recommends $APT_UNAT \
|
||||
openjdk-8-jre openjdk-8-jdk openjdk-8-jdk-headless gradle
|
||||
|
||||
ARG FRESHCLONE=0
|
||||
@ -74,11 +76,11 @@ ARG QT_INSTALLER_JWT_TOKEN
|
||||
RUN $PREPARE_TOOLCHAIN install_qt_android
|
||||
# Avoid Qt account details leak into the image
|
||||
RUN rm -f /root/.local/share/Qt/qtaccount.ini
|
||||
# Shrink image by removing unneded Qt components
|
||||
# Shrink image by removing unneeded Qt components
|
||||
RUN rm -r \
|
||||
$NATIVE_LIBS_TOOLCHAIN_PATH/Qt/Docs/ \
|
||||
$NATIVE_LIBS_TOOLCHAIN_PATH/Qt/Examples/ \
|
||||
$NATIVE_LIBS_TOOLCHAIN_PATH/Qt/Tools/
|
||||
$NATIVE_LIBS_TOOLCHAIN_PATH/Qt/Tools/
|
||||
|
||||
RUN mkdir /jsonapi-generator-build
|
||||
WORKDIR /jsonapi-generator-build/
|
||||
|
@ -112,6 +112,9 @@ define_default_value MVPTREE_SOURCE_VERSION origin/master
|
||||
|
||||
define_default_value REPORT_DIR "$(pwd)/$(basename ${NATIVE_LIBS_TOOLCHAIN_PATH})_build_report/"
|
||||
|
||||
define_default_value RS_SRC_DIR "$(realpath $(dirname $BASH_SOURCE)/../../)"
|
||||
|
||||
|
||||
cArch=""
|
||||
eABI=""
|
||||
cmakeABI=""
|
||||
@ -829,6 +832,15 @@ build_phash()
|
||||
popd
|
||||
}
|
||||
|
||||
task_register fetch_jni_hpp
|
||||
fetch_jni_hpp()
|
||||
{
|
||||
local rDir="supportlibs/jni.hpp/"
|
||||
|
||||
[ "$(ls "${RS_SRC_DIR}/${rDir}" | wc -l)" -gt "4" ] ||
|
||||
git -C ${RS_SRC_DIR} submodule update --init ${rDir}
|
||||
}
|
||||
|
||||
task_register build_mvptree
|
||||
build_mvptree()
|
||||
{
|
||||
@ -862,6 +874,7 @@ build_default_toolchain()
|
||||
task_run build_xapian || return $?
|
||||
task_run build_miniupnpc || return $?
|
||||
task_run build_phash || return $?
|
||||
task_run fetch_jni_hpp || return $?
|
||||
task_run deduplicate_includes || return $?
|
||||
task_run get_native_libs_toolchain_path || return $?
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
ARG ANDROID_NDK_ARCH=arm
|
||||
FROM registry.gitlab.com/retroshare/retroshare:android_${ANDROID_NDK_ARCH}_base
|
||||
|
||||
RUN apt-get update -y && apt-get upgrade -y
|
||||
ENV APT_UNAT="--assume-yes --quiet"
|
||||
|
||||
RUN apt-get update $APT_UNAT && apt-get upgrade $APT_UNAT --show-upgraded
|
||||
|
||||
ARG REPO_URL=https://gitlab.com/RetroShare/RetroShare.git
|
||||
ARG REPO_BRANCH=master
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit b260e58346b1eec782bdf88a7e8f3c9d36fd3ecb
|
||||
Subproject commit df16cb915465d058c75277678799ce4dadeae287
|
@ -1,447 +1,10 @@
|
||||
// SPDX-FileCopyrightText: (C) 2004-2019 Retroshare Team <contact@retroshare.cc>
|
||||
// SPDX-FileCopyrightText: (C) 2021 Retroshare Team <contact@retroshare.cc>
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
RetroShare JSON API
|
||||
===================
|
||||
= Moved
|
||||
|
||||
:Cxx: C++
|
||||
JSON API generator is now part of `libretroshare` look under `src/jsonapi/`
|
||||
directory in `libretroshare` repository.
|
||||
|
||||
== How to use RetroShare JSON API
|
||||
|
||||
Look for methods marked with +@jsonapi+ doxygen custom command into
|
||||
+libretroshare/src/retroshare+. The method path is composed by service instance
|
||||
pointer name like +rsGxsChannels+ for +RsGxsChannels+, and the method name like
|
||||
+createGroup+ and pass the input paramethers as a JSON object.
|
||||
|
||||
.Service instance pointer in rsgxschannels.h
|
||||
[source,cpp]
|
||||
--------------------------------------------------------------------------------
|
||||
/**
|
||||
* Pointer to global instance of RsGxsChannels service implementation
|
||||
* @jsonapi{development}
|
||||
*/
|
||||
extern RsGxsChannels* rsGxsChannels;
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
.Method declaration in rsgxschannels.h
|
||||
[source,cpp]
|
||||
--------------------------------------------------------------------------------
|
||||
/**
|
||||
* @brief Request channel creation.
|
||||
* The action is performed asyncronously, so it could fail in a subsequent
|
||||
* phase even after returning true.
|
||||
* @jsonapi{development}
|
||||
* @param[out] token Storage for RsTokenService token to track request
|
||||
* status.
|
||||
* @param[in] group Channel data (name, description...)
|
||||
* @return false on error, true otherwise
|
||||
*/
|
||||
virtual bool createGroup(uint32_t& token, RsGxsChannelGroup& group) = 0;
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
.paramethers.json
|
||||
[source,json]
|
||||
--------------------------------------------------------------------------------
|
||||
{
|
||||
"group":{
|
||||
"mMeta":{
|
||||
"mGroupName":"JSON test group",
|
||||
"mGroupFlags":4,
|
||||
"mSignFlags":520
|
||||
},
|
||||
"mDescription":"JSON test group description"
|
||||
},
|
||||
"caller_data":"Here can go any kind of JSON data (even objects) that the caller want to get back together with the response"
|
||||
}
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
.Calling the JSON API with curl on the terminal
|
||||
[source,bash]
|
||||
--------------------------------------------------------------------------------
|
||||
curl -u $API_USER --data @paramethers.json http://127.0.0.1:9092/rsGxsChannels/createGroup
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
.JSON API call result
|
||||
[source,json]
|
||||
--------------------------------------------------------------------------------
|
||||
{
|
||||
"caller_data": "Here can go any kind of JSON data (even objects) that the caller want to get back together with the response",
|
||||
"retval": true,
|
||||
"token": 3
|
||||
}
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Even if it is less efficient because of URL encoding HTTP +GET+ method is
|
||||
supported too, so in cases where the client cannot use +POST+ she can still use
|
||||
+GET+ taking care of encoding the JSON data. With +curl+ this can be done at
|
||||
least in two different ways.
|
||||
|
||||
.Calling the JSON API with GET method with curl on the terminal
|
||||
[source,bash]
|
||||
--------------------------------------------------------------------------------
|
||||
curl -u $API_USER --get --data-urlencode jsonData@paramethers.json \
|
||||
http://127.0.0.1:9092/rsGxsChannels/createGroup
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Letting +curl+ do the encoding is much more elegant but it is semantically
|
||||
equivalent to the following.
|
||||
|
||||
.Calling the JSON API with GET method and pre-encoded data with curl on the terminal
|
||||
--------------------------------------------------------------------------------
|
||||
curl -u $API_USER http://127.0.0.1:9092/rsGxsChannels/createGroup?jsonData=%7B%0A%20%20%20%20%22group%22%3A%7B%0A%20%20%20%20%20%20%20%20%22mMeta%22%3A%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22mGroupName%22%3A%22JSON%20test%20group%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22mGroupFlags%22%3A4%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22mSignFlags%22%3A520%0A%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%22mDescription%22%3A%22JSON%20test%20group%20description%22%0A%20%20%20%20%7D%2C%0A%20%20%20%20%22caller_data%22%3A%22Here%20can%20go%20any%20kind%20of%20JSON%20data%20%28even%20objects%29%20that%20the%20caller%20want%20to%20get%20back%20together%20with%20the%20response%22%0A%7D
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Note that using +GET+ method +?jsonData=+ and then the JSON data URL encoded are
|
||||
added after the path in the HTTP request.
|
||||
|
||||
|
||||
== JSON API authentication
|
||||
|
||||
Most of JSON API methods require authentication as they give access to
|
||||
RetroShare user data, and we don't want any application running on the system
|
||||
eventually by other users be able to access private data indiscriminately.
|
||||
JSON API support HTTP Basic as authentication scheme, this is enough as JSON API
|
||||
server is intented for usage on the same system (127.0.0.1) not over an
|
||||
untrusted network.
|
||||
If you need to use JSON API over an untrusted network consider using a reverse
|
||||
proxy with HTTPS such as NGINX in front of JSON API server.
|
||||
If RetroShare login has been effectuated through the JSON API you can use your
|
||||
location SSLID as username and your PGP password as credential for the JSON API,
|
||||
but we suggests you use specific meaningful and human readable credentials for
|
||||
each JSON API client so the human user can have better control over which client
|
||||
can access the JSON API.
|
||||
|
||||
.NewToken.json
|
||||
[source,json]
|
||||
--------------------------------------------------------------------------------
|
||||
{
|
||||
"token": "myNewUser:myNewPassword"
|
||||
}
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
.An authenticated client can authorize new tokens like this
|
||||
--------------------------------------------------------------------------------
|
||||
curl -u $API_USER --data @NewToken.json http://127.0.0.1:9092/jsonApiServer/authorizeToken
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
.An unauthenticated JSON API client can request access with
|
||||
--------------------------------------------------------------------------------
|
||||
curl --data @NewToken.json http://127.0.0.1:9092/jsonApiServer/requestNewTokenAutorization
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
When an unauthenticated client request his token to be authorized, JSON API
|
||||
server will try to ask confirmation to the human user if possible through
|
||||
+mNewAccessRequestCallback+, if it is not possible or the user didn't authorized
|
||||
the token +false+ is returned.
|
||||
|
||||
|
||||
== Offer new RetroShare services through JSON API
|
||||
|
||||
To offer a retroshare service through the JSON API, first of all one need find
|
||||
the global pointer to the service instance and document it in doxygen syntax,
|
||||
plus marking with the custom doxygen command +@jsonapi{RS_VERSION}+ where
|
||||
+RS_VERSION+ is the retroshare version in which this service became available
|
||||
with the current semantic (major changes to the service semantic, changes the
|
||||
meaning of the service itself, so the version should be updated in the
|
||||
documentation in that case).
|
||||
|
||||
.Service instance pointer in rsgxschannels.h
|
||||
[source,cpp]
|
||||
--------------------------------------------------------------------------------
|
||||
/**
|
||||
* Pointer to global instance of RsGxsChannels service implementation
|
||||
* @jsonapi{development}
|
||||
*/
|
||||
extern RsGxsChannels* rsGxsChannels;
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
Once the service instance itself is known to the JSON API you need to document
|
||||
in doxygen syntax and mark with the custom doxygen command
|
||||
+@jsonapi{RS_VERSION}+ the methods of the service that you want to make
|
||||
available through JSON API.
|
||||
|
||||
.Offering RsGxsChannels::getChannelDownloadDirectory in rsgxschannels.h
|
||||
[source,cpp]
|
||||
--------------------------------------------------------------------------------
|
||||
/**
|
||||
* Get download directory for the given channel
|
||||
* @jsonapi{development}
|
||||
* @param[in] channelId id of the channel
|
||||
* @param[out] directory reference to string where to store the path
|
||||
* @return false on error, true otherwise
|
||||
*/
|
||||
virtual bool getChannelDownloadDirectory( const RsGxsGroupId& channelId,
|
||||
std::string& directory ) = 0;
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
For each paramether you must specify if it is used as input +@param[in]+ as
|
||||
output +@param[out]+ or both +@param[inout]+. Paramethers and return value
|
||||
types must be of a type supported by +RsTypeSerializer+ which already support
|
||||
most basic types (+bool+, +std::string+...), +RsSerializable+ and containers of
|
||||
them like +std::vector<std::string>+. Paramethers passed by value and by
|
||||
reference of those types are both supported, while passing by pointer is not
|
||||
supported. If your paramether or return +class+/+struct+ type is not supported
|
||||
yet by +RsTypeSerializer+ most convenient approach is to make it derive from
|
||||
+RsSerializable+ and implement +serial_process+ method like I did with
|
||||
+RsGxsChannelGroup+.
|
||||
|
||||
.Deriving RsGxsChannelGroup from RsSerializable in rsgxschannels.h
|
||||
[source,cpp]
|
||||
--------------------------------------------------------------------------------
|
||||
struct RsGxsChannelGroup : RsSerializable
|
||||
{
|
||||
RsGroupMetaData mMeta;
|
||||
std::string mDescription;
|
||||
RsGxsImage mImage;
|
||||
|
||||
bool mAutoDownload;
|
||||
|
||||
/// @see RsSerializable
|
||||
virtual void serial_process( RsGenericSerializer::SerializeJob j,
|
||||
RsGenericSerializer::SerializeContext& ctx )
|
||||
{
|
||||
RS_SERIAL_PROCESS(mMeta);
|
||||
RS_SERIAL_PROCESS(mDescription);
|
||||
RS_SERIAL_PROCESS(mImage);
|
||||
RS_SERIAL_PROCESS(mAutoDownload);
|
||||
}
|
||||
};
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
You can do the same recursively for any member of your +struct+ that is not yet
|
||||
supported by +RsTypeSerializer+.
|
||||
|
||||
Some Retroshare {Cxx} API functions are asyncronous, historically RetroShare
|
||||
didn't follow a policy on how to expose asyncronous API so differents services
|
||||
and some times even differents method of the same service follow differents
|
||||
asyncronous patterns, thus making automatic generation of JSON API wrappers for
|
||||
those methods impractical. Instead of dealing with all those differents patterns
|
||||
I have chosed to support only one new pattern taking advantage of modern {Cxx}11
|
||||
and restbed features. On the {Cxx}11 side lambdas and +std::function+s are used,
|
||||
on the restbed side Server Side Events are used to send asyncronous results.
|
||||
|
||||
Lets see an example so it will be much esier to understand.
|
||||
|
||||
.RsGxsChannels::turtleSearchRequest asyncronous API
|
||||
[source,cpp]
|
||||
--------------------------------------------------------------------------------
|
||||
/**
|
||||
* @brief Request remote channels search
|
||||
* @jsonapi{development}
|
||||
* @param[in] matchString string to look for in the search
|
||||
* @param multiCallback function that will be called each time a search
|
||||
* result is received
|
||||
* @param[in] maxWait maximum wait time in seconds for search results
|
||||
* @return false on error, true otherwise
|
||||
*/
|
||||
virtual bool turtleSearchRequest(
|
||||
const std::string& matchString,
|
||||
const std::function<void (const RsGxsGroupSummary& result)>& multiCallback,
|
||||
std::time_t maxWait = 300 ) = 0;
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
+RsGxsChannels::turtleSearchRequest(...)+ is an asyncronous method because it
|
||||
send a channel search request on turtle network and then everytime a result is
|
||||
received from the network +multiCallback+ is called and the result is passed as
|
||||
parameter. To be supported by the automatic JSON API wrappers generator an
|
||||
asyncronous method need a parameter of type +std::function<void (...)>+ called
|
||||
+callback+ if the callback will be called only once or +multiCallback+ if the
|
||||
callback is expected to be called more then once like in this case.
|
||||
A second mandatory parameter is +maxWait+ of type +std::time_t+ it indicates the
|
||||
maximum amount of time in seconds for which the caller is willing to wait for
|
||||
results, in case the timeout is reached the callback will not be called anymore.
|
||||
|
||||
[IMPORTANT]
|
||||
================================================================================
|
||||
+callback+ and +multiCallback+ parameters documentation must *not* specify
|
||||
+[in]+, +[out]+, +[inout]+, in Doxygen documentation as this would fool the
|
||||
automatic wrapper generator, and ultimately break the compilation.
|
||||
================================================================================
|
||||
|
||||
.RsFiles::turtleSearchRequest asyncronous JSON API usage example
|
||||
[source,bash]
|
||||
--------------------------------------------------------------------------------
|
||||
$ cat turtle_search.json
|
||||
{
|
||||
"matchString":"linux"
|
||||
}
|
||||
$ curl --data @turtle_search.json http://127.0.0.1:9092/rsFiles/turtleSearchRequest
|
||||
data: {"retval":true}
|
||||
|
||||
data: {"results":[{"size":157631,"hash":"69709b4d01025584a8def5cd78ebbd1a3cf3fd05","name":"kill_bill_linux_1024x768.jpg"},{"size":192560,"hash":"000000000000000000009a93e5be8486c496f46c","name":"coffee_box_linux2.jpg"},{"size":455087,"hash":"9a93e5be8486c496f46c00000000000000000000","name":"Linux.png"},{"size":182004,"hash":"e8845280912ebf3779e400000000000000000000","name":"Linux_2_6.png"}]}
|
||||
|
||||
data: {"results":[{"size":668,"hash":"e8845280912ebf3779e400000000000000000000","name":"linux.png"},{"size":70,"hash":"e8845280912ebf3779e400000000000000000000","name":"kali-linux-2016.2-amd64.txt.sha1sum"},{"size":3076767744,"hash":"e8845280912ebf3779e400000000000000000000","name":"kali-linux-2016.2-amd64.iso"},{"size":2780872,"hash":"e8845280912ebf3779e400000000000000000000","name":"openwrt-ar71xx-generic-vmlinux.bin"},{"size":917504,"hash":"e8845280912ebf3779e400000000000000000000","name":"openwrt-ar71xx-generic-vmlinux.lzma"},{"size":2278404096,"hash":"e8845280912ebf3779e400000000000000000000","name":"gentoo-linux-livedvd-amd64-multilib-20160704.iso"},{"size":151770333,"hash":"e8845280912ebf3779e400000000000000000000","name":"flashtool-0.9.23.0-linux.tar.7z"},{"size":2847372,"hash":"e8845280912ebf3779e400000000000000000000","name":"openwrt-ar71xx-generic-vmlinux.elf"},{"size":1310720,"hash":"e8845280912ebf3779e400000000000000000000","name":"openwrt-ar71xx-generic-vmlinux.gz"},{"size":987809,"hash":"e8845280912ebf3779e400000000000000000000","name":"openwrt-ar71xx-generic-vmlinux-lzma.elf"}]}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
By default JSON API methods requires client authentication and their wrappers
|
||||
are automatically generated by +json-api-generator+.
|
||||
In some cases methods need do be accessible without authentication such as
|
||||
+rsLoginHelper/getLocations+ so in the doxygen documentaion they have the custom
|
||||
command +@jsonapi{RS_VERSION,unauthenticated}+.
|
||||
Other methods such as +/rsControl/rsGlobalShutDown+ need special care so they
|
||||
are marked with the custom doxygen command +@jsonapi{RS_VERSION,manualwrapper}+
|
||||
and their wrappers are not automatically generated but written manually into
|
||||
+JsonApiServer::JsonApiServer(...)+.
|
||||
|
||||
== Quirks
|
||||
|
||||
=== 64 bits integers handling
|
||||
|
||||
While JSON doesn't have problems representing 64 bits integers JavaScript, Dart
|
||||
and other languages are not capable to handle those numbers natively.
|
||||
To overcome this limitation JSON API output 64 bit integers as an object with
|
||||
two keys, one as proper integer and one as string representation.
|
||||
|
||||
.JSON API 64 bit integer output example
|
||||
[source,json]
|
||||
--------------------------------------------------------------------------------
|
||||
"lobby_id": { "xint64": 6215642878098695544, "xstr64": "6215642878098695544" }
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
So from languages that have proper 64bit integers support like Python or C++ one
|
||||
better read from `xint64` which is represented as a JSON integer, from languages
|
||||
where there is no proper 64bit integers support like JavaScript one can read from
|
||||
`xstr64` which is represented as JSON string (note that the first is not wrapped
|
||||
in "" while the latter is).
|
||||
|
||||
When one input a 64bit integer into the JSON API it first try to parse it as if
|
||||
it was sent the old way for retrocompatibility.
|
||||
|
||||
.JSON API 64 bit integer deprecated format input example
|
||||
[source,json]
|
||||
--------------------------------------------------------------------------------
|
||||
"lobby_id":6215642878098695544
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
This way is *DEPRECATED* and may disappear in the future, it is TEMPORALLY kept
|
||||
only for retrocompatibiliy with old clients.
|
||||
|
||||
If retrocompatible parsing attempt fail then it try to parse with the new way
|
||||
with proper JSON integer format.
|
||||
|
||||
.JSON API 64 bit integer new proper integer format input example
|
||||
[source,json]
|
||||
--------------------------------------------------------------------------------
|
||||
lobby_id": { "xint64": 6215642878098695544 }
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
If this fails then it try to parse with the new way with JSON string format.
|
||||
|
||||
.JSON API 64 bit integer new string format input example
|
||||
[source,json]
|
||||
--------------------------------------------------------------------------------
|
||||
"lobby_id": { "xstr64": "6215642878098695544" }
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
[WARNING]
|
||||
================================================================================
|
||||
Clients written in languages without proper 64bit integers support must
|
||||
use *ONLY* the string format otherwise they will send approximated values and
|
||||
get unexpected results from the JSON API, because parsing will success but the
|
||||
value will not be exactly the one you believe you sent.
|
||||
================================================================================
|
||||
|
||||
|
||||
== A bit of history
|
||||
|
||||
=== First writings about this
|
||||
|
||||
The previous attempt of exposing a RetroShare JSON API is called +libresapi+ and
|
||||
unfortunatley it requires a bunch of boilerplate code when we want to expose
|
||||
something present in the {Cxx} API in the JSON API.
|
||||
|
||||
As an example here you can see the libresapi that exposes part of the retroshare
|
||||
chat {Cxx} API and lot of boilerplate code just to convert {Cxx} objects to JSON
|
||||
|
||||
https://github.com/RetroShare/RetroShare/blob/v0.6.4/libresapi/src/api/ChatHandler.cpp#L44
|
||||
|
||||
To avoid the {Cxx} to JSON and back conversion boilerplate code I have worked out
|
||||
an extension to our {Cxx} serialization code so it is capable to serialize and
|
||||
deserialize to JSON you can see it in this pull request
|
||||
|
||||
https://github.com/RetroShare/RetroShare/pull/1155
|
||||
|
||||
So first step toward having a good API is to take advantage of the fact that RS
|
||||
is now capable of converting C++ objects from and to JSON.
|
||||
|
||||
The current API is accessible via HTTP and unix socket, there is no
|
||||
authentication in both of them, so anyone having access to the HTTP server or to
|
||||
the unix socket can access the API without extra restrictions.
|
||||
Expecially for the HTTP API this is a big risk because also if the http server
|
||||
listen on 127.0.0.1 every application on the machine (even rogue javascript
|
||||
running on your web browser) can access that and for example on android it is
|
||||
not safe at all (because of that I implemented the unix socket access so at
|
||||
least in android API was reasonably safe) because of this.
|
||||
|
||||
A second step to improve the API would be to implement some kind of API
|
||||
authentication mechanism (it would be nice that the mechanism is handled at API
|
||||
level and not at transport level so we can use it for any API trasport not just
|
||||
HTTP for example)
|
||||
|
||||
The HTTP server used by libresapi is libmicrohttpd server that is very minimal,
|
||||
it doesn't provide HTTPS nor modern HTTP goodies, like server notifications,
|
||||
websockets etc. because the lack of support we have a token polling mechanism in
|
||||
libresapi to avoid polling for every thing but it is still ugly, so if we can
|
||||
completely get rid of polling in the API that would be really nice.
|
||||
I have done a crawl to look for a replacement and briefly looked at
|
||||
|
||||
- https://www.gnu.org/software/libmicrohttpd/
|
||||
- http://wolkykim.github.io/libasyncd/
|
||||
- https://github.com/corvusoft/restbed
|
||||
- https://code.facebook.com/posts/1503205539947302/introducing-proxygen-facebook-s-c-http-framework/
|
||||
- https://github.com/cmouse/yahttp
|
||||
|
||||
taking in account a few metrics like modern HTTP goodies support, license,
|
||||
platform support, external dependencies and documentation it seemed to me that
|
||||
restbed is the more appropriate.
|
||||
|
||||
Another source of boilerplate code into libresapi is the mapping between JSON
|
||||
API requests and C++ API methods as an example you can look at this
|
||||
|
||||
https://github.com/RetroShare/RetroShare/blob/v0.6.4/libresapi/src/api/ChatHandler.cpp#L158
|
||||
|
||||
and this
|
||||
|
||||
https://github.com/RetroShare/RetroShare/blob/v0.6.4/libresapi/src/api/ApiServer.cpp#L253
|
||||
|
||||
The abstract logic of this thing is, when libreasapi get a request like
|
||||
+/chat/initiate_distant_chat+ then call
|
||||
+ChatHandler::handleInitiateDistantChatConnexion+ which in turn is just a
|
||||
wrapper of +RsMsgs::initiateDistantChatConnexion+ all this process is basically
|
||||
implemented as boilerplate code and would be unnecessary in a smarter design of
|
||||
the API because almost all the information needed is already present in the
|
||||
C++ API +libretroshare/src/retroshare+.
|
||||
|
||||
So a third step to improve the JSON API would be to remove this source of
|
||||
boilerplate code by automatizing the mapping between C++ and JSON API call.
|
||||
|
||||
This may result a little tricky as language parsing or other adevanced things
|
||||
may be required.
|
||||
|
||||
Hope this dive is useful for you +
|
||||
Cheers +
|
||||
G10h4ck
|
||||
|
||||
=== Second writings about this
|
||||
|
||||
I have been investigating a bit more about:
|
||||
[verse, G10h4ck]
|
||||
________________________________________________________________________________
|
||||
So a third step to improve the JSON API would be to remove this source of
|
||||
boilerplate code by automatizing the mapping between C++ and JSON API call
|
||||
________________________________________________________________________________
|
||||
|
||||
After spending some hours investigating this topic the most reasonable approach
|
||||
seems to:
|
||||
|
||||
1. Properly document headers in +libretroshare/src/retroshare/+ in doxygen syntax
|
||||
specifying wihich params are input and/or output (doxygen sysntax for this is
|
||||
+@param[in/out/inout]+) this will be the API documentation too.
|
||||
|
||||
2. At compile time use doxygen to generate XML description of the headers and use
|
||||
the XML to generate the JSON api server stub.
|
||||
http://www.stack.nl/~dimitri/doxygen/manual/customize.html#xmlgenerator
|
||||
|
||||
3. Enjoy
|
||||
This directory and all it's content is kept as is only for retro-compatibility
|
||||
with the old, deprecated `qmake` build system.
|
||||
|
@ -1,80 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* RetroShare JSON API *
|
||||
* *
|
||||
* Copyright (C) 2018-2019 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License version 3 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
registerHandler( "$%apiPath%$",
|
||||
[this](const std::shared_ptr<rb::Session> session)
|
||||
{
|
||||
const std::multimap<std::string, std::string> headers
|
||||
{
|
||||
{ "Connection", "keep-alive" },
|
||||
{ "Content-Type", "text/event-stream" }
|
||||
};
|
||||
session->yield(rb::OK, headers);
|
||||
|
||||
size_t reqSize = session->get_request()->get_header("Content-Length", 0);
|
||||
session->fetch( reqSize, [this](
|
||||
const std::shared_ptr<rb::Session> session,
|
||||
const rb::Bytes& body )
|
||||
{
|
||||
INITIALIZE_API_CALL_JSON_CONTEXT;
|
||||
|
||||
if( !checkRsServicePtrReady(
|
||||
$%instanceName%$, "$%instanceName%$", cAns, session ) )
|
||||
return;
|
||||
|
||||
$%paramsDeclaration%$
|
||||
|
||||
$%inputParamsDeserialization%$
|
||||
|
||||
const std::weak_ptr<rb::Service> weakService(mService);
|
||||
const std::weak_ptr<rb::Session> weakSession(session);
|
||||
$%callbackName%$ = [weakService, weakSession]($%callbackParams%$)
|
||||
{
|
||||
auto session = weakSession.lock();
|
||||
if(!session || session->is_closed()) return;
|
||||
|
||||
auto lService = weakService.lock();
|
||||
if(!lService || lService->is_down()) return;
|
||||
|
||||
$%callbackParamsSerialization%$
|
||||
|
||||
std::stringstream sStream;
|
||||
sStream << "data: " << compactJSON << ctx.mJson << "\n\n";
|
||||
const std::string message = sStream.str();
|
||||
|
||||
lService->schedule( [weakSession, message]()
|
||||
{
|
||||
auto session = weakSession.lock();
|
||||
if(!session || session->is_closed()) return;
|
||||
session->yield(message);
|
||||
$%sessionEarlyClose%$
|
||||
} );
|
||||
};
|
||||
|
||||
$%functionCall%$
|
||||
|
||||
$%outputParamsSerialization%$
|
||||
|
||||
// return them to the API caller
|
||||
std::stringstream message;
|
||||
message << "data: " << compactJSON << cAns.mJson << "\n\n";
|
||||
session->yield(message.str());
|
||||
$%sessionDelayedClose%$
|
||||
} );
|
||||
}, $%requiresAuth%$ );
|
1
jsonapi-generator/src/async-method-wrapper-template.cpp.tmpl
Symbolic link
1
jsonapi-generator/src/async-method-wrapper-template.cpp.tmpl
Symbolic link
@ -0,0 +1 @@
|
||||
../../libretroshare/src/jsonapi/async-method-wrapper-template.cpp.tmpl
|
@ -1,230 +0,0 @@
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
PROJECT_NAME = "libretroshare"
|
||||
|
||||
ALIASES += jsonapi{1}="\xmlonly<jsonapi minversion=\"\1\"/>\endxmlonly"
|
||||
ALIASES += jsonapi{2}="\xmlonly<jsonapi minversion=\"\1\" access=\"\2\"/>\endxmlonly"
|
||||
|
||||
# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
|
||||
# documentation from any documented member that it re-implements.
|
||||
# The default value is: YES.
|
||||
|
||||
INHERIT_DOCS = YES
|
||||
|
||||
# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
|
||||
# according to the Markdown format, which allows for more readable
|
||||
# documentation. See http://daringfireball.net/projects/markdown/ for details.
|
||||
# The output of markdown processing is further processed by doxygen, so you can
|
||||
# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
|
||||
# case of backward compatibilities issues.
|
||||
# The default value is: YES.
|
||||
|
||||
MARKDOWN_SUPPORT = YES
|
||||
|
||||
# When enabled doxygen tries to link words that correspond to documented
|
||||
# classes, or namespaces to their corresponding documentation. Such a link can
|
||||
# be prevented in individual cases by putting a % sign in front of the word or
|
||||
# globally by setting AUTOLINK_SUPPORT to NO.
|
||||
# The default value is: YES.
|
||||
|
||||
AUTOLINK_SUPPORT = YES
|
||||
|
||||
|
||||
# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
|
||||
# documentation are documented, even if no documentation was available. Private
|
||||
# class members and static file members will be hidden unless the
|
||||
# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
|
||||
# Note: This will also disable the warnings about undocumented members that are
|
||||
# normally produced when WARNINGS is set to YES.
|
||||
# The default value is: NO.
|
||||
|
||||
EXTRACT_ALL = YES
|
||||
|
||||
|
||||
# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
|
||||
# undocumented members inside documented classes or files. If set to NO these
|
||||
# members will be included in the various overviews, but no documentation
|
||||
# section is generated. This option has no effect if EXTRACT_ALL is enabled.
|
||||
# The default value is: NO.
|
||||
|
||||
HIDE_UNDOC_MEMBERS = NO
|
||||
|
||||
# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
|
||||
# undocumented classes that are normally visible in the class hierarchy. If set
|
||||
# to NO, these classes will be included in the various overviews. This option
|
||||
# has no effect if EXTRACT_ALL is enabled.
|
||||
# The default value is: NO.
|
||||
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# The INPUT tag is used to specify the files and/or directories that contain
|
||||
# documented source files. You may enter file names like myfile.cpp or
|
||||
# directories like /usr/src/myproject. Separate the files or directories with
|
||||
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
||||
# Note: If this tag is empty the current directory is searched.
|
||||
|
||||
#INPUT =
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
|
||||
# documentation (see: https://www.gnu.org/software/libiconv/) for the list of
|
||||
# possible encodings.
|
||||
# The default value is: UTF-8.
|
||||
|
||||
INPUT_ENCODING = UTF-8
|
||||
|
||||
# If the value of the INPUT tag contains directories, you can use the
|
||||
# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
|
||||
# *.h) to filter out the source-files in the directories.
|
||||
#
|
||||
# Note that for custom extensions or not directly supported extensions you also
|
||||
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
|
||||
# read by doxygen.
|
||||
#
|
||||
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
|
||||
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
|
||||
# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
|
||||
# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
|
||||
# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
|
||||
|
||||
FILE_PATTERNS = *.c \
|
||||
*.cc \
|
||||
*.cxx \
|
||||
*.cpp \
|
||||
*.c++ \
|
||||
*.java \
|
||||
*.ii \
|
||||
*.ixx \
|
||||
*.ipp \
|
||||
*.i++ \
|
||||
*.inl \
|
||||
*.idl \
|
||||
*.ddl \
|
||||
*.odl \
|
||||
*.h \
|
||||
*.hh \
|
||||
*.hxx \
|
||||
*.hpp \
|
||||
*.h++ \
|
||||
*.cs \
|
||||
*.d \
|
||||
*.php \
|
||||
*.php4 \
|
||||
*.php5 \
|
||||
*.phtml \
|
||||
*.inc \
|
||||
*.m \
|
||||
*.markdown \
|
||||
*.md \
|
||||
*.mm \
|
||||
*.dox \
|
||||
*.py \
|
||||
*.pyw \
|
||||
*.f90 \
|
||||
*.f95 \
|
||||
*.f03 \
|
||||
*.f08 \
|
||||
*.f \
|
||||
*.for \
|
||||
*.tcl \
|
||||
*.vhd \
|
||||
*.vhdl \
|
||||
*.ucf \
|
||||
*.qsf
|
||||
|
||||
# The RECURSIVE tag can be used to specify whether or not subdirectories should
|
||||
# be searched for input files as well.
|
||||
# The default value is: NO.
|
||||
|
||||
RECURSIVE = YES
|
||||
|
||||
# The EXCLUDE tag can be used to specify files and/or directories that should be
|
||||
# excluded from the INPUT source files. This way you can easily exclude a
|
||||
# subdirectory from a directory tree whose root is specified with the INPUT tag.
|
||||
#
|
||||
# Note that relative paths are relative to the directory from which doxygen is
|
||||
# run.
|
||||
|
||||
EXCLUDE =
|
||||
|
||||
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
|
||||
# directories that are symbolic links (a Unix file system feature) are excluded
|
||||
# from the input.
|
||||
# The default value is: NO.
|
||||
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
|
||||
# If the value of the INPUT tag contains directories, you can use the
|
||||
# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
|
||||
# certain files from those directories.
|
||||
#
|
||||
# Note that the wildcards are matched against the file with absolute path, so to
|
||||
# exclude all test directories for example use the pattern */test/*
|
||||
|
||||
EXCLUDE_PATTERNS =
|
||||
|
||||
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
|
||||
# (namespaces, classes, functions, etc.) that should be excluded from the
|
||||
# output. The symbol name can be a fully qualified name, a word, or if the
|
||||
# wildcard * is used, a substring. Examples: ANamespace, AClass,
|
||||
# AClass::ANamespace, ANamespace::*Test
|
||||
#
|
||||
# Note that the wildcards are matched against the file with absolute path, so to
|
||||
# exclude all test directories use the pattern */test/*
|
||||
|
||||
EXCLUDE_SYMBOLS =
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the HTML output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
|
||||
# The default value is: YES.
|
||||
|
||||
GENERATE_HTML = NO
|
||||
|
||||
# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
|
||||
# The default value is: YES.
|
||||
|
||||
GENERATE_LATEX = NO
|
||||
|
||||
# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
|
||||
# captures the structure of the code including all documentation.
|
||||
# The default value is: NO.
|
||||
|
||||
GENERATE_XML = YES
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the preprocessor
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
|
||||
# C-preprocessor directives found in the sources and include files.
|
||||
# The default value is: YES.
|
||||
|
||||
ENABLE_PREPROCESSING = YES
|
||||
|
||||
# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
|
||||
# in the source code. If set to NO, only conditional compilation will be
|
||||
# performed. Macro expansion can be done in a controlled way by setting
|
||||
# EXPAND_ONLY_PREDEF to YES.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
|
||||
|
||||
MACRO_EXPANSION = NO
|
||||
|
||||
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
|
||||
# the macro expansion is limited to the macros specified with the PREDEFINED and
|
||||
# EXPAND_AS_DEFINED tags.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
|
||||
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
|
1
jsonapi-generator/src/jsonapi-generator-doxygen.conf
Symbolic link
1
jsonapi-generator/src/jsonapi-generator-doxygen.conf
Symbolic link
@ -0,0 +1 @@
|
||||
../../libretroshare/src/jsonapi/jsonapi-generator-doxygen.conf
|
@ -1,50 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* RetroShare JSON API *
|
||||
* *
|
||||
* Copyright (C) 2018-2019 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
registerHandler( "$%apiPath%$",
|
||||
[](const std::shared_ptr<rb::Session> session)
|
||||
{
|
||||
size_t reqSize = session->get_request()->get_header("Content-Length", 0);
|
||||
session->fetch( reqSize, [](
|
||||
const std::shared_ptr<rb::Session> session,
|
||||
const rb::Bytes& body )
|
||||
{
|
||||
INITIALIZE_API_CALL_JSON_CONTEXT;
|
||||
|
||||
if( !checkRsServicePtrReady(
|
||||
$%instanceName%$, "$%instanceName%$", cAns, session ) )
|
||||
return;
|
||||
|
||||
$%paramsDeclaration%$
|
||||
|
||||
// deserialize input parameters from JSON
|
||||
$%inputParamsDeserialization%$
|
||||
|
||||
// call retroshare C++ API
|
||||
$%functionCall%$
|
||||
|
||||
// serialize out parameters and return value to JSON
|
||||
$%outputParamsSerialization%$
|
||||
|
||||
// return them to the API caller
|
||||
DEFAULT_API_CALL_JSON_RETURN(rb::OK);
|
||||
} );
|
||||
}, $%requiresAuth%$ );
|
||||
|
1
jsonapi-generator/src/method-wrapper-template.cpp.tmpl
Symbolic link
1
jsonapi-generator/src/method-wrapper-template.cpp.tmpl
Symbolic link
@ -0,0 +1 @@
|
||||
../../libretroshare/src/jsonapi/method-wrapper-template.cpp.tmpl
|
19
libbitdht/CMakeLists.txt
Normal file
19
libbitdht/CMakeLists.txt
Normal file
@ -0,0 +1,19 @@
|
||||
# RetroShare decentralized communication platform
|
||||
#
|
||||
# Copyright (C) 2021 Gioacchino Mazzurco <gio@eigenlab.org>
|
||||
# Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net>
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
cmake_minimum_required (VERSION 2.8.12)
|
||||
project(bitdht)
|
||||
|
||||
file(
|
||||
GLOB BITDHT_SOURCES
|
||||
src/bitdht/*.c src/bitdht/*.cc src/udp/*.cc src/util/*.cc )
|
||||
|
||||
add_library(${PROJECT_NAME} ${BITDHT_SOURCES})
|
||||
|
||||
target_include_directories(
|
||||
${PROJECT_NAME}
|
||||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src )
|
411
libretroshare/CMakeLists.txt
Normal file
411
libretroshare/CMakeLists.txt
Normal file
@ -0,0 +1,411 @@
|
||||
# RetroShare decentralized communication platform
|
||||
#
|
||||
# Copyright (C) 2021 Gioacchino Mazzurco <gio@eigenlab.org>
|
||||
# Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net>
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
cmake_minimum_required (VERSION 3.18.0)
|
||||
project(retroshare)
|
||||
|
||||
include(CMakeDependentOption)
|
||||
|
||||
set(FETCHCONTENT_QUIET OFF)
|
||||
include(FetchContent)
|
||||
|
||||
# sqlcipher
|
||||
option(
|
||||
RS_SQLCIPHER
|
||||
"SQLCipher encryption for GXS database"
|
||||
ON )
|
||||
|
||||
# rs_gxs_send_all
|
||||
option(
|
||||
RS_GXS_SEND_ALL
|
||||
"GXS distribute all available messages on request, indipendently from \
|
||||
local sync timer"
|
||||
ON )
|
||||
|
||||
# bitdht
|
||||
option(
|
||||
RS_BITDHT
|
||||
"Use bitdht (BitTorrent DHT own implementation) to look for online peers"
|
||||
ON )
|
||||
|
||||
# use_dht_stunner
|
||||
cmake_dependent_option(
|
||||
RS_BITDHT_STUNNER
|
||||
"Use bitdht (BitTorrent DHT own implementation) for NAT type discovery and \
|
||||
attempt the STUN (Session Traversal Utilities for NAT)"
|
||||
ON
|
||||
"RS_BITDHT"
|
||||
OFF )
|
||||
|
||||
# use_dht_stunner_ext_ip
|
||||
cmake_dependent_option(
|
||||
RS_BITDHT_STUNNER_EXT_IP
|
||||
"Use bitdht (BitTorrent DHT own implementation) stunner to figure out our \
|
||||
external IP. As this purely relying on random DHT peers that answer our \
|
||||
request, it can easily be abused. Therefore, it is turned off by default."
|
||||
OFF
|
||||
"RS_BITDHT_STUNNER"
|
||||
OFF )
|
||||
|
||||
# rs_jsonapi
|
||||
option(
|
||||
RS_JSON_API
|
||||
"Use restbed to expose libretroshare as JSON API via HTTP"
|
||||
OFF )
|
||||
|
||||
# rs_deep_forums_index
|
||||
option(
|
||||
RS_FORUM_DEEP_INDEX
|
||||
"Xapian based full text index and search of GXS forums"
|
||||
OFF )
|
||||
|
||||
# rs_broadcast_discovery
|
||||
option(
|
||||
RS_BRODCAST_DISCOVERY
|
||||
"Local area network peer discovery via udp-discovery-cpp"
|
||||
ON )
|
||||
|
||||
# rs_dh_init_check
|
||||
option(
|
||||
RS_DH_PRIME_INIT_CHECK
|
||||
"Check Diffie Hellman prime at each startup. This is not necessary and on \
|
||||
all Android mobile phones tested this take at least one minute at startup \
|
||||
which is untolerable for most phone users."
|
||||
ON )
|
||||
|
||||
option(
|
||||
RS_MINIUPNPC
|
||||
"Forward ports in NAT router via miniupnpc"
|
||||
ON )
|
||||
|
||||
cmake_dependent_option(
|
||||
RS_LIBUPNP
|
||||
"Forward ports in NAT router via libupnp (unstable)"
|
||||
OFF
|
||||
"NOT RS_MINIUPNPC"
|
||||
OFF )
|
||||
|
||||
option(
|
||||
RS_LIBRETROSHARE_STATIC
|
||||
"Build RetroShare static library"
|
||||
ON )
|
||||
|
||||
cmake_dependent_option(
|
||||
RS_LIBRETROSHARE_SHARED
|
||||
"Build RetroShare shared library"
|
||||
OFF
|
||||
"NOT RS_LIBRETROSHARE_STATIC"
|
||||
OFF )
|
||||
|
||||
# rs_deprecatedwarning
|
||||
option(
|
||||
RS_WARN_DEPRECATED
|
||||
"Print warning about RetroShare deprecated components usage during build"
|
||||
ON )
|
||||
|
||||
# rs_cppwarning
|
||||
option(
|
||||
RS_WARN_LESS
|
||||
"Silence a few at the moment very common warnings about RetroShare \
|
||||
components during build"
|
||||
OFF )
|
||||
|
||||
# rs_v07_changes
|
||||
option(
|
||||
RS_V07_BREAKING_CHANGES
|
||||
"Enable retro-compatibility breaking changes planned for RetroShare 0.7.0"
|
||||
OFF )
|
||||
|
||||
set(
|
||||
RS_DATA_DIR
|
||||
"${CMAKE_INSTALL_PREFIX}/share/retroshare"
|
||||
CACHE STRING
|
||||
"Path where to install RetroShare system wide data" )
|
||||
|
||||
################################################################################
|
||||
|
||||
find_package(Git REQUIRED)
|
||||
|
||||
#function(check_submodule sPath)
|
||||
# if(NOT EXISTS "${sPath}/.git" )
|
||||
# message("Initializing submodule ${sPath}")
|
||||
# execute_process(
|
||||
# COMMAND "${GIT_EXECUTABLE}" submodule update --init
|
||||
# WORKING_DIRECTORY "${sPath}"
|
||||
# COMMAND_ECHO STDERR
|
||||
# COMMAND_ERROR_IS_FATAL ANY)
|
||||
# endif()
|
||||
#endfunction()
|
||||
|
||||
################################################################################
|
||||
|
||||
include(src/CMakeLists.txt)
|
||||
list(TRANSFORM RS_SOURCES PREPEND src/)
|
||||
list(TRANSFORM RS_PUBLIC_HEADERS PREPEND src/)
|
||||
|
||||
if(RS_LIBRETROSHARE_STATIC)
|
||||
add_library(${PROJECT_NAME} STATIC ${RS_SOURCES})
|
||||
endif(RS_LIBRETROSHARE_STATIC)
|
||||
|
||||
if(RS_LIBRETROSHARE_SHARED)
|
||||
add_library(${PROJECT_NAME} SHARED ${RS_SOURCES})
|
||||
|
||||
## Ensure statically linked libraries such as openpgpsdk are compiled with
|
||||
## PIC Which is needed for shared library
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
endif(RS_LIBRETROSHARE_SHARED)
|
||||
|
||||
target_include_directories(
|
||||
${PROJECT_NAME}
|
||||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src )
|
||||
|
||||
|
||||
find_package(OpenSSL REQUIRED)
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE ${OPENSSL_INCLUDE_DIR})
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE OpenSSL::SSL OpenSSL::Crypto)
|
||||
|
||||
################################################################################
|
||||
|
||||
set(OPENPGPSDK_DEVEL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../openpgpsdk/")
|
||||
if(EXISTS "${OPENPGPSDK_DEVEL_DIR}/.git" )
|
||||
message(
|
||||
CHECK_PASS
|
||||
"openpgpsdk submodule found at ${OPENPGPSDK_DEVEL_DIR} using it" )
|
||||
add_subdirectory(${OPENPGPSDK_DEVEL_DIR} ${CMAKE_BINARY_DIR}/openpgpsdk)
|
||||
else()
|
||||
FetchContent_Declare(
|
||||
openpgpsdk
|
||||
GIT_REPOSITORY "https://gitlab.com/RetroShare/openpgpsdk.git"
|
||||
GIT_TAG "origin/master"
|
||||
GIT_SHALLOW TRUE
|
||||
GIT_PROGRESS TRUE
|
||||
TIMEOUT 10
|
||||
)
|
||||
FetchContent_MakeAvailable(openpgpsdk)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE openpgpsdk)
|
||||
|
||||
################################################################################
|
||||
|
||||
if(RS_BITDHT)
|
||||
set(BITDHT_DEVEL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../libbitdht/")
|
||||
if(EXISTS "${BITDHT_DEVEL_DIR}/.git" )
|
||||
message(
|
||||
CHECK_PASS
|
||||
"BitDHT submodule found at ${BITDHT_DEVEL_DIR} using it" )
|
||||
add_subdirectory(${BITDHT_DEVEL_DIR} ${CMAKE_BINARY_DIR}/bitdht)
|
||||
else()
|
||||
FetchContent_Declare(
|
||||
bitdht
|
||||
GIT_REPOSITORY "https://gitlab.com/RetroShare/bitdht.git"
|
||||
GIT_TAG "origin/master"
|
||||
GIT_SHALLOW TRUE
|
||||
GIT_PROGRESS TRUE
|
||||
TIMEOUT 10
|
||||
)
|
||||
FetchContent_MakeAvailable(bitdht)
|
||||
endif()
|
||||
|
||||
add_compile_definitions(RS_USE_BITDHT)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE bitdht)
|
||||
|
||||
if(RS_BITDHT_STUNNER)
|
||||
add_compile_definitions(RS_USE_DHT_STUNNER)
|
||||
|
||||
if(RS_BITDHT_STUNNER_EXT_IP)
|
||||
# TODO: Refactor this define to use proper naming
|
||||
add_compile_definitions(ALLOW_DHT_STUNNER)
|
||||
endif(RS_BITDHT_STUNNER_EXT_IP)
|
||||
endif(RS_BITDHT_STUNNER)
|
||||
endif(RS_BITDHT)
|
||||
|
||||
################################################################################
|
||||
|
||||
if(RS_JSON_API)
|
||||
find_package(Doxygen REQUIRED)
|
||||
find_package(Python3 REQUIRED)
|
||||
|
||||
## TODO: execute at build time instead that at cofiguration time see
|
||||
## add_custom_command or add_custom_target
|
||||
|
||||
set(
|
||||
JSON_API_GENERATOR_WORK_DIR
|
||||
"${CMAKE_BINARY_DIR}/jsonapi-generator.workdir/" )
|
||||
|
||||
set(
|
||||
JSON_API_GENERATOR_DOXYFILE
|
||||
"${JSON_API_GENERATOR_WORK_DIR}/jsonapi-generator-doxygen.conf" )
|
||||
|
||||
set(
|
||||
JSONAPI_GENERATOR_OUTPUT_DIR
|
||||
"${JSON_API_GENERATOR_WORK_DIR}/src/" )
|
||||
|
||||
set(
|
||||
JSONAPI_GENERATOR_SOURCE_DIR
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/jsonapi/" )
|
||||
|
||||
set(
|
||||
JSONAPI_GENERATOR_EXECUTABLE
|
||||
"${JSONAPI_GENERATOR_SOURCE_DIR}/jsonapi-generator.py" )
|
||||
|
||||
file(
|
||||
COPY "src/jsonapi/jsonapi-generator-doxygen.conf"
|
||||
DESTINATION "${JSON_API_GENERATOR_WORK_DIR}" )
|
||||
|
||||
file(
|
||||
APPEND
|
||||
"${JSON_API_GENERATOR_DOXYFILE}"
|
||||
"OUTPUT_DIRECTORY=${JSONAPI_GENERATOR_OUTPUT_DIR}\n"
|
||||
"INPUT=${CMAKE_CURRENT_SOURCE_DIR}" )
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
"${JSONAPI_GENERATOR_OUTPUT_DIR}/jsonapi-includes.inl"
|
||||
"${JSONAPI_GENERATOR_OUTPUT_DIR}/jsonapi-wrappers.inl"
|
||||
COMMAND ${DOXYGEN_EXECUTABLE} ${JSON_API_GENERATOR_DOXYFILE}
|
||||
COMMAND
|
||||
${Python3_EXECUTABLE} ${JSONAPI_GENERATOR_EXECUTABLE}
|
||||
${JSONAPI_GENERATOR_SOURCE_DIR} ${JSONAPI_GENERATOR_OUTPUT_DIR}
|
||||
MAIN_DEPENDENCY "${JSONAPI_GENERATOR_EXECUTABLE}"
|
||||
DEPENDS ${JSON_API_GENERATOR_DOXYFILE} ${RS_PUBLIC_HEADERS} )
|
||||
|
||||
target_sources(
|
||||
${PROJECT_NAME} PRIVATE
|
||||
"${JSONAPI_GENERATOR_OUTPUT_DIR}/jsonapi-includes.inl"
|
||||
"${JSONAPI_GENERATOR_OUTPUT_DIR}/jsonapi-wrappers.inl" )
|
||||
|
||||
include_directories(${JSONAPI_GENERATOR_OUTPUT_DIR})
|
||||
|
||||
set(BUILD_TESTS OFF CACHE BOOL "Do not build restbed tests")
|
||||
set(BUILD_SSL OFF CACHE BOOL "Do not build restbed SSL support")
|
||||
|
||||
FetchContent_Declare(
|
||||
restbed
|
||||
GIT_REPOSITORY "https://github.com/Corvusoft/restbed.git"
|
||||
GIT_TAG "4.8"
|
||||
GIT_SUBMODULES dependency/asio dependency/catch
|
||||
GIT_SHALLOW TRUE
|
||||
GIT_PROGRESS TRUE
|
||||
TIMEOUT 10
|
||||
)
|
||||
FetchContent_MakeAvailable(restbed)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE restbed)
|
||||
|
||||
## TODO: work around target_include_directories should be added upstream
|
||||
include_directories(${restbed_SOURCE_DIR}/source/)
|
||||
|
||||
add_compile_definitions(RS_JSONAPI)
|
||||
endif(RS_JSON_API)
|
||||
|
||||
################################################################################
|
||||
|
||||
if(RS_FORUM_DEEP_INDEX)
|
||||
find_package(Xapian REQUIRED)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE ${XAPIAN_LIBRARIES})
|
||||
|
||||
add_compile_definitions(RS_DEEP_FORUMS_INDEX)
|
||||
endif(RS_FORUM_DEEP_INDEX)
|
||||
|
||||
################################################################################
|
||||
|
||||
## TODO: Check if https://github.com/rbock/sqlpp11 or
|
||||
## https://github.com/rbock/sqlpp17 may improve GXS code
|
||||
if(RS_SQLCIPHER)
|
||||
find_library(RS_SQL_LIB "sqlcipher" REQUIRED)
|
||||
find_path(
|
||||
RS_SQL_LIB_INCLUDE "sqlcipher/sqlite3.h"
|
||||
PATH_SUFFIXES "include" "includes"
|
||||
REQUIRED )
|
||||
target_include_directories(
|
||||
${PROJECT_NAME}
|
||||
PRIVATE "${RS_SQL_LIB_INCLUDE}/sqlcipher" )
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE ${RS_SQL_LIB})
|
||||
else()
|
||||
add_compile_definitions(NO_SQLCIPHER)
|
||||
find_package(SQLite3 REQUIRED)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE SQLite::SQLite3)
|
||||
endif()
|
||||
|
||||
add_compile_definitions(
|
||||
SQLITE_HAS_CODEC
|
||||
RS_ENABLE_GXS
|
||||
GXS_ENABLE_SYNC_MSGS
|
||||
RS_USE_GXS_DISTANT_SYNC
|
||||
RS_GXS_TRANS
|
||||
V07_NON_BACKWARD_COMPATIBLE_CHANGE_001
|
||||
V07_NON_BACKWARD_COMPATIBLE_CHANGE_002
|
||||
V07_NON_BACKWARD_COMPATIBLE_CHANGE_003 )
|
||||
|
||||
if(RS_V07_BREAKING_CHANGES)
|
||||
add_compile_definitions(
|
||||
V07_NON_BACKWARD_COMPATIBLE_CHANGE_004
|
||||
V07_NON_BACKWARD_COMPATIBLE_CHANGE_UNNAMED )
|
||||
endif()
|
||||
|
||||
if(RS_DH_PRIME_INIT_CHECK)
|
||||
add_compile_definitions(RS_DISABLE_DIFFIE_HELLMAN_INIT_CHECK)
|
||||
endif(RS_DH_PRIME_INIT_CHECK)
|
||||
|
||||
if(RS_MINIUPNPC)
|
||||
add_compile_definitions(RS_USE_LIBMINIUPNPC)
|
||||
endif(RS_MINIUPNPC)
|
||||
|
||||
if(RS_LIBUPNP)
|
||||
message(FATAL_ERROR "UPnP support via libupnp is currently not supported")
|
||||
#add_compile_definitions(RS_USE_LIBUPNP)
|
||||
endif(RS_LIBUPNP)
|
||||
|
||||
if(RS_GXS_SEND_ALL)
|
||||
add_compile_definitions(RS_GXS_SEND_ALL)
|
||||
endif(RS_GXS_SEND_ALL)
|
||||
|
||||
if(RS_BRODCAST_DISCOVERY)
|
||||
## TODO: upstream option to disable tests building
|
||||
set(BUILD_EXAMPLE OFF CACHE BOOL "Do not build udp-discovery-cpp examples")
|
||||
set(BUILD_TOOL OFF CACHE BOOL "Do not build udp-discovery-tool application")
|
||||
FetchContent_Declare(
|
||||
udp-discovery-cpp
|
||||
GIT_REPOSITORY "https://github.com/truvorskameikin/udp-discovery-cpp.git"
|
||||
GIT_TAG "origin/master"
|
||||
GIT_SHALLOW TRUE
|
||||
GIT_PROGRESS TRUE
|
||||
TIMEOUT 10
|
||||
)
|
||||
FetchContent_MakeAvailable(udp-discovery-cpp)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE udp-discovery-cpp)
|
||||
|
||||
## TODO: Temporary work around target_include_directories should be added
|
||||
## upstream
|
||||
include_directories(${udp-discovery-cpp_SOURCE_DIR})
|
||||
endif(RS_BRODCAST_DISCOVERY)
|
||||
|
||||
if(NOT RS_WARN_DEPRECATED)
|
||||
add_compile_definitions(RS_NO_WARN_DEPRECATED)
|
||||
target_compile_options(
|
||||
${PROJECT_NAME} PRIVATE
|
||||
-Wno-deprecated -Wno-deprecated-declarations )
|
||||
endif(NOT RS_WARN_DEPRECATED)
|
||||
|
||||
if(RS_WARN_LESS)
|
||||
add_compile_definitions(RS_NO_WARN_CPP)
|
||||
|
||||
target_compile_options(
|
||||
${PROJECT_NAME} PRIVATE
|
||||
-Wno-cpp -Wno-inconsistent-missing-override )
|
||||
endif(RS_WARN_LESS)
|
||||
|
||||
################################################################################
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
add_compile_definitions(RS_DATA_DIR="${RS_DATA_DIR}")
|
||||
endif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
|
||||
## Useful to debug CMake
|
||||
#set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
408
libretroshare/src/CMakeLists.txt
Normal file
408
libretroshare/src/CMakeLists.txt
Normal file
@ -0,0 +1,408 @@
|
||||
# RetroShare decentralized communication platform
|
||||
#
|
||||
# Copyright (C) 2021 Gioacchino Mazzurco <gio@eigenlab.org>
|
||||
# Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net>
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
list(
|
||||
APPEND RS_PUBLIC_HEADERS
|
||||
retroshare/rsexpr.h
|
||||
retroshare/rsgxsdistsync.h
|
||||
retroshare/rsiface.h
|
||||
retroshare/rsrtt.h
|
||||
retroshare/rsbanlist.h
|
||||
retroshare/rsconfig.h
|
||||
retroshare/rsdisc.h
|
||||
retroshare/rsflags.h
|
||||
retroshare/rsgrouter.h
|
||||
retroshare/rsgxsflags.h
|
||||
retroshare/rsgxsservice.h
|
||||
retroshare/rsgxstrans.h
|
||||
retroshare/rsgxstunnel.h
|
||||
retroshare/rsids.h
|
||||
retroshare/rsnotify.h
|
||||
retroshare/rsphoto.h
|
||||
retroshare/rsplugin.h
|
||||
retroshare/rsreputations.h
|
||||
retroshare/rsservicecontrol.h
|
||||
retroshare/rstokenservice.h
|
||||
retroshare/rsturtle.h
|
||||
retroshare/rsgossipdiscovery.h
|
||||
retroshare/rsgxscommon.h
|
||||
retroshare/rsposted.h
|
||||
retroshare/rsstatus.h
|
||||
retroshare/rsversion.h
|
||||
retroshare/rsgxsifacehelper.h
|
||||
retroshare/rshistory.h
|
||||
retroshare/rsidentity.h
|
||||
retroshare/rsmsgs.h
|
||||
retroshare/rsgxschannels.h
|
||||
retroshare/rsgxscircles.h
|
||||
retroshare/rsgxsiface.h
|
||||
retroshare/rsgxsifacetypes.h
|
||||
retroshare/rstypes.h
|
||||
retroshare/rsgxsforums.h
|
||||
retroshare/rsevents.h
|
||||
retroshare/rsfiles.h
|
||||
retroshare/rsinit.h
|
||||
retroshare/rspeers.h )
|
||||
|
||||
list(
|
||||
APPEND RS_SOURCES
|
||||
chat/distantchat.cc
|
||||
chat/p3chatservice.cc
|
||||
chat/rschatitems.cc
|
||||
chat/distributedchat.cc
|
||||
crypto/chacha20.cpp
|
||||
crypto/hashstream.cc
|
||||
crypto/rsaes.cc
|
||||
crypto/rscrypto.cpp )
|
||||
|
||||
if(RS_BITDHT)
|
||||
list(
|
||||
APPEND RS_PUBLIC_HEADERS
|
||||
retroshare/rsdht.h )
|
||||
|
||||
list(
|
||||
APPEND RS_SOURCES
|
||||
dht/connectstatebox.cc
|
||||
dht/p3bitdht.cc
|
||||
dht/p3bitdht_interface.cc
|
||||
dht/p3bitdht_peernet.cc
|
||||
dht/p3bitdht_peers.cc
|
||||
dht/p3bitdht_relay.cc )
|
||||
endif(RS_BITDHT)
|
||||
|
||||
list(
|
||||
APPEND RS_SOURCES
|
||||
file_sharing/filelist_io.cc
|
||||
file_sharing/rsfilelistitems.cc
|
||||
file_sharing/file_tree.cc
|
||||
file_sharing/directory_updater.cc
|
||||
file_sharing/p3filelists.cc
|
||||
file_sharing/hash_cache.cc
|
||||
file_sharing/dir_hierarchy.cc
|
||||
file_sharing/directory_storage.cc
|
||||
ft/ftchunkmap.cc
|
||||
ft/ftfilecreator.cc
|
||||
ft/ftfileprovider.cc
|
||||
ft/ftfilesearch.cc
|
||||
ft/ftturtlefiletransferitem.cc
|
||||
ft/fttransfermodule.cc
|
||||
ft/ftcontroller.cc
|
||||
ft/ftdatamultiplex.cc
|
||||
ft/ftextralist.cc
|
||||
ft/ftserver.cc )
|
||||
|
||||
list(
|
||||
APPEND RS_SOURCES
|
||||
grouter/groutermatrix.cc
|
||||
grouter/grouteritems.cc
|
||||
grouter/p3grouter.cc )
|
||||
|
||||
list(
|
||||
APPEND RS_SOURCES
|
||||
gxs/rsgxsdata.cc
|
||||
gxs/rsgxsrequesttypes.cc
|
||||
gxs/gxssecurity.cc
|
||||
gxs/gxstokenqueue.cc
|
||||
gxs/rsdataservice.cc
|
||||
gxs/rsgxsdataaccess.cc
|
||||
gxs/rsgxsnetutils.cc
|
||||
gxs/rsgxsnettunnel.cc
|
||||
gxs/rsgxsutil.cc
|
||||
gxs/rsnxsobserver.cpp
|
||||
gxs/rsgenexchange.cc
|
||||
gxs/rsgxsnetservice.cc )
|
||||
|
||||
list(
|
||||
APPEND RS_SOURCES
|
||||
gxstrans/p3gxstransitems.cc
|
||||
gxstrans/p3gxstrans.cc )
|
||||
|
||||
list(
|
||||
APPEND RS_SOURCES
|
||||
gxstunnel/rsgxstunnelitems.cc
|
||||
gxstunnel/p3gxstunnel.cc )
|
||||
|
||||
if(RS_JSON_API)
|
||||
list(
|
||||
APPEND RS_PUBLIC_HEADERS
|
||||
retroshare/rsjsonapi.h )
|
||||
|
||||
list(
|
||||
APPEND RS_SOURCES
|
||||
jsonapi/jsonapi.cpp )
|
||||
endif(RS_JSON_API)
|
||||
|
||||
list(
|
||||
APPEND RS_SOURCES
|
||||
pgp/pgpkeyutil.cc
|
||||
pgp/pgpauxutils.cc
|
||||
pgp/pgphandler.cc
|
||||
pgp/rscertificate.cc )
|
||||
|
||||
#./plugins/dlfcn_win32.cc
|
||||
#./plugins/dlfcn_win32.h
|
||||
#./plugins/pluginmanager.h
|
||||
#./plugins/rscacheservice.h
|
||||
#./plugins/rspqiservice.h
|
||||
#./plugins/pluginmanager.cc
|
||||
|
||||
list(
|
||||
APPEND RS_SOURCES
|
||||
pqi/pqibin.cc
|
||||
pqi/pqiipset.cc
|
||||
pqi/pqiloopback.cc
|
||||
pqi/pqimonitor.cc
|
||||
pqi/pqipersongrp.cc
|
||||
pqi/pqiqos.cc
|
||||
pqi/pqiqosstreamer.cc
|
||||
pqi/pqisslproxy.cc
|
||||
pqi/pqistore.cc
|
||||
pqi/authgpg.cc
|
||||
pqi/p3cfgmgr.cc
|
||||
pqi/p3notify.cc
|
||||
pqi/p3servicecontrol.cc
|
||||
pqi/pqinetstatebox.cc
|
||||
pqi/pqiperson.cc
|
||||
pqi/pqiservice.cc
|
||||
pqi/pqissllistener.cc
|
||||
pqi/pqissludp.cc
|
||||
pqi/pqithreadstreamer.cc
|
||||
pqi/sslfns.cc
|
||||
pqi/authssl.cc
|
||||
pqi/p3historymgr.cc
|
||||
pqi/p3linkmgr.cc
|
||||
pqi/pqihandler.cc
|
||||
pqi/pqistreamer.cc
|
||||
pqi/p3netmgr.cc
|
||||
pqi/p3peermgr.cc
|
||||
pqi/pqinetwork.cc
|
||||
pqi/pqissl.cc
|
||||
pqi/pqisslpersongrp.cc )
|
||||
|
||||
#./pqi/pqissli2psam3.cpp
|
||||
#./pqi/pqissli2psam3.h
|
||||
|
||||
list(
|
||||
APPEND RS_SOURCES
|
||||
rsitems/rsbanlistitems.cc
|
||||
rsitems/rsbwctrlitems.cc
|
||||
rsitems/rsconfigitems.cc
|
||||
rsitems/rsfiletransferitems.cc
|
||||
rsitems/rsgxscommentitems.cc
|
||||
rsitems/rsgxsforumitems.cc
|
||||
rsitems/rsgxsiditems.cc
|
||||
rsitems/rsgxsrecognitems.cc
|
||||
rsitems/rsgxsreputationitems.cc
|
||||
rsitems/rsgxsupdateitems.cc
|
||||
rsitems/rshistoryitems.cc
|
||||
rsitems/rsrttitems.cc
|
||||
rsitems/rsserviceinfoitems.cc )
|
||||
|
||||
#retroshare/rswiki.h
|
||||
#./rsitems/rswikiitems.cc
|
||||
#./rsitems/rswikiitems.h
|
||||
#./rsitems/rswireitems.h
|
||||
|
||||
list(
|
||||
APPEND RS_SOURCES
|
||||
rsitems/rsgxschannelitems.cc
|
||||
rsitems/rsgxscircleitems.cc
|
||||
rsitems/rsgxsitems.cc
|
||||
rsitems/rsmsgitems.cc )
|
||||
|
||||
#./rsitems/rsphotoitems.cc
|
||||
#./rsitems/rsphotoitems.h
|
||||
#./rsitems/rsposteditems.cc
|
||||
#./rsitems/rsposteditems.h
|
||||
#./rsitems/rswireitems.cc
|
||||
#retroshare/rswire.h
|
||||
|
||||
list(
|
||||
APPEND RS_SOURCES
|
||||
rsitems/rsnxsitems.cc )
|
||||
|
||||
list(
|
||||
APPEND RS_SOURCES
|
||||
rsserver/p3status.cc
|
||||
rsserver/p3face-config.cc
|
||||
rsserver/p3face-info.cc
|
||||
rsserver/p3history.cc
|
||||
rsserver/p3serverconfig.cc
|
||||
rsserver/rsloginhandler.cc
|
||||
rsserver/p3face-server.cc
|
||||
rsserver/p3msgs.cc
|
||||
rsserver/p3peers.cc
|
||||
rsserver/rsaccounts.cc
|
||||
rsserver/rsinit.cc )
|
||||
|
||||
list(
|
||||
APPEND RS_SOURCES
|
||||
serialiser/rsbaseserial.cc
|
||||
serialiser/rsserializable.cc
|
||||
serialiser/rstlvaddrs.cc
|
||||
serialiser/rstlvbanlist.cc
|
||||
serialiser/rstlvbase.cc
|
||||
serialiser/rstlvbinary.cc
|
||||
serialiser/rstlvfileitem.cc
|
||||
serialiser/rstlvgenericmap.inl
|
||||
serialiser/rstlvgenericparam.cc
|
||||
serialiser/rstlvidset.cc
|
||||
serialiser/rstlvimage.cc
|
||||
serialiser/rstlvitem.cc
|
||||
serialiser/rstlvkeys.cc
|
||||
serialiser/rstlvkeyvalue.cc
|
||||
serialiser/rstlvstring.cc
|
||||
serialiser/rsserializer.cc
|
||||
serialiser/rstypeserializer.cc
|
||||
serialiser/rsserial.cc )
|
||||
|
||||
# ./services/autoproxy
|
||||
#./services/autoproxy/p3i2psam3.cpp
|
||||
#./services/autoproxy/p3i2psam3.h
|
||||
|
||||
list(
|
||||
APPEND RS_SOURCES
|
||||
services/autoproxy/rsautoproxymonitor.cc
|
||||
services/p3bwctrl.cc
|
||||
services/p3heartbeat.cc
|
||||
services/p3service.cc
|
||||
services/p3serviceinfo.cc
|
||||
services/p3statusservice.cc
|
||||
services/p3banlist.cc
|
||||
services/p3rtt.cc
|
||||
services/rseventsservice.cc
|
||||
services/p3gxscircles.cc
|
||||
services/p3gxscommon.cc
|
||||
services/p3gxsreputation.cc
|
||||
services/p3msgservice.cc
|
||||
services/p3idservice.cc
|
||||
services/p3gxschannels.cc
|
||||
services/p3gxsforums.cc )
|
||||
|
||||
#./services/p3wiki.cc
|
||||
#./services/p3wiki.h
|
||||
#./services/p3wire.cc
|
||||
#./services/p3wire.h
|
||||
|
||||
#./services/p3photoservice.cc
|
||||
#./services/p3photoservice.h
|
||||
#./services/p3postbase.cc
|
||||
#./services/p3postbase.h
|
||||
#./services/p3posted.cc
|
||||
#./services/p3posted.h
|
||||
|
||||
if(RS_BRODCAST_DISCOVERY)
|
||||
list(
|
||||
APPEND RS_PUBLIC_HEADERS
|
||||
retroshare/rsbroadcastdiscovery.h )
|
||||
|
||||
list(
|
||||
APPEND RS_SOURCES
|
||||
services/broadcastdiscoveryservice.cc )
|
||||
endif(RS_BRODCAST_DISCOVERY)
|
||||
|
||||
list(
|
||||
APPEND RS_SOURCES
|
||||
tcponudp/tcppacket.cc
|
||||
tcponudp/tcpstream.cc
|
||||
tcponudp/tou.cc
|
||||
tcponudp/udppeer.cc
|
||||
tcponudp/bss_tou.cc
|
||||
tcponudp/udprelay.cc )
|
||||
|
||||
if(RS_BITDHT_STUNNER)
|
||||
list(
|
||||
APPEND RS_SOURCES
|
||||
tcponudp/udpstunner.cc )
|
||||
endif(RS_BITDHT_STUNNER)
|
||||
|
||||
list(
|
||||
APPEND RS_SOURCES
|
||||
turtle/rsturtleitem.cc
|
||||
turtle/p3turtle.cc )
|
||||
|
||||
list(
|
||||
APPEND RS_SOURCES
|
||||
# util/contentvalue.cc
|
||||
# util/exampletst.c
|
||||
# util/rsdbbind.cc
|
||||
# util/rsdiscspace.cc
|
||||
util/rsexpr.cc
|
||||
util/rsprint.cc
|
||||
# util/rsrecogn.cc
|
||||
# util/rssharedptr.h
|
||||
# util/rstickevent.cc
|
||||
util/rstime.cc
|
||||
util/smallobject.cc
|
||||
# util/retrodb.cc
|
||||
util/rsbase64.cc
|
||||
util/rsjson.cc
|
||||
# util/rskbdinput.cc
|
||||
util/rsrandom.cc
|
||||
util/rsstring.cc
|
||||
util/rsurl.cc
|
||||
util/folderiterator.cc
|
||||
util/rsdir.cc
|
||||
util/dnsresolver.cc
|
||||
util/extaddrfinder.cc
|
||||
util/rsdebug.cc
|
||||
util/rsdnsutils.cc
|
||||
util/rsnet.cc
|
||||
util/rsnet_ss.cc
|
||||
util/rsthreads.cc )
|
||||
|
||||
# util/i2pcommon.cpp
|
||||
# util/i2pcommon.h
|
||||
|
||||
if(RS_FORUM_DEEP_INDEX)
|
||||
list(
|
||||
APPEND RS_SOURCES
|
||||
deep_search/commonutils.cpp
|
||||
deep_search/forumsindex.cpp )
|
||||
endif(RS_FORUM_DEEP_INDEX)
|
||||
|
||||
|
||||
#./deep_search/filesflacindexer.hpp
|
||||
#./deep_search/filesoggindexer.hpp
|
||||
#./deep_search/filestaglibindexer.hpp
|
||||
#./deep_search/filesindex.cpp
|
||||
#./deep_search/filesindex.hpp
|
||||
#./deep_search/channelsindex.cpp
|
||||
#./deep_search/channelsindex.hpp
|
||||
|
||||
list(
|
||||
APPEND RS_SOURCES
|
||||
gossipdiscovery/gossipdiscoveryitems.cc
|
||||
gossipdiscovery/p3gossipdiscovery.cc )
|
||||
|
||||
if(RS_MINIUPNPC)
|
||||
list(
|
||||
APPEND RS_SOURCES
|
||||
rs_upnp/upnphandler_miniupnp.cc )
|
||||
endif(RS_MINIUPNPC)
|
||||
|
||||
#./rs_upnp/UPnPBase.cpp
|
||||
#./rs_upnp/upnphandler_libupnp.cc
|
||||
#./rs_upnp/upnptest.cc
|
||||
#./rs_upnp/upnputil.cc
|
||||
|
||||
#./rs_android/LocalArray.h
|
||||
#./rs_android/README-ifaddrs-android.adoc
|
||||
#./rs_android/ScopedFd.h
|
||||
#./rs_android/androidcoutcerrcatcher.hpp
|
||||
#./rs_android/errorconditionwrap.cpp
|
||||
#./rs_android/ifaddrs-android.h
|
||||
#./rs_android/org
|
||||
#./rs_android/org/retroshare
|
||||
#./rs_android/org/retroshare/service
|
||||
#./rs_android/org/retroshare/service/AssetHelper.java
|
||||
#./rs_android/org/retroshare/service/ErrorConditionWrap.java
|
||||
#./rs_android/org/retroshare/service/RetroShareServiceAndroid.java
|
||||
#./rs_android/retroshareserviceandroid.cpp
|
||||
#./rs_android/retroshareserviceandroid.hpp
|
||||
#./rs_android/rsjni.cpp
|
||||
#./rs_android/rsjni.hpp
|
@ -46,7 +46,9 @@ std::error_condition DeepForumsIndex::search(
|
||||
// End of prefix configuration.
|
||||
|
||||
// And parse the query.
|
||||
Xapian::Query query = queryparser.parse_query(queryStr);
|
||||
using XQP = Xapian::QueryParser;
|
||||
Xapian::Query query = queryparser.parse_query(
|
||||
queryStr, XQP::FLAG_WILDCARD | XQP::FLAG_DEFAULT );
|
||||
|
||||
// Use an Enquire object on the database to run the query.
|
||||
Xapian::Enquire enquire(db);
|
||||
|
@ -107,7 +107,7 @@ p3discovery2::p3discovery2(
|
||||
addSerialType(new RsDiscSerialiser());
|
||||
|
||||
// Add self into PGP FriendList.
|
||||
mFriendList[AuthGPG::getAuthGPG()->getGPGOwnId()] = DiscPgpInfo();
|
||||
mFriendList[AuthPGP::getPgpOwnId()] = DiscPgpInfo();
|
||||
}
|
||||
|
||||
|
||||
@ -219,7 +219,7 @@ void p3discovery2::removeFriend(const RsPeerId &sslId)
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
/* pgp peer without any ssl entries -> check if they are still a real friend */
|
||||
if (!(AuthGPG::getAuthGPG()->isGPGAccepted(pgpId)))
|
||||
if (!(AuthPGP::isPGPAccepted(pgpId)))
|
||||
{
|
||||
#ifdef P3DISC_DEBUG
|
||||
std::cerr << "p3discovery2::addFriend() pgpId is no longer a friend, removing";
|
||||
@ -604,8 +604,8 @@ void p3discovery2::updatePgpFriendList()
|
||||
std::list<RsPgpId>::iterator lit;
|
||||
std::map<RsPgpId, DiscPgpInfo>::iterator it;
|
||||
|
||||
RsPgpId ownPgpId = AuthGPG::getAuthGPG()->getGPGOwnId();
|
||||
AuthGPG::getAuthGPG()->getGPGAcceptedList(pgpList);
|
||||
RsPgpId ownPgpId = AuthPGP::getPgpOwnId();
|
||||
AuthPGP::getPgpAcceptedList(pgpList);
|
||||
pgpList.push_back(ownPgpId);
|
||||
|
||||
// convert to set for ordering.
|
||||
@ -723,7 +723,7 @@ void p3discovery2::processPGPList(const RsPeerId &fromId, const RsDiscPgpListIte
|
||||
std::set<RsPgpId>::const_iterator fit;
|
||||
for(fit = item->pgpIdSet.ids.begin(); fit != item->pgpIdSet.ids.end(); ++fit)
|
||||
{
|
||||
if (!AuthGPG::getAuthGPG()->isGPGId(*fit))
|
||||
if (!AuthPGP::isPGPId(*fit))
|
||||
{
|
||||
#ifdef P3DISC_DEBUG
|
||||
std::cerr << "p3discovery2::processPGPList() requesting certificate for PgpId: " << *fit;
|
||||
@ -1058,11 +1058,11 @@ void p3discovery2::recvPGPCertificateRequest( const RsPeerId& fromId, const RsDi
|
||||
return;
|
||||
}
|
||||
|
||||
RsPgpId ownPgpId = AuthGPG::getAuthGPG()->getGPGOwnId();
|
||||
RsPgpId ownPgpId = AuthPGP::getPgpOwnId();
|
||||
for(const RsPgpId& pgpId : item->pgpIdSet.ids)
|
||||
if (pgpId == ownPgpId)
|
||||
sendPGPCertificate(pgpId, fromId);
|
||||
else if(ps.vs_disc != RS_VS_DISC_OFF && AuthGPG::getAuthGPG()->isGPGAccepted(pgpId))
|
||||
else if(ps.vs_disc != RS_VS_DISC_OFF && AuthPGP::isPGPAccepted(pgpId))
|
||||
sendPGPCertificate(pgpId, fromId);
|
||||
else
|
||||
std::cerr << "(WW) not sending certificate " << pgpId << " asked by friend " << fromId << " because this either this cert is not a friend, or discovery is off" << std::endl;
|
||||
@ -1078,7 +1078,7 @@ void p3discovery2::sendPGPCertificate(const RsPgpId &aboutId, const RsPeerId &to
|
||||
unsigned char *bin_data;
|
||||
size_t bin_len;
|
||||
|
||||
if(!AuthGPG::getAuthGPG()->exportPublicKey(aboutId,bin_data,bin_len,false,true))
|
||||
if(!AuthPGP::exportPublicKey(aboutId,bin_data,bin_len,false,true))
|
||||
{
|
||||
std::cerr << "(EE) cannot export public key " << aboutId << " requested by peer " << toId << std::endl;
|
||||
return ;
|
||||
@ -1098,7 +1098,7 @@ void p3discovery2::recvPGPCertificate(const RsPeerId& fromId, RsDiscPgpKeyItem*
|
||||
std::string cert_name;
|
||||
std::list<RsPgpId> cert_signers;
|
||||
|
||||
if(!AuthGPG::getAuthGPG()->getGPGDetailsFromBinaryBlock( (unsigned char*)item->bin_data,item->bin_len, cert_pgp_id, cert_name, cert_signers ))
|
||||
if(!AuthPGP::getPgpDetailsFromBinaryBlock( (unsigned char*)item->bin_data,item->bin_len, cert_pgp_id, cert_name, cert_signers ))
|
||||
{
|
||||
std::cerr << "(EE) cannot parse own PGP key sent by " << fromId << std::endl;
|
||||
return;
|
||||
@ -1147,7 +1147,7 @@ void p3discovery2::recvPGPCertificate(const RsPeerId& fromId, RsDiscPgpKeyItem*
|
||||
// otherwise the connection should already be accepted. This only happens when the short invite peer sends its own PGP key.
|
||||
|
||||
if(det.skip_pgp_signature_validation)
|
||||
AuthGPG::getAuthGPG()->AllowConnection(det.gpg_id,true);
|
||||
AuthPGP::AllowConnection(det.gpg_id,true);
|
||||
}
|
||||
|
||||
/************* from pqiServiceMonitor *******************/
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include "rsserver/p3face.h"
|
||||
#include "retroshare/rsevents.h"
|
||||
#include "util/radix64.h"
|
||||
#include "util/cxx17retrocompat.h"
|
||||
|
||||
#define PUB_GRP_MASK 0x000f
|
||||
#define RESTR_GRP_MASK 0x00f0
|
||||
@ -2285,8 +2286,9 @@ bool RsGenExchange::processGrpMask(const RsGxsGroupId& grpId, ContentValue &grpC
|
||||
|
||||
void RsGenExchange::publishMsgs()
|
||||
{
|
||||
bool atLeastOneMessageCreatedSuccessfully = false;
|
||||
|
||||
RS_STACK_MUTEX(mGenMtx) ;
|
||||
RS_STACK_MUTEX(mGenMtx);
|
||||
|
||||
rstime_t now = time(NULL);
|
||||
|
||||
@ -2463,6 +2465,8 @@ void RsGenExchange::publishMsgs()
|
||||
// add to published to allow acknowledgement
|
||||
mMsgNotify.insert(std::make_pair(mit->first, std::make_pair(grpId, msgId)));
|
||||
mDataAccess->updatePublicRequestStatus(mit->first, RsTokenService::COMPLETE);
|
||||
|
||||
atLeastOneMessageCreatedSuccessfully = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2496,6 +2500,8 @@ void RsGenExchange::publishMsgs()
|
||||
|
||||
mNotifications.push_back(ch);
|
||||
}
|
||||
|
||||
if(atLeastOneMessageCreatedSuccessfully) mNetService->requestPull();
|
||||
}
|
||||
|
||||
RsGenExchange::ServiceCreate_Return RsGenExchange::service_CreateGroup(RsGxsGrpItem* /* grpItem */,
|
||||
@ -2723,7 +2729,8 @@ bool RsGenExchange::checkKeys(const RsTlvSecurityKeySet& keySet)
|
||||
|
||||
void RsGenExchange::publishGrps()
|
||||
{
|
||||
std::list<RsGxsGroupId> groups_to_subscribe ;
|
||||
bool atLeastOneGroupCreatedSuccessfully = false;
|
||||
std::list<RsGxsGroupId> groups_to_subscribe;
|
||||
|
||||
{
|
||||
RS_STACK_MUTEX(mGenMtx) ;
|
||||
@ -2954,6 +2961,8 @@ void RsGenExchange::publishGrps()
|
||||
|
||||
// add to published to allow acknowledgement
|
||||
toNotify.insert(std::make_pair(token, GrpNote(true,ggps.mIsUpdate,grpId)));
|
||||
|
||||
atLeastOneGroupCreatedSuccessfully = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2972,9 +2981,14 @@ void RsGenExchange::publishGrps()
|
||||
|
||||
// This is done off-mutex to avoid possible cross deadlocks with the net service.
|
||||
|
||||
if(mNetService!=NULL)
|
||||
for(std::list<RsGxsGroupId>::const_iterator it(groups_to_subscribe.begin());it!=groups_to_subscribe.end();++it)
|
||||
mNetService->subscribeStatusChanged((*it),true) ;
|
||||
if(mNetService != nullptr)
|
||||
{
|
||||
for(auto& grpId : std::as_const(groups_to_subscribe))
|
||||
mNetService->subscribeStatusChanged(grpId, true);
|
||||
|
||||
if(atLeastOneGroupCreatedSuccessfully)
|
||||
mNetService->requestPull();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t RsGenExchange::generatePublicToken()
|
||||
|
@ -35,7 +35,7 @@
|
||||
// |
|
||||
// +----------- sharePublishKeys()
|
||||
// |
|
||||
// +----------- syncWithPeers()
|
||||
// +----------- checkUpdatesFromPeers()
|
||||
// | |
|
||||
// | +--if AutoSync--- send global UpdateTS of each peer to itself => the peer knows the last
|
||||
// | | time current peer has received an updated from himself
|
||||
@ -127,14 +127,14 @@
|
||||
// (Set at server side to be mGrpServerUpdateItem->grpUpdateTS)
|
||||
//
|
||||
// Only updated in processCompletedIncomingTransaction() from Grp list transaction.
|
||||
// Used in syncWithPeers() sending in RsNxsSyncGrp once to all peers: peer will send data if
|
||||
// Used in checkUpdatesFromPeers() sending in RsNxsSyncGrp once to all peers: peer will send data if
|
||||
// has something new. All time comparisons are in the friends' clock time.
|
||||
//
|
||||
// mClientMsgUpdateMap: map< RsPeerId, map<grpId,TimeStamp > >
|
||||
//
|
||||
// Last msg list modification time sent by that peer Id
|
||||
// Updated in processCompletedIncomingTransaction() from Grp list trans.
|
||||
// Used in syncWithPeers() sending in RsNxsSyncGrp once to all peers.
|
||||
// Used in checkUpdatesFromPeers() sending in RsNxsSyncGrp once to all peers.
|
||||
// Set at server to be mServerMsgUpdateMap[grpId]->msgUpdateTS
|
||||
//
|
||||
// mGrpServerUpdateItem: TimeStamp Last group local modification timestamp over all groups
|
||||
@ -150,7 +150,7 @@
|
||||
//
|
||||
// tick() tick()
|
||||
// | |
|
||||
// +---- SyncWithPeers +-- recvNxsItemQueue()
|
||||
// +---- checkUpdatesFromPeers() +-- recvNxsItemQueue()
|
||||
// | |
|
||||
// +---------------- Send global UpdateTS of each peer to itself => the peer knows +---------> +------ handleRecvSyncGroup( RsNxsSyncGrp*)
|
||||
// | the last msg sent (stored in mClientGrpUpdateMap[peer_id]), | | - parse all subscribed groups. For each, send a RsNxsSyncGrpItem with publish TS
|
||||
@ -457,7 +457,7 @@ int RsGxsNetService::tick()
|
||||
|
||||
if((elapsed) < now)
|
||||
{
|
||||
syncWithPeers();
|
||||
checkUpdatesFromPeers();
|
||||
syncGrpStatistics();
|
||||
checkDistantSyncState();
|
||||
|
||||
@ -570,39 +570,40 @@ RsGxsGroupId RsGxsNetService::hashGrpId(const RsGxsGroupId& gid,const RsPeerId&
|
||||
return RsGxsGroupId( RsDirUtil::sha1sum(tmpmem,SIZE).toByteArray() );
|
||||
}
|
||||
|
||||
void RsGxsNetService::syncWithPeers()
|
||||
std::error_condition RsGxsNetService::checkUpdatesFromPeers(
|
||||
std::set<RsPeerId> peers )
|
||||
{
|
||||
#ifdef NXS_NET_DEBUG_0
|
||||
GXSNETDEBUG___ << "RsGxsNetService::syncWithPeers() this=" << (void*)this << ". serviceInfo=" << mServiceInfo << std::endl;
|
||||
RS_DBG("this=", (void*)this, ". serviceInfo=", mServiceInfo);
|
||||
#endif
|
||||
|
||||
static RsNxsSerialiser ser(mServType) ; // this is used to estimate bandwidth.
|
||||
|
||||
RS_STACK_MUTEX(mNxsMutex) ;
|
||||
|
||||
std::set<RsPeerId> peers;
|
||||
mNetMgr->getOnlineList(mServiceInfo.mServiceType, peers);
|
||||
|
||||
if(mAllowDistSync && mGxsNetTunnel != NULL)
|
||||
/* If specific peers are passed as paramether ask only to them */
|
||||
if(peers.empty())
|
||||
{
|
||||
// Grab all online virtual peers of distant tunnels for the current service.
|
||||
mNetMgr->getOnlineList(mServiceInfo.mServiceType, peers);
|
||||
|
||||
std::list<RsGxsNetTunnelVirtualPeerId> vpids ;
|
||||
mGxsNetTunnel->getVirtualPeers(vpids);
|
||||
if(mAllowDistSync && mGxsNetTunnel != nullptr)
|
||||
{
|
||||
/* Grab all online virtual peers of distant tunnels for the current
|
||||
* service. */
|
||||
|
||||
for(auto it(vpids.begin());it!=vpids.end();++it)
|
||||
peers.insert(RsPeerId(*it)) ;
|
||||
std::list<RsGxsNetTunnelVirtualPeerId> vpids ;
|
||||
mGxsNetTunnel->getVirtualPeers(vpids);
|
||||
|
||||
for(auto it(vpids.begin());it!=vpids.end();++it)
|
||||
peers.insert(RsPeerId(*it)) ;
|
||||
}
|
||||
}
|
||||
|
||||
if (peers.empty()) {
|
||||
// nothing to do
|
||||
return;
|
||||
}
|
||||
// Still empty? Reports there are no available peers
|
||||
if (peers.empty()) return std::errc::network_down;
|
||||
|
||||
|
||||
RS_STACK_MUTEX(mNxsMutex);
|
||||
|
||||
// for now just grps
|
||||
for(auto sit = peers.begin(); sit != peers.end(); ++sit)
|
||||
{
|
||||
|
||||
const RsPeerId peerId = *sit;
|
||||
|
||||
ClientGrpMap::const_iterator cit = mClientGrpUpdateMap.find(peerId);
|
||||
@ -624,8 +625,7 @@ void RsGxsNetService::syncWithPeers()
|
||||
generic_sendItem(grp);
|
||||
}
|
||||
|
||||
if(!mAllowMsgSync)
|
||||
return ;
|
||||
if(!mAllowMsgSync) return std::error_condition();
|
||||
|
||||
#ifndef GXS_DISABLE_SYNC_MSGS
|
||||
|
||||
@ -743,10 +743,12 @@ void RsGxsNetService::syncWithPeers()
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // ndef GXS_DISABLE_SYNC_MSGS
|
||||
|
||||
return std::error_condition();
|
||||
}
|
||||
|
||||
void RsGxsNetService::generic_sendItem(RsNxsItem *si)
|
||||
void RsGxsNetService::generic_sendItem(rs_owner_ptr<RsItem> si)
|
||||
{
|
||||
// check if the item is to be sent to a distant peer or not
|
||||
|
||||
@ -1022,32 +1024,32 @@ void RsGxsNetService::locked_resetClientTS(const RsGxsGroupId& grpId)
|
||||
it->second.msgUpdateInfos.erase(grpId) ;
|
||||
}
|
||||
|
||||
void RsGxsNetService::subscribeStatusChanged(const RsGxsGroupId& grpId,bool subscribed)
|
||||
void RsGxsNetService::subscribeStatusChanged(
|
||||
const RsGxsGroupId& grpId, bool subscribed )
|
||||
{
|
||||
RS_STACK_MUTEX(mNxsMutex) ;
|
||||
|
||||
if(!subscribed)
|
||||
return ;
|
||||
if(!subscribed) return;
|
||||
|
||||
// When we subscribe, we reset the time stamps, so that the entire group list
|
||||
// gets requested once again, for a proper update.
|
||||
|
||||
RS_STACK_MUTEX(mNxsMutex);
|
||||
|
||||
#ifdef NXS_NET_DEBUG_0
|
||||
GXSNETDEBUG__G(grpId) << "Changing subscribe status for grp " << grpId << " to " << subscribed << ": reseting all server msg time stamps for this group, and server global TS." << std::endl;
|
||||
std::map<RsGxsGroupId,RsGxsServerMsgUpdate>::iterator it = mServerMsgUpdateMap.find(grpId) ;
|
||||
RS_DBG( "Changing subscribe status for grp", grpId, " to ", subscribed,
|
||||
": reseting all server msg time stamps for this group, and "
|
||||
"server global TS." );
|
||||
#endif
|
||||
|
||||
RsGxsServerMsgUpdate& item(mServerMsgUpdateMap[grpId]) ;
|
||||
RsGxsServerMsgUpdate& item(mServerMsgUpdateMap[grpId]);
|
||||
item.msgUpdateTS = static_cast<uint32_t>(time(nullptr));
|
||||
|
||||
item.msgUpdateTS = time(NULL) ;
|
||||
/* We also update mGrpServerUpdateItem so as to trigger a new grp list
|
||||
* exchange with friends (friends will send their known ClientTS which
|
||||
* will be lower than our own grpUpdateTS, triggering our sending of the
|
||||
* new subscribed grp list. */
|
||||
mGrpServerUpdate.grpUpdateTS = static_cast<uint32_t>(time(nullptr));
|
||||
|
||||
// We also update mGrpServerUpdateItem so as to trigger a new grp list exchange with friends (friends will send their known ClientTS which
|
||||
// will be lower than our own grpUpdateTS, triggering our sending of the new subscribed grp list.
|
||||
|
||||
mGrpServerUpdate.grpUpdateTS = time(NULL) ;
|
||||
|
||||
if(subscribed)
|
||||
locked_resetClientTS(grpId) ;
|
||||
locked_resetClientTS(grpId);
|
||||
}
|
||||
|
||||
bool RsGxsNetService::fragmentMsg(RsNxsMsg& msg, MsgFragments& msgFragments) const
|
||||
@ -1718,13 +1720,25 @@ RsItem *RsGxsNetService::generic_recvItem()
|
||||
|
||||
void RsGxsNetService::recvNxsItemQueue()
|
||||
{
|
||||
RsItem *item ;
|
||||
RsItem* item;
|
||||
|
||||
while(NULL != (item=generic_recvItem()))
|
||||
{
|
||||
while(nullptr != (item=generic_recvItem()))
|
||||
{
|
||||
#ifdef NXS_NET_DEBUG_1
|
||||
GXSNETDEBUG_P_(item->PeerId()) << "Received RsGxsNetService Item:" << (void*)item << " type=" << std::hex << item->PacketId() << std::dec << std::endl ;
|
||||
RS_DBG( "Received RsGxsNetService Item: ", (void*)item, " type=",
|
||||
item->PacketId() );
|
||||
#endif
|
||||
/* Handle pull request and other new items here to not mess with all the
|
||||
* old nested code and items hell */
|
||||
switch(static_cast<RsNxsSubtype>(item->PacketSubType()))
|
||||
{
|
||||
case RsNxsSubtype::PULL_REQUEST:
|
||||
std::unique_ptr<RsNxsPullRequestItem> pullItem(
|
||||
static_cast<RsNxsPullRequestItem*>(item) );
|
||||
handlePullRequest(std::move(pullItem));
|
||||
continue;
|
||||
}
|
||||
|
||||
// RsNxsItem needs dynamic_cast, since they have derived siblings.
|
||||
//
|
||||
RsNxsItem *ni = dynamic_cast<RsNxsItem*>(item) ;
|
||||
@ -4690,7 +4704,7 @@ bool RsGxsNetService::checkPermissionsForFriendGroup(const RsPeerId& sslId,const
|
||||
if(!grpMeta.mInternalCircle.isNull())
|
||||
{
|
||||
RsGroupInfo ginfo ;
|
||||
RsPgpId pgpId = mPgpUtils->getPGPId(sslId) ;
|
||||
RsPgpId pgpId = mPgpUtils->getPgpId(sslId) ;
|
||||
|
||||
#ifdef NXS_NET_DEBUG_4
|
||||
GXSNETDEBUG_PG(sslId,grpMeta.mGroupId) << " Group internal circle: " << grpMeta.mInternalCircle << ", We're owner. Sending to everyone in the group." << std::endl;
|
||||
@ -5075,6 +5089,46 @@ void RsGxsNetService::handleRecvPublishKeys(RsNxsGroupPublishKeyItem *item)
|
||||
}
|
||||
}
|
||||
|
||||
std::error_condition RsGxsNetService::requestPull(std::set<RsPeerId> peers)
|
||||
{
|
||||
/* If specific peers are passed as paramether ask only to them */
|
||||
if(peers.empty())
|
||||
{
|
||||
mNetMgr->getOnlineList(mServiceInfo.mServiceType, peers);
|
||||
|
||||
if(mAllowDistSync && mGxsNetTunnel != nullptr)
|
||||
{
|
||||
/* Grab all online virtual peers of distant tunnels for the current
|
||||
* service. */
|
||||
|
||||
std::list<RsGxsNetTunnelVirtualPeerId> vpids ;
|
||||
mGxsNetTunnel->getVirtualPeers(vpids);
|
||||
|
||||
for(auto it(vpids.begin());it!=vpids.end();++it)
|
||||
peers.insert(RsPeerId(*it)) ;
|
||||
}
|
||||
}
|
||||
|
||||
// Still empty? Reports there are no available peers
|
||||
if (peers.empty()) return std::errc::network_down;
|
||||
|
||||
for(auto& peerId: std::as_const(peers))
|
||||
{
|
||||
auto item = new RsNxsPullRequestItem(
|
||||
static_cast<RsServiceType>(mServType) );
|
||||
item->PeerId(peerId);
|
||||
generic_sendItem(item);
|
||||
}
|
||||
|
||||
return std::error_condition();
|
||||
}
|
||||
|
||||
void RsGxsNetService::handlePullRequest(
|
||||
std::unique_ptr<RsNxsPullRequestItem> item )
|
||||
{
|
||||
checkUpdatesFromPeers(std::set<RsPeerId>{item->PeerId()});
|
||||
}
|
||||
|
||||
bool RsGxsNetService::getGroupServerUpdateTS(const RsGxsGroupId& gid,rstime_t& group_server_update_TS, rstime_t& msg_server_update_TS)
|
||||
{
|
||||
RS_STACK_MUTEX(mNxsMutex) ;
|
||||
|
@ -250,6 +250,15 @@ public:
|
||||
|
||||
void threadTick() override; /// @see RsTickingThread
|
||||
|
||||
|
||||
/// @see RsNetworkExchangeService
|
||||
std::error_condition checkUpdatesFromPeers(
|
||||
std::set<RsPeerId> peers = std::set<RsPeerId>() ) override;
|
||||
|
||||
/// @see RsNetworkExchangeService
|
||||
std::error_condition requestPull(
|
||||
std::set<RsPeerId> peers = std::set<RsPeerId>() ) override;
|
||||
|
||||
private:
|
||||
|
||||
/*!
|
||||
@ -423,6 +432,8 @@ private:
|
||||
*/
|
||||
void handleRecvPublishKeys(RsNxsGroupPublishKeyItem*) ;
|
||||
|
||||
void handlePullRequest(std::unique_ptr<RsNxsPullRequestItem> item);
|
||||
|
||||
/** E: item handlers **/
|
||||
|
||||
|
||||
@ -459,7 +470,7 @@ private:
|
||||
void locked_pushMsgRespFromList(std::list<RsNxsItem*>& itemL, const RsPeerId& sslId, const RsGxsGroupId &grp_id, const uint32_t& transN);
|
||||
|
||||
void checkDistantSyncState();
|
||||
void syncWithPeers();
|
||||
|
||||
void syncGrpStatistics();
|
||||
void addGroupItemToList(NxsTransaction*& tr,
|
||||
const RsGxsGroupId& grpId, uint32_t& transN,
|
||||
@ -559,7 +570,7 @@ private:
|
||||
void cleanRejectedMessages();
|
||||
void processObserverNotifications();
|
||||
|
||||
void generic_sendItem(RsNxsItem *si);
|
||||
void generic_sendItem(rs_owner_ptr<RsItem> si);
|
||||
RsItem *generic_recvItem();
|
||||
|
||||
private:
|
||||
|
@ -223,7 +223,7 @@ bool GrpCircleVetting::canSend(
|
||||
{
|
||||
if(mCircles->isLoaded(circleId))
|
||||
{
|
||||
const RsPgpId& pgpId = mPgpUtils->getPGPId(peerId);
|
||||
const RsPgpId& pgpId = mPgpUtils->getPgpId(peerId);
|
||||
return mCircles->canSend(circleId, pgpId,should_encrypt);
|
||||
}
|
||||
|
||||
@ -302,7 +302,7 @@ bool MsgCircleIdsRequestVetting::cleared()
|
||||
if(filtered_out_msgs>0)
|
||||
std::cerr << "(WW) " << filtered_out_msgs << " messages not sent because they are signed by author(s) not member of that circle " << mCircleId << std::endl;
|
||||
|
||||
RsPgpId pgpId = mPgpUtils->getPGPId(mPeerId);
|
||||
RsPgpId pgpId = mPgpUtils->getPgpId(mPeerId);
|
||||
bool can_send_res = mCircles->canSend(mCircleId, pgpId,mShouldEncrypt);
|
||||
|
||||
if(mShouldEncrypt) // that means the circle is external
|
||||
|
@ -26,7 +26,7 @@
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <stdlib.h>
|
||||
#include <cstdlib>
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
@ -325,4 +325,20 @@ public:
|
||||
return RsReputationLevel::NEUTRAL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if new stuff is available from peers
|
||||
* @param peers peers to check, if empty all available peers are checked
|
||||
*/
|
||||
virtual std::error_condition checkUpdatesFromPeers(
|
||||
std::set<RsPeerId> peers = std::set<RsPeerId>() ) = 0;
|
||||
|
||||
/**
|
||||
* @brief request online peers to pull updates from our node ASAP
|
||||
* @param peers peers to which request pull from, if empty all available
|
||||
* peers are requested to pull
|
||||
* @return success or error details
|
||||
*/
|
||||
virtual std::error_condition requestPull(
|
||||
std::set<RsPeerId> peers = std::set<RsPeerId>() ) = 0;
|
||||
};
|
||||
|
447
libretroshare/src/jsonapi/README.adoc
Normal file
447
libretroshare/src/jsonapi/README.adoc
Normal file
@ -0,0 +1,447 @@
|
||||
// SPDX-FileCopyrightText: (C) 2004-2019 Retroshare Team <contact@retroshare.cc>
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
RetroShare JSON API
|
||||
===================
|
||||
|
||||
:Cxx: C++
|
||||
|
||||
== How to use RetroShare JSON API
|
||||
|
||||
Look for methods marked with +@jsonapi+ doxygen custom command into
|
||||
+libretroshare/src/retroshare+. The method path is composed by service instance
|
||||
pointer name like +rsGxsChannels+ for +RsGxsChannels+, and the method name like
|
||||
+createGroup+ and pass the input paramethers as a JSON object.
|
||||
|
||||
.Service instance pointer in rsgxschannels.h
|
||||
[source,cpp]
|
||||
--------------------------------------------------------------------------------
|
||||
/**
|
||||
* Pointer to global instance of RsGxsChannels service implementation
|
||||
* @jsonapi{development}
|
||||
*/
|
||||
extern RsGxsChannels* rsGxsChannels;
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
.Method declaration in rsgxschannels.h
|
||||
[source,cpp]
|
||||
--------------------------------------------------------------------------------
|
||||
/**
|
||||
* @brief Request channel creation.
|
||||
* The action is performed asyncronously, so it could fail in a subsequent
|
||||
* phase even after returning true.
|
||||
* @jsonapi{development}
|
||||
* @param[out] token Storage for RsTokenService token to track request
|
||||
* status.
|
||||
* @param[in] group Channel data (name, description...)
|
||||
* @return false on error, true otherwise
|
||||
*/
|
||||
virtual bool createGroup(uint32_t& token, RsGxsChannelGroup& group) = 0;
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
.paramethers.json
|
||||
[source,json]
|
||||
--------------------------------------------------------------------------------
|
||||
{
|
||||
"group":{
|
||||
"mMeta":{
|
||||
"mGroupName":"JSON test group",
|
||||
"mGroupFlags":4,
|
||||
"mSignFlags":520
|
||||
},
|
||||
"mDescription":"JSON test group description"
|
||||
},
|
||||
"caller_data":"Here can go any kind of JSON data (even objects) that the caller want to get back together with the response"
|
||||
}
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
.Calling the JSON API with curl on the terminal
|
||||
[source,bash]
|
||||
--------------------------------------------------------------------------------
|
||||
curl -u $API_USER --data @paramethers.json http://127.0.0.1:9092/rsGxsChannels/createGroup
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
.JSON API call result
|
||||
[source,json]
|
||||
--------------------------------------------------------------------------------
|
||||
{
|
||||
"caller_data": "Here can go any kind of JSON data (even objects) that the caller want to get back together with the response",
|
||||
"retval": true,
|
||||
"token": 3
|
||||
}
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Even if it is less efficient because of URL encoding HTTP +GET+ method is
|
||||
supported too, so in cases where the client cannot use +POST+ she can still use
|
||||
+GET+ taking care of encoding the JSON data. With +curl+ this can be done at
|
||||
least in two different ways.
|
||||
|
||||
.Calling the JSON API with GET method with curl on the terminal
|
||||
[source,bash]
|
||||
--------------------------------------------------------------------------------
|
||||
curl -u $API_USER --get --data-urlencode jsonData@paramethers.json \
|
||||
http://127.0.0.1:9092/rsGxsChannels/createGroup
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Letting +curl+ do the encoding is much more elegant but it is semantically
|
||||
equivalent to the following.
|
||||
|
||||
.Calling the JSON API with GET method and pre-encoded data with curl on the terminal
|
||||
--------------------------------------------------------------------------------
|
||||
curl -u $API_USER http://127.0.0.1:9092/rsGxsChannels/createGroup?jsonData=%7B%0A%20%20%20%20%22group%22%3A%7B%0A%20%20%20%20%20%20%20%20%22mMeta%22%3A%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22mGroupName%22%3A%22JSON%20test%20group%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22mGroupFlags%22%3A4%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22mSignFlags%22%3A520%0A%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%22mDescription%22%3A%22JSON%20test%20group%20description%22%0A%20%20%20%20%7D%2C%0A%20%20%20%20%22caller_data%22%3A%22Here%20can%20go%20any%20kind%20of%20JSON%20data%20%28even%20objects%29%20that%20the%20caller%20want%20to%20get%20back%20together%20with%20the%20response%22%0A%7D
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Note that using +GET+ method +?jsonData=+ and then the JSON data URL encoded are
|
||||
added after the path in the HTTP request.
|
||||
|
||||
|
||||
== JSON API authentication
|
||||
|
||||
Most of JSON API methods require authentication as they give access to
|
||||
RetroShare user data, and we don't want any application running on the system
|
||||
eventually by other users be able to access private data indiscriminately.
|
||||
JSON API support HTTP Basic as authentication scheme, this is enough as JSON API
|
||||
server is intented for usage on the same system (127.0.0.1) not over an
|
||||
untrusted network.
|
||||
If you need to use JSON API over an untrusted network consider using a reverse
|
||||
proxy with HTTPS such as NGINX in front of JSON API server.
|
||||
If RetroShare login has been effectuated through the JSON API you can use your
|
||||
location SSLID as username and your PGP password as credential for the JSON API,
|
||||
but we suggests you use specific meaningful and human readable credentials for
|
||||
each JSON API client so the human user can have better control over which client
|
||||
can access the JSON API.
|
||||
|
||||
.NewToken.json
|
||||
[source,json]
|
||||
--------------------------------------------------------------------------------
|
||||
{
|
||||
"token": "myNewUser:myNewPassword"
|
||||
}
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
.An authenticated client can authorize new tokens like this
|
||||
--------------------------------------------------------------------------------
|
||||
curl -u $API_USER --data @NewToken.json http://127.0.0.1:9092/jsonApiServer/authorizeToken
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
.An unauthenticated JSON API client can request access with
|
||||
--------------------------------------------------------------------------------
|
||||
curl --data @NewToken.json http://127.0.0.1:9092/jsonApiServer/requestNewTokenAutorization
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
When an unauthenticated client request his token to be authorized, JSON API
|
||||
server will try to ask confirmation to the human user if possible through
|
||||
+mNewAccessRequestCallback+, if it is not possible or the user didn't authorized
|
||||
the token +false+ is returned.
|
||||
|
||||
|
||||
== Offer new RetroShare services through JSON API
|
||||
|
||||
To offer a retroshare service through the JSON API, first of all one need find
|
||||
the global pointer to the service instance and document it in doxygen syntax,
|
||||
plus marking with the custom doxygen command +@jsonapi{RS_VERSION}+ where
|
||||
+RS_VERSION+ is the retroshare version in which this service became available
|
||||
with the current semantic (major changes to the service semantic, changes the
|
||||
meaning of the service itself, so the version should be updated in the
|
||||
documentation in that case).
|
||||
|
||||
.Service instance pointer in rsgxschannels.h
|
||||
[source,cpp]
|
||||
--------------------------------------------------------------------------------
|
||||
/**
|
||||
* Pointer to global instance of RsGxsChannels service implementation
|
||||
* @jsonapi{development}
|
||||
*/
|
||||
extern RsGxsChannels* rsGxsChannels;
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
Once the service instance itself is known to the JSON API you need to document
|
||||
in doxygen syntax and mark with the custom doxygen command
|
||||
+@jsonapi{RS_VERSION}+ the methods of the service that you want to make
|
||||
available through JSON API.
|
||||
|
||||
.Offering RsGxsChannels::getChannelDownloadDirectory in rsgxschannels.h
|
||||
[source,cpp]
|
||||
--------------------------------------------------------------------------------
|
||||
/**
|
||||
* Get download directory for the given channel
|
||||
* @jsonapi{development}
|
||||
* @param[in] channelId id of the channel
|
||||
* @param[out] directory reference to string where to store the path
|
||||
* @return false on error, true otherwise
|
||||
*/
|
||||
virtual bool getChannelDownloadDirectory( const RsGxsGroupId& channelId,
|
||||
std::string& directory ) = 0;
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
For each paramether you must specify if it is used as input +@param[in]+ as
|
||||
output +@param[out]+ or both +@param[inout]+. Paramethers and return value
|
||||
types must be of a type supported by +RsTypeSerializer+ which already support
|
||||
most basic types (+bool+, +std::string+...), +RsSerializable+ and containers of
|
||||
them like +std::vector<std::string>+. Paramethers passed by value and by
|
||||
reference of those types are both supported, while passing by pointer is not
|
||||
supported. If your paramether or return +class+/+struct+ type is not supported
|
||||
yet by +RsTypeSerializer+ most convenient approach is to make it derive from
|
||||
+RsSerializable+ and implement +serial_process+ method like I did with
|
||||
+RsGxsChannelGroup+.
|
||||
|
||||
.Deriving RsGxsChannelGroup from RsSerializable in rsgxschannels.h
|
||||
[source,cpp]
|
||||
--------------------------------------------------------------------------------
|
||||
struct RsGxsChannelGroup : RsSerializable
|
||||
{
|
||||
RsGroupMetaData mMeta;
|
||||
std::string mDescription;
|
||||
RsGxsImage mImage;
|
||||
|
||||
bool mAutoDownload;
|
||||
|
||||
/// @see RsSerializable
|
||||
virtual void serial_process( RsGenericSerializer::SerializeJob j,
|
||||
RsGenericSerializer::SerializeContext& ctx )
|
||||
{
|
||||
RS_SERIAL_PROCESS(mMeta);
|
||||
RS_SERIAL_PROCESS(mDescription);
|
||||
RS_SERIAL_PROCESS(mImage);
|
||||
RS_SERIAL_PROCESS(mAutoDownload);
|
||||
}
|
||||
};
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
You can do the same recursively for any member of your +struct+ that is not yet
|
||||
supported by +RsTypeSerializer+.
|
||||
|
||||
Some Retroshare {Cxx} API functions are asyncronous, historically RetroShare
|
||||
didn't follow a policy on how to expose asyncronous API so differents services
|
||||
and some times even differents method of the same service follow differents
|
||||
asyncronous patterns, thus making automatic generation of JSON API wrappers for
|
||||
those methods impractical. Instead of dealing with all those differents patterns
|
||||
I have chosed to support only one new pattern taking advantage of modern {Cxx}11
|
||||
and restbed features. On the {Cxx}11 side lambdas and +std::function+s are used,
|
||||
on the restbed side Server Side Events are used to send asyncronous results.
|
||||
|
||||
Lets see an example so it will be much esier to understand.
|
||||
|
||||
.RsGxsChannels::turtleSearchRequest asyncronous API
|
||||
[source,cpp]
|
||||
--------------------------------------------------------------------------------
|
||||
/**
|
||||
* @brief Request remote channels search
|
||||
* @jsonapi{development}
|
||||
* @param[in] matchString string to look for in the search
|
||||
* @param multiCallback function that will be called each time a search
|
||||
* result is received
|
||||
* @param[in] maxWait maximum wait time in seconds for search results
|
||||
* @return false on error, true otherwise
|
||||
*/
|
||||
virtual bool turtleSearchRequest(
|
||||
const std::string& matchString,
|
||||
const std::function<void (const RsGxsGroupSummary& result)>& multiCallback,
|
||||
std::time_t maxWait = 300 ) = 0;
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
+RsGxsChannels::turtleSearchRequest(...)+ is an asyncronous method because it
|
||||
send a channel search request on turtle network and then everytime a result is
|
||||
received from the network +multiCallback+ is called and the result is passed as
|
||||
parameter. To be supported by the automatic JSON API wrappers generator an
|
||||
asyncronous method need a parameter of type +std::function<void (...)>+ called
|
||||
+callback+ if the callback will be called only once or +multiCallback+ if the
|
||||
callback is expected to be called more then once like in this case.
|
||||
A second mandatory parameter is +maxWait+ of type +std::time_t+ it indicates the
|
||||
maximum amount of time in seconds for which the caller is willing to wait for
|
||||
results, in case the timeout is reached the callback will not be called anymore.
|
||||
|
||||
[IMPORTANT]
|
||||
================================================================================
|
||||
+callback+ and +multiCallback+ parameters documentation must *not* specify
|
||||
+[in]+, +[out]+, +[inout]+, in Doxygen documentation as this would fool the
|
||||
automatic wrapper generator, and ultimately break the compilation.
|
||||
================================================================================
|
||||
|
||||
.RsFiles::turtleSearchRequest asyncronous JSON API usage example
|
||||
[source,bash]
|
||||
--------------------------------------------------------------------------------
|
||||
$ cat turtle_search.json
|
||||
{
|
||||
"matchString":"linux"
|
||||
}
|
||||
$ curl --data @turtle_search.json http://127.0.0.1:9092/rsFiles/turtleSearchRequest
|
||||
data: {"retval":true}
|
||||
|
||||
data: {"results":[{"size":157631,"hash":"69709b4d01025584a8def5cd78ebbd1a3cf3fd05","name":"kill_bill_linux_1024x768.jpg"},{"size":192560,"hash":"000000000000000000009a93e5be8486c496f46c","name":"coffee_box_linux2.jpg"},{"size":455087,"hash":"9a93e5be8486c496f46c00000000000000000000","name":"Linux.png"},{"size":182004,"hash":"e8845280912ebf3779e400000000000000000000","name":"Linux_2_6.png"}]}
|
||||
|
||||
data: {"results":[{"size":668,"hash":"e8845280912ebf3779e400000000000000000000","name":"linux.png"},{"size":70,"hash":"e8845280912ebf3779e400000000000000000000","name":"kali-linux-2016.2-amd64.txt.sha1sum"},{"size":3076767744,"hash":"e8845280912ebf3779e400000000000000000000","name":"kali-linux-2016.2-amd64.iso"},{"size":2780872,"hash":"e8845280912ebf3779e400000000000000000000","name":"openwrt-ar71xx-generic-vmlinux.bin"},{"size":917504,"hash":"e8845280912ebf3779e400000000000000000000","name":"openwrt-ar71xx-generic-vmlinux.lzma"},{"size":2278404096,"hash":"e8845280912ebf3779e400000000000000000000","name":"gentoo-linux-livedvd-amd64-multilib-20160704.iso"},{"size":151770333,"hash":"e8845280912ebf3779e400000000000000000000","name":"flashtool-0.9.23.0-linux.tar.7z"},{"size":2847372,"hash":"e8845280912ebf3779e400000000000000000000","name":"openwrt-ar71xx-generic-vmlinux.elf"},{"size":1310720,"hash":"e8845280912ebf3779e400000000000000000000","name":"openwrt-ar71xx-generic-vmlinux.gz"},{"size":987809,"hash":"e8845280912ebf3779e400000000000000000000","name":"openwrt-ar71xx-generic-vmlinux-lzma.elf"}]}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
By default JSON API methods requires client authentication and their wrappers
|
||||
are automatically generated by +json-api-generator+.
|
||||
In some cases methods need do be accessible without authentication such as
|
||||
+rsLoginHelper/getLocations+ so in the doxygen documentaion they have the custom
|
||||
command +@jsonapi{RS_VERSION,unauthenticated}+.
|
||||
Other methods such as +/rsControl/rsGlobalShutDown+ need special care so they
|
||||
are marked with the custom doxygen command +@jsonapi{RS_VERSION,manualwrapper}+
|
||||
and their wrappers are not automatically generated but written manually into
|
||||
+JsonApiServer::JsonApiServer(...)+.
|
||||
|
||||
== Quirks
|
||||
|
||||
=== 64 bits integers handling
|
||||
|
||||
While JSON doesn't have problems representing 64 bits integers JavaScript, Dart
|
||||
and other languages are not capable to handle those numbers natively.
|
||||
To overcome this limitation JSON API output 64 bit integers as an object with
|
||||
two keys, one as proper integer and one as string representation.
|
||||
|
||||
.JSON API 64 bit integer output example
|
||||
[source,json]
|
||||
--------------------------------------------------------------------------------
|
||||
"lobby_id": { "xint64": 6215642878098695544, "xstr64": "6215642878098695544" }
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
So from languages that have proper 64bit integers support like Python or C++ one
|
||||
better read from `xint64` which is represented as a JSON integer, from languages
|
||||
where there is no proper 64bit integers support like JavaScript one can read from
|
||||
`xstr64` which is represented as JSON string (note that the first is not wrapped
|
||||
in "" while the latter is).
|
||||
|
||||
When one input a 64bit integer into the JSON API it first try to parse it as if
|
||||
it was sent the old way for retrocompatibility.
|
||||
|
||||
.JSON API 64 bit integer deprecated format input example
|
||||
[source,json]
|
||||
--------------------------------------------------------------------------------
|
||||
"lobby_id":6215642878098695544
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
This way is *DEPRECATED* and may disappear in the future, it is TEMPORALLY kept
|
||||
only for retrocompatibiliy with old clients.
|
||||
|
||||
If retrocompatible parsing attempt fail then it try to parse with the new way
|
||||
with proper JSON integer format.
|
||||
|
||||
.JSON API 64 bit integer new proper integer format input example
|
||||
[source,json]
|
||||
--------------------------------------------------------------------------------
|
||||
lobby_id": { "xint64": 6215642878098695544 }
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
If this fails then it try to parse with the new way with JSON string format.
|
||||
|
||||
.JSON API 64 bit integer new string format input example
|
||||
[source,json]
|
||||
--------------------------------------------------------------------------------
|
||||
"lobby_id": { "xstr64": "6215642878098695544" }
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
[WARNING]
|
||||
================================================================================
|
||||
Clients written in languages without proper 64bit integers support must
|
||||
use *ONLY* the string format otherwise they will send approximated values and
|
||||
get unexpected results from the JSON API, because parsing will success but the
|
||||
value will not be exactly the one you believe you sent.
|
||||
================================================================================
|
||||
|
||||
|
||||
== A bit of history
|
||||
|
||||
=== First writings about this
|
||||
|
||||
The previous attempt of exposing a RetroShare JSON API is called +libresapi+ and
|
||||
unfortunatley it requires a bunch of boilerplate code when we want to expose
|
||||
something present in the {Cxx} API in the JSON API.
|
||||
|
||||
As an example here you can see the libresapi that exposes part of the retroshare
|
||||
chat {Cxx} API and lot of boilerplate code just to convert {Cxx} objects to JSON
|
||||
|
||||
https://github.com/RetroShare/RetroShare/blob/v0.6.4/libresapi/src/api/ChatHandler.cpp#L44
|
||||
|
||||
To avoid the {Cxx} to JSON and back conversion boilerplate code I have worked out
|
||||
an extension to our {Cxx} serialization code so it is capable to serialize and
|
||||
deserialize to JSON you can see it in this pull request
|
||||
|
||||
https://github.com/RetroShare/RetroShare/pull/1155
|
||||
|
||||
So first step toward having a good API is to take advantage of the fact that RS
|
||||
is now capable of converting C++ objects from and to JSON.
|
||||
|
||||
The current API is accessible via HTTP and unix socket, there is no
|
||||
authentication in both of them, so anyone having access to the HTTP server or to
|
||||
the unix socket can access the API without extra restrictions.
|
||||
Expecially for the HTTP API this is a big risk because also if the http server
|
||||
listen on 127.0.0.1 every application on the machine (even rogue javascript
|
||||
running on your web browser) can access that and for example on android it is
|
||||
not safe at all (because of that I implemented the unix socket access so at
|
||||
least in android API was reasonably safe) because of this.
|
||||
|
||||
A second step to improve the API would be to implement some kind of API
|
||||
authentication mechanism (it would be nice that the mechanism is handled at API
|
||||
level and not at transport level so we can use it for any API trasport not just
|
||||
HTTP for example)
|
||||
|
||||
The HTTP server used by libresapi is libmicrohttpd server that is very minimal,
|
||||
it doesn't provide HTTPS nor modern HTTP goodies, like server notifications,
|
||||
websockets etc. because the lack of support we have a token polling mechanism in
|
||||
libresapi to avoid polling for every thing but it is still ugly, so if we can
|
||||
completely get rid of polling in the API that would be really nice.
|
||||
I have done a crawl to look for a replacement and briefly looked at
|
||||
|
||||
- https://www.gnu.org/software/libmicrohttpd/
|
||||
- http://wolkykim.github.io/libasyncd/
|
||||
- https://github.com/corvusoft/restbed
|
||||
- https://code.facebook.com/posts/1503205539947302/introducing-proxygen-facebook-s-c-http-framework/
|
||||
- https://github.com/cmouse/yahttp
|
||||
|
||||
taking in account a few metrics like modern HTTP goodies support, license,
|
||||
platform support, external dependencies and documentation it seemed to me that
|
||||
restbed is the more appropriate.
|
||||
|
||||
Another source of boilerplate code into libresapi is the mapping between JSON
|
||||
API requests and C++ API methods as an example you can look at this
|
||||
|
||||
https://github.com/RetroShare/RetroShare/blob/v0.6.4/libresapi/src/api/ChatHandler.cpp#L158
|
||||
|
||||
and this
|
||||
|
||||
https://github.com/RetroShare/RetroShare/blob/v0.6.4/libresapi/src/api/ApiServer.cpp#L253
|
||||
|
||||
The abstract logic of this thing is, when libreasapi get a request like
|
||||
+/chat/initiate_distant_chat+ then call
|
||||
+ChatHandler::handleInitiateDistantChatConnexion+ which in turn is just a
|
||||
wrapper of +RsMsgs::initiateDistantChatConnexion+ all this process is basically
|
||||
implemented as boilerplate code and would be unnecessary in a smarter design of
|
||||
the API because almost all the information needed is already present in the
|
||||
C++ API +libretroshare/src/retroshare+.
|
||||
|
||||
So a third step to improve the JSON API would be to remove this source of
|
||||
boilerplate code by automatizing the mapping between C++ and JSON API call.
|
||||
|
||||
This may result a little tricky as language parsing or other adevanced things
|
||||
may be required.
|
||||
|
||||
Hope this dive is useful for you +
|
||||
Cheers +
|
||||
G10h4ck
|
||||
|
||||
=== Second writings about this
|
||||
|
||||
I have been investigating a bit more about:
|
||||
[verse, G10h4ck]
|
||||
________________________________________________________________________________
|
||||
So a third step to improve the JSON API would be to remove this source of
|
||||
boilerplate code by automatizing the mapping between C++ and JSON API call
|
||||
________________________________________________________________________________
|
||||
|
||||
After spending some hours investigating this topic the most reasonable approach
|
||||
seems to:
|
||||
|
||||
1. Properly document headers in +libretroshare/src/retroshare/+ in doxygen syntax
|
||||
specifying wihich params are input and/or output (doxygen sysntax for this is
|
||||
+@param[in/out/inout]+) this will be the API documentation too.
|
||||
|
||||
2. At compile time use doxygen to generate XML description of the headers and use
|
||||
the XML to generate the JSON api server stub.
|
||||
http://www.stack.nl/~dimitri/doxygen/manual/customize.html#xmlgenerator
|
||||
|
||||
3. Enjoy
|
@ -0,0 +1,80 @@
|
||||
/*******************************************************************************
|
||||
* RetroShare JSON API *
|
||||
* *
|
||||
* Copyright (C) 2018-2019 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License version 3 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
registerHandler( "$%apiPath%$",
|
||||
[this](const std::shared_ptr<rb::Session> session)
|
||||
{
|
||||
const std::multimap<std::string, std::string> headers
|
||||
{
|
||||
{ "Connection", "keep-alive" },
|
||||
{ "Content-Type", "text/event-stream" }
|
||||
};
|
||||
session->yield(rb::OK, headers);
|
||||
|
||||
size_t reqSize = session->get_request()->get_header("Content-Length", 0);
|
||||
session->fetch( reqSize, [this](
|
||||
const std::shared_ptr<rb::Session> session,
|
||||
const rb::Bytes& body )
|
||||
{
|
||||
INITIALIZE_API_CALL_JSON_CONTEXT;
|
||||
|
||||
if( !checkRsServicePtrReady(
|
||||
$%instanceName%$, "$%instanceName%$", cAns, session ) )
|
||||
return;
|
||||
|
||||
$%paramsDeclaration%$
|
||||
|
||||
$%inputParamsDeserialization%$
|
||||
|
||||
const std::weak_ptr<rb::Service> weakService(mService);
|
||||
const std::weak_ptr<rb::Session> weakSession(session);
|
||||
$%callbackName%$ = [weakService, weakSession]($%callbackParams%$)
|
||||
{
|
||||
auto session = weakSession.lock();
|
||||
if(!session || session->is_closed()) return;
|
||||
|
||||
auto lService = weakService.lock();
|
||||
if(!lService || lService->is_down()) return;
|
||||
|
||||
$%callbackParamsSerialization%$
|
||||
|
||||
std::stringstream sStream;
|
||||
sStream << "data: " << compactJSON << ctx.mJson << "\n\n";
|
||||
const std::string message = sStream.str();
|
||||
|
||||
lService->schedule( [weakSession, message]()
|
||||
{
|
||||
auto session = weakSession.lock();
|
||||
if(!session || session->is_closed()) return;
|
||||
session->yield(message);
|
||||
$%sessionEarlyClose%$
|
||||
} );
|
||||
};
|
||||
|
||||
$%functionCall%$
|
||||
|
||||
$%outputParamsSerialization%$
|
||||
|
||||
// return them to the API caller
|
||||
std::stringstream message;
|
||||
message << "data: " << compactJSON << cAns.mJson << "\n\n";
|
||||
session->yield(message.str());
|
||||
$%sessionDelayedClose%$
|
||||
} );
|
||||
}, $%requiresAuth%$ );
|
230
libretroshare/src/jsonapi/jsonapi-generator-doxygen.conf
Normal file
230
libretroshare/src/jsonapi/jsonapi-generator-doxygen.conf
Normal file
@ -0,0 +1,230 @@
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
PROJECT_NAME = "libretroshare"
|
||||
|
||||
ALIASES += jsonapi{1}="\xmlonly<jsonapi minversion=\"\1\"/>\endxmlonly"
|
||||
ALIASES += jsonapi{2}="\xmlonly<jsonapi minversion=\"\1\" access=\"\2\"/>\endxmlonly"
|
||||
|
||||
# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
|
||||
# documentation from any documented member that it re-implements.
|
||||
# The default value is: YES.
|
||||
|
||||
INHERIT_DOCS = YES
|
||||
|
||||
# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
|
||||
# according to the Markdown format, which allows for more readable
|
||||
# documentation. See http://daringfireball.net/projects/markdown/ for details.
|
||||
# The output of markdown processing is further processed by doxygen, so you can
|
||||
# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
|
||||
# case of backward compatibilities issues.
|
||||
# The default value is: YES.
|
||||
|
||||
MARKDOWN_SUPPORT = YES
|
||||
|
||||
# When enabled doxygen tries to link words that correspond to documented
|
||||
# classes, or namespaces to their corresponding documentation. Such a link can
|
||||
# be prevented in individual cases by putting a % sign in front of the word or
|
||||
# globally by setting AUTOLINK_SUPPORT to NO.
|
||||
# The default value is: YES.
|
||||
|
||||
AUTOLINK_SUPPORT = YES
|
||||
|
||||
|
||||
# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
|
||||
# documentation are documented, even if no documentation was available. Private
|
||||
# class members and static file members will be hidden unless the
|
||||
# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
|
||||
# Note: This will also disable the warnings about undocumented members that are
|
||||
# normally produced when WARNINGS is set to YES.
|
||||
# The default value is: NO.
|
||||
|
||||
EXTRACT_ALL = YES
|
||||
|
||||
|
||||
# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
|
||||
# undocumented members inside documented classes or files. If set to NO these
|
||||
# members will be included in the various overviews, but no documentation
|
||||
# section is generated. This option has no effect if EXTRACT_ALL is enabled.
|
||||
# The default value is: NO.
|
||||
|
||||
HIDE_UNDOC_MEMBERS = NO
|
||||
|
||||
# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
|
||||
# undocumented classes that are normally visible in the class hierarchy. If set
|
||||
# to NO, these classes will be included in the various overviews. This option
|
||||
# has no effect if EXTRACT_ALL is enabled.
|
||||
# The default value is: NO.
|
||||
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# The INPUT tag is used to specify the files and/or directories that contain
|
||||
# documented source files. You may enter file names like myfile.cpp or
|
||||
# directories like /usr/src/myproject. Separate the files or directories with
|
||||
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
||||
# Note: If this tag is empty the current directory is searched.
|
||||
|
||||
#INPUT =
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
|
||||
# documentation (see: https://www.gnu.org/software/libiconv/) for the list of
|
||||
# possible encodings.
|
||||
# The default value is: UTF-8.
|
||||
|
||||
INPUT_ENCODING = UTF-8
|
||||
|
||||
# If the value of the INPUT tag contains directories, you can use the
|
||||
# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
|
||||
# *.h) to filter out the source-files in the directories.
|
||||
#
|
||||
# Note that for custom extensions or not directly supported extensions you also
|
||||
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
|
||||
# read by doxygen.
|
||||
#
|
||||
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
|
||||
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
|
||||
# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
|
||||
# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
|
||||
# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
|
||||
|
||||
FILE_PATTERNS = *.c \
|
||||
*.cc \
|
||||
*.cxx \
|
||||
*.cpp \
|
||||
*.c++ \
|
||||
*.java \
|
||||
*.ii \
|
||||
*.ixx \
|
||||
*.ipp \
|
||||
*.i++ \
|
||||
*.inl \
|
||||
*.idl \
|
||||
*.ddl \
|
||||
*.odl \
|
||||
*.h \
|
||||
*.hh \
|
||||
*.hxx \
|
||||
*.hpp \
|
||||
*.h++ \
|
||||
*.cs \
|
||||
*.d \
|
||||
*.php \
|
||||
*.php4 \
|
||||
*.php5 \
|
||||
*.phtml \
|
||||
*.inc \
|
||||
*.m \
|
||||
*.markdown \
|
||||
*.md \
|
||||
*.mm \
|
||||
*.dox \
|
||||
*.py \
|
||||
*.pyw \
|
||||
*.f90 \
|
||||
*.f95 \
|
||||
*.f03 \
|
||||
*.f08 \
|
||||
*.f \
|
||||
*.for \
|
||||
*.tcl \
|
||||
*.vhd \
|
||||
*.vhdl \
|
||||
*.ucf \
|
||||
*.qsf
|
||||
|
||||
# The RECURSIVE tag can be used to specify whether or not subdirectories should
|
||||
# be searched for input files as well.
|
||||
# The default value is: NO.
|
||||
|
||||
RECURSIVE = YES
|
||||
|
||||
# The EXCLUDE tag can be used to specify files and/or directories that should be
|
||||
# excluded from the INPUT source files. This way you can easily exclude a
|
||||
# subdirectory from a directory tree whose root is specified with the INPUT tag.
|
||||
#
|
||||
# Note that relative paths are relative to the directory from which doxygen is
|
||||
# run.
|
||||
|
||||
EXCLUDE =
|
||||
|
||||
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
|
||||
# directories that are symbolic links (a Unix file system feature) are excluded
|
||||
# from the input.
|
||||
# The default value is: NO.
|
||||
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
|
||||
# If the value of the INPUT tag contains directories, you can use the
|
||||
# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
|
||||
# certain files from those directories.
|
||||
#
|
||||
# Note that the wildcards are matched against the file with absolute path, so to
|
||||
# exclude all test directories for example use the pattern */test/*
|
||||
|
||||
EXCLUDE_PATTERNS =
|
||||
|
||||
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
|
||||
# (namespaces, classes, functions, etc.) that should be excluded from the
|
||||
# output. The symbol name can be a fully qualified name, a word, or if the
|
||||
# wildcard * is used, a substring. Examples: ANamespace, AClass,
|
||||
# AClass::ANamespace, ANamespace::*Test
|
||||
#
|
||||
# Note that the wildcards are matched against the file with absolute path, so to
|
||||
# exclude all test directories use the pattern */test/*
|
||||
|
||||
EXCLUDE_SYMBOLS =
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the HTML output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
|
||||
# The default value is: YES.
|
||||
|
||||
GENERATE_HTML = NO
|
||||
|
||||
# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
|
||||
# The default value is: YES.
|
||||
|
||||
GENERATE_LATEX = NO
|
||||
|
||||
# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
|
||||
# captures the structure of the code including all documentation.
|
||||
# The default value is: NO.
|
||||
|
||||
GENERATE_XML = YES
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the preprocessor
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
|
||||
# C-preprocessor directives found in the sources and include files.
|
||||
# The default value is: YES.
|
||||
|
||||
ENABLE_PREPROCESSING = YES
|
||||
|
||||
# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
|
||||
# in the source code. If set to NO, only conditional compilation will be
|
||||
# performed. Macro expansion can be done in a controlled way by setting
|
||||
# EXPAND_ONLY_PREDEF to YES.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
|
||||
|
||||
MACRO_EXPANSION = NO
|
||||
|
||||
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
|
||||
# the macro expansion is limited to the macros specified with the PREDEFINED and
|
||||
# EXPAND_AS_DEFINED tags.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
|
||||
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
|
365
libretroshare/src/jsonapi/jsonapi-generator.py
Executable file
365
libretroshare/src/jsonapi/jsonapi-generator.py
Executable file
@ -0,0 +1,365 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
# RetroShare JSON API generator
|
||||
#
|
||||
# Copyright (C) 2019 selankon <selankon@selankon.xyz>
|
||||
# Copyright (C) 2021 Gioacchino Mazzurco <gio@eigenlab.org>
|
||||
# Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the
|
||||
# Free Software Foundation, version 3.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
#
|
||||
# SPDX-FileCopyrightText: Retroshare Team <contact@retroshare.cc>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
|
||||
# Original idea and implementation by G10h4ck (jsonapi-generator.cpp)
|
||||
# Initial python reimplementation by Sehraf
|
||||
#
|
||||
# This python 3 script has superseded the original C++/Qt implementation this
|
||||
# and is now used at build time in without depending on Qt.
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
from string import Template
|
||||
|
||||
|
||||
class MethodParam:
|
||||
_type = ''
|
||||
_name = ''
|
||||
_defval = ''
|
||||
_in = False
|
||||
_out = False
|
||||
_isMultiCallback = False
|
||||
_isSingleCallback = False
|
||||
|
||||
|
||||
class TemplateOwn(Template):
|
||||
delimiter = '$%'
|
||||
pattern = '''
|
||||
\$%(?:
|
||||
(?P<escaped>\$\%) | # Escape sequence of two delimiters
|
||||
(?P<named>[_a-z][_a-z0-9]*)%\$ | # delimiter and a Python identifier
|
||||
{(?P<braced>[_a-z][_a-z0-9]*)} | # delimiter and a braced identifier
|
||||
(?P<invalid>) # Other ill-formed delimiter exprs
|
||||
)
|
||||
'''
|
||||
|
||||
|
||||
def getText(e):
|
||||
return "".join(e.itertext())
|
||||
|
||||
|
||||
def processFile(file):
|
||||
try:
|
||||
dom1 = ET.parse(file).getroot()
|
||||
except FileNotFoundError:
|
||||
print('Can\'t open:', file)
|
||||
|
||||
headerFileInfo = dom1[0].findall('location')[0].attrib['file']
|
||||
headerRelPath = os.path.dirname(headerFileInfo).split('/')[-1] + '/' + os.path.basename(headerFileInfo)
|
||||
|
||||
for sectDef in dom1.findall('.//memberdef'):
|
||||
if sectDef.attrib['kind'] != 'variable' or sectDef.find('.//jsonapi') == None:
|
||||
continue
|
||||
|
||||
instanceName = sectDef.find('name').text
|
||||
typeName = sectDef.find('type/ref').text
|
||||
|
||||
typeFilePath = sectDef.find('type/ref').attrib['refid']
|
||||
|
||||
try:
|
||||
dom2 = ET.parse(doxPrefix + typeFilePath + '.xml').getroot()
|
||||
except FileNotFoundError:
|
||||
print('Can\'t open:', doxPrefix + typeFilePath + '.xml')
|
||||
|
||||
for member in dom2.findall('.//member'):
|
||||
refid = member.attrib['refid']
|
||||
methodName = member.find('name').text
|
||||
|
||||
requiresAuth = True
|
||||
|
||||
defFilePath = refid.split('_')[0] + '.xml'
|
||||
defFile = defFilePath
|
||||
|
||||
print('Looking for', typeName, methodName, 'into', typeFilePath)
|
||||
|
||||
try:
|
||||
defDoc = ET.parse(doxPrefix + defFilePath).getroot()
|
||||
except FileNotFoundError:
|
||||
print('Can\'t open:', doxPrefix + defFilePath)
|
||||
|
||||
memberdef = None
|
||||
for tmpMBD in defDoc.findall('.//memberdef'):
|
||||
tmpId = tmpMBD.attrib['id']
|
||||
tmpKind = tmpMBD.attrib['kind']
|
||||
tmpJsonApiTagList = tmpMBD.findall('.//jsonapi')
|
||||
|
||||
if len(tmpJsonApiTagList) != 0 and tmpId == refid and tmpKind == 'function':
|
||||
tmpJsonApiTag = tmpJsonApiTagList[0]
|
||||
|
||||
tmpAccessValue = None
|
||||
if 'access' in tmpJsonApiTag.attrib:
|
||||
tmpAccessValue = tmpJsonApiTag.attrib['access']
|
||||
|
||||
requiresAuth = 'unauthenticated' != tmpAccessValue;
|
||||
|
||||
if 'manualwrapper' != tmpAccessValue:
|
||||
memberdef = tmpMBD
|
||||
|
||||
break
|
||||
|
||||
if memberdef == None:
|
||||
continue
|
||||
|
||||
apiPath = '/' + instanceName + '/' + methodName
|
||||
|
||||
retvalType = getText(memberdef.find('type'))
|
||||
# Apparently some xml declarations include new lines ('\n') and/or multiple spaces
|
||||
# Strip them using python magic
|
||||
retvalType = ' '.join(retvalType.split())
|
||||
|
||||
paramsMap = {}
|
||||
orderedParamNames = []
|
||||
|
||||
hasInput = False
|
||||
hasOutput = False
|
||||
hasSingleCallback = False
|
||||
hasMultiCallback = False
|
||||
callbackName = ''
|
||||
callbackParams = ''
|
||||
|
||||
for tmpPE in memberdef.findall('param'):
|
||||
mp = MethodParam()
|
||||
|
||||
pName = getText(tmpPE.find('declname'))
|
||||
tmpDefval = tmpPE.find('defval')
|
||||
mp._defval = getText(tmpDefval) if tmpDefval != None else ''
|
||||
pType = getText(tmpPE.find('type'))
|
||||
|
||||
if pType.startswith('const '): pType = pType[6:]
|
||||
if pType.startswith('std::function'):
|
||||
if pType.endswith('&'): pType = pType[:-1]
|
||||
if pName.startswith('multiCallback'):
|
||||
mp._isMultiCallback = True
|
||||
hasMultiCallback = True
|
||||
elif pName.startswith('callback'):
|
||||
mp._isSingleCallback = True
|
||||
hasSingleCallback = True
|
||||
callbackName = pName
|
||||
callbackParams = pType
|
||||
else:
|
||||
pType = pType.replace('&', '').replace(' ', '')
|
||||
|
||||
# Apparently some xml declarations include new lines ('\n') and/or multiple spaces
|
||||
# Strip them using python magic
|
||||
pType = ' '.join(pType.split())
|
||||
mp._defval = ' '.join(mp._defval.split())
|
||||
|
||||
mp._type = pType
|
||||
mp._name = pName
|
||||
|
||||
paramsMap[pName] = mp
|
||||
orderedParamNames.append(pName)
|
||||
|
||||
for tmpPN in memberdef.findall('.//parametername'):
|
||||
tmpParam = paramsMap[tmpPN.text]
|
||||
tmpD = tmpPN.attrib['direction'] if 'direction' in tmpPN.attrib else ''
|
||||
|
||||
if 'in' in tmpD:
|
||||
tmpParam._in = True
|
||||
hasInput = True
|
||||
if 'out' in tmpD:
|
||||
tmpParam._out = True
|
||||
hasOutput = True
|
||||
|
||||
# Params sanity check
|
||||
for pmKey in paramsMap:
|
||||
pm = paramsMap[pmKey]
|
||||
if not (pm._isMultiCallback or pm._isSingleCallback or pm._in or pm._out):
|
||||
print('ERROR', 'Parameter:', pm._name, 'of:', apiPath,
|
||||
'declared in:', headerRelPath,
|
||||
'miss doxygen parameter direction attribute!',
|
||||
defFile)
|
||||
sys.exit()
|
||||
|
||||
functionCall = '\t\t'
|
||||
if retvalType != 'void':
|
||||
functionCall += retvalType + ' retval = '
|
||||
hasOutput = True
|
||||
functionCall += instanceName + '->' + methodName + '('
|
||||
functionCall += ', '.join(orderedParamNames) + ');\n'
|
||||
|
||||
print(instanceName, apiPath, retvalType, typeName, methodName)
|
||||
for pn in orderedParamNames:
|
||||
mp = paramsMap[pn]
|
||||
print('\t', mp._type, mp._name, mp._in, mp._out)
|
||||
|
||||
inputParamsDeserialization = ''
|
||||
if hasInput:
|
||||
inputParamsDeserialization += '\t\t{\n'
|
||||
inputParamsDeserialization += '\t\t\tRsGenericSerializer::SerializeContext& ctx(cReq);\n'
|
||||
inputParamsDeserialization += '\t\t\tRsGenericSerializer::SerializeJob j(RsGenericSerializer::FROM_JSON);\n';
|
||||
|
||||
outputParamsSerialization = ''
|
||||
if hasOutput:
|
||||
outputParamsSerialization += '\t\t{\n'
|
||||
outputParamsSerialization += '\t\t\tRsGenericSerializer::SerializeContext& ctx(cAns);\n'
|
||||
outputParamsSerialization += '\t\t\tRsGenericSerializer::SerializeJob j(RsGenericSerializer::TO_JSON);\n';
|
||||
|
||||
paramsDeclaration = ''
|
||||
for pn in orderedParamNames:
|
||||
mp = paramsMap[pn]
|
||||
paramsDeclaration += '\t\t' + mp._type + ' ' + mp._name
|
||||
if mp._defval != '':
|
||||
paramsDeclaration += ' = ' + mp._defval
|
||||
paramsDeclaration += ';\n'
|
||||
if mp._in:
|
||||
inputParamsDeserialization += '\t\t\tRS_SERIAL_PROCESS('
|
||||
inputParamsDeserialization += mp._name + ');\n'
|
||||
if mp._out:
|
||||
outputParamsSerialization += '\t\t\tRS_SERIAL_PROCESS('
|
||||
outputParamsSerialization += mp._name + ');\n'
|
||||
|
||||
if hasInput:
|
||||
inputParamsDeserialization += '\t\t}\n'
|
||||
if retvalType != 'void':
|
||||
outputParamsSerialization += '\t\t\tRS_SERIAL_PROCESS(retval);\n'
|
||||
if hasOutput:
|
||||
outputParamsSerialization += '\t\t}\n'
|
||||
|
||||
captureVars = ''
|
||||
|
||||
sessionEarlyClose = ''
|
||||
if hasSingleCallback:
|
||||
sessionEarlyClose = 'session->close();'
|
||||
|
||||
sessionDelayedClose = ''
|
||||
if hasMultiCallback:
|
||||
sessionDelayedClose = """
|
||||
RsThread::async( [=]()
|
||||
{
|
||||
std::this_thread::sleep_for(
|
||||
std::chrono::seconds(maxWait+120) );
|
||||
auto lService = weakService.lock();
|
||||
if(!lService || lService->is_down()) return;
|
||||
lService->schedule( [=]()
|
||||
{
|
||||
auto session = weakSession.lock();
|
||||
if(session && session->is_open())
|
||||
session->close();
|
||||
} );
|
||||
} );
|
||||
"""
|
||||
captureVars = 'this'
|
||||
|
||||
callbackParamsSerialization = ''
|
||||
|
||||
if hasSingleCallback or hasMultiCallback or (callbackParams.find('(') + 2 < callbackParams.find(')')):
|
||||
cbs = ''
|
||||
|
||||
callbackParams = callbackParams.split('(')[1]
|
||||
callbackParams = callbackParams.split(')')[0]
|
||||
|
||||
cbs += '\t\t\tRsGenericSerializer::SerializeContext ctx;\n'
|
||||
|
||||
for cbPar in callbackParams.split(','):
|
||||
isConst = cbPar.startswith('const ')
|
||||
pSep = ' '
|
||||
isRef = '&' in cbPar
|
||||
if isRef: pSep = '&'
|
||||
sepIndex = cbPar.rfind(pSep) + 1
|
||||
cpt = cbPar[0:sepIndex][6:]
|
||||
cpn = cbPar[sepIndex:]
|
||||
|
||||
cbs += '\t\t\tRsTypeSerializer::serial_process('
|
||||
cbs += 'RsGenericSerializer::TO_JSON, ctx, '
|
||||
if isConst:
|
||||
cbs += 'const_cast<'
|
||||
cbs += cpt
|
||||
cbs += '>('
|
||||
cbs += cpn
|
||||
if isConst: cbs += ')'
|
||||
cbs += ', "'
|
||||
cbs += cpn
|
||||
cbs += '" );\n'
|
||||
|
||||
callbackParamsSerialization += cbs
|
||||
|
||||
substitutionsMap = dict()
|
||||
substitutionsMap['paramsDeclaration'] = paramsDeclaration
|
||||
substitutionsMap['inputParamsDeserialization'] = inputParamsDeserialization
|
||||
substitutionsMap['outputParamsSerialization'] = outputParamsSerialization
|
||||
substitutionsMap['instanceName'] = instanceName
|
||||
substitutionsMap['functionCall'] = functionCall
|
||||
substitutionsMap['apiPath'] = apiPath
|
||||
substitutionsMap['sessionEarlyClose'] = sessionEarlyClose
|
||||
substitutionsMap['sessionDelayedClose'] = sessionDelayedClose
|
||||
substitutionsMap['captureVars'] = captureVars
|
||||
substitutionsMap['callbackName'] = callbackName
|
||||
substitutionsMap['callbackParams'] = callbackParams
|
||||
substitutionsMap['callbackParamsSerialization'] = callbackParamsSerialization
|
||||
substitutionsMap['requiresAuth'] = 'true' if requiresAuth else 'false'
|
||||
|
||||
# print(substitutionsMap)
|
||||
|
||||
templFilePath = sourcePath
|
||||
if hasMultiCallback or hasSingleCallback:
|
||||
templFilePath += '/async-method-wrapper-template.cpp.tmpl'
|
||||
else:
|
||||
templFilePath += '/method-wrapper-template.cpp.tmpl'
|
||||
|
||||
templFile = open(templFilePath, 'r')
|
||||
wrapperDef = TemplateOwn(templFile.read())
|
||||
|
||||
tmp = wrapperDef.substitute(substitutionsMap)
|
||||
wrappersDefFile.write(tmp)
|
||||
|
||||
cppApiIncludesSet.add('#include "' + headerRelPath + '"\n')
|
||||
|
||||
|
||||
if len(sys.argv) != 3:
|
||||
print('Usage:', sys.argv[0], 'SOURCE_PATH OUTPUT_PATH Got:', sys.argv[:])
|
||||
sys.exit(-1)
|
||||
|
||||
sourcePath = str(sys.argv[1])
|
||||
outputPath = str(sys.argv[2])
|
||||
doxPrefix = outputPath + '/xml/'
|
||||
|
||||
try:
|
||||
wrappersDefFile = open(outputPath + '/jsonapi-wrappers.inl', 'w')
|
||||
except FileNotFoundError:
|
||||
print('Can\'t open:', outputPath + '/jsonapi-wrappers.inl')
|
||||
|
||||
try:
|
||||
cppApiIncludesFile = open(outputPath + '/jsonapi-includes.inl', 'w');
|
||||
except FileNotFoundError:
|
||||
print('Can\'t open:', outputPath + '/jsonapi-includes.inl')
|
||||
|
||||
cppApiIncludesSet = set()
|
||||
|
||||
filesIterator = None
|
||||
try:
|
||||
filesIterator = os.listdir(doxPrefix)
|
||||
except FileNotFoundError:
|
||||
print("Doxygen xml output dir not found: ", doxPrefix)
|
||||
os.exit(-1)
|
||||
|
||||
for file in filesIterator:
|
||||
if file.endswith("8h.xml"):
|
||||
processFile(os.path.join(doxPrefix, file))
|
||||
|
||||
|
||||
for incl in cppApiIncludesSet:
|
||||
cppApiIncludesFile.write(incl)
|
@ -796,8 +796,9 @@ void JsonApiServer::run()
|
||||
}
|
||||
catch(std::exception& e)
|
||||
{
|
||||
RsErr() << __PRETTY_FUNCTION__ << " Failure starting JSON API server: "
|
||||
<< e.what() << std::endl;
|
||||
/* TODO: find a way to report back programmatically if failed listening
|
||||
* port */
|
||||
RS_ERR("Failure starting JSON API server: ", e.what());
|
||||
print_stacktrace();
|
||||
return;
|
||||
}
|
||||
|
50
libretroshare/src/jsonapi/method-wrapper-template.cpp.tmpl
Normal file
50
libretroshare/src/jsonapi/method-wrapper-template.cpp.tmpl
Normal file
@ -0,0 +1,50 @@
|
||||
/*******************************************************************************
|
||||
* RetroShare JSON API *
|
||||
* *
|
||||
* Copyright (C) 2018-2019 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
registerHandler( "$%apiPath%$",
|
||||
[](const std::shared_ptr<rb::Session> session)
|
||||
{
|
||||
size_t reqSize = session->get_request()->get_header("Content-Length", 0);
|
||||
session->fetch( reqSize, [](
|
||||
const std::shared_ptr<rb::Session> session,
|
||||
const rb::Bytes& body )
|
||||
{
|
||||
INITIALIZE_API_CALL_JSON_CONTEXT;
|
||||
|
||||
if( !checkRsServicePtrReady(
|
||||
$%instanceName%$, "$%instanceName%$", cAns, session ) )
|
||||
return;
|
||||
|
||||
$%paramsDeclaration%$
|
||||
|
||||
// deserialize input parameters from JSON
|
||||
$%inputParamsDeserialization%$
|
||||
|
||||
// call retroshare C++ API
|
||||
$%functionCall%$
|
||||
|
||||
// serialize out parameters and return value to JSON
|
||||
$%outputParamsSerialization%$
|
||||
|
||||
// return them to the API caller
|
||||
DEFAULT_API_CALL_JSON_RETURN(rb::OK);
|
||||
} );
|
||||
}, $%requiresAuth%$ );
|
||||
|
@ -1,4 +1,4 @@
|
||||
# SPDX-FileCopyrightText: (C) 2004-2019 Retroshare Team <contact@retroshare.cc>
|
||||
# SPDX-FileCopyrightText: (C) 2004-2021 Retroshare Team <contact@retroshare.cc>
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
!include("../../retroshare.pri"): error("Could not include file ../../retroshare.pri")
|
||||
@ -207,7 +207,7 @@ linux-* {
|
||||
LIBS *= -ldl
|
||||
|
||||
DEFINES *= PLUGIN_DIR=\"\\\"$${PLUGIN_DIR}\\\"\"
|
||||
DEFINES *= DATA_DIR=\"\\\"$${DATA_DIR}\\\"\"
|
||||
DEFINES *= RS_DATA_DIR=\"\\\"$${RS_DATA_DIR}\\\"\"
|
||||
}
|
||||
|
||||
linux-g++ {
|
||||
@ -291,7 +291,7 @@ mac {
|
||||
#LIBS += -lsqlite3
|
||||
|
||||
DEFINES *= PLUGIN_DIR=\"\\\"$${PLUGIN_DIR}\\\"\"
|
||||
DEFINES *= DATA_DIR=\"\\\"$${DATA_DIR}\\\"\"
|
||||
DEFINES *= RS_DATA_DIR=\"\\\"$${RS_DATA_DIR}\\\"\"
|
||||
}
|
||||
|
||||
################################# FreeBSD ##########################################
|
||||
@ -365,6 +365,7 @@ HEADERS += chat/distantchat.h \
|
||||
HEADERS += pqi/authssl.h \
|
||||
pqi/authgpg.h \
|
||||
pgp/pgphandler.h \
|
||||
pgp/openpgpsdkhandler.h \
|
||||
pgp/pgpkeyutil.h \
|
||||
pqi/pqifdbin.h \
|
||||
pqi/rstcpsocket.h \
|
||||
@ -511,7 +512,8 @@ HEADERS += util/folderiterator.h \
|
||||
util/cxx11retrocompat.h \
|
||||
util/cxx14retrocompat.h \
|
||||
util/cxx17retrocompat.h \
|
||||
util/rsurl.h
|
||||
util/cxx23retrocompat.h \
|
||||
util/rsurl.h
|
||||
|
||||
SOURCES += ft/ftchunkmap.cc \
|
||||
ft/ftcontroller.cc \
|
||||
@ -538,6 +540,7 @@ SOURCES += chat/distantchat.cc \
|
||||
SOURCES += pqi/authgpg.cc \
|
||||
pqi/authssl.cc \
|
||||
pgp/pgphandler.cc \
|
||||
pgp/openpgpsdkhandler.cc \
|
||||
pgp/pgpkeyutil.cc \
|
||||
pgp/rscertificate.cc \
|
||||
pgp/pgpauxutils.cc \
|
||||
@ -1132,6 +1135,8 @@ test_bitdht {
|
||||
################################# Android #####################################
|
||||
|
||||
android-* {
|
||||
lessThan(ANDROID_API_VERSION, 24) {
|
||||
|
||||
## TODO: This probably disable largefile support and maybe is not necessary with
|
||||
## __ANDROID_API__ >= 24 hence should be made conditional or moved to a
|
||||
## compatibility header
|
||||
@ -1139,12 +1144,26 @@ android-* {
|
||||
DEFINES *= "fseeko64=fseeko"
|
||||
DEFINES *= "ftello64=ftello"
|
||||
|
||||
## @See: rs_android/README-ifaddrs-android.adoc
|
||||
HEADERS += \
|
||||
rs_android/ifaddrs-android.h \
|
||||
rs_android/LocalArray.h \
|
||||
rs_android/ScopedFd.h
|
||||
}
|
||||
|
||||
## Static library are very susceptible to order in command line
|
||||
sLibs = bz2 $$RS_UPNP_LIB $$RS_SQL_LIB ssl crypto
|
||||
|
||||
LIBS += $$linkStaticLibs(sLibs)
|
||||
PRE_TARGETDEPS += $$pretargetStaticLibs(sLibs)
|
||||
|
||||
HEADERS += util/androiddebug.h
|
||||
HEADERS += \
|
||||
rs_android/androidcoutcerrcatcher.hpp \
|
||||
rs_android/retroshareserviceandroid.hpp \
|
||||
rs_android/rsjni.hpp
|
||||
|
||||
SOURCES += rs_android/rsjni.cpp \
|
||||
rs_android/retroshareserviceandroid.cpp \
|
||||
rs_android/errorconditionwrap.cpp
|
||||
}
|
||||
|
||||
|
1810
libretroshare/src/pgp/openpgpsdkhandler.cc
Normal file
1810
libretroshare/src/pgp/openpgpsdkhandler.cc
Normal file
File diff suppressed because it is too large
Load Diff
116
libretroshare/src/pgp/openpgpsdkhandler.h
Normal file
116
libretroshare/src/pgp/openpgpsdkhandler.h
Normal file
@ -0,0 +1,116 @@
|
||||
/*******************************************************************************
|
||||
* libretroshare/src/pgp: pgphandler.h *
|
||||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright 2018 Cyril Soler <csoler@users.sourceforge.net> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public License *
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include "util/rsthreads.h"
|
||||
#include "pgp/pgphandler.h"
|
||||
#include "retroshare/rstypes.h"
|
||||
|
||||
extern "C" {
|
||||
// we should make sure later on to get rid of these structures in the .h
|
||||
#include "openpgpsdk/keyring.h"
|
||||
}
|
||||
|
||||
/// This class offer an abstract pgp handler to be used in RetroShare.
|
||||
class OpenPGPSDKHandler: public PGPHandler
|
||||
{
|
||||
public:
|
||||
OpenPGPSDKHandler( const std::string& path_to_public_keyring,
|
||||
const std::string& path_to_secret_keyring,
|
||||
const std::string& path_to_trust_database,
|
||||
const std::string& pgp_lock_file) ;
|
||||
|
||||
virtual ~OpenPGPSDKHandler() ;
|
||||
|
||||
//================================================================================================//
|
||||
// Implemented API from PGPHandler //
|
||||
//================================================================================================//
|
||||
|
||||
//virtual std::string makeRadixEncodedPGPKey(uint32_t key_index,bool include_signatures) override;
|
||||
virtual bool removeKeysFromPGPKeyring(const std::set<RsPgpId>& key_ids,std::string& backup_file,uint32_t& error_code) override;
|
||||
virtual bool availableGPGCertificatesWithPrivateKeys(std::list<RsPgpId>& ids) override;
|
||||
virtual bool GeneratePGPCertificate(const std::string& name, const std::string& email, const std::string& passphrase, RsPgpId& pgpId, const int keynumbits, std::string& errString) override;
|
||||
|
||||
virtual std::string SaveCertificateToString(const RsPgpId& id,bool include_signatures) const override;
|
||||
virtual bool exportPublicKey( const RsPgpId& id, unsigned char*& mem_block, size_t& mem_size, bool armoured, bool include_signatures ) const override;
|
||||
|
||||
virtual bool exportGPGKeyPair(const std::string& filename,const RsPgpId& exported_key_id) const override;
|
||||
virtual bool exportGPGKeyPairToString( std::string& data, const RsPgpId& exportedKeyId, bool includeSignatures, std::string& errorMsg ) const override;
|
||||
virtual bool getGPGDetailsFromBinaryBlock(const unsigned char *mem_block,size_t mem_size,RsPgpId& key_id, std::string& name, std::list<RsPgpId>& signers) const override;
|
||||
virtual bool importGPGKeyPair(const std::string& filename,RsPgpId& imported_key_id,std::string& import_error) override;
|
||||
virtual bool importGPGKeyPairFromString(const std::string &data, RsPgpId &imported_key_id, std::string &import_error) override;
|
||||
virtual bool LoadCertificateFromBinaryData(const unsigned char *data,uint32_t data_len,RsPgpId& id,std::string& error_string) override;
|
||||
virtual bool LoadCertificateFromString(const std::string& pgp_cert,RsPgpId& id,std::string& error_string) override;
|
||||
virtual bool encryptTextToFile(const RsPgpId& key_id,const std::string& text,const std::string& outfile) override;
|
||||
virtual bool encryptDataBin(const RsPgpId& key_id,const void *data, const uint32_t len, unsigned char *encrypted_data, unsigned int *encrypted_data_len) override;
|
||||
virtual bool decryptDataBin(const RsPgpId& /*key_id*/,const void *encrypted_data, const uint32_t encrypted_len, unsigned char *data, unsigned int *data_len) override;
|
||||
virtual bool decryptTextFromFile(const RsPgpId&,std::string& text,const std::string& inputfile) override;
|
||||
virtual bool SignDataBin(const RsPgpId& id,const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen,bool use_raw_signature, std::string reason /* = "" */) override;
|
||||
virtual bool privateSignCertificate(const RsPgpId& ownId,const RsPgpId& id_of_key_to_sign) override;
|
||||
virtual bool VerifySignBin(const void *literal_data, uint32_t literal_data_length, unsigned char *sign, unsigned int sign_len, const PGPFingerprintType& key_fingerprint) override;
|
||||
virtual bool getKeyFingerprint(const RsPgpId& id, RsPgpFingerprint& fp) const override;
|
||||
virtual bool haveSecretKey(const RsPgpId& id) const override;
|
||||
virtual bool syncDatabase() override;
|
||||
private:
|
||||
bool locked_syncPublicKeyring() ;
|
||||
|
||||
void initCertificateInfo(PGPCertificateInfo& cert,const ops_keydata_t *keydata,uint32_t i) ;
|
||||
bool LoadCertificate(const unsigned char *data,uint32_t data_len,bool armoured,RsPgpId& id,std::string& error_string) ;
|
||||
|
||||
// Returns true if the signatures have been updated
|
||||
//
|
||||
bool validateAndUpdateSignatures(PGPCertificateInfo& cert,const ops_keydata_t *keydata) ;
|
||||
|
||||
/** Check public/private key and import them into the keyring
|
||||
* @param keyring keyring with the new public/private key pair. Will be freed by the function.
|
||||
* @param imported_key_id PGP id of the imported key
|
||||
* @param import_error human readbale error message
|
||||
* @returns true on success
|
||||
* */
|
||||
bool checkAndImportKeyPair(ops_keyring_t *keyring, RsPgpId& imported_key_id,std::string& import_error);
|
||||
|
||||
const ops_keydata_t *locked_getPublicKey(const RsPgpId&,bool stamp_the_key) const;
|
||||
const ops_keydata_t *locked_getSecretKey(const RsPgpId&) const ;
|
||||
|
||||
void locked_mergeKeyringFromDisk(ops_keyring_t *keyring, std::map<RsPgpId,PGPCertificateInfo>& kmap, const std::string& keyring_file) ;
|
||||
bool locked_addOrMergeKey(ops_keyring_t *keyring,std::map<RsPgpId,PGPCertificateInfo>& kmap,const ops_keydata_t *keydata) ;
|
||||
|
||||
// Members.
|
||||
//
|
||||
ops_keyring_t *_pubring ;
|
||||
ops_keyring_t *_secring ;
|
||||
|
||||
void printOPSKeys() const;
|
||||
|
||||
// Helper functions.
|
||||
//
|
||||
static std::string makeRadixEncodedPGPKey(const ops_keydata_t *key,bool include_signatures) ;
|
||||
static ops_keyring_t *allocateOPSKeyring() ;
|
||||
static void addNewKeyToOPSKeyring(ops_keyring_t*, const ops_keydata_t&) ;
|
||||
static bool mergeKeySignatures(ops_keydata_t *dst,const ops_keydata_t *src) ; // returns true if signature lists are different
|
||||
};
|
@ -34,17 +34,17 @@ PgpAuxUtilsImpl::PgpAuxUtilsImpl()
|
||||
|
||||
const RsPgpId& PgpAuxUtilsImpl::getPGPOwnId()
|
||||
{
|
||||
return AuthGPG::getAuthGPG()->getGPGOwnId();
|
||||
return AuthPGP::getPgpOwnId();
|
||||
}
|
||||
|
||||
RsPgpId PgpAuxUtilsImpl::getPGPId(const RsPeerId& sslid)
|
||||
RsPgpId PgpAuxUtilsImpl::getPgpId(const RsPeerId& sslid)
|
||||
{
|
||||
return rsPeers->getGPGId(sslid);
|
||||
}
|
||||
|
||||
bool PgpAuxUtilsImpl::getKeyFingerprint(const RsPgpId& id,PGPFingerprintType& fp) const
|
||||
{
|
||||
return AuthGPG::getAuthGPG()->getKeyFingerprint(id, fp);
|
||||
return AuthPGP::getKeyFingerprint(id, fp);
|
||||
}
|
||||
|
||||
bool PgpAuxUtilsImpl::VerifySignBin(const void *data,
|
||||
@ -54,17 +54,17 @@ bool PgpAuxUtilsImpl::VerifySignBin(const void *data,
|
||||
const PGPFingerprintType& withfingerprint)
|
||||
|
||||
{
|
||||
return AuthGPG::getAuthGPG()->VerifySignBin(data, len, sign, signlen, withfingerprint);
|
||||
return AuthPGP::VerifySignBin(data, len, sign, signlen, withfingerprint);
|
||||
}
|
||||
|
||||
bool PgpAuxUtilsImpl::getGPGAllList(std::list<RsPgpId> &ids)
|
||||
bool PgpAuxUtilsImpl::getPgpAllList(std::list<RsPgpId> &ids)
|
||||
{
|
||||
return AuthGPG::getAuthGPG()->getGPGAllList(ids);
|
||||
return AuthPGP::getPgpAllList(ids);
|
||||
}
|
||||
|
||||
bool PgpAuxUtilsImpl::parseSignature(unsigned char *sign, unsigned int signlen, RsPgpId& issuer) const
|
||||
{
|
||||
return AuthGPG::getAuthGPG()->parseSignature(sign,signlen,issuer);
|
||||
return AuthPGP::parseSignature(sign,signlen,issuer);
|
||||
}
|
||||
|
||||
|
||||
|
@ -35,8 +35,8 @@ class PgpAuxUtils
|
||||
virtual ~PgpAuxUtils(){}
|
||||
|
||||
virtual const RsPgpId &getPGPOwnId() = 0;
|
||||
virtual RsPgpId getPGPId(const RsPeerId& sslid) = 0;
|
||||
virtual bool getGPGAllList(std::list<RsPgpId> &ids) = 0;
|
||||
virtual RsPgpId getPgpId(const RsPeerId& sslid) = 0;
|
||||
virtual bool getPgpAllList(std::list<RsPgpId> &ids) = 0;
|
||||
virtual bool getKeyFingerprint(const RsPgpId& id,PGPFingerprintType& fp) const = 0;
|
||||
|
||||
virtual bool parseSignature(unsigned char *sign, unsigned int signlen, RsPgpId& issuer) const =0;
|
||||
@ -49,12 +49,12 @@ public:
|
||||
PgpAuxUtilsImpl();
|
||||
|
||||
virtual const RsPgpId &getPGPOwnId();
|
||||
virtual RsPgpId getPGPId(const RsPeerId& sslid);
|
||||
virtual RsPgpId getPgpId(const RsPeerId& sslid);
|
||||
|
||||
virtual bool parseSignature(unsigned char *sign, unsigned int signlen, RsPgpId& issuer) const ;
|
||||
virtual bool getKeyFingerprint(const RsPgpId& id,PGPFingerprintType& fp) const;
|
||||
virtual bool VerifySignBin(const void *data, uint32_t len, unsigned char *sign, unsigned int signlen, const PGPFingerprintType& withfingerprint);
|
||||
virtual bool getGPGAllList(std::list<RsPgpId> &ids);
|
||||
virtual bool getPgpAllList(std::list<RsPgpId> &ids);
|
||||
};
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -29,12 +29,6 @@
|
||||
#include <util/rsthreads.h>
|
||||
#include <retroshare/rstypes.h>
|
||||
|
||||
extern "C" {
|
||||
#include <openpgpsdk/types.h>
|
||||
#include <openpgpsdk/keyring.h>
|
||||
#include <openpgpsdk/keyring_local.h>
|
||||
}
|
||||
|
||||
typedef std::string (*PassphraseCallback)(void *data, const char *uid_title, const char *uid_hint, const char *passphrase_info, int prev_was_bad,bool *cancelled) ;
|
||||
|
||||
class PGPCertificateInfo
|
||||
@ -56,9 +50,11 @@ class PGPCertificateInfo
|
||||
mutable rstime_t _time_stamp ; // last time the key was used (received, used for signature verification, etc)
|
||||
|
||||
PGPFingerprintType _fpr; /* fingerprint */
|
||||
// RsPgpId _key_id ;
|
||||
|
||||
uint32_t _key_index ; // index to array of keys in the public keyring
|
||||
// Index to array of keys in the public keyring. Dependign on the specific implementation
|
||||
// of how the keyring is stored, this may be used differently.
|
||||
|
||||
uint32_t _key_index ;
|
||||
|
||||
static const uint32_t PGP_CERTIFICATE_FLAG_ACCEPT_CONNEXION = 0x0001 ;
|
||||
static const uint32_t PGP_CERTIFICATE_FLAG_HAS_OWN_SIGNATURE = 0x0002 ;
|
||||
@ -80,53 +76,87 @@ class PGPCertificateInfo
|
||||
class PGPHandler
|
||||
{
|
||||
public:
|
||||
PGPHandler( const std::string& path_to_public_keyring,
|
||||
PGPHandler( const std::string& path_to_public_keyring,
|
||||
const std::string& path_to_secret_keyring,
|
||||
const std::string& path_to_trust_database,
|
||||
const std::string& pgp_lock_file) ;
|
||||
|
||||
virtual ~PGPHandler() ;
|
||||
|
||||
/**
|
||||
//=======================================================================================//
|
||||
// Methods that needs to be derived depending on how PGP is implemented //
|
||||
//=======================================================================================//
|
||||
|
||||
// Removes the given keys from the keyring. Also backup the keyring to a file which name is automatically generated
|
||||
// and given pack for proper display.
|
||||
//
|
||||
virtual bool removeKeysFromPGPKeyring(const std::set<RsPgpId>& key_ids,std::string& backup_file,uint32_t& error_code) =0;
|
||||
//virtual std::string makeRadixEncodedPGPKey(uint32_t key_index,bool include_signatures) =0;
|
||||
|
||||
virtual bool availableGPGCertificatesWithPrivateKeys(std::list<RsPgpId>& ids)=0;
|
||||
virtual bool GeneratePGPCertificate(const std::string& name, const std::string& email, const std::string& passwd, RsPgpId& pgpId, const int keynumbits, std::string& errString) =0;
|
||||
|
||||
virtual std::string SaveCertificateToString(const RsPgpId& id,bool include_signatures) const=0;
|
||||
|
||||
/** The caller is in charge of freeing `mem` once finished */
|
||||
virtual bool exportPublicKey( const RsPgpId& id, unsigned char*& mem_block, size_t& mem_size, bool armoured, bool include_signatures ) const =0;
|
||||
|
||||
virtual bool exportGPGKeyPair(const std::string& filename,const RsPgpId& exported_key_id) const=0;
|
||||
virtual bool exportGPGKeyPairToString( std::string& data, const RsPgpId& exportedKeyId, bool includeSignatures, std::string& errorMsg ) const =0;
|
||||
|
||||
// Gets info about the key. Who are the signers, what's the owner's name, etc.
|
||||
//
|
||||
virtual bool getGPGDetailsFromBinaryBlock(const unsigned char *mem,size_t mem_size,RsPgpId& key_id, std::string& name, std::list<RsPgpId>& signers) const =0;
|
||||
|
||||
virtual bool importGPGKeyPair(const std::string& filename,RsPgpId& imported_id,std::string& import_error) =0;
|
||||
/**
|
||||
* @param ids list of gpg certificate ids (note, not the actual certificates)
|
||||
*/
|
||||
|
||||
virtual bool importGPGKeyPairFromString(const std::string& data,RsPgpId& imported_id,std::string& import_error) =0;
|
||||
|
||||
virtual bool LoadCertificateFromString(const std::string& pem, RsPgpId& gpg_id, std::string& error_string)=0;
|
||||
virtual bool LoadCertificateFromBinaryData(const unsigned char *bin_data,uint32_t bin_data_len, RsPgpId& gpg_id, std::string& error_string)=0;
|
||||
|
||||
virtual bool encryptTextToFile(const RsPgpId& key_id,const std::string& text,const std::string& outfile) =0;
|
||||
virtual bool decryptTextFromFile(const RsPgpId& key_id,std::string& text,const std::string& encrypted_inputfile) =0;
|
||||
|
||||
// The client should supply a memory chunk to store the data. The length will be updated to the real length of the data.
|
||||
//
|
||||
virtual bool encryptDataBin(const RsPgpId& key_id,const void *data, const uint32_t len , unsigned char *encrypted_data, unsigned int *encrypted_data_len) =0;
|
||||
virtual bool decryptDataBin(const RsPgpId& key_id,const void *encrypted_data, const uint32_t encrypted_len , unsigned char *data, unsigned int *data_len) =0;
|
||||
|
||||
virtual bool SignDataBin(const RsPgpId& id, const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen, bool make_raw_signature=false, std::string reason = "") =0;
|
||||
virtual bool privateSignCertificate(const RsPgpId& own_id,const RsPgpId& id_of_key_to_sign) =0;
|
||||
virtual bool VerifySignBin(const void *data, uint32_t data_len, unsigned char *sign, unsigned int sign_len, const PGPFingerprintType& withfingerprint) =0;
|
||||
/**
|
||||
* @brief Get PGP fingerprint for the given key
|
||||
* @param id PGP 64bit key id
|
||||
* @param fp storage for the retrived key fingerpring, the contained value
|
||||
* is meaningfull only if true is returned
|
||||
* @return true if the key was found, false if not
|
||||
*/
|
||||
virtual bool getKeyFingerprint(const RsPgpId& id, RsPgpFingerprint& fp) const=0;
|
||||
|
||||
virtual bool haveSecretKey(const RsPgpId& id) const =0;
|
||||
|
||||
// Syncs the keyrings and trust database between memory and disk. The algorithm is:
|
||||
// 1 - lock the keyrings
|
||||
// 2 - compare file modification dates with last writing date
|
||||
// - if file is modified, load it, and merge with memory
|
||||
// 3 - look into memory modification flags
|
||||
// - if flag says keyring has changed, write to disk
|
||||
//
|
||||
virtual bool syncDatabase() =0;
|
||||
|
||||
|
||||
//=======================================================================================//
|
||||
// Common methods to PGPHandler //
|
||||
//=======================================================================================//
|
||||
|
||||
bool getGPGFilteredList(std::list<RsPgpId>& list,bool (*filter)(const PGPCertificateInfo&) = NULL) const ;
|
||||
bool haveSecretKey(const RsPgpId& id) const ;
|
||||
|
||||
bool importGPGKeyPair(const std::string& filename,RsPgpId& imported_id,std::string& import_error) ;
|
||||
bool importGPGKeyPairFromString(const std::string& data,RsPgpId& imported_id,std::string& import_error) ;
|
||||
bool exportGPGKeyPair(const std::string& filename,const RsPgpId& exported_id) const ;
|
||||
bool exportGPGKeyPairToString(
|
||||
std::string& data, const RsPgpId& exportedKeyId,
|
||||
bool includeSignatures, std::string& errorMsg ) const;
|
||||
|
||||
bool availableGPGCertificatesWithPrivateKeys(std::list<RsPgpId>& ids);
|
||||
bool GeneratePGPCertificate(const std::string& name, const std::string& email, const std::string& passwd, RsPgpId& pgpId, const int keynumbits, std::string& errString) ;
|
||||
|
||||
bool LoadCertificateFromString(const std::string& pem, RsPgpId& gpg_id, std::string& error_string);
|
||||
bool LoadCertificateFromBinaryData(const unsigned char *bin_data,uint32_t bin_data_len, RsPgpId& gpg_id, std::string& error_string);
|
||||
|
||||
std::string SaveCertificateToString(const RsPgpId& id,bool include_signatures) const ;
|
||||
|
||||
/** The caller is in charge of freeing `mem` once finished */
|
||||
bool exportPublicKey( const RsPgpId& id,
|
||||
unsigned char*& mem, size_t& mem_size,
|
||||
bool armoured, bool include_signatures) const;
|
||||
|
||||
bool parseSignature(unsigned char *sign, unsigned int signlen,RsPgpId& issuer_id) ;
|
||||
bool SignDataBin(const RsPgpId& id, const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen, bool make_raw_signature=false, std::string reason = "") ;
|
||||
bool VerifySignBin(const void *data, uint32_t data_len, unsigned char *sign, unsigned int sign_len, const PGPFingerprintType& withfingerprint) ;
|
||||
bool privateSignCertificate(const RsPgpId& own_id,const RsPgpId& id_of_key_to_sign) ;
|
||||
|
||||
// The client should supply a memory chunk to store the data. The length will be updated to the real length of the data.
|
||||
//
|
||||
bool encryptDataBin(const RsPgpId& key_id,const void *data, const uint32_t len
|
||||
, unsigned char *encrypted_data, unsigned int *encrypted_data_len) ;
|
||||
bool decryptDataBin(const RsPgpId& key_id,const void *encrypted_data, const uint32_t encrypted_len
|
||||
, unsigned char *data, unsigned int *data_len) ;
|
||||
|
||||
bool encryptTextToFile(const RsPgpId& key_id,const std::string& text,const std::string& outfile) ;
|
||||
bool decryptTextFromFile(const RsPgpId& key_id,std::string& text,const std::string& encrypted_inputfile) ;
|
||||
bool parseSignature(unsigned char *sign, unsigned int signlen,RsPgpId& issuer_id) ;
|
||||
|
||||
void setAcceptConnexion(const RsPgpId&,bool) ;
|
||||
|
||||
@ -135,11 +165,6 @@ public:
|
||||
|
||||
void locked_updateOwnSignatureFlag(PGPCertificateInfo&, const RsPgpId&, PGPCertificateInfo&, const RsPgpId&) ;
|
||||
|
||||
// Removes the given keys from the keyring. Also backup the keyring to a file which name is automatically generated
|
||||
// and given pack for proper display.
|
||||
//
|
||||
bool removeKeysFromPGPKeyring(const std::set<RsPgpId>& key_ids,std::string& backup_file,uint32_t& error_code) ;
|
||||
|
||||
//bool isKeySupported(const RsPgpId& id) const ;
|
||||
|
||||
bool privateTrustCertificate(const RsPgpId& id,int valid_level) ;
|
||||
@ -174,66 +199,18 @@ public:
|
||||
*/
|
||||
static RsPgpId pgpIdFromFingerprint(const RsPgpFingerprint& f);
|
||||
|
||||
/**
|
||||
* @brief Get PGP fingerprint for the given key
|
||||
* @param id PGP 64bit key id
|
||||
* @param fp storage for the retrived key fingerpring, the contained value
|
||||
* is meaningfull only if true is returned
|
||||
* @return true if the key was found, false if not
|
||||
*/
|
||||
bool getKeyFingerprint(const RsPgpId& id, RsPgpFingerprint& fp) const;
|
||||
|
||||
// Gets info about the key. Who are the signers, what's the owner's name, etc.
|
||||
//
|
||||
bool getGPGDetailsFromBinaryBlock(const unsigned char *mem,size_t mem_size,RsPgpId& key_id, std::string& name, std::list<RsPgpId>& signers) const ;
|
||||
|
||||
// Debug stuff.
|
||||
virtual bool printKeys() const ;
|
||||
|
||||
// Syncs the keyrings and trust database between memory and disk. The algorithm is:
|
||||
// 1 - lock the keyrings
|
||||
// 2 - compare file modification dates with last writing date
|
||||
// - if file is modified, load it, and merge with memory
|
||||
// 3 - look into memory modification flags
|
||||
// - if flag says keyring has changed, write to disk
|
||||
//
|
||||
bool syncDatabase() ;
|
||||
|
||||
private:
|
||||
bool LoadCertificate(const unsigned char *bin_data,uint32_t bin_data_len, bool armoured, RsPgpId& gpg_id, std::string& error_string);
|
||||
void initCertificateInfo(PGPCertificateInfo& cert,const ops_keydata_t *keydata,uint32_t i) ;
|
||||
|
||||
// Returns true if the signatures have been updated
|
||||
//
|
||||
bool validateAndUpdateSignatures(PGPCertificateInfo& cert,const ops_keydata_t *keydata) ;
|
||||
|
||||
/** Check public/private key and import them into the keyring
|
||||
* @param keyring keyring with the new public/private key pair. Will be freed by the function.
|
||||
* @param imported_key_id PGP id of the imported key
|
||||
* @param import_error human readbale error message
|
||||
* @returns true on success
|
||||
* */
|
||||
bool checkAndImportKeyPair(ops_keyring_t *keyring, RsPgpId& imported_key_id,std::string& import_error);
|
||||
|
||||
const ops_keydata_t *locked_getPublicKey(const RsPgpId&,bool stamp_the_key) const;
|
||||
const ops_keydata_t *locked_getSecretKey(const RsPgpId&) const ;
|
||||
|
||||
protected:
|
||||
void locked_readPrivateTrustDatabase() ;
|
||||
bool locked_writePrivateTrustDatabase() ;
|
||||
|
||||
bool locked_syncPublicKeyring() ;
|
||||
bool locked_syncTrustDatabase() ;
|
||||
|
||||
void locked_mergeKeyringFromDisk(ops_keyring_t *keyring, std::map<RsPgpId,PGPCertificateInfo>& kmap, const std::string& keyring_file) ;
|
||||
bool locked_addOrMergeKey(ops_keyring_t *keyring,std::map<RsPgpId,PGPCertificateInfo>& kmap,const ops_keydata_t *keydata) ;
|
||||
bool locked_syncTrustDatabase() ;
|
||||
|
||||
// Members.
|
||||
//
|
||||
mutable RsMutex pgphandlerMtx ;
|
||||
|
||||
ops_keyring_t *_pubring ;
|
||||
ops_keyring_t *_secring ;
|
||||
|
||||
std::map<RsPgpId,PGPCertificateInfo> _public_keyring_map ; // used for fast access to keys. Gives the index in the keyring.
|
||||
std::map<RsPgpId,PGPCertificateInfo> _secret_keyring_map ;
|
||||
|
||||
@ -249,11 +226,5 @@ public:
|
||||
rstime_t _secring_last_update_time ;
|
||||
rstime_t _trustdb_last_update_time ;
|
||||
|
||||
// Helper functions.
|
||||
//
|
||||
static std::string makeRadixEncodedPGPKey(const ops_keydata_t *key,bool include_signatures) ;
|
||||
static ops_keyring_t *allocateOPSKeyring() ;
|
||||
static void addNewKeyToOPSKeyring(ops_keyring_t*, const ops_keydata_t&) ;
|
||||
static PassphraseCallback _passphrase_callback ;
|
||||
static bool mergeKeySignatures(ops_keydata_t *dst,const ops_keydata_t *src) ; // returns true if signature lists are different
|
||||
};
|
||||
|
@ -552,26 +552,24 @@ unsigned short RsCertificate::loc_port_us() const
|
||||
return (int)ipv4_internal_ip_and_port[4]*256 + (int)ipv4_internal_ip_and_port[5] ;
|
||||
}
|
||||
|
||||
bool RsCertificate::cleanCertificate( const std::string& input, std::string& output, Format& format, uint32_t& error_code, bool check_content )
|
||||
bool RsCertificate::cleanCertificate( const std::string& input, std::string& output, Format& format, uint32_t& error_code, bool check_content, RsPeerDetails& details)
|
||||
{
|
||||
if(cleanRadix64(input,output,error_code))
|
||||
{
|
||||
RsPeerDetails details;
|
||||
|
||||
if(rsPeers->parseShortInvite(output,details,error_code))
|
||||
{
|
||||
format = RS_CERTIFICATE_SHORT_RADIX;
|
||||
return true;
|
||||
}
|
||||
if(rsPeers->parseShortInvite(output,details,error_code))
|
||||
{
|
||||
format = RS_CERTIFICATE_SHORT_RADIX;
|
||||
return true;
|
||||
}
|
||||
|
||||
//Clear details. As parseShortInvite may make it dirty.
|
||||
details = RsPeerDetails();
|
||||
format = RS_CERTIFICATE_RADIX;
|
||||
|
||||
if(!check_content) return true;
|
||||
|
||||
uint32_t errCode;
|
||||
auto crt = RsCertificate::fromString(input, errCode);
|
||||
error_code = static_cast<int>(errCode);
|
||||
return crt != nullptr;
|
||||
return rsPeers->loadDetailsFromStringCert(input,details,error_code);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -84,7 +84,7 @@ public:
|
||||
|
||||
static bool cleanCertificate(
|
||||
const std::string& input, std::string& output,
|
||||
RsCertificate::Format& format, uint32_t& error_code, bool check_content);
|
||||
RsCertificate::Format& format, uint32_t& error_code, bool check_content, RsPeerDetails& details);
|
||||
|
||||
const std::set<RsUrl>& locators() const { return mLocators; }
|
||||
|
||||
|
@ -46,7 +46,7 @@
|
||||
|
||||
//const rstime_t STORE_KEY_TIMEOUT = 1 * 60 * 60; //store key is call around every hour
|
||||
|
||||
AuthGPG *AuthGPG::_instance = NULL ;
|
||||
AuthPGP *AuthPGP::_instance = NULL ;
|
||||
|
||||
void cleanupZombies(int numkill); // function to cleanup zombies under OSX.
|
||||
|
||||
@ -54,34 +54,46 @@ void cleanupZombies(int numkill); // function to cleanup zombies under OSX.
|
||||
|
||||
/* Function to sign X509_REQ via GPGme. */
|
||||
|
||||
bool AuthGPG::decryptTextFromFile(std::string& text,const std::string& inputfile)
|
||||
int AuthPGP::availablePgpCertificatesWithPrivateKeys(std::list<RsPgpId>& pgpIds)
|
||||
{
|
||||
return PGPHandler::decryptTextFromFile(mOwnGpgId,text,inputfile) ;
|
||||
return instance()->mPgpHandler->availableGPGCertificatesWithPrivateKeys(pgpIds);
|
||||
}
|
||||
bool AuthPGP::getPgpDetailsFromBinaryBlock(const unsigned char *mem,size_t mem_size,RsPgpId& key_id, std::string& name, std::list<RsPgpId>& signers)
|
||||
{
|
||||
return instance()->mPgpHandler->getGPGDetailsFromBinaryBlock(mem,mem_size,key_id,name,signers);
|
||||
}
|
||||
void AuthPGP::registerToConfigMgr(const std::string& fname,p3ConfigMgr *CfgMgr)
|
||||
{
|
||||
CfgMgr->addConfiguration(fname, instance());
|
||||
}
|
||||
bool AuthPGP::decryptTextFromFile(std::string& text,const std::string& inputfile)
|
||||
{
|
||||
return instance()->mPgpHandler->decryptTextFromFile(instance()->mOwnGpgId,text,inputfile) ;
|
||||
}
|
||||
|
||||
bool AuthGPG::removeKeysFromPGPKeyring(const std::set<RsPgpId>& pgp_ids,std::string& backup_file,uint32_t& error_code)
|
||||
bool AuthPGP::removeKeysFromPGPKeyring(const std::set<RsPgpId>& pgp_ids,std::string& backup_file,uint32_t& error_code)
|
||||
{
|
||||
// std::list<RsPgpId> pids ;
|
||||
//
|
||||
// for(std::list<RsPgpId>::const_iterator it(pgp_ids.begin());it!=pgp_ids.end();++it)
|
||||
// pids.push_back(RsPgpId(*it)) ;
|
||||
|
||||
return PGPHandler::removeKeysFromPGPKeyring(pgp_ids,backup_file,error_code) ;
|
||||
return instance()->mPgpHandler->removeKeysFromPGPKeyring(pgp_ids,backup_file,error_code) ;
|
||||
}
|
||||
|
||||
// bool AuthGPG::decryptTextFromString(std::string& encrypted_text,std::string& output)
|
||||
// {
|
||||
// return PGPHandler::decryptTextFromString(mOwnGpgId,encrypted_text,output) ;
|
||||
// return instance()->mPgpHandler->decryptTextFromString(mOwnGpgId,encrypted_text,output) ;
|
||||
// }
|
||||
|
||||
bool AuthGPG::encryptTextToFile(const std::string& text,const std::string& outfile)
|
||||
bool AuthPGP::encryptTextToFile(const std::string& text,const std::string& outfile)
|
||||
{
|
||||
return PGPHandler::encryptTextToFile(mOwnGpgId,text,outfile) ;
|
||||
return instance()->mPgpHandler->encryptTextToFile(instance()->mOwnGpgId,text,outfile) ;
|
||||
}
|
||||
|
||||
// bool AuthGPG::encryptTextToString(const std::string& pgp_id,const std::string& text,std::string& outstr)
|
||||
// {
|
||||
// return PGPHandler::encryptTextToString(RsPgpId(pgp_id),text,outstr) ;
|
||||
// return instance()->mPgpHandler->encryptTextToString(RsPgpId(pgp_id),text,outstr) ;
|
||||
// }
|
||||
|
||||
std::string pgp_pwd_callback(void * /*hook*/, const char *uid_title, const char *uid_hint, const char * /*passphrase_info*/, int prev_was_bad,bool *cancelled)
|
||||
@ -95,7 +107,7 @@ std::string pgp_pwd_callback(void * /*hook*/, const char *uid_title, const char
|
||||
return password ;
|
||||
}
|
||||
|
||||
void AuthGPG::init(
|
||||
void AuthPGP::init(
|
||||
const std::string& path_to_public_keyring,
|
||||
const std::string& path_to_secret_keyring,
|
||||
const std::string& path_to_trustdb,
|
||||
@ -107,14 +119,14 @@ void AuthGPG::init(
|
||||
std::cerr << "AuthGPG::init() called twice!" << std::endl ;
|
||||
}
|
||||
|
||||
// if(cb) PGPHandler::setPassphraseCallback(cb);else
|
||||
PGPHandler::setPassphraseCallback(pgp_pwd_callback);
|
||||
_instance = new AuthGPG( path_to_public_keyring,
|
||||
// if(cb) instance()->mPgpHandler->setPassphraseCallback(cb);else
|
||||
instance()->mPgpHandler->setPassphraseCallback(pgp_pwd_callback);
|
||||
_instance = new AuthPGP( path_to_public_keyring,
|
||||
path_to_secret_keyring,
|
||||
path_to_trustdb, pgp_lock_file );
|
||||
}
|
||||
|
||||
void AuthGPG::exit()
|
||||
void AuthPGP::exit()
|
||||
{
|
||||
if(_instance)
|
||||
{
|
||||
@ -124,9 +136,8 @@ void AuthGPG::exit()
|
||||
}
|
||||
}
|
||||
|
||||
AuthGPG::AuthGPG(const std::string& path_to_public_keyring,const std::string& path_to_secret_keyring,const std::string& path_to_trustdb,const std::string& pgp_lock_file)
|
||||
AuthPGP::AuthPGP(const std::string& path_to_public_keyring,const std::string& path_to_secret_keyring,const std::string& path_to_trustdb,const std::string& pgp_lock_file)
|
||||
:p3Config(),
|
||||
PGPHandler(path_to_public_keyring,path_to_secret_keyring,path_to_trustdb,pgp_lock_file),
|
||||
gpgMtxService("AuthGPG-service"),
|
||||
gpgMtxEngine("AuthGPG-engine"),
|
||||
gpgMtxData("AuthGPG-data"),
|
||||
@ -135,7 +146,9 @@ AuthGPG::AuthGPG(const std::string& path_to_public_keyring,const std::string& pa
|
||||
_force_sync_database(false),
|
||||
mCount(0)
|
||||
{
|
||||
start("AuthGPG");
|
||||
mPgpHandler = new OpenPGPSDKHandler(path_to_public_keyring,path_to_secret_keyring,path_to_trustdb,pgp_lock_file);
|
||||
|
||||
start("AuthGPG");
|
||||
}
|
||||
|
||||
/* This function is called when retroshare is first started
|
||||
@ -149,7 +162,7 @@ AuthGPG::AuthGPG(const std::string& path_to_public_keyring,const std::string& pa
|
||||
//{
|
||||
// std::list<RsPgpId> pids ;
|
||||
//
|
||||
// PGPHandler::availableGPGCertificatesWithPrivateKeys(pids) ;
|
||||
// mPgpHandler->availableGPGCertificatesWithPrivateKeys(pids) ;
|
||||
//
|
||||
// for(std::list<RsPgpId>::const_iterator it(pids.begin());it!=pids.end();++it)
|
||||
// ids.push_back( (*it).toStdString() ) ;
|
||||
@ -165,17 +178,17 @@ AuthGPG::AuthGPG(const std::string& path_to_public_keyring,const std::string& pa
|
||||
* This function must be called successfully (return == 1)
|
||||
* before anything else can be done. (except above fn).
|
||||
*/
|
||||
int AuthGPG::GPGInit(const RsPgpId &ownId)
|
||||
int AuthPGP::PgpInit(const RsPgpId &ownId)
|
||||
{
|
||||
#ifdef DEBUG_AUTHGPG
|
||||
std::cerr << "AuthGPG::GPGInit() called with own gpg id : " << ownId.toStdString() << std::endl;
|
||||
#endif
|
||||
|
||||
mOwnGpgId = RsPgpId(ownId);
|
||||
instance()->mOwnGpgId = ownId;
|
||||
|
||||
//force the validity of the private key. When set to unknown, it caused signature and text encryptions bugs
|
||||
privateTrustCertificate(ownId, 5);
|
||||
updateOwnSignatureFlag(mOwnGpgId) ;
|
||||
instance()->privateTrustCertificate(ownId, 5);
|
||||
instance()->mPgpHandler->updateOwnSignatureFlag(ownId) ;
|
||||
|
||||
#ifdef DEBUG_AUTHGPG
|
||||
std::cerr << "AuthGPG::GPGInit finished." << std::endl;
|
||||
@ -184,11 +197,11 @@ int AuthGPG::GPGInit(const RsPgpId &ownId)
|
||||
return 1;
|
||||
}
|
||||
|
||||
AuthGPG::~AuthGPG()
|
||||
AuthPGP::~AuthPGP()
|
||||
{
|
||||
}
|
||||
|
||||
void AuthGPG::threadTick()
|
||||
void AuthPGP::threadTick()
|
||||
{
|
||||
rstime::rs_usleep(100 * 1000); //100 msec
|
||||
|
||||
@ -204,13 +217,13 @@ void AuthGPG::threadTick()
|
||||
/// - checks whether the keyring has changed on disk.
|
||||
/// - merges/updates according to status.
|
||||
///
|
||||
PGPHandler::syncDatabase() ;
|
||||
mPgpHandler->syncDatabase() ;
|
||||
mCount = 0;
|
||||
_force_sync_database = false ;
|
||||
}//if (++count >= 100 || _force_sync_database)
|
||||
}
|
||||
|
||||
void AuthGPG::processServices()
|
||||
void AuthPGP::processServices()
|
||||
{
|
||||
AuthGPGOperation *operation = NULL;
|
||||
AuthGPGService *service = NULL;
|
||||
@ -251,7 +264,7 @@ void AuthGPG::processServices()
|
||||
|
||||
|
||||
/* don't bother loading - if we already have the certificate */
|
||||
if (isGPGId(loadOrSave->m_certGpgId))
|
||||
if (mPgpHandler->isGPGId(loadOrSave->m_certGpgId))
|
||||
{
|
||||
#ifdef GPG_DEBUG
|
||||
std::cerr << "AuthGPGimpl::processServices() Skipping load - already have it" << std::endl;
|
||||
@ -305,66 +318,66 @@ void AuthGPG::processServices()
|
||||
delete operation;
|
||||
}
|
||||
|
||||
bool AuthGPG::DoOwnSignature(const void *data, unsigned int datalen, void *buf_sigout, unsigned int *outl, std::string reason /* = "" */)
|
||||
bool AuthPGP::DoOwnSignature(const void *data, unsigned int datalen, void *buf_sigout, unsigned int *outl, std::string reason /* = "" */)
|
||||
{
|
||||
return PGPHandler::SignDataBin(mOwnGpgId,data,datalen,(unsigned char *)buf_sigout,outl,false,reason) ;
|
||||
return instance()->mPgpHandler->SignDataBin(mOwnGpgId,data,datalen,(unsigned char *)buf_sigout,outl,false,reason) ;
|
||||
}
|
||||
|
||||
|
||||
/* import to GnuPG and other Certificates */
|
||||
bool AuthGPG::VerifySignature(const void *data, int datalen, const void *sig, unsigned int siglen, const PGPFingerprintType& withfingerprint)
|
||||
bool AuthPGP::VerifySignature(const void *data, int datalen, const void *sig, unsigned int siglen, const PGPFingerprintType& withfingerprint)
|
||||
{
|
||||
return PGPHandler::VerifySignBin((unsigned char*)data,datalen,(unsigned char*)sig,siglen,withfingerprint) ;
|
||||
return instance()->mPgpHandler->VerifySignBin((unsigned char*)data,datalen,(unsigned char*)sig,siglen,withfingerprint) ;
|
||||
}
|
||||
|
||||
bool AuthGPG::parseSignature(const void *sig, unsigned int siglen, RsPgpId& issuer_id)
|
||||
bool AuthPGP::parseSignature(const void *sig, unsigned int siglen, RsPgpId& issuer_id)
|
||||
{
|
||||
return PGPHandler::parseSignature((unsigned char*)sig,siglen,issuer_id) ;
|
||||
return instance()->mPgpHandler->parseSignature((unsigned char*)sig,siglen,issuer_id) ;
|
||||
}
|
||||
|
||||
bool AuthGPG::exportProfile(const std::string& fname,const RsPgpId& exported_id)
|
||||
bool AuthPGP::exportProfile(const std::string& fname,const RsPgpId& exported_id)
|
||||
{
|
||||
return PGPHandler::exportGPGKeyPair(fname,exported_id) ;
|
||||
return instance()->mPgpHandler->exportGPGKeyPair(fname,exported_id) ;
|
||||
}
|
||||
|
||||
bool AuthGPG::exportIdentityToString(
|
||||
bool AuthPGP::exportIdentityToString(
|
||||
std::string& data, const RsPgpId& pgpId, bool includeSignatures,
|
||||
std::string& errorMsg )
|
||||
{
|
||||
return PGPHandler::exportGPGKeyPairToString(
|
||||
return instance()->mPgpHandler->exportGPGKeyPairToString(
|
||||
data, pgpId, includeSignatures, errorMsg);
|
||||
}
|
||||
|
||||
bool AuthGPG::importProfile(const std::string& fname,RsPgpId& imported_id,std::string& import_error)
|
||||
bool AuthPGP::importProfile(const std::string& fname,RsPgpId& imported_id,std::string& import_error)
|
||||
{
|
||||
return PGPHandler::importGPGKeyPair(fname,imported_id,import_error) ;
|
||||
return instance()->mPgpHandler->importGPGKeyPair(fname,imported_id,import_error) ;
|
||||
}
|
||||
|
||||
bool AuthGPG::importProfileFromString(const std::string &data, RsPgpId &gpg_id, std::string &import_error)
|
||||
bool AuthPGP::importProfileFromString(const std::string &data, RsPgpId &gpg_id, std::string &import_error)
|
||||
{
|
||||
return PGPHandler::importGPGKeyPairFromString(data, gpg_id, import_error);
|
||||
return instance()->mPgpHandler->importGPGKeyPairFromString(data, gpg_id, import_error);
|
||||
}
|
||||
|
||||
bool AuthGPG::active()
|
||||
bool AuthPGP::active()
|
||||
{
|
||||
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
|
||||
RsStackMutex stack(instance()->gpgMtxData); /******* LOCKED ******/
|
||||
|
||||
return gpgKeySelected;
|
||||
return instance()->gpgKeySelected;
|
||||
}
|
||||
|
||||
bool AuthGPG::GeneratePGPCertificate(const std::string& name, const std::string& email, const std::string& passwd, RsPgpId& pgpId, const int keynumbits, std::string& errString)
|
||||
bool AuthPGP::GeneratePgpCertificate(const std::string& name, const std::string& email, const std::string& passwd, RsPgpId& pgpId, const int keynumbits, std::string& errString)
|
||||
{
|
||||
RsStackMutex stack(gpgMtxEngine); /******* LOCKED ******/
|
||||
RsStackMutex stack(instance()->gpgMtxEngine); /******* LOCKED ******/
|
||||
|
||||
return PGPHandler::GeneratePGPCertificate(name, email, passwd, pgpId, keynumbits, errString) ;
|
||||
return instance()->mPgpHandler->GeneratePGPCertificate(name, email, passwd, pgpId, keynumbits, errString) ;
|
||||
}
|
||||
|
||||
/**** These Two are common */
|
||||
std::string AuthGPG::getGPGName(const RsPgpId& id,bool *success)
|
||||
std::string AuthPGP::getPgpName(const RsPgpId& id,bool *success)
|
||||
{
|
||||
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
|
||||
RsStackMutex stack(instance()->gpgMtxData); /******* LOCKED ******/
|
||||
|
||||
const PGPCertificateInfo *info = getCertificateInfo(id) ;
|
||||
const PGPCertificateInfo *info = instance()->mPgpHandler->getCertificateInfo(id) ;
|
||||
|
||||
if(info != NULL)
|
||||
{
|
||||
@ -378,11 +391,25 @@ std::string AuthGPG::getGPGName(const RsPgpId& id,bool *success)
|
||||
}
|
||||
}
|
||||
|
||||
/**** These Two are common */
|
||||
std::string AuthGPG::getGPGEmail(const RsPgpId& id,bool *success)
|
||||
AuthPGP *AuthPGP::instance()
|
||||
{
|
||||
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
|
||||
const PGPCertificateInfo *info = getCertificateInfo(id) ;
|
||||
if(!_instance)
|
||||
{
|
||||
RsFatal() << "AuthGPG::instance() called before AuthGPG::init()! This should not happen." << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return _instance;
|
||||
}
|
||||
bool AuthPGP::isPGPId(const RsPgpId& id)
|
||||
{
|
||||
return instance()->mPgpHandler->isGPGId(id);
|
||||
}
|
||||
/**** These Two are common */
|
||||
std::string AuthPGP::getPgpEmail(const RsPgpId& id,bool *success)
|
||||
{
|
||||
RsStackMutex stack(instance()->gpgMtxData); /******* LOCKED ******/
|
||||
const PGPCertificateInfo *info = instance()->mPgpHandler->getCertificateInfo(id) ;
|
||||
|
||||
if(info != NULL)
|
||||
{
|
||||
@ -398,30 +425,30 @@ std::string AuthGPG::getGPGEmail(const RsPgpId& id,bool *success)
|
||||
|
||||
/**** GPG versions ***/
|
||||
|
||||
const RsPgpId& AuthGPG::getGPGOwnId()
|
||||
const RsPgpId& AuthPGP::getPgpOwnId()
|
||||
{
|
||||
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
|
||||
return mOwnGpgId ;
|
||||
RsStackMutex stack(instance()->gpgMtxData); /******* LOCKED ******/
|
||||
return instance()->mOwnGpgId ;
|
||||
}
|
||||
|
||||
std::string AuthGPG::getGPGOwnName()
|
||||
std::string AuthPGP::getPgpOwnName()
|
||||
{
|
||||
return getGPGName(mOwnGpgId) ;
|
||||
return getPgpName(instance()->mOwnGpgId) ;
|
||||
}
|
||||
|
||||
bool AuthGPG::getGPGAllList(std::list<RsPgpId> &ids)
|
||||
bool AuthPGP::getPgpAllList(std::list<RsPgpId> &ids)
|
||||
{
|
||||
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
|
||||
RsStackMutex stack(instance()->gpgMtxData); /******* LOCKED ******/
|
||||
|
||||
PGPHandler::getGPGFilteredList(ids) ;
|
||||
instance()->mPgpHandler->getGPGFilteredList(ids) ;
|
||||
|
||||
return true;
|
||||
}
|
||||
const PGPCertificateInfo *AuthGPG::getCertInfoFromStdString(const std::string& pgp_id) const
|
||||
const PGPCertificateInfo *AuthPGP::getCertInfoFromStdString(const std::string& pgp_id) const
|
||||
{
|
||||
try
|
||||
{
|
||||
return PGPHandler::getCertificateInfo(RsPgpId(pgp_id)) ;
|
||||
return instance()->mPgpHandler->getCertificateInfo(RsPgpId(pgp_id)) ;
|
||||
}
|
||||
catch(std::exception& e)
|
||||
{
|
||||
@ -429,13 +456,13 @@ const PGPCertificateInfo *AuthGPG::getCertInfoFromStdString(const std::string& p
|
||||
return NULL ;
|
||||
}
|
||||
}
|
||||
bool AuthGPG::haveSecretKey(const RsPgpId& id) const
|
||||
bool AuthPGP::haveSecretKey(const RsPgpId& id)
|
||||
{
|
||||
return PGPHandler::haveSecretKey(id) ;
|
||||
return instance()->mPgpHandler->haveSecretKey(id) ;
|
||||
}
|
||||
bool AuthGPG::isKeySupported(const RsPgpId& id) const
|
||||
bool AuthPGP::isKeySupported(const RsPgpId& id)
|
||||
{
|
||||
const PGPCertificateInfo *pc = getCertificateInfo(id) ;
|
||||
const PGPCertificateInfo *pc = instance()->mPgpHandler->getCertificateInfo(id) ;
|
||||
|
||||
if(pc == NULL)
|
||||
return false ;
|
||||
@ -443,11 +470,11 @@ bool AuthGPG::isKeySupported(const RsPgpId& id) const
|
||||
return !(pc->_flags & PGPCertificateInfo::PGP_CERTIFICATE_FLAG_UNSUPPORTED_ALGORITHM) ;
|
||||
}
|
||||
|
||||
bool AuthGPG::getGPGDetails(const RsPgpId& pgp_id, RsPeerDetails &d)
|
||||
bool AuthPGP::getPgpDetails(const RsPgpId& pgp_id, RsPeerDetails &d)
|
||||
{
|
||||
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
|
||||
RsStackMutex stack(instance()->gpgMtxData); /******* LOCKED ******/
|
||||
|
||||
const PGPCertificateInfo *pc = PGPHandler::getCertificateInfo(pgp_id) ;
|
||||
const PGPCertificateInfo *pc = instance()->mPgpHandler->getCertificateInfo(pgp_id) ;
|
||||
|
||||
if(pc == NULL)
|
||||
return false ;
|
||||
@ -474,28 +501,26 @@ bool AuthGPG::getGPGDetails(const RsPgpId& pgp_id, RsPeerDetails &d)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AuthGPG::getGPGFilteredList(std::list<RsPgpId>& list,bool (*filter)(const PGPCertificateInfo&))
|
||||
bool AuthPGP::getGPGFilteredList(std::list<RsPgpId>& list,bool (*filter)(const PGPCertificateInfo&))
|
||||
{
|
||||
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
|
||||
|
||||
return PGPHandler::getGPGFilteredList(list,filter) ;
|
||||
return instance()->mPgpHandler->getGPGFilteredList(list,filter) ;
|
||||
}
|
||||
|
||||
static bool filter_Validity(const PGPCertificateInfo& /*info*/) { return true ; } //{ return info._validLvl >= PGPCertificateInfo::GPGME_VALIDITY_MARGINAL ; }
|
||||
static bool filter_Accepted(const PGPCertificateInfo& info) { return info._flags & PGPCertificateInfo::PGP_CERTIFICATE_FLAG_ACCEPT_CONNEXION ; }
|
||||
static bool filter_OwnSigned(const PGPCertificateInfo& info) { return info._flags & PGPCertificateInfo::PGP_CERTIFICATE_FLAG_HAS_OWN_SIGNATURE ; }
|
||||
|
||||
bool AuthGPG::getGPGValidList(std::list<RsPgpId> &ids)
|
||||
bool AuthPGP::getPgpValidList(std::list<RsPgpId> &ids)
|
||||
{
|
||||
return getGPGFilteredList(ids,&filter_Validity);
|
||||
}
|
||||
|
||||
bool AuthGPG::getGPGAcceptedList(std::list<RsPgpId> &ids)
|
||||
bool AuthPGP::getPgpAcceptedList(std::list<RsPgpId> &ids)
|
||||
{
|
||||
return getGPGFilteredList(ids,&filter_Accepted);
|
||||
}
|
||||
|
||||
bool AuthGPG::getGPGSignedList(std::list<RsPgpId> &ids)
|
||||
bool AuthPGP::getPgpSignedList(std::list<RsPgpId> &ids)
|
||||
{
|
||||
return getGPGFilteredList(ids,&filter_OwnSigned);
|
||||
}
|
||||
@ -504,9 +529,9 @@ bool AuthGPG::getGPGSignedList(std::list<RsPgpId> &ids)
|
||||
// {
|
||||
// RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
|
||||
// #ifdef LIMIT_CERTIFICATE_SIZE
|
||||
// certificate = PGPHandler::SaveCertificateToString(RsPgpId(id),false) ;
|
||||
// certificate = instance()->mPgpHandler->SaveCertificateToString(RsPgpId(id),false) ;
|
||||
// #else
|
||||
// certificate = PGPHandler::SaveCertificateToString(RsPgpId(id),true) ;
|
||||
// certificate = instance()->mPgpHandler->SaveCertificateToString(RsPgpId(id),true) ;
|
||||
// #endif
|
||||
//
|
||||
// // #ifdef LIMIT_CERTIFICATE_SIZE
|
||||
@ -528,20 +553,20 @@ bool AuthGPG::getGPGSignedList(std::list<RsPgpId> &ids)
|
||||
|
||||
|
||||
/* SKTAN : do not know how to use std::string id */
|
||||
std::string AuthGPG::SaveCertificateToString(const RsPgpId &id,bool include_signatures)
|
||||
std::string AuthPGP::SaveCertificateToString(const RsPgpId &id,bool include_signatures)
|
||||
{
|
||||
RsStackMutex stack(gpgMtxEngine); /******* LOCKED ******/
|
||||
RsStackMutex stack(instance()->gpgMtxEngine); /******* LOCKED ******/
|
||||
|
||||
return PGPHandler::SaveCertificateToString(id,include_signatures) ;
|
||||
return instance()->mPgpHandler->SaveCertificateToString(id,include_signatures) ;
|
||||
}
|
||||
/* import to GnuPG and other Certificates */
|
||||
bool AuthGPG::LoadPGPKeyFromBinaryData(const unsigned char *data,uint32_t data_len, RsPgpId& gpg_id,std::string& error_string)
|
||||
bool AuthPGP::LoadPGPKeyFromBinaryData(const unsigned char *data,uint32_t data_len, RsPgpId& gpg_id,std::string& error_string)
|
||||
{
|
||||
RsStackMutex stack(gpgMtxEngine); /******* LOCKED ******/
|
||||
RsStackMutex stack(instance()->gpgMtxEngine); /******* LOCKED ******/
|
||||
|
||||
if(PGPHandler::LoadCertificateFromBinaryData(data,data_len,gpg_id,error_string))
|
||||
if(instance()->mPgpHandler->LoadCertificateFromBinaryData(data,data_len,gpg_id,error_string))
|
||||
{
|
||||
updateOwnSignatureFlag(gpg_id,mOwnGpgId) ;
|
||||
instance()->mPgpHandler->updateOwnSignatureFlag(gpg_id,instance()->mOwnGpgId) ;
|
||||
return true ;
|
||||
}
|
||||
|
||||
@ -549,13 +574,13 @@ bool AuthGPG::LoadPGPKeyFromBinaryData(const unsigned char *data,uint32_t data_l
|
||||
}
|
||||
|
||||
/* import to GnuPG and other Certificates */
|
||||
bool AuthGPG::LoadCertificateFromString(const std::string &str, RsPgpId& gpg_id,std::string& error_string)
|
||||
bool AuthPGP::LoadCertificateFromString(const std::string &str, RsPgpId& gpg_id,std::string& error_string)
|
||||
{
|
||||
RsStackMutex stack(gpgMtxEngine); /******* LOCKED ******/
|
||||
RsStackMutex stack(instance()->gpgMtxEngine); /******* LOCKED ******/
|
||||
|
||||
if(PGPHandler::LoadCertificateFromString(str,gpg_id,error_string))
|
||||
if(instance()->mPgpHandler->LoadCertificateFromString(str,gpg_id,error_string))
|
||||
{
|
||||
updateOwnSignatureFlag(gpg_id,mOwnGpgId) ;
|
||||
instance()->mPgpHandler->updateOwnSignatureFlag(gpg_id,instance()->mOwnGpgId) ;
|
||||
return true ;
|
||||
}
|
||||
|
||||
@ -576,7 +601,7 @@ bool AuthGPG::LoadCertificateFromString(const std::string &str, RsPgpId& gpg_id,
|
||||
/*************************************/
|
||||
|
||||
/* These take PGP Ids */
|
||||
bool AuthGPG::AllowConnection(const RsPgpId& gpg_id, bool accept)
|
||||
bool AuthPGP::AllowConnection(const RsPgpId& gpg_id, bool accept)
|
||||
{
|
||||
#ifdef GPG_DEBUG
|
||||
std::cerr << "AuthGPG::AllowConnection(" << gpg_id << ")" << std::endl;
|
||||
@ -584,11 +609,11 @@ bool AuthGPG::AllowConnection(const RsPgpId& gpg_id, bool accept)
|
||||
|
||||
/* Was a "Reload Certificates" here -> be shouldn't be needed -> and very expensive, try without. */
|
||||
{
|
||||
RsStackMutex stack(gpgMtxData);
|
||||
PGPHandler::setAcceptConnexion(gpg_id,accept) ;
|
||||
RsStackMutex stack(instance()->gpgMtxData);
|
||||
instance()->mPgpHandler->setAcceptConnexion(gpg_id,accept) ;
|
||||
}
|
||||
|
||||
IndicateConfigChanged();
|
||||
instance()->IndicateConfigChanged();
|
||||
|
||||
RsServer::notify()->notifyListChange(NOTIFY_LIST_FRIENDS, accept ? NOTIFY_TYPE_ADD : NOTIFY_TYPE_DEL);
|
||||
|
||||
@ -596,16 +621,16 @@ bool AuthGPG::AllowConnection(const RsPgpId& gpg_id, bool accept)
|
||||
}
|
||||
|
||||
/* These take PGP Ids */
|
||||
bool AuthGPG::SignCertificateLevel0(const RsPgpId &id)
|
||||
bool AuthPGP::SignCertificateLevel0(const RsPgpId &id)
|
||||
{
|
||||
#ifdef GPG_DEBUG
|
||||
std::cerr << "AuthGPG::SignCertificat(" << id << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
return privateSignCertificate(id) ;
|
||||
return instance()->privateSignCertificate(id) ;
|
||||
}
|
||||
|
||||
bool AuthGPG::RevokeCertificate(const RsPgpId &id)
|
||||
bool AuthPGP::RevokeCertificate(const RsPgpId &id)
|
||||
{
|
||||
/* remove unused parameter warnings */
|
||||
(void) id;
|
||||
@ -617,46 +642,59 @@ bool AuthGPG::RevokeCertificate(const RsPgpId &id)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AuthGPG::TrustCertificate(const RsPgpId& id, int trustlvl)
|
||||
bool AuthPGP::TrustCertificate(const RsPgpId& id, int trustlvl)
|
||||
{
|
||||
#ifdef GPG_DEBUG
|
||||
std::cerr << "AuthGPG::TrustCertificate(" << id << ", " << trustlvl << ")" << std::endl;
|
||||
#endif
|
||||
return privateTrustCertificate(id, trustlvl) ;
|
||||
return instance()->privateTrustCertificate(id, trustlvl) ;
|
||||
}
|
||||
|
||||
bool AuthGPG::encryptDataBin(const RsPgpId& pgp_id,const void *data, unsigned int datalen, unsigned char *sign, unsigned int *signlen)
|
||||
bool AuthPGP::encryptDataBin(const RsPgpId& pgp_id,const void *data, unsigned int datalen, unsigned char *sign, unsigned int *signlen)
|
||||
{
|
||||
return PGPHandler::encryptDataBin(RsPgpId(pgp_id),data,datalen,sign,signlen) ;
|
||||
return instance()->mPgpHandler->encryptDataBin(RsPgpId(pgp_id),data,datalen,sign,signlen) ;
|
||||
}
|
||||
|
||||
bool AuthGPG::decryptDataBin(const void *data, unsigned int datalen, unsigned char *sign, unsigned int *signlen)
|
||||
bool AuthPGP::decryptDataBin(const void *data, unsigned int datalen, unsigned char *sign, unsigned int *signlen)
|
||||
{
|
||||
return PGPHandler::decryptDataBin(mOwnGpgId,data,datalen,sign,signlen) ;
|
||||
return instance()->mPgpHandler->decryptDataBin(instance()->mOwnGpgId,data,datalen,sign,signlen) ;
|
||||
}
|
||||
bool AuthGPG::SignDataBin(const void *data, unsigned int datalen, unsigned char *sign, unsigned int *signlen, std::string reason /*= ""*/)
|
||||
bool AuthPGP::SignDataBin(const void *data, unsigned int datalen, unsigned char *sign, unsigned int *signlen, std::string reason /*= ""*/)
|
||||
{
|
||||
return DoOwnSignature(data, datalen, sign, signlen, reason);
|
||||
return instance()->DoOwnSignature(data, datalen, sign, signlen, reason);
|
||||
}
|
||||
|
||||
bool AuthGPG::VerifySignBin(const void *data, uint32_t datalen, unsigned char *sign, unsigned int signlen, const PGPFingerprintType& withfingerprint)
|
||||
bool AuthPGP::exportPublicKey( const RsPgpId& id, unsigned char*& mem_block, size_t& mem_size, bool armoured, bool include_signatures )
|
||||
{
|
||||
return VerifySignature(data, datalen, sign, signlen, withfingerprint);
|
||||
return instance()->mPgpHandler->exportPublicKey(id,mem_block,mem_size,armoured,include_signatures);
|
||||
}
|
||||
|
||||
bool AuthPGP::isPgpPubKeyAvailable(const RsPgpId& pgp_id)
|
||||
{
|
||||
return instance()->mPgpHandler->isPgpPubKeyAvailable(pgp_id);
|
||||
}
|
||||
bool AuthPGP::getKeyFingerprint(const RsPgpId& id,PGPFingerprintType& fp)
|
||||
{
|
||||
return instance()->mPgpHandler->getKeyFingerprint(id,fp);
|
||||
}
|
||||
bool AuthPGP::VerifySignBin(const void *data, uint32_t datalen, unsigned char *sign, unsigned int signlen, const PGPFingerprintType& withfingerprint)
|
||||
{
|
||||
return instance()->VerifySignature(data, datalen, sign, signlen, withfingerprint);
|
||||
}
|
||||
|
||||
/* Sign/Trust stuff */
|
||||
|
||||
int AuthGPG::privateSignCertificate(const RsPgpId &id)
|
||||
int AuthPGP::privateSignCertificate(const RsPgpId &id)
|
||||
{
|
||||
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
|
||||
|
||||
int ret = PGPHandler::privateSignCertificate(mOwnGpgId,id) ;
|
||||
int ret = mPgpHandler->privateSignCertificate(mOwnGpgId,id) ;
|
||||
_force_sync_database = true ;
|
||||
return ret ;
|
||||
}
|
||||
|
||||
/* revoke the signature on Certificate */
|
||||
int AuthGPG::privateRevokeCertificate(const RsPgpId &/*id*/)
|
||||
int AuthPGP::privateRevokeCertificate(const RsPgpId &/*id*/)
|
||||
{
|
||||
//RsStackMutex stack(gpgMtx); /******* LOCKED ******/
|
||||
std::cerr << __PRETTY_FUNCTION__ << ": not implemented!" << std::endl;
|
||||
@ -664,7 +702,7 @@ int AuthGPG::privateRevokeCertificate(const RsPgpId &/*id*/)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AuthGPG::privateTrustCertificate(const RsPgpId& id, int trustlvl)
|
||||
int AuthPGP::privateTrustCertificate(const RsPgpId& id, int trustlvl)
|
||||
{
|
||||
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
|
||||
|
||||
@ -672,10 +710,10 @@ int AuthGPG::privateTrustCertificate(const RsPgpId& id, int trustlvl)
|
||||
// The trust level is only a user-defined property that has nothing to
|
||||
// do with the fact that we allow connections or not.
|
||||
|
||||
if(!isGPGAccepted(id))
|
||||
if(!isPGPAccepted(id))
|
||||
return 0;
|
||||
|
||||
int res = PGPHandler::privateTrustCertificate(id,trustlvl) ;
|
||||
int res = instance()->mPgpHandler->privateTrustCertificate(id,trustlvl) ;
|
||||
_force_sync_database = true ;
|
||||
return res ;
|
||||
}
|
||||
@ -684,20 +722,24 @@ int AuthGPG::privateTrustCertificate(const RsPgpId& id, int trustlvl)
|
||||
// -------------------------------- Config functions ------------------------------ //
|
||||
// -----------------------------------------------------------------------------------//
|
||||
//
|
||||
RsSerialiser *AuthGPG::setupSerialiser()
|
||||
RsSerialiser *AuthPGP::setupSerialiser()
|
||||
{
|
||||
RsSerialiser *rss = new RsSerialiser ;
|
||||
rss->addSerialType(new RsGeneralConfigSerialiser());
|
||||
return rss ;
|
||||
}
|
||||
bool AuthPGP::isPGPAccepted(const RsPgpId& id)
|
||||
{
|
||||
return instance()->mPgpHandler->isGPGAccepted(id);
|
||||
}
|
||||
|
||||
bool AuthGPG::saveList(bool& cleanup, std::list<RsItem*>& lst)
|
||||
bool AuthPGP::saveList(bool& cleanup, std::list<RsItem*>& lst)
|
||||
{
|
||||
#ifdef GPG_DEBUG
|
||||
std::cerr << "AuthGPG::saveList() called" << std::endl ;
|
||||
#endif
|
||||
std::list<RsPgpId> ids ;
|
||||
getGPGAcceptedList(ids) ; // needs to be done before the lock
|
||||
getPgpAcceptedList(ids) ; // needs to be done before the lock
|
||||
|
||||
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
|
||||
|
||||
@ -722,7 +764,7 @@ bool AuthGPG::saveList(bool& cleanup, std::list<RsItem*>& lst)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AuthGPG::loadList(std::list<RsItem*>& load)
|
||||
bool AuthPGP::loadList(std::list<RsItem*>& load)
|
||||
{
|
||||
#ifdef GPG_DEBUG
|
||||
std::cerr << "AuthGPG::loadList() Item Count: " << load.size() << std::endl;
|
||||
@ -745,7 +787,7 @@ bool AuthGPG::loadList(std::list<RsItem*>& load)
|
||||
std::list<RsTlvKeyValue>::iterator kit;
|
||||
for(kit = vitem->tlvkvs.pairs.begin(); kit != vitem->tlvkvs.pairs.end(); ++kit)
|
||||
if (kit->key != mOwnGpgId.toStdString())
|
||||
PGPHandler::setAcceptConnexion(RsPgpId(kit->key), (kit->value == "TRUE"));
|
||||
instance()->mPgpHandler->setAcceptConnexion(RsPgpId(kit->key), (kit->value == "TRUE"));
|
||||
}
|
||||
delete (*it);
|
||||
}
|
||||
@ -753,16 +795,16 @@ bool AuthGPG::loadList(std::list<RsItem*>& load)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AuthGPG::addService(AuthGPGService *service)
|
||||
bool AuthPGP::addService(AuthGPGService *service)
|
||||
{
|
||||
RsStackMutex stack(gpgMtxService); /********* LOCKED *********/
|
||||
RsStackMutex stack(instance()->gpgMtxService); /********* LOCKED *********/
|
||||
|
||||
if (std::find(services.begin(), services.end(), service) != services.end()) {
|
||||
if (std::find(instance()->services.begin(), instance()->services.end(), service) != instance()->services.end()) {
|
||||
/* it exists already! */
|
||||
return false;
|
||||
}
|
||||
|
||||
services.push_back(service);
|
||||
instance()->services.push_back(service);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@
|
||||
|
||||
#include "util/rsthreads.h"
|
||||
#include "pqi/p3cfgmgr.h"
|
||||
#include "pgp/pgphandler.h"
|
||||
#include "pgp/openpgpsdkhandler.h"
|
||||
|
||||
#define MAX_GPG_SIGNATURE_SIZE 4096
|
||||
|
||||
@ -89,16 +89,19 @@ public:
|
||||
virtual void setGPGOperation(AuthGPGOperation *operation) = 0;
|
||||
};
|
||||
|
||||
class AuthGPG: public p3Config, public RsTickingThread, public PGPHandler
|
||||
class AuthPGP: public p3Config, public RsTickingThread
|
||||
{
|
||||
public:
|
||||
static void init(const std::string& path_to_pubring,
|
||||
const std::string& path_to_secring,
|
||||
const std::string& path_to_trustdb,
|
||||
const std::string& pgp_lock_file);
|
||||
static void init(const std::string& path_to_pubring,
|
||||
const std::string& path_to_secring,
|
||||
const std::string& path_to_trustdb,
|
||||
const std::string& pgp_lock_file);
|
||||
|
||||
static void exit();
|
||||
static AuthGPG *getAuthGPG() { return _instance ; }
|
||||
static void registerToConfigMgr(const std::string& fname,p3ConfigMgr *CfgMgr);
|
||||
static void exit();
|
||||
|
||||
static bool isPGPId(const RsPgpId& id) ;
|
||||
static bool isPGPAccepted(const RsPgpId& id) ;
|
||||
|
||||
/**
|
||||
* @param ids list of gpg certificate ids (note, not the actual certificates)
|
||||
@ -118,7 +121,7 @@ public:
|
||||
* (see storage at the end of the class)
|
||||
*
|
||||
****/
|
||||
virtual bool active();
|
||||
static bool active();
|
||||
|
||||
// /* Initialize */
|
||||
// virtual bool InitAuth ();
|
||||
@ -126,10 +129,13 @@ public:
|
||||
|
||||
/* Init by generating new Own PGP Cert, or selecting existing PGP Cert */
|
||||
|
||||
virtual int GPGInit(const RsPgpId &ownId);
|
||||
virtual bool GeneratePGPCertificate(const std::string& name, const std::string& email, const std::string& passwd, RsPgpId &pgpId, const int keynumbits, std::string &errString);
|
||||
static int PgpInit(const RsPgpId &ownId);
|
||||
static bool GeneratePgpCertificate(const std::string& name, const std::string& email, const std::string& passwd, RsPgpId &pgpId, const int keynumbits, std::string &errString);
|
||||
|
||||
/*********************************************************************************/
|
||||
static bool getPgpDetailsFromBinaryBlock(const unsigned char *mem,size_t mem_size,RsPgpId& key_id, std::string& name, std::list<RsPgpId>& signers) ;
|
||||
static int availablePgpCertificatesWithPrivateKeys(std::list<RsPgpId>& pgpIds);
|
||||
|
||||
/*********************************************************************************/
|
||||
/************************* STAGE 3 ***********************************************/
|
||||
/*********************************************************************************/
|
||||
/*****
|
||||
@ -140,29 +146,33 @@ public:
|
||||
* provide access to details in cache list.
|
||||
*
|
||||
****/
|
||||
virtual std::string getGPGName(const RsPgpId &pgp_id,bool *success = NULL);
|
||||
virtual std::string getGPGEmail(const RsPgpId &pgp_id,bool *success = NULL);
|
||||
static std::string getPgpName(const RsPgpId &pgp_id,bool *success = NULL);
|
||||
static std::string getPgpEmail(const RsPgpId &pgp_id,bool *success = NULL);
|
||||
|
||||
/* PGP web of trust management */
|
||||
virtual const RsPgpId& getGPGOwnId();
|
||||
virtual std::string getGPGOwnName();
|
||||
static bool exportPublicKey( const RsPgpId& id, unsigned char*& mem_block, size_t& mem_size, bool armoured, bool include_signatures );
|
||||
|
||||
//virtual std::string getGPGOwnEmail();
|
||||
virtual bool isKeySupported(const RsPgpId &id) const ;
|
||||
virtual bool haveSecretKey(const RsPgpId &id) const ;
|
||||
virtual bool getGPGDetails(const RsPgpId& id, RsPeerDetails &d);
|
||||
virtual bool getGPGAllList(std::list<RsPgpId> &ids);
|
||||
virtual bool getGPGValidList(std::list<RsPgpId> &ids);
|
||||
virtual bool getGPGAcceptedList(std::list<RsPgpId> &ids);
|
||||
virtual bool getGPGSignedList(std::list<RsPgpId> &ids);
|
||||
virtual bool importProfile(const std::string& filename,RsPgpId& gpg_id,std::string& import_error) ;
|
||||
virtual bool importProfileFromString(const std::string& data,RsPgpId& gpg_id,std::string& import_error) ;
|
||||
virtual bool exportProfile(const std::string& filename,const RsPgpId& gpg_id) ;
|
||||
virtual bool exportIdentityToString(
|
||||
/* PGP web of trust management */
|
||||
static const RsPgpId& getPgpOwnId();
|
||||
static std::string getPgpOwnName();
|
||||
|
||||
//virtual std::string getGPGOwnEmail();
|
||||
static bool getKeyFingerprint(const RsPgpId& id,PGPFingerprintType& fp) ;
|
||||
static bool isKeySupported(const RsPgpId &id) ;
|
||||
static bool isPgpPubKeyAvailable(const RsPgpId& pgp_id);
|
||||
static bool haveSecretKey(const RsPgpId &id) ;
|
||||
static bool getPgpDetails(const RsPgpId& id, RsPeerDetails &d);
|
||||
static bool getPgpAllList(std::list<RsPgpId> &ids);
|
||||
static bool getPgpValidList(std::list<RsPgpId> &ids);
|
||||
static bool getPgpAcceptedList(std::list<RsPgpId> &ids);
|
||||
static bool getPgpSignedList(std::list<RsPgpId> &ids);
|
||||
static bool importProfile(const std::string& filename,RsPgpId& gpg_id,std::string& import_error) ;
|
||||
static bool importProfileFromString(const std::string& data,RsPgpId& gpg_id,std::string& import_error) ;
|
||||
static bool exportProfile(const std::string& filename,const RsPgpId& gpg_id) ;
|
||||
static bool exportIdentityToString(
|
||||
std::string& data, const RsPgpId& pgpId, bool includeSignatures,
|
||||
std::string& errorMsg );
|
||||
|
||||
virtual bool removeKeysFromPGPKeyring(const std::set<RsPgpId> &pgp_ids,std::string& backup_file,uint32_t& error_code) ;
|
||||
static bool removeKeysFromPGPKeyring(const std::set<RsPgpId> &pgp_ids,std::string& backup_file,uint32_t& error_code) ;
|
||||
|
||||
/*********************************************************************************/
|
||||
/************************* STAGE 4 ***********************************************/
|
||||
@ -171,9 +181,9 @@ public:
|
||||
* STAGE 4: Loading and Saving Certificates. (Strings and Files)
|
||||
*
|
||||
****/
|
||||
virtual bool LoadCertificateFromString(const std::string &pem, RsPgpId& gpg_id,std::string& error_string);
|
||||
virtual bool LoadPGPKeyFromBinaryData(const unsigned char *data,uint32_t data_len, RsPgpId& gpg_id,std::string& error_string);
|
||||
virtual std::string SaveCertificateToString(const RsPgpId &id,bool include_signatures) ;
|
||||
static bool LoadCertificateFromString(const std::string &pem, RsPgpId& gpg_id,std::string& error_string);
|
||||
static bool LoadPGPKeyFromBinaryData(const unsigned char *data,uint32_t data_len, RsPgpId& gpg_id,std::string& error_string);
|
||||
static std::string SaveCertificateToString(const RsPgpId &id,bool include_signatures) ;
|
||||
|
||||
// Cached certificates.
|
||||
//bool getCachedGPGCertificate(const RsPgpId &id, std::string &certificate);
|
||||
@ -188,12 +198,12 @@ public:
|
||||
* done in gpgroot already.
|
||||
*
|
||||
****/
|
||||
virtual bool AllowConnection(const RsPgpId &gpg_id, bool accept);
|
||||
static bool AllowConnection(const RsPgpId &gpg_id, bool accept);
|
||||
|
||||
virtual bool SignCertificateLevel0(const RsPgpId &id);
|
||||
virtual bool RevokeCertificate(const RsPgpId &id); /* Particularly hard - leave for later */
|
||||
static bool SignCertificateLevel0(const RsPgpId &id);
|
||||
static bool RevokeCertificate(const RsPgpId &id); /* Particularly hard - leave for later */
|
||||
|
||||
virtual bool TrustCertificate(const RsPgpId& id, int trustlvl); //trustlvl is 2 for none, 3 for marginal and 4 for full trust
|
||||
static bool TrustCertificate(const RsPgpId& id, int trustlvl); //trustlvl is 2 for none, 3 for marginal and 4 for full trust
|
||||
|
||||
/*********************************************************************************/
|
||||
/************************* STAGE 7 ***********************************************/
|
||||
@ -204,39 +214,39 @@ public:
|
||||
* There should also be Encryption Functions... (do later).
|
||||
*
|
||||
****/
|
||||
virtual bool SignDataBin(const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen, std::string reason = "");
|
||||
virtual bool VerifySignBin(const void*, uint32_t, unsigned char*, unsigned int, const PGPFingerprintType& withfingerprint);
|
||||
virtual bool parseSignature(const void *sig, unsigned int siglen, RsPgpId& issuer_id);
|
||||
static bool SignDataBin(const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen, std::string reason = "");
|
||||
static bool VerifySignBin(const void*, uint32_t, unsigned char*, unsigned int, const PGPFingerprintType& withfingerprint);
|
||||
static bool parseSignature(const void *sig, unsigned int siglen, RsPgpId& issuer_id);
|
||||
|
||||
virtual bool encryptDataBin(const RsPgpId& pgp_id,const void *data, const uint32_t len, unsigned char *encr, unsigned int *encrlen);
|
||||
virtual bool decryptDataBin(const void *data, const uint32_t len, unsigned char *decr, unsigned int *decrlen);
|
||||
static bool encryptDataBin(const RsPgpId& pgp_id,const void *data, const uint32_t len, unsigned char *encr, unsigned int *encrlen);
|
||||
static bool decryptDataBin(const void *data, const uint32_t len, unsigned char *decr, unsigned int *decrlen);
|
||||
|
||||
virtual bool decryptTextFromFile( std::string& text,const std::string& filename);
|
||||
virtual bool encryptTextToFile (const std::string& text,const std::string& filename);
|
||||
static bool decryptTextFromFile( std::string& text,const std::string& filename);
|
||||
static bool encryptTextToFile (const std::string& text,const std::string& filename);
|
||||
|
||||
// virtual bool decryptTextFromString( std::string& encrypted_text,std::string& clear_string);
|
||||
// virtual bool encryptTextToString (const std::string& pgp_id,const std::string& clear_text,std::string& encrypted_string);
|
||||
|
||||
bool getGPGFilteredList(std::list<RsPgpId>& list,bool (*filter)(const PGPCertificateInfo&) = NULL) ;
|
||||
static bool getGPGFilteredList(std::list<RsPgpId>& list,bool (*filter)(const PGPCertificateInfo&) = NULL) ;
|
||||
|
||||
//END of PGP public functions
|
||||
|
||||
/* GPG service */
|
||||
virtual bool addService(AuthGPGService *service) ;
|
||||
static bool addService(AuthGPGService *service) ;
|
||||
|
||||
// This is for debug purpose only. Don't use it !!
|
||||
static void setAuthGPG_debug(AuthGPG *auth_gpg) { _instance = auth_gpg ; }
|
||||
static void setAuthGPG_debug(AuthPGP *auth_gpg) { _instance = auth_gpg ; }
|
||||
|
||||
protected:
|
||||
AuthGPG(const std::string& path_to_pubring, const std::string& path_to_secring,const std::string& path_to_trustdb,const std::string& pgp_lock_file);
|
||||
virtual ~AuthGPG();
|
||||
AuthPGP(const std::string& path_to_pubring, const std::string& path_to_secring,const std::string& path_to_trustdb,const std::string& pgp_lock_file);
|
||||
virtual ~AuthPGP();
|
||||
|
||||
/*****************************************************************/
|
||||
/*********************** p3config ******************************/
|
||||
/* Key Functions to be overloaded for Full Configuration */
|
||||
virtual RsSerialiser *setupSerialiser();
|
||||
virtual bool saveList(bool &cleanup, std::list<RsItem *>&);
|
||||
virtual bool loadList(std::list<RsItem *>& load);
|
||||
virtual RsSerialiser *setupSerialiser() override;
|
||||
virtual bool saveList(bool &cleanup, std::list<RsItem *>&) override;
|
||||
virtual bool loadList(std::list<RsItem *>& load) override;
|
||||
/*****************************************************************/
|
||||
|
||||
private:
|
||||
@ -274,8 +284,7 @@ private:
|
||||
void threadTick() override; /// @see RsTickingThread
|
||||
|
||||
private:
|
||||
|
||||
static AuthGPG *instance_gpg; // pointeur vers le singleton
|
||||
static AuthPGP *instance();
|
||||
|
||||
RsMutex gpgMtxService;
|
||||
RsMutex gpgMtxEngine;
|
||||
@ -290,6 +299,8 @@ private:
|
||||
|
||||
rstime_t mStoreKeyTime;
|
||||
|
||||
PGPHandler *mPgpHandler;
|
||||
|
||||
RsPgpId mOwnGpgId;
|
||||
bool gpgKeySelected;
|
||||
bool _force_sync_database ;
|
||||
@ -297,7 +308,7 @@ private:
|
||||
|
||||
std::list<AuthGPGService*> services ;
|
||||
|
||||
static AuthGPG *_instance ;
|
||||
static AuthPGP *_instance ;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -759,8 +759,7 @@ X509 *AuthSSLimpl::SignX509ReqWithGPG(X509_REQ *req, long /*days*/)
|
||||
//long version = 0x00;
|
||||
unsigned long chtype = MBSTRING_UTF8;
|
||||
X509_NAME *issuer_name = X509_NAME_new();
|
||||
X509_NAME_add_entry_by_txt(issuer_name, "CN", chtype,
|
||||
(unsigned char *) AuthGPG::getAuthGPG()->getGPGOwnId().toStdString().c_str(), -1, -1, 0);
|
||||
X509_NAME_add_entry_by_txt(issuer_name, "CN", chtype, (unsigned char *) AuthPGP::getPgpOwnId().toStdString().c_str(), -1, -1, 0);
|
||||
/****
|
||||
X509_NAME_add_entry_by_NID(issuer_name, 48, 0,
|
||||
(unsigned char *) "email@email.com", -1, -1, 0);
|
||||
@ -770,7 +769,7 @@ X509 *AuthSSLimpl::SignX509ReqWithGPG(X509_REQ *req, long /*days*/)
|
||||
(unsigned char *) "loc", -1, -1, 0);
|
||||
****/
|
||||
|
||||
std::cerr << "AuthSSLimpl::SignX509Req() Issuer name: " << AuthGPG::getAuthGPG()->getGPGOwnId().toStdString() << std::endl;
|
||||
std::cerr << "AuthSSLimpl::SignX509Req() Issuer name: " << AuthPGP::getPgpOwnId().toStdString() << std::endl;
|
||||
|
||||
#ifdef V07_NON_BACKWARD_COMPATIBLE_CHANGE_002
|
||||
static const uint64_t CERTIFICATE_SERIAL_NUMBER = RS_CERTIFICATE_VERSION_NUMBER_07_0001 ;
|
||||
@ -945,7 +944,7 @@ X509 *AuthSSLimpl::SignX509ReqWithGPG(X509_REQ *req, long /*days*/)
|
||||
std::cerr << "Buffers Allocated" << std::endl;
|
||||
|
||||
/* NOW Sign via GPG Functions */
|
||||
if (!AuthGPG::getAuthGPG()->SignDataBin(buf_in, inl, buf_sigout, (unsigned int *) &sigoutl,"AuthSSLimpl::SignX509ReqWithGPG()"))
|
||||
if (!AuthPGP::SignDataBin(buf_in, inl, buf_sigout, (unsigned int *) &sigoutl,"AuthSSLimpl::SignX509ReqWithGPG()"))
|
||||
{
|
||||
sigoutl = 0;
|
||||
goto err;
|
||||
@ -1040,7 +1039,7 @@ bool AuthSSLimpl::AuthX509WithGPG(X509 *x509,bool verbose, uint32_t& diagnostic)
|
||||
{
|
||||
RsPgpId issuer = RsX509Cert::getCertIssuer(*x509);
|
||||
RsPeerDetails pd;
|
||||
if (!AuthGPG::getAuthGPG()->getGPGDetails(issuer, pd))
|
||||
if (!AuthPGP::getPgpDetails(issuer, pd))
|
||||
{
|
||||
RsInfo() << __PRETTY_FUNCTION__ << " X509 NOT authenticated : "
|
||||
<< "AuthGPG::getAuthGPG()->getGPGDetails(" << issuer
|
||||
@ -1185,9 +1184,7 @@ bool AuthSSLimpl::AuthX509WithGPG(X509 *x509,bool verbose, uint32_t& diagnostic)
|
||||
|
||||
// passed, verify the signature itself
|
||||
|
||||
if (!AuthGPG::getAuthGPG()->VerifySignBin(
|
||||
signed_data, signed_data_length, signature->data,
|
||||
static_cast<unsigned int>(signature->length), pd.fpr ))
|
||||
if (!AuthPGP::VerifySignBin( signed_data, signed_data_length, signature->data, static_cast<unsigned int>(signature->length), pd.fpr ))
|
||||
{
|
||||
diagnostic = RS_SSL_HANDSHAKE_DIAGNOSTIC_WRONG_SIGNATURE;
|
||||
goto err;
|
||||
@ -1383,7 +1380,7 @@ int AuthSSLimpl::VerifyX509Callback(int /*preverify_ok*/, X509_STORE_CTX* ctx)
|
||||
std::cerr << "******* VerifyX509Callback cert: " << std::hex << ctx->cert <<std::dec << std::endl;
|
||||
#endif
|
||||
|
||||
if ( !isSslOnlyFriend && pgpId != AuthGPG::getAuthGPG()->getGPGOwnId() && !AuthGPG::getAuthGPG()->isGPGAccepted(pgpId) )
|
||||
if ( !isSslOnlyFriend && pgpId != AuthPGP::getPgpOwnId() && !AuthPGP::isPGPAccepted(pgpId) )
|
||||
{
|
||||
std::string errMsg = "Connection attempt signed by PGP key id: " +
|
||||
pgpId.toStdString() + " not accepted because it is not"
|
||||
|
@ -812,11 +812,11 @@ int p3PeerMgrIMPL::getFriendCount(bool ssl, bool online)
|
||||
|
||||
// count all gpg id's
|
||||
std::list<RsPgpId> gpgIds;
|
||||
AuthGPG::getAuthGPG()->getGPGAcceptedList(gpgIds);
|
||||
AuthPGP::getPgpAcceptedList(gpgIds);
|
||||
|
||||
// add own gpg id, if we have more than one location
|
||||
std::list<RsPeerId> ownSslIds;
|
||||
getAssociatedPeers(AuthGPG::getAuthGPG()->getGPGOwnId(), ownSslIds);
|
||||
getAssociatedPeers(AuthPGP::getPgpOwnId(), ownSslIds);
|
||||
|
||||
return gpgIds.size() + ((ownSslIds.size() > 0) ? 1 : 0);
|
||||
}
|
||||
@ -962,7 +962,7 @@ bool p3PeerMgrIMPL::addFriend(const RsPeerId& input_id, const RsPgpId& input_gpg
|
||||
|
||||
// check that the PGP key is known
|
||||
|
||||
if(!AuthGPG::getAuthGPG()->isGPGId(gpg_id))
|
||||
if(!AuthPGP::isPGPId(gpg_id))
|
||||
{
|
||||
RsErr() << "Trying to add SSL id (" << id << ") to be validated with unknown PGP key (" << gpg_id << ". This is a bug!" << std::endl;
|
||||
return false;
|
||||
@ -970,7 +970,7 @@ bool p3PeerMgrIMPL::addFriend(const RsPeerId& input_id, const RsPgpId& input_gpg
|
||||
|
||||
//Authentication is now tested at connection time, we don't store the ssl cert anymore
|
||||
//
|
||||
if (!AuthGPG::getAuthGPG()->isGPGAccepted(gpg_id) && gpg_id != AuthGPG::getAuthGPG()->getGPGOwnId())
|
||||
if (!AuthPGP::isPGPAccepted(gpg_id) && gpg_id != AuthPGP::getPgpOwnId())
|
||||
{
|
||||
#ifdef PEER_DEBUG
|
||||
std::cerr << "p3PeerMgrIMPL::addFriend() gpg is not accepted" << std::endl;
|
||||
@ -1024,7 +1024,7 @@ bool p3PeerMgrIMPL::addFriend(const RsPeerId& input_id, const RsPgpId& input_gpg
|
||||
|
||||
pstate.id = id;
|
||||
pstate.gpg_id = gpg_id;
|
||||
pstate.name = AuthGPG::getAuthGPG()->getGPGName(gpg_id);
|
||||
pstate.name = AuthPGP::getPgpName(gpg_id);
|
||||
|
||||
pstate.vs_disc = vs_disc;
|
||||
pstate.vs_dht = vs_dht;
|
||||
@ -1126,8 +1126,8 @@ bool p3PeerMgrIMPL::addSslOnlyFriend( const RsPeerId& sslId, const RsPgpId& pgp_
|
||||
* superficially set to true the PGP signature verification would have been
|
||||
* skipped and the attacker connection would be accepted.
|
||||
* If the PGP key is available add it as full friend. */
|
||||
if(AuthGPG::getAuthGPG()->isPgpPubKeyAvailable(pgp_id))
|
||||
AuthGPG::getAuthGPG()->AllowConnection(pgp_id, true);
|
||||
if(AuthPGP::isPgpPubKeyAvailable(pgp_id))
|
||||
AuthPGP::AllowConnection(pgp_id, true);
|
||||
else
|
||||
pstate.skip_pgp_signature_validation = true;
|
||||
|
||||
@ -1398,11 +1398,11 @@ bool p3PeerMgrIMPL::UpdateOwnAddress( const sockaddr_storage& pLocalAddr,
|
||||
sockaddr_storage_copy(pExtAddr, extAddr);
|
||||
sockaddr_storage_ipv6_to_ipv4(extAddr);
|
||||
|
||||
//#ifdef PEER_DEBUG
|
||||
#ifdef PEER_DEBUG
|
||||
std::cerr << "p3PeerMgrIMPL::UpdateOwnAddress("
|
||||
<< sockaddr_storage_tostring(localAddr) << ", "
|
||||
<< sockaddr_storage_tostring(extAddr) << ")" << std::endl;
|
||||
//#endif
|
||||
#endif
|
||||
|
||||
if( rsBanList &&
|
||||
!rsBanList->isAddressAccepted(localAddr,
|
||||
@ -2470,7 +2470,7 @@ bool p3PeerMgrIMPL::loadList(std::list<RsItem *>& load)
|
||||
setOwnNetworkMode(pitem->netMode);
|
||||
setOwnVisState(pitem->vs_disc, pitem->vs_dht);
|
||||
|
||||
mOwnState.gpg_id = AuthGPG::getAuthGPG()->getGPGOwnId();
|
||||
mOwnState.gpg_id = AuthPGP::getPgpOwnId();
|
||||
mOwnState.location = AuthSSL::getAuthSSL()->getOwnLocation();
|
||||
}
|
||||
else
|
||||
@ -2642,7 +2642,7 @@ bool p3PeerMgrIMPL::loadList(std::list<RsItem *>& load)
|
||||
#endif
|
||||
|
||||
for(uint32_t i=0;i<sitem->pgp_ids.size();++i)
|
||||
if(AuthGPG::getAuthGPG()->isGPGAccepted(sitem->pgp_ids[i]) || sitem->pgp_ids[i] == AuthGPG::getAuthGPG()->getGPGOwnId())
|
||||
if(AuthPGP::isPGPAccepted(sitem->pgp_ids[i]) || sitem->pgp_ids[i] == AuthPGP::getPgpOwnId())
|
||||
{
|
||||
mFriendsPermissionFlags[sitem->pgp_ids[i]] = sitem->service_flags[i] ;
|
||||
#ifdef PEER_DEBUG
|
||||
@ -2684,7 +2684,7 @@ bool p3PeerMgrIMPL::loadList(std::list<RsItem *>& load)
|
||||
for(auto group_pair:groupList)
|
||||
{
|
||||
for(auto profileIdIt(group_pair.second.peerIds.begin());profileIdIt!=group_pair.second.peerIds.end();)
|
||||
if(AuthGPG::getAuthGPG()->isGPGAccepted(*profileIdIt) || *profileIdIt == AuthGPG::getAuthGPG()->getGPGOwnId())
|
||||
if(AuthPGP::isPGPAccepted(*profileIdIt) || *profileIdIt == AuthPGP::getPgpOwnId())
|
||||
++profileIdIt;
|
||||
else
|
||||
{
|
||||
|
@ -46,9 +46,13 @@ void RsFdBinInterface::setSocket(int s)
|
||||
int flags = fcntl(s,F_GETFL);
|
||||
|
||||
if(!(flags & O_NONBLOCK))
|
||||
throw std::runtime_error("Trying to use a blocking file descriptor in RsFdBinInterface. This is not going to work!");
|
||||
{
|
||||
RsWarn() << "Trying to use a blocking file descriptor in RsFdBinInterface. This is not going to work! Setting the socket to be non blocking.";
|
||||
unix_fcntl_nonblock(s);
|
||||
}
|
||||
|
||||
#else
|
||||
// On windows, there is no way to determine whether a socket is blobking or not, so we set it to non blocking whatsoever.
|
||||
// On windows, there is no way to determine whether a socket is blocking or not, so we set it to non blocking whatsoever.
|
||||
unsigned long int on = 1;
|
||||
ioctlsocket(s, FIONBIO, &on);
|
||||
#endif
|
||||
|
@ -21,15 +21,6 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
#ifdef WINDOWS_SYS
|
||||
# include "util/rswin.h"
|
||||
# include "util/rsmemory.h"
|
||||
# include <ws2tcpip.h>
|
||||
#endif // WINDOWS_SYS
|
||||
|
||||
#ifdef __ANDROID__
|
||||
# include <android/api-level.h>
|
||||
#endif // def __ANDROID__
|
||||
|
||||
#include <cerrno>
|
||||
#include <iostream>
|
||||
@ -43,6 +34,28 @@
|
||||
#include "util/rsnet.h"
|
||||
#include "util/stacktrace.h"
|
||||
|
||||
#ifdef WINDOWS_SYS
|
||||
# include "util/rswin.h"
|
||||
# include "util/rsmemory.h"
|
||||
# include <ws2tcpip.h>
|
||||
#endif // WINDOWS_SYS
|
||||
|
||||
/// @See: android_ifaddrs/README.adoc
|
||||
#ifdef __ANDROID__
|
||||
# include <android/api-level.h>
|
||||
#endif // def __ANDROID__
|
||||
|
||||
#ifdef WINDOWS_SYS /* Windows - define errno */
|
||||
int errno;
|
||||
#else /* Windows - define errno */
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
#ifdef __HAIKU__
|
||||
# include <sys/sockio.h>
|
||||
# define IFF_RUNNING 0x0001
|
||||
#endif
|
||||
|
||||
static struct RsLog::logInfo pqinetzoneInfo = {RsLog::Default, "pqinet"};
|
||||
#define pqinetzone &pqinetzoneInfo
|
||||
|
||||
@ -50,21 +63,6 @@ static struct RsLog::logInfo pqinetzoneInfo = {RsLog::Default, "pqinet"};
|
||||
* #define NET_DEBUG 1
|
||||
****/
|
||||
|
||||
#ifdef WINDOWS_SYS /* Windows - define errno */
|
||||
|
||||
int errno;
|
||||
|
||||
#else /* Windows - define errno */
|
||||
|
||||
#include <netdb.h>
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __HAIKU__
|
||||
#include <sys/sockio.h>
|
||||
#define IFF_RUNNING 0x0001
|
||||
#endif
|
||||
|
||||
/********************************** WINDOWS/UNIX SPECIFIC PART ******************/
|
||||
#ifndef WINDOWS_SYS
|
||||
|
||||
@ -270,18 +268,16 @@ int inet_aton(const char *name, struct in_addr *addr)
|
||||
#endif
|
||||
/********************************** WINDOWS/UNIX SPECIFIC PART ******************/
|
||||
|
||||
|
||||
#include "util/cxx17retrocompat.h"
|
||||
#include <sys/types.h>
|
||||
#ifdef WINDOWS_SYS
|
||||
# include <winsock2.h>
|
||||
# include <iphlpapi.h>
|
||||
# pragma comment(lib, "IPHLPAPI.lib")
|
||||
#elif defined(__ANDROID__) && __ANDROID_API__ < 24
|
||||
# include <string>
|
||||
# include <QString>
|
||||
# include <QHostAddress>
|
||||
# include <QNetworkInterface>
|
||||
#else // not __ANDROID__ nor WINDOWS => Linux and other unixes
|
||||
/// @See: android_ifaddrs/README.adoc
|
||||
# include "rs_android/ifaddrs-android.h"
|
||||
#else // not WINDOWS => Linux and other unixes
|
||||
# include <ifaddrs.h>
|
||||
# include <net/if.h>
|
||||
#endif // WINDOWS_SYS
|
||||
@ -324,20 +320,12 @@ bool getLocalAddresses(std::vector<sockaddr_storage>& addrs)
|
||||
}
|
||||
}
|
||||
free(adapter_addresses);
|
||||
#elif defined(__ANDROID__) && __ANDROID_API__ < 24
|
||||
for(auto& qAddr: QNetworkInterface::allAddresses())
|
||||
{
|
||||
sockaddr_storage tmpAddr;
|
||||
sockaddr_storage_clear(tmpAddr);
|
||||
if(sockaddr_storage_ipv4_aton(tmpAddr, qAddr.toString().toStdString().c_str()))
|
||||
addrs.push_back(tmpAddr);
|
||||
}
|
||||
#else // not WINDOWS_SYS not ANDROID => Linux and other unixes
|
||||
#else // not WINDOWS_SYS => Linux and other unixes
|
||||
struct ifaddrs *ifsaddrs, *ifa;
|
||||
if(getifaddrs(&ifsaddrs) != 0)
|
||||
{
|
||||
std::cerr << __PRETTY_FUNCTION__ << " FATAL ERROR: " << errno << " "
|
||||
<< strerror(errno) << std::endl;
|
||||
RS_ERR( "getifaddrs failed with: ", errno, " ",
|
||||
rs_errno_to_condition(errno) );
|
||||
print_stacktrace();
|
||||
return false;
|
||||
}
|
||||
@ -346,18 +334,19 @@ bool getLocalAddresses(std::vector<sockaddr_storage>& addrs)
|
||||
{
|
||||
sockaddr_storage tmp;
|
||||
sockaddr_storage_clear(tmp);
|
||||
if (sockaddr_storage_copyip(tmp, *reinterpret_cast<sockaddr_storage*>(ifa->ifa_addr)))
|
||||
if(sockaddr_storage_copyip(
|
||||
tmp,
|
||||
*reinterpret_cast<sockaddr_storage*>(ifa->ifa_addr) ))
|
||||
addrs.push_back(tmp);
|
||||
}
|
||||
freeifaddrs(ifsaddrs);
|
||||
#endif // WINDOWS_SYS
|
||||
|
||||
#ifdef NET_DEBUG
|
||||
std::list<sockaddr_storage>::iterator it;
|
||||
std::cout << "getLocalAddresses(...) returning: <" ;
|
||||
for(it = addrs.begin(); it != addrs.end(); ++it)
|
||||
std::cout << sockaddr_storage_iptostring(*it) << ", ";
|
||||
std::cout << ">" << std::endl;
|
||||
auto&& dbg = RS_DBG("returning: [");
|
||||
for(auto& addr: std::as_const(addrs))
|
||||
dbg << sockaddr_storage_iptostring(addr) << ", ";
|
||||
dbg << "]" << std::endl;
|
||||
#endif
|
||||
|
||||
return !addrs.empty();
|
||||
|
@ -4,7 +4,8 @@
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright (C) 2004-2006 Robert Fernie <retroshare@lunamutt.com> *
|
||||
* Copyright (C) 2015-2018 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* Copyright (C) 2015-2021 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
@ -20,8 +21,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
#ifndef MRK_PQI_NETWORKING_HEADER
|
||||
#define MRK_PQI_NETWORKING_HEADER
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
@ -86,9 +86,13 @@ extern int errno; /* Define extern errno, to duplicate unix behaviour */
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
#include "util/rsdeprecate.h"
|
||||
|
||||
// Same def - different functions...
|
||||
RS_DEPRECATED_FOR("use std::error_condition instead")
|
||||
void showSocketError(std::string &out);
|
||||
|
||||
RS_DEPRECATED_FOR("use std::error_condition instead")
|
||||
std::string socket_errorType(int err);
|
||||
|
||||
bool getLocalAddresses(std::vector<sockaddr_storage> & addrs);
|
||||
@ -103,10 +107,6 @@ int unix_getsockopt_error(int sockfd, int *err);
|
||||
|
||||
#ifdef WINDOWS_SYS // WINDOWS
|
||||
/******************* WINDOWS SPECIFIC PART ******************/
|
||||
RS_DEPRECATED_FOR("use std::error_condition instead")
|
||||
int WinToUnixError(int error);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -1213,8 +1213,7 @@ int pqissl::Authorise_SSL_Connection()
|
||||
}
|
||||
|
||||
RsPgpId pgpId = RsX509Cert::getCertIssuer(*peercert);
|
||||
if( !isSslOnlyFriend && pgpId != AuthGPG::getAuthGPG()->getGPGOwnId() &&
|
||||
!AuthGPG::getAuthGPG()->isGPGAccepted(pgpId) )
|
||||
if( !isSslOnlyFriend && pgpId != AuthPGP::getPgpOwnId() && !AuthPGP::isPGPAccepted(pgpId) )
|
||||
{
|
||||
RsFatal() << __PRETTY_FUNCTION__ << " pgpId: " << pgpId
|
||||
<< " is not friend. It is very unlikely to happen at this "
|
||||
|
@ -797,8 +797,7 @@ int pqissllistener::completeConnection(int fd, IncomingSSLInfo& info)
|
||||
exit(failure);
|
||||
}
|
||||
|
||||
if( !isSslOnlyFriend && pgpId != AuthGPG::getAuthGPG()->getGPGOwnId() &&
|
||||
!AuthGPG::getAuthGPG()->isGPGAccepted(pgpId) )
|
||||
if( !isSslOnlyFriend && pgpId != AuthPGP::getPgpOwnId() && !AuthPGP::isPGPAccepted(pgpId) )
|
||||
{
|
||||
RsFatal() << __PRETTY_FUNCTION__ << " pgpId: " << pgpId
|
||||
<< " is not friend. It is very unlikely to happen at this "
|
||||
|
@ -450,6 +450,17 @@ public:
|
||||
const std::string& matchString,
|
||||
std::vector<RsGxsSearchResult>& searchResults ) = 0;
|
||||
|
||||
/**
|
||||
* @brief Request Synchronization with available peers
|
||||
* Usually syncronization already happen automatically so be carefull
|
||||
* to call this method only if necessary.
|
||||
* It has been thinked for use cases like mobile phone where internet
|
||||
* connection is intermittent and calling this may be useful when a system
|
||||
* event about connection being available or about to go offline is received
|
||||
* @jsonapi{development}
|
||||
* @return Success or error details
|
||||
*/
|
||||
virtual std::error_condition requestSynchronization() = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
/* Following functions are deprecated and should not be considered a stable
|
||||
|
@ -887,7 +887,7 @@ public:
|
||||
// Certificate utils
|
||||
virtual bool cleanCertificate(
|
||||
const std::string& certstr, std::string& cleanCert,
|
||||
bool& is_short_format, uint32_t& error_code ) = 0;
|
||||
bool& is_short_format, uint32_t& error_code, RsPeerDetails& details) = 0;
|
||||
virtual std::string saveCertificateToString(const RsPeerId &id) = 0;
|
||||
|
||||
virtual bool signGPGCertificate(const RsPgpId &gpg_id,const std::string& gpg_passphrase) = 0;
|
||||
|
75
libretroshare/src/rs_android/LocalArray.h
Normal file
75
libretroshare/src/rs_android/LocalArray.h
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef LOCAL_ARRAY_H_included
|
||||
#define LOCAL_ARRAY_H_included
|
||||
|
||||
#include <cstddef>
|
||||
#include <new>
|
||||
|
||||
/**
|
||||
* A fixed-size array with a size hint. That number of bytes will be allocated
|
||||
* on the stack, and used if possible, but if more bytes are requested at
|
||||
* construction time, a buffer will be allocated on the heap (and deallocated
|
||||
* by the destructor).
|
||||
*
|
||||
* The API is intended to be a compatible subset of C++0x's std::array.
|
||||
*/
|
||||
template <size_t STACK_BYTE_COUNT>
|
||||
class LocalArray {
|
||||
public:
|
||||
/**
|
||||
* Allocates a new fixed-size array of the given size. If this size is
|
||||
* less than or equal to the template parameter STACK_BYTE_COUNT, an
|
||||
* internal on-stack buffer will be used. Otherwise a heap buffer will
|
||||
* be allocated.
|
||||
*/
|
||||
LocalArray(size_t desiredByteCount) : mSize(desiredByteCount) {
|
||||
if (desiredByteCount > STACK_BYTE_COUNT) {
|
||||
mPtr = new char[mSize];
|
||||
} else {
|
||||
mPtr = &mOnStackBuffer[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees the heap-allocated buffer, if there was one.
|
||||
*/
|
||||
~LocalArray() {
|
||||
if (mPtr != &mOnStackBuffer[0]) {
|
||||
delete[] mPtr;
|
||||
}
|
||||
}
|
||||
|
||||
// Capacity.
|
||||
size_t size() { return mSize; }
|
||||
bool empty() { return mSize == 0; }
|
||||
|
||||
// Element access.
|
||||
char& operator[](size_t n) { return mPtr[n]; }
|
||||
const char& operator[](size_t n) const { return mPtr[n]; }
|
||||
|
||||
private:
|
||||
char mOnStackBuffer[STACK_BYTE_COUNT];
|
||||
char* mPtr;
|
||||
size_t mSize;
|
||||
|
||||
// Disallow copy and assignment.
|
||||
LocalArray(const LocalArray&);
|
||||
void operator=(const LocalArray&);
|
||||
};
|
||||
|
||||
#endif // LOCAL_ARRAY_H_included
|
49
libretroshare/src/rs_android/README-ifaddrs-android.adoc
Normal file
49
libretroshare/src/rs_android/README-ifaddrs-android.adoc
Normal file
@ -0,0 +1,49 @@
|
||||
= README Android ifaddrs
|
||||
|
||||
Android API level < 24 doesn't provide `getifaddrs` and related functions, we
|
||||
have tested multiple ways to overcome this issue.
|
||||
|
||||
|
||||
== Non Weorking alternative implementations
|
||||
|
||||
https://github.com/kmackay/android-ifaddrs
|
||||
https://github.com/morristech/android-ifaddrs
|
||||
https://www.openhub.net/p/android-ifaddrs/
|
||||
|
||||
Compiles but then segfault at runtime.
|
||||
|
||||
|
||||
== Qt implementation
|
||||
|
||||
Using `QNetworkInterface::allAddresses()` provided by Qt works but at time of
|
||||
writing (Q4 2021) on newer Android the log is flooded by warnings as we reported
|
||||
here
|
||||
https://bugreports.qt.io/browse/QTBUG-78659
|
||||
plus depending on Qt networking module just for this is frustrating.
|
||||
|
||||
Update: the warning flood seems have been fixed in later Qt versions
|
||||
https://bugreports.qt.io/browse/QTBUG-86394
|
||||
|
||||
This solution was the first working we implemented in our code it has been
|
||||
removed to avoid dependency on Qt, as lighter alternatives are possible.
|
||||
|
||||
|
||||
== Code copied from Android Gingerbread release
|
||||
|
||||
As explained here
|
||||
https://stackoverflow.com/a/57112520
|
||||
|
||||
even older Android have `getifaddrs` implementations but doesn't make them
|
||||
accessible in the API, in particular the one included in Android Gingerbread
|
||||
|
||||
https://android.googlesource.com/platform/libcore/+/refs/heads/gingerbread-release/luni/src/main/native/ifaddrs-android.h
|
||||
https://android.googlesource.com/platform/libcore/+/refs/heads/gingerbread-release/
|
||||
|
||||
is particularly easy to include in our code base and compile.
|
||||
|
||||
This solution seems the best fitting and doesn't introduce dependency on Qt.
|
||||
Newer Android releases (expecially 11) have introduced multiple restrictions
|
||||
on network information access so we suggest you to prepare different APK for
|
||||
different API level in order to use the `getifaddrs` provided by Android NDK
|
||||
which deal gracefully with those restrictions as soon as available.
|
||||
|
46
libretroshare/src/rs_android/ScopedFd.h
Normal file
46
libretroshare/src/rs_android/ScopedFd.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef SCOPED_FD_H_included
|
||||
#define SCOPED_FD_H_included
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
// A smart pointer that closes the given fd on going out of scope.
|
||||
// Use this when the fd is incidental to the purpose of your function,
|
||||
// but needs to be cleaned up on exit.
|
||||
class ScopedFd {
|
||||
public:
|
||||
explicit ScopedFd(int fd) : fd(fd) {
|
||||
}
|
||||
|
||||
~ScopedFd() {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
int get() const {
|
||||
return fd;
|
||||
}
|
||||
|
||||
private:
|
||||
int fd;
|
||||
|
||||
// Disallow copy and assignment.
|
||||
ScopedFd(const ScopedFd&);
|
||||
void operator=(const ScopedFd&);
|
||||
};
|
||||
|
||||
#endif // SCOPED_FD_H_included
|
@ -1,9 +1,9 @@
|
||||
/*******************************************************************************
|
||||
* libretroshare/src/util: androiddebug.h *
|
||||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright (C) 2016 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* Copyright (C) 2016-2021 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
@ -36,10 +36,10 @@
|
||||
* class at the beginning of the main of your program to get them (stdout and
|
||||
* stderr) on logcat output.
|
||||
*/
|
||||
class AndroidStdIOCatcher
|
||||
class AndroidCoutCerrCatcher
|
||||
{
|
||||
public:
|
||||
AndroidStdIOCatcher(const std::string& dTag = "RetroShare",
|
||||
AndroidCoutCerrCatcher(const std::string& dTag = "RetroShare",
|
||||
android_LogPriority stdout_pri = ANDROID_LOG_INFO,
|
||||
android_LogPriority stderr_pri = ANDROID_LOG_ERROR) :
|
||||
tag(dTag), cout_pri(stdout_pri), cerr_pri(stderr_pri), should_stop(false)
|
||||
@ -63,10 +63,10 @@ public:
|
||||
pthread_detach(thr);
|
||||
}
|
||||
|
||||
~AndroidStdIOCatcher()
|
||||
~AndroidCoutCerrCatcher()
|
||||
{
|
||||
should_stop = true;
|
||||
pthread_join(thr, NULL);
|
||||
pthread_join(thr, nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -79,11 +79,13 @@ private:
|
||||
pthread_t thr;
|
||||
std::atomic<bool> should_stop;
|
||||
|
||||
static void *thread_func(void* instance)
|
||||
static void* thread_func(void* instance)
|
||||
{
|
||||
__android_log_write(ANDROID_LOG_INFO, "RetroShare", "Android debugging start");
|
||||
__android_log_write(
|
||||
ANDROID_LOG_INFO, "RetroShare",
|
||||
"Android standard I/O catcher start" );
|
||||
|
||||
AndroidStdIOCatcher &i = *static_cast<AndroidStdIOCatcher*>(instance);
|
||||
AndroidCoutCerrCatcher &i = *static_cast<AndroidCoutCerrCatcher*>(instance);
|
||||
|
||||
std::string out_buf;
|
||||
std::string err_buf;
|
||||
@ -113,9 +115,11 @@ private:
|
||||
usleep(10000);
|
||||
}
|
||||
|
||||
__android_log_write(ANDROID_LOG_INFO, "RetroShare", "Android debugging stop");
|
||||
__android_log_write(
|
||||
ANDROID_LOG_INFO, "RetroShare",
|
||||
"Android standard I/O catcher stop" );
|
||||
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
42
libretroshare/src/rs_android/errorconditionwrap.cpp
Normal file
42
libretroshare/src/rs_android/errorconditionwrap.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright (C) 2021 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public License *
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
#include "rs_android/rsjni.hpp"
|
||||
|
||||
namespace jni
|
||||
{
|
||||
Local<Object<RsJni::ErrorConditionWrap>> MakeAnything(
|
||||
ThingToMake<RsJni::ErrorConditionWrap>, JNIEnv& env,
|
||||
const std::error_condition& ec )
|
||||
{
|
||||
auto& clazz = jni::Class<RsJni::ErrorConditionWrap>::Singleton(env);
|
||||
|
||||
static auto method =
|
||||
clazz.GetConstructor<jni::jint, jni::String, jni::String>(env);
|
||||
|
||||
jni::jint value = ec.value();
|
||||
auto message = jni::Make<jni::String>(env, ec.message());
|
||||
auto category = jni::Make<jni::String>(env, ec.category().name());
|
||||
|
||||
return clazz.New(env, method, value, message, category);
|
||||
}
|
||||
}
|
228
libretroshare/src/rs_android/ifaddrs-android.h
Normal file
228
libretroshare/src/rs_android/ifaddrs-android.h
Normal file
@ -0,0 +1,228 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef IFADDRS_ANDROID_H_included
|
||||
#define IFADDRS_ANDROID_H_included
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <cstring>
|
||||
#include <errno.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <new>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <stdio.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
#include "LocalArray.h"
|
||||
#include "ScopedFd.h"
|
||||
|
||||
// Android (bionic) doesn't have getifaddrs(3)/freeifaddrs(3).
|
||||
// We fake it here, so java_net_NetworkInterface.cpp can use that API
|
||||
// with all the non-portable code being in this file.
|
||||
|
||||
// Source-compatible subset of the BSD struct.
|
||||
struct ifaddrs {
|
||||
// Pointer to next struct in list, or NULL at end.
|
||||
ifaddrs* ifa_next;
|
||||
|
||||
// Interface name.
|
||||
char* ifa_name;
|
||||
|
||||
// Interface flags.
|
||||
unsigned int ifa_flags;
|
||||
|
||||
// Interface network address.
|
||||
sockaddr* ifa_addr;
|
||||
|
||||
// Interface netmask.
|
||||
sockaddr* ifa_netmask;
|
||||
|
||||
ifaddrs(ifaddrs* next)
|
||||
: ifa_next(next), ifa_name(NULL), ifa_flags(0), ifa_addr(NULL), ifa_netmask(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
~ifaddrs() {
|
||||
delete ifa_next;
|
||||
delete[] ifa_name;
|
||||
delete ifa_addr;
|
||||
delete ifa_netmask;
|
||||
}
|
||||
|
||||
// Sadly, we can't keep the interface index for portability with BSD.
|
||||
// We'll have to keep the name instead, and re-query the index when
|
||||
// we need it later.
|
||||
bool setNameAndFlagsByIndex(int interfaceIndex) {
|
||||
// Get the name.
|
||||
char buf[IFNAMSIZ];
|
||||
char* name = if_indextoname(interfaceIndex, buf);
|
||||
if (name == NULL) {
|
||||
return false;
|
||||
}
|
||||
ifa_name = new char[strlen(name) + 1];
|
||||
strcpy(ifa_name, name);
|
||||
|
||||
// Get the flags.
|
||||
ScopedFd fd(socket(AF_INET, SOCK_DGRAM, 0));
|
||||
if (fd.get() == -1) {
|
||||
return false;
|
||||
}
|
||||
ifreq ifr;
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strcpy(ifr.ifr_name, name);
|
||||
int rc = ioctl(fd.get(), SIOCGIFFLAGS, &ifr);
|
||||
if (rc == -1) {
|
||||
return false;
|
||||
}
|
||||
ifa_flags = ifr.ifr_flags;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Netlink gives us the address family in the header, and the
|
||||
// sockaddr_in or sockaddr_in6 bytes as the payload. We need to
|
||||
// stitch the two bits together into the sockaddr that's part of
|
||||
// our portable interface.
|
||||
void setAddress(int family, void* data, size_t byteCount) {
|
||||
// Set the address proper...
|
||||
sockaddr_storage* ss = new sockaddr_storage;
|
||||
memset(ss, 0, sizeof(*ss));
|
||||
ifa_addr = reinterpret_cast<sockaddr*>(ss);
|
||||
ss->ss_family = family;
|
||||
uint8_t* dst = sockaddrBytes(family, ss);
|
||||
memcpy(dst, data, byteCount);
|
||||
}
|
||||
|
||||
// Netlink gives us the prefix length as a bit count. We need to turn
|
||||
// that into a BSD-compatible netmask represented by a sockaddr*.
|
||||
void setNetmask(int family, size_t prefixLength) {
|
||||
// ...and work out the netmask from the prefix length.
|
||||
sockaddr_storage* ss = new sockaddr_storage;
|
||||
memset(ss, 0, sizeof(*ss));
|
||||
ifa_netmask = reinterpret_cast<sockaddr*>(ss);
|
||||
ss->ss_family = family;
|
||||
uint8_t* dst = sockaddrBytes(family, ss);
|
||||
memset(dst, 0xff, prefixLength / 8);
|
||||
if ((prefixLength % 8) != 0) {
|
||||
dst[prefixLength/8] = (0xff << (8 - (prefixLength % 8)));
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a pointer to the first byte in the address data (which is
|
||||
// stored in network byte order).
|
||||
uint8_t* sockaddrBytes(int family, sockaddr_storage* ss) {
|
||||
if (family == AF_INET) {
|
||||
sockaddr_in* ss4 = reinterpret_cast<sockaddr_in*>(ss);
|
||||
return reinterpret_cast<uint8_t*>(&ss4->sin_addr);
|
||||
} else if (family == AF_INET6) {
|
||||
sockaddr_in6* ss6 = reinterpret_cast<sockaddr_in6*>(ss);
|
||||
return reinterpret_cast<uint8_t*>(&ss6->sin6_addr);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
// Disallow copy and assignment.
|
||||
ifaddrs(const ifaddrs&);
|
||||
void operator=(const ifaddrs&);
|
||||
};
|
||||
|
||||
// FIXME: use iovec instead.
|
||||
struct addrReq_struct {
|
||||
nlmsghdr netlinkHeader;
|
||||
ifaddrmsg msg;
|
||||
};
|
||||
|
||||
inline bool sendNetlinkMessage(int fd, const void* data, size_t byteCount) {
|
||||
ssize_t sentByteCount = TEMP_FAILURE_RETRY(send(fd, data, byteCount, 0));
|
||||
return (sentByteCount == static_cast<ssize_t>(byteCount));
|
||||
}
|
||||
|
||||
inline ssize_t recvNetlinkMessage(int fd, char* buf, size_t byteCount) {
|
||||
return TEMP_FAILURE_RETRY(recv(fd, buf, byteCount, 0));
|
||||
}
|
||||
|
||||
// Source-compatible with the BSD function.
|
||||
inline int getifaddrs(ifaddrs** result) {
|
||||
// Simplify cleanup for callers.
|
||||
*result = NULL;
|
||||
|
||||
// Create a netlink socket.
|
||||
ScopedFd fd(socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE));
|
||||
if (fd.get() < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Ask for the address information.
|
||||
addrReq_struct addrRequest;
|
||||
memset(&addrRequest, 0, sizeof(addrRequest));
|
||||
addrRequest.netlinkHeader.nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH;
|
||||
addrRequest.netlinkHeader.nlmsg_type = RTM_GETADDR;
|
||||
addrRequest.netlinkHeader.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(addrRequest)));
|
||||
addrRequest.msg.ifa_family = AF_UNSPEC; // All families.
|
||||
addrRequest.msg.ifa_index = 0; // All interfaces.
|
||||
if (!sendNetlinkMessage(fd.get(), &addrRequest, addrRequest.netlinkHeader.nlmsg_len)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Read the responses.
|
||||
LocalArray<0> buf(65536); // We don't necessarily have std::vector.
|
||||
ssize_t bytesRead;
|
||||
while ((bytesRead = recvNetlinkMessage(fd.get(), &buf[0], buf.size())) > 0) {
|
||||
nlmsghdr* hdr = reinterpret_cast<nlmsghdr*>(&buf[0]);
|
||||
for (; NLMSG_OK(hdr, (size_t)bytesRead); hdr = NLMSG_NEXT(hdr, bytesRead)) {
|
||||
switch (hdr->nlmsg_type) {
|
||||
case NLMSG_DONE:
|
||||
return 0;
|
||||
case NLMSG_ERROR:
|
||||
return -1;
|
||||
case RTM_NEWADDR:
|
||||
{
|
||||
ifaddrmsg* address = reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(hdr));
|
||||
rtattr* rta = IFA_RTA(address);
|
||||
size_t ifaPayloadLength = IFA_PAYLOAD(hdr);
|
||||
while (RTA_OK(rta, ifaPayloadLength)) {
|
||||
if (rta->rta_type == IFA_LOCAL) {
|
||||
int family = address->ifa_family;
|
||||
if (family == AF_INET || family == AF_INET6) {
|
||||
*result = new ifaddrs(*result);
|
||||
if (!(*result)->setNameAndFlagsByIndex(address->ifa_index)) {
|
||||
return -1;
|
||||
}
|
||||
(*result)->setAddress(family, RTA_DATA(rta), RTA_PAYLOAD(rta));
|
||||
(*result)->setNetmask(family, address->ifa_prefixlen);
|
||||
}
|
||||
}
|
||||
rta = RTA_NEXT(rta, ifaPayloadLength);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// We only get here if recv fails before we see a NLMSG_DONE.
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Source-compatible with the BSD function.
|
||||
inline void freeifaddrs(ifaddrs* addresses) {
|
||||
delete addresses;
|
||||
}
|
||||
|
||||
#endif // IFADDRS_ANDROID_H_included
|
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* RetroShare
|
||||
* Copyright (C) 2021 Gioacchino Mazzurco <gio@eigenlab.org>
|
||||
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-FileCopyrightText: Retroshare Team <contact@retroshare.cc>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package org.retroshare.service;
|
||||
|
||||
import android.util.Log;
|
||||
import android.content.Context;
|
||||
import java.io.OutputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
public class AssetHelper
|
||||
{
|
||||
public static boolean copyAsset(
|
||||
Context ctx, String assetPath, String destinationFilePath )
|
||||
{
|
||||
Log.d(TAG, "copyAsset " + assetPath + " -> " + destinationFilePath);
|
||||
|
||||
InputStream in;
|
||||
OutputStream out;
|
||||
|
||||
try { in = ctx.getAssets().open(assetPath); }
|
||||
catch(Exception e)
|
||||
{
|
||||
Log.e(
|
||||
TAG,
|
||||
"Failure opening asset: " + assetPath + " " + e.getMessage() );
|
||||
return false;
|
||||
}
|
||||
|
||||
try { out = new FileOutputStream(destinationFilePath); }
|
||||
catch(Exception e)
|
||||
{
|
||||
Log.e(
|
||||
TAG,
|
||||
"Failure opening destination: " + destinationFilePath + " " +
|
||||
e.getMessage() );
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
byte[] buf = new byte[1024];
|
||||
int len;
|
||||
while ((len = in.read(buf)) > 0) out.write(buf, 0, len);
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
Log.e(
|
||||
TAG,
|
||||
"Failure coping: " + assetPath + " -> " + destinationFilePath +
|
||||
" " + e.getMessage() );
|
||||
return false;
|
||||
}
|
||||
|
||||
try { in.close(); }
|
||||
catch(IOException e)
|
||||
{
|
||||
Log.e(TAG, "Failure closing: " + assetPath + " " + e.getMessage() );
|
||||
return false;
|
||||
}
|
||||
|
||||
try { out.close(); }
|
||||
catch(IOException e)
|
||||
{
|
||||
Log.e(
|
||||
TAG,
|
||||
"Failure closing: " + destinationFilePath + " " +
|
||||
e.getMessage() );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static final String TAG = "RetroShare AssetHelper.java";
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* RetroShare
|
||||
* Copyright (C) 2021 Gioacchino Mazzurco <gio@eigenlab.org>
|
||||
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-FileCopyrightText: Retroshare Team <contact@retroshare.cc>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package org.retroshare.service;
|
||||
|
||||
public class ErrorConditionWrap
|
||||
{
|
||||
public ErrorConditionWrap(
|
||||
int value, String message, String categoryName )
|
||||
{
|
||||
mValue = value;
|
||||
mMessage = message;
|
||||
mCategoryName = categoryName;
|
||||
}
|
||||
|
||||
public int value() { return mValue; }
|
||||
public String message() { return mMessage; }
|
||||
public String categoryName() { return mCategoryName; }
|
||||
|
||||
public boolean toBool() { return mValue != 0; }
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{ return String.format("%d", mValue)+" "+mMessage+" [" + mCategoryName+ "]"; }
|
||||
|
||||
private int mValue = 0;
|
||||
private String mMessage;
|
||||
private String mCategoryName;
|
||||
}
|
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* RetroShare
|
||||
* Copyright (C) 2016-2021 Gioacchino Mazzurco <gio@eigenlab.org>
|
||||
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-FileCopyrightText: Retroshare Team <contact@retroshare.cc>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package org.retroshare.service;
|
||||
|
||||
import android.app.Service;
|
||||
import android.os.IBinder;
|
||||
import android.os.Bundle;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
import android.app.ActivityManager;
|
||||
|
||||
|
||||
public class RetroShareServiceAndroid extends Service
|
||||
{
|
||||
public static final int DEFAULT_JSON_API_PORT = 9092;
|
||||
public static final String DEFAULT_JSON_API_BINDING_ADDRESS = "127.0.0.1";
|
||||
|
||||
static { System.loadLibrary("retroshare-service"); }
|
||||
|
||||
public static void start(
|
||||
Context ctx, int jsonApiPort, String jsonApiBindAddress )
|
||||
{
|
||||
Log.d(TAG, "start");
|
||||
Intent intent = new Intent(ctx, RetroShareServiceAndroid.class);
|
||||
intent.putExtra(JSON_API_PORT_KEY, jsonApiPort);
|
||||
intent.putExtra(JSON_API_BIND_ADDRESS_KEY, jsonApiBindAddress);
|
||||
ctx.startService(intent);
|
||||
}
|
||||
|
||||
public static void stop(Context ctx)
|
||||
{
|
||||
Log.d(TAG, "stop");
|
||||
ctx.stopService(new Intent(ctx, RetroShareServiceAndroid.class));
|
||||
}
|
||||
|
||||
public static boolean isRunning(Context ctx)
|
||||
{
|
||||
Log.d(TAG, "isRunning");
|
||||
ActivityManager manager =
|
||||
(ActivityManager) ctx.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
for( ActivityManager.RunningServiceInfo service :
|
||||
manager.getRunningServices(Integer.MAX_VALUE) )
|
||||
if( RetroShareServiceAndroid.class.getName()
|
||||
.equals(service.service.getClassName()) )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Context getServiceContext()
|
||||
{
|
||||
if(sServiceContext == null)
|
||||
{
|
||||
Log.e(TAG, "getServiceContext() called before onCreate");
|
||||
throw new NullPointerException();
|
||||
}
|
||||
return sServiceContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(
|
||||
Intent intent, int flags, int startId )
|
||||
{
|
||||
if(intent == null)
|
||||
{
|
||||
Log.i(TAG, "onStartCommand called without intent");
|
||||
return Service.START_REDELIVER_INTENT;
|
||||
}
|
||||
|
||||
int jsonApiPort = DEFAULT_JSON_API_PORT;
|
||||
String jsonApiBindAddress = DEFAULT_JSON_API_BINDING_ADDRESS;
|
||||
|
||||
Bundle args = intent.getExtras();
|
||||
if(args.containsKey(JSON_API_PORT_KEY))
|
||||
jsonApiPort = args.getInt(JSON_API_PORT_KEY);
|
||||
if(args.containsKey(JSON_API_BIND_ADDRESS_KEY))
|
||||
jsonApiBindAddress =
|
||||
args.getString(JSON_API_BIND_ADDRESS_KEY);
|
||||
|
||||
ErrorConditionWrap ec = nativeStart(jsonApiPort, jsonApiBindAddress);
|
||||
if(ec.toBool()) Log.e(TAG, "onStartCommand(...) " + ec.toString());
|
||||
|
||||
return super.onStartCommand(intent, flags, startId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate ()
|
||||
{
|
||||
super.onCreate();
|
||||
sServiceContext = this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy()
|
||||
{
|
||||
ErrorConditionWrap ec = nativeStop();
|
||||
if(ec.toBool()) Log.e(TAG, "onDestroy() " + ec.toString());
|
||||
sServiceContext = null;
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent arg0) { return null; }
|
||||
|
||||
private static final String JSON_API_PORT_KEY =
|
||||
RetroShareServiceAndroid.class.getCanonicalName() +
|
||||
"/JSON_API_PORT_KEY";
|
||||
|
||||
private static final String JSON_API_BIND_ADDRESS_KEY =
|
||||
RetroShareServiceAndroid.class.getCanonicalName() +
|
||||
"/JSON_API_BIND_ADDRESS_KEY" ;
|
||||
|
||||
private static final String TAG = "RetroShareServiceAndroid.java";
|
||||
|
||||
private static Context sServiceContext;
|
||||
|
||||
protected static native ErrorConditionWrap nativeStart(
|
||||
int jsonApiPort, String jsonApiBindAddress );
|
||||
|
||||
protected static native ErrorConditionWrap nativeStop();
|
||||
}
|
103
libretroshare/src/rs_android/retroshareserviceandroid.cpp
Normal file
103
libretroshare/src/rs_android/retroshareserviceandroid.cpp
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* RetroShare Service Android
|
||||
* Copyright (C) 2016-2021 Gioacchino Mazzurco <gio@eigenlab.org>
|
||||
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-FileCopyrightText: Retroshare Team <contact@retroshare.cc>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include <limits>
|
||||
#include <cstdint>
|
||||
|
||||
#include "util/stacktrace.h"
|
||||
#include "retroshare/rsinit.h"
|
||||
#include "retroshare/rsiface.h"
|
||||
#include "util/rsdebug.h"
|
||||
|
||||
#include "rs_android/retroshareserviceandroid.hpp"
|
||||
#include "rs_android/rsjni.hpp"
|
||||
|
||||
|
||||
/*static*/ std::unique_ptr<AndroidCoutCerrCatcher>
|
||||
RetroShareServiceAndroid::sAndroidCoutCerrCatcher = nullptr;
|
||||
|
||||
using ErrorConditionWrap = RsJni::ErrorConditionWrap;
|
||||
|
||||
/*static*/ jni::Local<jni::Object<ErrorConditionWrap>>
|
||||
RetroShareServiceAndroid::start(
|
||||
JNIEnv& env, jni::Class<RetroShareServiceAndroid>&,
|
||||
jni::jint jsonApiPort, const jni::String& jsonApiBindAddress )
|
||||
{
|
||||
if(jsonApiPort < 0 || jsonApiPort > std::numeric_limits<uint16_t>::max())
|
||||
{
|
||||
RS_ERR("Got invalid JSON API port: ", jsonApiPort);
|
||||
return jni::Make<ErrorConditionWrap>(env, std::errc::invalid_argument);
|
||||
}
|
||||
|
||||
RsInfo() << "\n" <<
|
||||
"+================================================================+\n"
|
||||
"| o---o o |\n"
|
||||
"| \\ / - Retroshare Service Android - / \\ |\n"
|
||||
"| o o---o |\n"
|
||||
"+================================================================+"
|
||||
<< std::endl << std::endl;
|
||||
|
||||
sAndroidCoutCerrCatcher = std::make_unique<AndroidCoutCerrCatcher>();
|
||||
|
||||
RsInit::InitRsConfig();
|
||||
RsControl::earlyInitNotificationSystem();
|
||||
|
||||
RsConfigOptions conf;
|
||||
conf.jsonApiPort = static_cast<uint16_t>(jsonApiPort);
|
||||
conf.jsonApiBindAddress = jni::Make<std::string>(env, jsonApiBindAddress);
|
||||
|
||||
// Dirty workaround plugins not supported on Android ATM
|
||||
conf.main_executable_path = " ";
|
||||
|
||||
int initResult = RsInit::InitRetroShare(conf);
|
||||
if(initResult != RS_INIT_OK)
|
||||
{
|
||||
RS_ERR("Retroshare core initalization failed with: ", initResult);
|
||||
return jni::Make<ErrorConditionWrap>(env, std::errc::no_child_process);
|
||||
}
|
||||
|
||||
return jni::Make<ErrorConditionWrap>(env, std::error_condition());
|
||||
}
|
||||
|
||||
jni::Local<jni::Object<ErrorConditionWrap>> RetroShareServiceAndroid::stop(
|
||||
JNIEnv& env, jni::Class<RetroShareServiceAndroid>& )
|
||||
{
|
||||
if(RsControl::instance()->isReady())
|
||||
{
|
||||
RsControl::instance()->rsGlobalShutDown();
|
||||
return jni::Make<ErrorConditionWrap>(env, std::error_condition());
|
||||
}
|
||||
|
||||
sAndroidCoutCerrCatcher.reset();
|
||||
|
||||
return jni::Make<ErrorConditionWrap>(env, std::errc::no_such_process);
|
||||
}
|
||||
|
||||
jni::Local<jni::Object<RetroShareServiceAndroid::Context> >
|
||||
RetroShareServiceAndroid::getAndroidContext(JNIEnv& env)
|
||||
{
|
||||
auto& clazz = jni::Class<RetroShareServiceAndroid>::Singleton(env);
|
||||
static auto method =
|
||||
clazz.GetStaticMethod<jni::Object<RetroShareServiceAndroid::Context>()>(
|
||||
env, "getServiceContext" );
|
||||
return clazz.Call(env, method);
|
||||
}
|
84
libretroshare/src/rs_android/retroshareserviceandroid.hpp
Normal file
84
libretroshare/src/rs_android/retroshareserviceandroid.hpp
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* RetroShare Service Android
|
||||
* Copyright (C) 2016-2021 Gioacchino Mazzurco <gio@eigenlab.org>
|
||||
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-FileCopyrightText: Retroshare Team <contact@retroshare.cc>
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <system_error>
|
||||
#include <memory>
|
||||
|
||||
#include <jni/jni.hpp>
|
||||
|
||||
#include "rs_android/rsjni.hpp"
|
||||
#include "rs_android/androidcoutcerrcatcher.hpp"
|
||||
|
||||
#include "util/stacktrace.h"
|
||||
|
||||
/** Provide native methods that are registered into corresponding Java class
|
||||
* to start/stop RetroShare with reasonable comfort on Android platform */
|
||||
struct RetroShareServiceAndroid
|
||||
{
|
||||
static constexpr auto Name()
|
||||
{ return "org/retroshare/service/RetroShareServiceAndroid"; }
|
||||
|
||||
using ErrorConditionWrap = RsJni::ErrorConditionWrap;
|
||||
|
||||
/**
|
||||
* Called from RetroShareServiceAndroid Java to init libretroshare
|
||||
* @param[in] env the usual JNI parafernalia
|
||||
* @param[in] jclass the usual JNI parafernalia
|
||||
* @param[in] jsonApiPort port on which JSON API server will listen
|
||||
* @param[in] jsonApiBindAddress binding address of the JSON API server
|
||||
* @note Yeah you read it well we use a full 32 bit signed integer for JSON
|
||||
* API port. This is because Java lack even the minimum decency to implement
|
||||
* unsigned integral types so we need to wrap the port (16 bit unsigned
|
||||
* integer everywhere reasonable) into a full integer and then check at
|
||||
* runtime the value.
|
||||
*/
|
||||
static jni::Local<jni::Object<ErrorConditionWrap>> start(
|
||||
JNIEnv& env, jni::Class<RetroShareServiceAndroid>& jclass,
|
||||
jni::jint jsonApiPort, const jni::String& jsonApiBindAddress );
|
||||
|
||||
/**
|
||||
* Called from RetroShareServiceAndroid Java to shutdown libretroshare
|
||||
* @param[in] env the usual JNI parafernalia
|
||||
* @param[in] jclass the usual JNI parafernalia
|
||||
*/
|
||||
static jni::Local<jni::Object<ErrorConditionWrap>> stop(
|
||||
JNIEnv& env, jni::Class<RetroShareServiceAndroid>& );
|
||||
|
||||
struct Context
|
||||
{
|
||||
/// JNI parafernalia
|
||||
static constexpr auto Name() { return "android/content/Context"; }
|
||||
};
|
||||
|
||||
/// Return RetroShare Service Android Context
|
||||
static jni::Local<jni::Object<Context>> getAndroidContext(JNIEnv& env);
|
||||
|
||||
private:
|
||||
/** Doesn't involve complex liftime handling stuff better let the runtime
|
||||
* handle costruction (ASAP)/destruction for us */
|
||||
static CrashStackTrace CrashStackTrace;
|
||||
|
||||
/** Involve threads, file descriptors etc. better handle lifetime
|
||||
* explicitely */
|
||||
static std::unique_ptr<AndroidCoutCerrCatcher> sAndroidCoutCerrCatcher;
|
||||
};
|
70
libretroshare/src/rs_android/rsjni.cpp
Normal file
70
libretroshare/src/rs_android/rsjni.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
/*******************************************************************************
|
||||
* RetroShare JNI utilities *
|
||||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright (C) 2021 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public License *
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
#include "rs_android/rsjni.hpp"
|
||||
#include "rs_android/retroshareserviceandroid.hpp"
|
||||
|
||||
rs_view_ptr<JavaVM> RsJni::mJvm = nullptr;
|
||||
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL JNI_OnLoad_retroshare(JavaVM* vm, void*)
|
||||
{
|
||||
RS_DBG(vm);
|
||||
|
||||
RsJni::mJvm = vm;
|
||||
|
||||
jni::JNIEnv& env { jni::GetEnv(*vm) };
|
||||
|
||||
/** Ensure singleton refereces to our own Java classes are inizialized here
|
||||
* because default Java class loader which is the one accessible by native
|
||||
* threads which is not main even if attached, is not capable to find them.
|
||||
* https://stackoverflow.com/questions/20752352/classnotfoundexception-when-finding-a-class-in-jni-background-thread
|
||||
* https://groups.google.com/g/android-ndk/c/2gkr1mXKn_E */
|
||||
jni::Class<RsJni::AssetHelper>::Singleton(env);
|
||||
jni::Class<RsJni::ErrorConditionWrap>::Singleton(env);
|
||||
|
||||
jni::RegisterNatives(
|
||||
env, *jni::Class<RetroShareServiceAndroid>::Singleton(env),
|
||||
jni::MakeNativeMethod<
|
||||
decltype(&RetroShareServiceAndroid::start),
|
||||
&RetroShareServiceAndroid::start >("nativeStart"),
|
||||
jni::MakeNativeMethod<
|
||||
decltype(&RetroShareServiceAndroid::stop),
|
||||
&RetroShareServiceAndroid::stop >("nativeStop")
|
||||
);
|
||||
|
||||
return jni::Unwrap(jni::jni_version_1_2);
|
||||
}
|
||||
|
||||
#ifdef RS_LIBRETROSHARE_EXPORT_JNI_ONLOAD
|
||||
/** If libretroshare is linked statically to other components which already
|
||||
* export JNI_OnLoad then a symbol clash may happen
|
||||
* if RS_LIBRETROSHARE_EXPORT_JNI_ONLOAD is defined.
|
||||
* @see JNI_OnLoad_retroshare should instead be called from the exported
|
||||
* JNI_OnLoad */
|
||||
extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* _reserved)
|
||||
{
|
||||
RS_DBG(vm);
|
||||
return JNI_OnLoad_retroshare(vm, _reserved);
|
||||
}
|
||||
#endif // def RS_LIBRETROSHARE_EXPORT_JNI_ONLOAD
|
90
libretroshare/src/rs_android/rsjni.hpp
Normal file
90
libretroshare/src/rs_android/rsjni.hpp
Normal file
@ -0,0 +1,90 @@
|
||||
/*******************************************************************************
|
||||
* RetroShare JNI utilities *
|
||||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright (C) 2021 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public License *
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include <system_error>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <jni/jni.hpp>
|
||||
|
||||
#include "util/rsmemory.h"
|
||||
#include "util/cxx23retrocompat.h"
|
||||
|
||||
|
||||
/** Store JVM pointer safely and register native methods */
|
||||
extern "C" JNIEXPORT jint JNICALL JNI_OnLoad_retroshare(JavaVM* vm, void*);
|
||||
|
||||
|
||||
/** Provide library wide JVM access with some safe measures
|
||||
* The JVM pointer is set properly by @see JNI_OnLoad_retroshare
|
||||
*/
|
||||
class RsJni
|
||||
{
|
||||
public:
|
||||
static inline JavaVM& getVM()
|
||||
{
|
||||
if(!mJvm) // [[unlikely]]
|
||||
{
|
||||
RS_FATAL( "Attempt to access JVM before JNI_OnLoad_retroshare ",
|
||||
std::errc::bad_address );
|
||||
print_stacktrace();
|
||||
std::exit(std::to_underlying(std::errc::bad_address));
|
||||
}
|
||||
|
||||
return *mJvm;
|
||||
}
|
||||
|
||||
friend jint JNI_OnLoad_retroshare(JavaVM* vm, void*);
|
||||
|
||||
/** Provide a comfortable way to access Android package assets like
|
||||
* bdboot.txt from C++ */
|
||||
struct AssetHelper
|
||||
{
|
||||
static constexpr auto Name()
|
||||
{ return "org/retroshare/service/AssetHelper"; }
|
||||
};
|
||||
|
||||
/** Provide a comfortable way to propagate C++ error_conditions to Java
|
||||
* callers */
|
||||
struct ErrorConditionWrap
|
||||
{
|
||||
static constexpr auto Name()
|
||||
{ return "org/retroshare/service/ErrorConditionWrap"; }
|
||||
};
|
||||
|
||||
private:
|
||||
static rs_view_ptr<JavaVM> mJvm;
|
||||
};
|
||||
|
||||
|
||||
namespace jni
|
||||
{
|
||||
/** Provides idiomatic way of creating instances via
|
||||
@code{.cpp}
|
||||
jni::Make<ErrorConditionWrap>(env, std::error_condition());
|
||||
@endcode */
|
||||
jni::Local<jni::Object<RsJni::ErrorConditionWrap>>
|
||||
MakeAnything(
|
||||
jni::ThingToMake<RsJni::ErrorConditionWrap>, JNIEnv& env,
|
||||
const std::error_condition& ec );
|
||||
}
|
@ -3,7 +3,9 @@
|
||||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright 2011-2011 by Cyril Soler <csoler@users.sourceforge.net> *
|
||||
* Copyright (C) 2011-2018 Cyril Soler <csoler@users.sourceforge.net> *
|
||||
* Copyright (C) 2021 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
@ -21,7 +23,9 @@
|
||||
*******************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cstdint>
|
||||
|
||||
using RsItemPriority = uint8_t;
|
||||
|
||||
// This file centralises QoS priorities for all transfer RsItems
|
||||
//
|
||||
|
@ -3,7 +3,8 @@
|
||||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* Copyright (C) 2018-2021 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
@ -28,6 +29,9 @@
|
||||
#include "serialiser/rsserializer.h"
|
||||
#include "serialiser/rsserializable.h"
|
||||
#include "util/stacktrace.h"
|
||||
#include "rsitems/itempriorities.h"
|
||||
#include "rsitems/rsserviceids.h"
|
||||
|
||||
|
||||
#include <typeinfo>
|
||||
|
||||
@ -42,8 +46,13 @@ struct RsItem : RsMemoryManagement::SmallObject, RsSerializable
|
||||
|
||||
virtual ~RsItem();
|
||||
|
||||
/// TODO: Do this make sense with the new serialization system?
|
||||
virtual void clear() = 0;
|
||||
/** TODO: Does the existence of this method make sense with the new
|
||||
* serialization system? **/
|
||||
virtual void clear()
|
||||
{
|
||||
RS_ERR("Called without being overridden, report to developers");
|
||||
print_stacktrace();
|
||||
}
|
||||
|
||||
/// @deprecated use << ostream operator instead
|
||||
RS_DEPRECATED_FOR("<< ostream operator")
|
||||
@ -70,14 +79,21 @@ struct RsItem : RsMemoryManagement::SmallObject, RsSerializable
|
||||
uint8_t PacketType();
|
||||
uint8_t PacketSubType() const;
|
||||
|
||||
/** For Service Packets, @deprecated use the costructor with priority
|
||||
* paramether instead */
|
||||
RS_DEPRECATED RsItem(uint8_t ver, uint16_t service, uint8_t subtype);
|
||||
|
||||
/// For Service Packets
|
||||
RsItem(uint8_t ver, uint16_t service, uint8_t subtype);
|
||||
RsItem( uint8_t ver, RsServiceType service, uint8_t subtype,
|
||||
RsItemPriority prio );
|
||||
|
||||
uint16_t PacketService() const; /* combined Packet class/type (mid 16bits) */
|
||||
void setPacketService(uint16_t service);
|
||||
|
||||
inline uint8_t priority_level() const { return _priority_level ;}
|
||||
inline void setPriorityLevel(uint8_t l) { _priority_level = l ;}
|
||||
|
||||
#ifdef RS_DEAD_CODE
|
||||
/*
|
||||
* TODO: This default implementation should be removed and childs structs
|
||||
* implement ::serial_process(...) as soon as all the codebase is ported to
|
||||
@ -90,11 +106,12 @@ struct RsItem : RsMemoryManagement::SmallObject, RsSerializable
|
||||
"overriding Class is: ", typeid(*this).name() );
|
||||
print_stacktrace();
|
||||
}
|
||||
#endif //def RS_DEAD_CODE
|
||||
|
||||
protected:
|
||||
uint32_t type;
|
||||
RsPeerId peerId;
|
||||
uint8_t _priority_level;
|
||||
RsItemPriority _priority_level;
|
||||
};
|
||||
|
||||
/// TODO: Do this make sense with the new serialization system?
|
||||
@ -108,9 +125,17 @@ public:
|
||||
uint32_t getRawLength() { return len; }
|
||||
void * getRawData() { return data; }
|
||||
|
||||
virtual void clear() {}
|
||||
// virtual void clear() override {}
|
||||
virtual std::ostream &print(std::ostream &out, uint16_t indent = 0);
|
||||
|
||||
virtual void serial_process(RsGenericSerializer::SerializeJob,
|
||||
RsGenericSerializer::SerializeContext&) override
|
||||
{
|
||||
RS_ERR( "called by an item using new serialization system ",
|
||||
typeid(*this).name() );
|
||||
print_stacktrace();
|
||||
}
|
||||
|
||||
private:
|
||||
void *data;
|
||||
uint32_t len;
|
||||
|
@ -64,6 +64,12 @@ RsItem *RsNxsSerialiser::create_item(uint16_t service_id,uint8_t item_subtype) c
|
||||
if(service_id != SERVICE_TYPE)
|
||||
return NULL ;
|
||||
|
||||
switch(static_cast<RsNxsSubtype>(item_subtype))
|
||||
{
|
||||
case RsNxsSubtype::PULL_REQUEST:
|
||||
return new RsNxsPullRequestItem(static_cast<RsServiceType>(service_id));
|
||||
}
|
||||
|
||||
switch(item_subtype)
|
||||
{
|
||||
case RS_PKT_SUBTYPE_NXS_SYNC_GRP_REQ_ITEM: return new RsNxsSyncGrpReqItem(SERVICE_TYPE) ;
|
||||
|
@ -3,7 +3,10 @@
|
||||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright 2012 Christopher Evi-Parker,Robert Fernie<retroshare@lunamutt.com>*
|
||||
* Copyright (C) 2012 Christopher Evi-Parker *
|
||||
* Copyright (C) 2012 Robert Fernie <retroshare@lunamutt.com> *
|
||||
* Copyright (C) 2021 Gioacchino Mazzurco <gio@altermundi.net> *
|
||||
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
@ -19,8 +22,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
#ifndef RSNXSITEMS_H
|
||||
#define RSNXSITEMS_H
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <openssl/ssl.h>
|
||||
@ -33,8 +35,13 @@
|
||||
#include "serialiser/rstlvkeys.h"
|
||||
#include "gxs/rsgxsdata.h"
|
||||
|
||||
// These items have "flag type" numbers, but this is not used.
|
||||
enum class RsNxsSubtype : uint8_t
|
||||
{
|
||||
PULL_REQUEST = 0x90 /// @see RsNxsPullRequestItem
|
||||
};
|
||||
|
||||
// These items have "flag type" numbers, but this is not used.
|
||||
// TODO: refactor as C++11 enum class
|
||||
const uint8_t RS_PKT_SUBTYPE_NXS_SYNC_GRP_REQ_ITEM = 0x01;
|
||||
const uint8_t RS_PKT_SUBTYPE_NXS_SYNC_GRP_ITEM = 0x02;
|
||||
const uint8_t RS_PKT_SUBTYPE_NXS_SYNC_GRP_STATS_ITEM = 0x03;
|
||||
@ -47,14 +54,15 @@ const uint8_t RS_PKT_SUBTYPE_NXS_MSG_ITEM = 0x20;
|
||||
const uint8_t RS_PKT_SUBTYPE_NXS_TRANSAC_ITEM = 0x40;
|
||||
const uint8_t RS_PKT_SUBTYPE_NXS_GRP_PUBLISH_KEY_ITEM = 0x80;
|
||||
|
||||
// possibility create second service to deal with this functionality
|
||||
|
||||
#ifdef RS_DEAD_CODE
|
||||
// possibility create second service to deal with this functionality
|
||||
const uint8_t RS_PKT_SUBTYPE_EXT_SEARCH_GRP = 0x0001;
|
||||
const uint8_t RS_PKT_SUBTYPE_EXT_SEARCH_MSG = 0x0002;
|
||||
const uint8_t RS_PKT_SUBTYPE_EXT_DELETE_GRP = 0x0004;
|
||||
const uint8_t RS_PKT_SUBTYPE_EXT_DELETE_MSG = 0x0008;
|
||||
const uint8_t RS_PKT_SUBTYPE_EXT_SEARCH_REQ = 0x0010;
|
||||
|
||||
#endif // def RS_DEAD_CODE
|
||||
|
||||
/*!
|
||||
* Base class for Network exchange service
|
||||
@ -65,17 +73,14 @@ const uint8_t RS_PKT_SUBTYPE_EXT_SEARCH_REQ = 0x0010;
|
||||
*/
|
||||
class RsNxsItem : public RsItem
|
||||
{
|
||||
|
||||
public:
|
||||
RsNxsItem(uint16_t servtype, uint8_t subtype) : RsItem(RS_PKT_VERSION_SERVICE, servtype, subtype), transactionNumber(0)
|
||||
{
|
||||
setPriorityLevel(QOS_PRIORITY_RS_GXS_NET);
|
||||
return;
|
||||
}
|
||||
virtual ~RsNxsItem(){}
|
||||
virtual void clear() = 0;
|
||||
RsNxsItem(uint16_t servtype, uint8_t subtype):
|
||||
RsItem(RS_PKT_VERSION_SERVICE, servtype, subtype), transactionNumber(0)
|
||||
{ setPriorityLevel(QOS_PRIORITY_RS_GXS_NET); }
|
||||
|
||||
uint32_t transactionNumber; // set to zero if this is not a transaction item
|
||||
virtual ~RsNxsItem() = default;
|
||||
|
||||
uint32_t transactionNumber; // set to zero if this is not a transaction item
|
||||
};
|
||||
|
||||
|
||||
@ -362,6 +367,22 @@ public:
|
||||
|
||||
};
|
||||
|
||||
/*!
|
||||
* Used to request to a peer pull updates from us ASAP without waiting GXS sync
|
||||
* timer */
|
||||
struct RsNxsPullRequestItem: RsItem
|
||||
{
|
||||
explicit RsNxsPullRequestItem(RsServiceType servtype):
|
||||
RsItem( RS_PKT_VERSION_SERVICE,
|
||||
servtype,
|
||||
static_cast<uint8_t>(RsNxsSubtype::PULL_REQUEST),
|
||||
QOS_PRIORITY_RS_GXS_NET ) {}
|
||||
|
||||
/// @see RsSerializable
|
||||
void serial_process( RsGenericSerializer::SerializeJob,
|
||||
RsGenericSerializer::SerializeContext& ) override {}
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
* Used to respond to a RsGrpMsgsReq
|
||||
@ -401,6 +422,7 @@ struct RsNxsMsg : RsNxsItem
|
||||
RsGxsMsgMetaData* metaData;
|
||||
};
|
||||
|
||||
#ifdef RS_DEAD_CODE
|
||||
/*!
|
||||
* Used to request a search of user data
|
||||
*/
|
||||
@ -422,7 +444,7 @@ public:
|
||||
RsTlvBinaryData serviceSearchItem; // service aware of item class
|
||||
uint32_t expiration; // expiration date
|
||||
};
|
||||
|
||||
#endif //def RS_DEAD_CODE
|
||||
|
||||
#ifdef UNUSED_CODE
|
||||
|
||||
@ -503,14 +525,12 @@ class RsNxsSerialiser : public RsServiceSerializer
|
||||
{
|
||||
public:
|
||||
|
||||
explicit RsNxsSerialiser(uint16_t servtype) : RsServiceSerializer(servtype), SERVICE_TYPE(servtype) {}
|
||||
virtual ~RsNxsSerialiser() {}
|
||||
explicit RsNxsSerialiser(uint16_t servtype):
|
||||
RsServiceSerializer(servtype), SERVICE_TYPE(servtype) {}
|
||||
virtual ~RsNxsSerialiser() = default;
|
||||
|
||||
|
||||
virtual RsItem *create_item(uint16_t service_id,uint8_t item_subtype) const ;
|
||||
protected:
|
||||
const uint16_t SERVICE_TYPE;
|
||||
};
|
||||
|
||||
|
||||
#endif // RSNXSITEMS_H
|
||||
|
@ -118,7 +118,7 @@ void RsServer::rsGlobalShutDown()
|
||||
// if(mWire) mWire->join();
|
||||
// #endif
|
||||
|
||||
AuthGPG::exit();
|
||||
AuthPGP::exit();
|
||||
|
||||
mShutdownCallback(0);
|
||||
}
|
||||
|
@ -254,7 +254,7 @@ bool p3Peers::setPeerMaximumRates(const RsPgpId& pid,uint32_t maxUploadRate,uint
|
||||
|
||||
bool p3Peers::haveSecretKey(const RsPgpId& id)
|
||||
{
|
||||
return AuthGPG::getAuthGPG()->haveSecretKey(id);
|
||||
return AuthPGP::haveSecretKey(id);
|
||||
}
|
||||
|
||||
/* There are too many dependancies of this function
|
||||
@ -273,7 +273,7 @@ bool p3Peers::getPeerDetails(const RsPeerId& id, RsPeerDetails &d)
|
||||
if (id == sOwnId)
|
||||
{
|
||||
mPeerMgr->getOwnNetStatus(ps);
|
||||
ps.gpg_id = AuthGPG::getAuthGPG()->getGPGOwnId();
|
||||
ps.gpg_id = AuthPGP::getPgpOwnId();
|
||||
}
|
||||
else if (!mPeerMgr->getFriendNetStatus(id, ps))
|
||||
{
|
||||
@ -559,17 +559,17 @@ bool p3Peers::isProxyAddress(const uint32_t type, const sockaddr_storage& addr)
|
||||
|
||||
bool p3Peers::isKeySupported(const RsPgpId& id)
|
||||
{
|
||||
return AuthGPG::getAuthGPG()->isKeySupported(id);
|
||||
return AuthPGP::isKeySupported(id);
|
||||
}
|
||||
|
||||
std::string p3Peers::getGPGName(const RsPgpId &gpg_id)
|
||||
{
|
||||
/* get from mAuthMgr as it should have more peers? */
|
||||
return AuthGPG::getAuthGPG()->getGPGName(gpg_id);
|
||||
return AuthPGP::getPgpName(gpg_id);
|
||||
}
|
||||
|
||||
bool p3Peers::isPgpFriend(const RsPgpId& pgpId)
|
||||
{ return AuthGPG::getAuthGPG()->isGPGAccepted(pgpId); }
|
||||
{ return AuthPGP::isPGPAccepted(pgpId); }
|
||||
|
||||
bool p3Peers::isSslOnlyFriend(const RsPeerId& sslId)
|
||||
{
|
||||
@ -597,7 +597,7 @@ std::string p3Peers::getPeerName(const RsPeerId& ssl)
|
||||
#endif
|
||||
std::string name;
|
||||
if (ssl == AuthSSL::getAuthSSL()->OwnId())
|
||||
return AuthGPG::getAuthGPG()->getGPGOwnName();
|
||||
return AuthPGP::getPgpOwnName();
|
||||
|
||||
if (mPeerMgr->getPeerName(ssl, name))
|
||||
{
|
||||
@ -617,7 +617,7 @@ bool p3Peers::getGPGAllList(std::list<RsPgpId> &ids)
|
||||
#endif
|
||||
|
||||
/* get from mAuthMgr */
|
||||
AuthGPG::getAuthGPG()->getGPGAllList(ids);
|
||||
AuthPGP::getPgpAllList(ids);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -628,7 +628,7 @@ bool p3Peers::getGPGValidList(std::list<RsPgpId> &ids)
|
||||
#endif
|
||||
|
||||
/* get from mAuthMgr */
|
||||
AuthGPG::getAuthGPG()->getGPGValidList(ids);
|
||||
AuthPGP::getPgpValidList(ids);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -639,14 +639,14 @@ bool p3Peers::getGPGSignedList(std::list<RsPgpId> &ids)
|
||||
#endif
|
||||
|
||||
/* get from mAuthMgr */
|
||||
AuthGPG::getAuthGPG()->getGPGSignedList(ids);
|
||||
AuthPGP::getPgpSignedList(ids);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool p3Peers::getPgpFriendList(std::vector<RsPgpId>& pgpIds)
|
||||
{
|
||||
std::list<RsPgpId> ids;
|
||||
if(AuthGPG::getAuthGPG()->getGPGAcceptedList(ids))
|
||||
if(AuthPGP::getPgpAcceptedList(ids))
|
||||
{
|
||||
pgpIds.clear();
|
||||
std::copy(ids.begin(), ids.end(), std::back_inserter(pgpIds));
|
||||
@ -660,7 +660,7 @@ bool p3Peers::getGPGAcceptedList(std::list<RsPgpId> &ids)
|
||||
#ifdef P3PEERS_DEBUG
|
||||
std::cerr << "p3Peers::getGPGAcceptedList()" << std::endl;
|
||||
#endif
|
||||
AuthGPG::getAuthGPG()->getGPGAcceptedList(ids);
|
||||
AuthPGP::getPgpAcceptedList(ids);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -676,7 +676,7 @@ bool p3Peers::getAssociatedSSLIds(const RsPgpId &gpg_id, std::list<RsPeerId> &id
|
||||
|
||||
bool p3Peers::gpgSignData(const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen, std::string reason /* = "" */)
|
||||
{
|
||||
return AuthGPG::getAuthGPG()->SignDataBin(data,len,sign,signlen, reason);
|
||||
return AuthPGP::SignDataBin(data,len,sign,signlen, reason);
|
||||
}
|
||||
|
||||
RsPgpId p3Peers::pgpIdFromFingerprint(const RsPgpFingerprint& fpr)
|
||||
@ -691,7 +691,7 @@ bool p3Peers::getGPGDetails(const RsPgpId &pgp_id, RsPeerDetails &d)
|
||||
#endif
|
||||
|
||||
/* get from mAuthMgr */
|
||||
bool res = AuthGPG::getAuthGPG()->getGPGDetails(pgp_id, d);
|
||||
bool res = AuthPGP::getPgpDetails(pgp_id, d);
|
||||
|
||||
d.isOnlyGPGdetail = true ;
|
||||
d.service_perm_flags = mPeerMgr->servicePermissionFlags(pgp_id) ;
|
||||
@ -706,7 +706,7 @@ const RsPgpId& p3Peers::getGPGOwnId()
|
||||
#endif
|
||||
|
||||
/* get from mAuthMgr */
|
||||
return AuthGPG::getAuthGPG()->getGPGOwnId();
|
||||
return AuthPGP::getPgpOwnId();
|
||||
}
|
||||
|
||||
RsPgpId p3Peers::getGPGId(const RsPeerId& sslid)
|
||||
@ -718,7 +718,7 @@ RsPgpId p3Peers::getGPGId(const RsPeerId& sslid)
|
||||
/* get from mAuthMgr */
|
||||
if (sslid == AuthSSL::getAuthSSL()->OwnId())
|
||||
{
|
||||
return AuthGPG::getAuthGPG()->getGPGOwnId();
|
||||
return AuthPGP::getPgpOwnId();
|
||||
}
|
||||
peerState pcs;
|
||||
if (mPeerMgr->getFriendNetStatus(sslid, pcs))
|
||||
@ -739,12 +739,12 @@ bool p3Peers::addFriend(const RsPeerId &ssl_id, const RsPgpId &gpg_id,ServicePe
|
||||
#ifdef P3PEERS_DEBUG
|
||||
std::cerr << "p3Peers::addFriend() with : id : " << id << "; gpg_id : " << gpg_id << std::endl;
|
||||
#endif
|
||||
if(AuthGPG::getAuthGPG()->isGPGId(gpg_id))
|
||||
if(AuthPGP::isPGPId(gpg_id))
|
||||
{
|
||||
#ifdef P3PEERS_DEBUG
|
||||
std::cerr << "p3Peers::addFriend() Authorising GPG Id: " << gpg_id << std::endl;
|
||||
#endif
|
||||
if (AuthGPG::getAuthGPG()->AllowConnection(gpg_id, true))
|
||||
if (AuthPGP::AllowConnection(gpg_id, true))
|
||||
{
|
||||
#ifdef P3PEERS_DEBUG
|
||||
std::cerr << "p3Peers::addFriend() Authorization OK." << std::endl;
|
||||
@ -797,7 +797,7 @@ bool p3Peers::addSslOnlyFriend( const RsPeerId& sslId, const RsPgpId& pgp_id,con
|
||||
|
||||
bool p3Peers::removeKeysFromPGPKeyring(const std::set<RsPgpId>& pgp_ids,std::string& backup_file,uint32_t& error_code)
|
||||
{
|
||||
return AuthGPG::getAuthGPG()->removeKeysFromPGPKeyring(pgp_ids,backup_file,error_code) ;
|
||||
return AuthPGP::removeKeysFromPGPKeyring(pgp_ids,backup_file,error_code) ;
|
||||
}
|
||||
|
||||
bool p3Peers::removeFriendLocation(const RsPeerId &sslId)
|
||||
@ -817,7 +817,7 @@ bool p3Peers::removeFriend(const RsPgpId& gpgId)
|
||||
#ifdef P3PEERS_DEBUG
|
||||
std::cerr << "p3Peers::removeFriend() " << gpgId << std::endl;
|
||||
#endif
|
||||
if (gpgId == AuthGPG::getAuthGPG()->getGPGOwnId()) {
|
||||
if (gpgId == AuthPGP::getPgpOwnId()) {
|
||||
std::cerr << "p3Peers::removeFriend() ERROR we're not going to remove our own GPG id." << std::endl;
|
||||
return false;
|
||||
}
|
||||
@ -825,7 +825,7 @@ bool p3Peers::removeFriend(const RsPgpId& gpgId)
|
||||
#ifdef P3PEERS_DEBUG
|
||||
std::cerr << "p3Peers::removeFriend() Removing GPG Id: " << gpgId << std::endl;
|
||||
#endif
|
||||
if (AuthGPG::getAuthGPG()->AllowConnection(gpgId, false))
|
||||
if (AuthPGP::AllowConnection(gpgId, false))
|
||||
{
|
||||
#ifdef P3PEERS_DEBUG
|
||||
std::cerr << "p3Peers::removeFriend() OK." << std::endl;
|
||||
@ -1113,9 +1113,7 @@ std::string p3Peers::getPGPKey(const RsPgpId& pgp_id,bool include_signatures)
|
||||
rs_owner_ptr<unsigned char> mem_block = nullptr;
|
||||
size_t mem_block_size = 0;
|
||||
|
||||
if( !AuthGPG::getAuthGPG()->exportPublicKey(
|
||||
RsPgpId(pgp_id), mem_block, mem_block_size,
|
||||
false, include_signatures ) )
|
||||
if( !AuthPGP::exportPublicKey( RsPgpId(pgp_id), mem_block, mem_block_size, false, include_signatures ) )
|
||||
{
|
||||
RsErr() << __PRETTY_FUNCTION__
|
||||
<< " Failure retriving certificate for id " << pgp_id
|
||||
@ -1146,8 +1144,7 @@ bool p3Peers::GetPGPBase64StringAndCheckSum(
|
||||
|
||||
rs_owner_ptr<unsigned char> mem_block = nullptr;
|
||||
size_t mem_block_size = 0;
|
||||
if(!AuthGPG::getAuthGPG()->exportPublicKey(
|
||||
gpg_id,mem_block,mem_block_size,false,false ))
|
||||
if(!AuthPGP::exportPublicKey( gpg_id,mem_block,mem_block_size,false,false ))
|
||||
return false;
|
||||
|
||||
RsBase64::encode(mem_block, mem_block_size, gpg_base64_string, true, false);
|
||||
@ -1644,7 +1641,7 @@ std::string p3Peers::GetRetroshareInvite( const RsPeerId& sslId, RetroshareInvit
|
||||
unsigned char *mem_block = nullptr;
|
||||
size_t mem_block_size = 0;
|
||||
|
||||
if(!AuthGPG::getAuthGPG()->exportPublicKey( RsPgpId(detail.gpg_id), mem_block, mem_block_size, false, !!(invite_flags & RetroshareInviteFlags::PGP_SIGNATURES) ))
|
||||
if(!AuthPGP::exportPublicKey( RsPgpId(detail.gpg_id), mem_block, mem_block_size, false, !!(invite_flags & RetroshareInviteFlags::PGP_SIGNATURES) ))
|
||||
{
|
||||
std::cerr << "Cannot output certificate for id \"" << detail.gpg_id
|
||||
<< "\". Sorry." << std::endl;
|
||||
@ -1680,7 +1677,7 @@ bool p3Peers::loadCertificateFromString(
|
||||
}
|
||||
|
||||
RsPgpId gpgid;
|
||||
bool res = AuthGPG::getAuthGPG()->LoadCertificateFromString( crt->armouredPGPKey(), gpgid, error_string );
|
||||
bool res = AuthPGP::LoadCertificateFromString( crt->armouredPGPKey(), gpgid, error_string );
|
||||
|
||||
gpg_id = gpgid;
|
||||
ssl_id = crt->sslid();
|
||||
@ -1697,7 +1694,7 @@ bool p3Peers::loadCertificateFromString(
|
||||
}
|
||||
bool p3Peers::loadPgpKeyFromBinaryData( const unsigned char *bin_key_data,uint32_t bin_key_len, RsPgpId& gpg_id, std::string& error_string )
|
||||
{
|
||||
bool res = AuthGPG::getAuthGPG()->LoadPGPKeyFromBinaryData( bin_key_data,bin_key_len, gpg_id, error_string );
|
||||
bool res = AuthPGP::LoadPGPKeyFromBinaryData( bin_key_data,bin_key_len, gpg_id, error_string );
|
||||
|
||||
if(res)
|
||||
mPeerMgr->notifyPgpKeyReceived(gpg_id);
|
||||
@ -1716,9 +1713,7 @@ bool p3Peers::loadDetailsFromStringCert( const std::string &certstr,
|
||||
|
||||
RsCertificate& cert = *certPtr;
|
||||
|
||||
if(!AuthGPG::getAuthGPG()->getGPGDetailsFromBinaryBlock(
|
||||
cert.pgp_key(), cert.pgp_key_size(),
|
||||
pd.gpg_id, pd.name, pd.gpgSigners ))
|
||||
if(!AuthPGP::getPgpDetailsFromBinaryBlock( cert.pgp_key(), cert.pgp_key_size(), pd.gpg_id, pd.name, pd.gpgSigners ))
|
||||
return false;
|
||||
|
||||
Dbg4() << __PRETTY_FUNCTION__ << " Parsing cert for sslid, location, ext "
|
||||
@ -1758,11 +1753,11 @@ bool p3Peers::loadDetailsFromStringCert( const std::string &certstr,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool p3Peers::cleanCertificate(const std::string &certstr, std::string &cleanCert,bool& is_short_format,uint32_t& error_code)
|
||||
bool p3Peers::cleanCertificate(const std::string &certstr, std::string &cleanCert,bool& is_short_format,uint32_t& error_code,RsPeerDetails& details)
|
||||
{
|
||||
RsCertificate::Format format ;
|
||||
|
||||
bool res = RsCertificate::cleanCertificate(certstr,cleanCert,format,error_code,true) ;
|
||||
bool res = RsCertificate::cleanCertificate(certstr,cleanCert,format,error_code,true,details) ;
|
||||
|
||||
if(format == RsCertificate::RS_CERTIFICATE_RADIX)
|
||||
is_short_format = false;
|
||||
@ -1796,7 +1791,7 @@ bool p3Peers::signGPGCertificate(const RsPgpId &id, const std::string &gpg_pass
|
||||
rsNotify->cachePgpPassphrase(gpg_passphrase);
|
||||
rsNotify->setDisableAskPassword(true);
|
||||
|
||||
bool res = AuthGPG::getAuthGPG()->SignCertificateLevel0(id);
|
||||
bool res = AuthPGP::SignCertificateLevel0(id);
|
||||
|
||||
rsNotify->clearPgpPassphrase();
|
||||
rsNotify->setDisableAskPassword(false);
|
||||
@ -1810,7 +1805,7 @@ bool p3Peers::trustGPGCertificate(const RsPgpId &id, uint32_t trustlvl)
|
||||
std::cerr << "p3Peers::TrustCertificate() " << id;
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return AuthGPG::getAuthGPG()->TrustCertificate(id, trustlvl);
|
||||
return AuthPGP::TrustCertificate(id, trustlvl);
|
||||
}
|
||||
|
||||
/* Group Stuff */
|
||||
|
@ -163,7 +163,7 @@ public:
|
||||
virtual bool loadPgpKeyFromBinaryData( const unsigned char *bin_key_data,uint32_t bin_key_len, RsPgpId& gpg_id, std::string& error_string ) override;
|
||||
virtual bool loadDetailsFromStringCert(const std::string &cert, RsPeerDetails &pd, uint32_t& error_code) override;
|
||||
|
||||
virtual bool cleanCertificate(const std::string &certstr, std::string &cleanCert, bool &is_short_format, uint32_t& error_code) override;
|
||||
virtual bool cleanCertificate(const std::string &certstr, std::string &cleanCert, bool &is_short_format, uint32_t& error_code, RsPeerDetails& details) override;
|
||||
virtual std::string saveCertificateToString(const RsPeerId &id) override;
|
||||
|
||||
virtual bool signGPGCertificate(const RsPgpId &id,const std::string& gpg_passphrase) override;
|
||||
|
@ -140,7 +140,7 @@ bool p3ServerConfig::setConfigurationOption(uint32_t key, const std::string &opt
|
||||
int p3ServerConfig::getConfigNetStatus(RsConfigNetStatus &status)
|
||||
{
|
||||
status.ownId = AuthSSL::getAuthSSL()->OwnId();
|
||||
status.ownName = AuthGPG::getAuthGPG()->getGPGOwnName();
|
||||
status.ownName = AuthPGP::getPgpOwnName();
|
||||
|
||||
// Details from PeerMgr.
|
||||
peerState pstate;
|
||||
|
@ -32,12 +32,12 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <system_error>
|
||||
#include <iostream>
|
||||
|
||||
#include "retroshare/rsinit.h"
|
||||
#include "rsaccounts.h"
|
||||
|
||||
#include "util/rsdebug.h"
|
||||
#include "util/rsdir.h"
|
||||
#include "util/rsstring.h"
|
||||
#include "util/folderiterator.h"
|
||||
@ -48,6 +48,11 @@
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#ifdef __ANDROID__
|
||||
# include "rs_android/rsjni.hpp"
|
||||
# include "rs_android/retroshareserviceandroid.hpp"
|
||||
#endif
|
||||
|
||||
// Global singleton declaration of data.
|
||||
RsAccountsDetail* RsAccounts::rsAccountsDetails = nullptr;
|
||||
|
||||
@ -328,22 +333,7 @@ bool RsAccountsDetail::defaultBaseDirectory()
|
||||
{
|
||||
std::string basedir;
|
||||
|
||||
/******************************** WINDOWS/UNIX SPECIFIC PART ******************/
|
||||
#ifndef WINDOWS_SYS
|
||||
|
||||
// unix: homedir + /.retroshare
|
||||
char *h = getenv("HOME");
|
||||
if (h == NULL)
|
||||
{
|
||||
std::cerr << "defaultBaseDirectory() Error: cannot determine $HOME dir"
|
||||
<< std::endl;
|
||||
return false ;
|
||||
}
|
||||
|
||||
basedir = h;
|
||||
basedir += "/.retroshare";
|
||||
|
||||
#else
|
||||
#ifdef WINDOWS_SYS
|
||||
if (RsInit::isPortable())
|
||||
{
|
||||
// use directory "Data" in portable version
|
||||
@ -375,13 +365,53 @@ bool RsAccountsDetail::defaultBaseDirectory()
|
||||
}
|
||||
basedir += "\\RetroShare";
|
||||
}
|
||||
#endif
|
||||
/******************************** WINDOWS/UNIX SPECIFIC PART ******************/
|
||||
#elif defined (__ANDROID__) // def WINDOWS_SYS
|
||||
|
||||
struct ApplicationInfo
|
||||
{
|
||||
static constexpr auto Name()
|
||||
{ return "android/content/pm/ApplicationInfo"; }
|
||||
};
|
||||
|
||||
auto uenv = jni::GetAttachedEnv(RsJni::getVM());
|
||||
JNIEnv& env = *uenv;
|
||||
auto androidContext = RetroShareServiceAndroid::getAndroidContext(env);
|
||||
auto& contextClass =
|
||||
jni::Class<RetroShareServiceAndroid::Context>::Singleton(env);
|
||||
|
||||
auto& applicationInfoClass = jni::Class<ApplicationInfo>::Singleton(env);
|
||||
|
||||
auto getApplicationInfo =
|
||||
contextClass.GetMethod<jni::Object<ApplicationInfo> ()>(
|
||||
env, "getApplicationInfo" );
|
||||
|
||||
auto applicationInfo = androidContext.Call(env, getApplicationInfo);
|
||||
|
||||
auto dataDirField = jni::Field<ApplicationInfo, jni::String>(
|
||||
env, applicationInfoClass, "dataDir" );
|
||||
|
||||
jni::Local<jni::String> dataDir = applicationInfo.Get<jni::String>(
|
||||
env, dataDirField );
|
||||
|
||||
basedir = jni::Make<std::string>(env, dataDir) + "/.retroshare/";
|
||||
|
||||
#else // def WINDOWS_SYS, if defined (__ANDROID__)
|
||||
// unix: homedir + /.retroshare
|
||||
char* h = getenv("HOME");
|
||||
if(h == nullptr)
|
||||
{
|
||||
RS_ERR("cannot determine $HOME dir");
|
||||
return false ;
|
||||
}
|
||||
|
||||
basedir = h;
|
||||
basedir += "/.retroshare";
|
||||
#endif // def WINDOWS_SYS
|
||||
|
||||
/* store to class variable */
|
||||
mBaseDirectory = basedir;
|
||||
std::cerr << "defaultBaseDirectory() = " << mBaseDirectory;
|
||||
std::cerr << std::endl;
|
||||
|
||||
RS_INFO(mBaseDirectory);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -701,10 +731,10 @@ static bool checkAccount(const std::string &accountdir, AccountDetails &account,
|
||||
if(! RsAccounts::GetPGPLoginDetails(account.mPgpId, account.mPgpName, account.mPgpEmail))
|
||||
return false ;
|
||||
|
||||
if(!AuthGPG::getAuthGPG()->haveSecretKey(account.mPgpId))
|
||||
if(!AuthPGP::haveSecretKey(account.mPgpId))
|
||||
return false ;
|
||||
|
||||
if(!AuthGPG::getAuthGPG()->isKeySupported(account.mPgpId))
|
||||
if(!AuthPGP::isKeySupported(account.mPgpId))
|
||||
{
|
||||
std::string keystring = account.mPgpId.toStdString() + " " + account.mPgpName + "<" + account.mPgpEmail ;
|
||||
unsupported_keys[keystring].push_back("Location: " + account.mLocation + " (" + account.mSslId.toStdString() + ")") ;
|
||||
@ -811,14 +841,15 @@ static bool checkAccount(const std::string &accountdir, AccountDetails &account,
|
||||
|
||||
/* Use RetroShare's exe dir */
|
||||
dataDirectory = ".";
|
||||
#elif defined(ANDROID)
|
||||
#elif defined(__ANDROID__)
|
||||
// TODO: This is probably not really used on Android
|
||||
dataDirectory = PathBaseDirectory()+"/usr/share/retroshare";
|
||||
#elif defined(DATA_DIR)
|
||||
#elif defined(RS_DATA_DIR)
|
||||
// cppcheck-suppress ConfigurationNotChecked
|
||||
dataDirectory = DATA_DIR;
|
||||
dataDirectory = RS_DATA_DIR;
|
||||
// For all other OS the data directory must be set in libretroshare.pro
|
||||
#else
|
||||
# error "For your target OS automatic data dir discovery is not supported, cannot compile if DATA_DIR variable not set."
|
||||
# error "For your target OS automatic data dir discovery is not supported, cannot compile if RS_DATA_DIR variable not set."
|
||||
#endif
|
||||
|
||||
if (!check)
|
||||
@ -851,9 +882,10 @@ static bool checkAccount(const std::string &accountdir, AccountDetails &account,
|
||||
|
||||
|
||||
/* Generating GPGme Account */
|
||||
int RsAccountsDetail::GetPGPLogins(std::list<RsPgpId> &pgpIds) {
|
||||
AuthGPG::getAuthGPG()->availableGPGCertificatesWithPrivateKeys(pgpIds);
|
||||
return 1;
|
||||
int RsAccountsDetail::GetPGPLogins(std::list<RsPgpId>& pgpIds)
|
||||
{
|
||||
AuthPGP::availablePgpCertificatesWithPrivateKeys(pgpIds);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int RsAccountsDetail::GetPGPLoginDetails(const RsPgpId& id, std::string &name, std::string &email)
|
||||
@ -863,10 +895,10 @@ int RsAccountsDetail::GetPGPLoginDetails(const RsPgpId& id, std::string &na
|
||||
#endif
|
||||
|
||||
bool ok = true ;
|
||||
name = AuthGPG::getAuthGPG()->getGPGName(id,&ok);
|
||||
name = AuthPGP::getPgpName(id,&ok);
|
||||
if(!ok)
|
||||
return 0 ;
|
||||
email = AuthGPG::getAuthGPG()->getGPGEmail(id,&ok);
|
||||
email = AuthPGP::getPgpEmail(id,&ok);
|
||||
if(!ok)
|
||||
return 0 ;
|
||||
|
||||
@ -886,7 +918,7 @@ bool RsAccountsDetail::SelectPGPAccount(const RsPgpId& pgpId)
|
||||
{
|
||||
bool retVal = false;
|
||||
|
||||
if (0 < AuthGPG::getAuthGPG() -> GPGInit(pgpId))
|
||||
if (0 < AuthPGP::PgpInit(pgpId))
|
||||
{
|
||||
retVal = true;
|
||||
#ifdef DEBUG_ACCOUNTS
|
||||
@ -906,7 +938,7 @@ bool RsAccountsDetail::SelectPGPAccount(const RsPgpId& pgpId)
|
||||
|
||||
bool RsAccountsDetail::GeneratePGPCertificate(const std::string& name, const std::string& email, const std::string& passwd, RsPgpId &pgpId, const int keynumbits, std::string &errString)
|
||||
{
|
||||
return AuthGPG::getAuthGPG()->GeneratePGPCertificate(name, email, passwd, pgpId, keynumbits, errString);
|
||||
return AuthPGP::GeneratePgpCertificate(name, email, passwd, pgpId, keynumbits, errString);
|
||||
}
|
||||
|
||||
// PGP Support Functions.
|
||||
@ -918,29 +950,34 @@ void RsAccountsDetail::getUnsupportedKeys(std::map<std::string,std::vector<std::
|
||||
|
||||
bool RsAccountsDetail::exportIdentity(const std::string& fname,const RsPgpId& id)
|
||||
{
|
||||
return AuthGPG::getAuthGPG()->exportProfile(fname,id);
|
||||
return AuthPGP::exportProfile(fname,id);
|
||||
}
|
||||
|
||||
bool RsAccountsDetail::importIdentity(const std::string& fname,RsPgpId& id,std::string& import_error)
|
||||
{
|
||||
return AuthGPG::getAuthGPG()->importProfile(fname,id,import_error);
|
||||
return AuthPGP::importProfile(fname,id,import_error);
|
||||
}
|
||||
|
||||
bool RsAccountsDetail::importIdentityFromString(const std::string &data, RsPgpId &imported_pgp_id, std::string &import_error)
|
||||
{
|
||||
return AuthGPG::getAuthGPG()->importProfileFromString(data, imported_pgp_id, import_error);
|
||||
return AuthPGP::importProfileFromString(data, imported_pgp_id, import_error);
|
||||
}
|
||||
|
||||
bool RsAccountsDetail::exportIdentityToString(
|
||||
std::string& data, const RsPgpId& pgpId, bool includeSignatures,
|
||||
std::string& errorMsg )
|
||||
{
|
||||
return AuthGPG::getAuthGPG()->exportIdentityToString(
|
||||
return AuthPGP::exportIdentityToString(
|
||||
data, pgpId, includeSignatures, errorMsg );
|
||||
}
|
||||
|
||||
bool RsAccountsDetail::copyGnuPGKeyrings()
|
||||
{
|
||||
#ifdef __ANDROID__
|
||||
RS_ERR(std::errc::not_supported);
|
||||
print_stacktrace();
|
||||
return false;
|
||||
#else
|
||||
std::string pgp_dir = PathPGPDirectory() ;
|
||||
|
||||
if(!RsDirUtil::checkCreateDirectory(pgp_dir))
|
||||
@ -992,6 +1029,7 @@ bool RsAccountsDetail::copyGnuPGKeyrings()
|
||||
}
|
||||
|
||||
return true ;
|
||||
#endif // def __ANDROID__
|
||||
}
|
||||
|
||||
|
||||
@ -1020,7 +1058,7 @@ bool RsAccountsDetail::GenerateSSLCertificate(const RsPgpId& pgp_id, const s
|
||||
|
||||
int nbits = 4096;
|
||||
|
||||
//std::string pgp_name = AuthGPG::getAuthGPG()->getGPGName(pgp_id);
|
||||
//std::string pgp_name = AuthGPG::getGPGName(pgp_id);
|
||||
|
||||
// Create the filename .....
|
||||
// Temporary Directory for creating files....
|
||||
@ -1295,7 +1333,7 @@ bool RsAccounts::init(const std::string& opt_base_dir,int& error_code)
|
||||
if(!RsDirUtil::checkCreateDirectory(pgp_dir))
|
||||
throw std::runtime_error("Cannot create pgp directory " + pgp_dir) ;
|
||||
|
||||
AuthGPG::init( pgp_dir + "/retroshare_public_keyring.gpg",
|
||||
AuthPGP::init( pgp_dir + "/retroshare_public_keyring.gpg",
|
||||
pgp_dir + "/retroshare_secret_keyring.gpg",
|
||||
pgp_dir + "/retroshare_trustdb.gpg",
|
||||
pgp_dir + "/lock");
|
||||
|
@ -32,8 +32,9 @@
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
# include <QFile> // To install bdboot.txt
|
||||
# include <QString> // for QString::fromStdString(...)
|
||||
# include <jni/jni.hpp>
|
||||
# include "rs_android/rsjni.hpp"
|
||||
# include "rs_android/retroshareserviceandroid.hpp"
|
||||
#endif
|
||||
|
||||
#include "util/argstream.h"
|
||||
@ -196,7 +197,7 @@ static const int SSLPWD_LEN = 64;
|
||||
|
||||
void RsInit::InitRsConfig()
|
||||
{
|
||||
RsInfo() << " libretroshare version: " << RS_HUMAN_READABLE_VERSION
|
||||
RsInfo() << "libretroshare version: " << RS_HUMAN_READABLE_VERSION
|
||||
<< std::endl;
|
||||
|
||||
rsInitConfig = new RsInitConfig;
|
||||
@ -514,7 +515,7 @@ RsInit::LoadCertificateStatus RsInit::LockAndLoadCertificates(
|
||||
if(!RsAccounts::GetAccountDetails(accountId, pgpId, pgpName, pgpEmail, location))
|
||||
throw RsInit::ERR_UNKNOWN; // invalid PreferredAccount;
|
||||
|
||||
if(0 == AuthGPG::getAuthGPG() -> GPGInit(pgpId))
|
||||
if(0 == AuthPGP::PgpInit(pgpId))
|
||||
throw RsInit::ERR_UNKNOWN; // PGP Error.
|
||||
|
||||
LoadCertificateStatus retVal =
|
||||
@ -914,8 +915,8 @@ int RsServer::StartupRetroShare()
|
||||
/* History Manager */
|
||||
mHistoryMgr = new p3HistoryMgr();
|
||||
mPeerMgr = new p3PeerMgrIMPL( AuthSSL::getAuthSSL()->OwnId(),
|
||||
AuthGPG::getAuthGPG()->getGPGOwnId(),
|
||||
AuthGPG::getAuthGPG()->getGPGOwnName(),
|
||||
AuthPGP::getPgpOwnId(),
|
||||
AuthPGP::getPgpOwnName(),
|
||||
AuthSSL::getAuthSSL()->getOwnLocation());
|
||||
mNetMgr = new p3NetMgrIMPL();
|
||||
mLinkMgr = new p3LinkMgrIMPL(mPeerMgr, mNetMgr);
|
||||
@ -1014,32 +1015,32 @@ int RsServer::StartupRetroShare()
|
||||
uint64_t tmp_size ;
|
||||
if (!RsDirUtil::checkFile(bootstrapfile,tmp_size,true))
|
||||
{
|
||||
std::cerr << "DHT bootstrap file not in ConfigDir: " << bootstrapfile
|
||||
<< std::endl;
|
||||
#ifdef __ANDROID__
|
||||
QFile bdbootRF("assets:/values/bdboot.txt");
|
||||
if(!bdbootRF.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
std::cerr << __PRETTY_FUNCTION__
|
||||
<< " bdbootRF(assets:/values/bdboot.txt).open(...) fail: "
|
||||
<< bdbootRF.errorString().toStdString() << std::endl;
|
||||
else
|
||||
{
|
||||
QFile bdbootCF(QString::fromStdString(bootstrapfile));
|
||||
if(!bdbootCF.open(QIODevice::WriteOnly | QIODevice::Text))
|
||||
std::cerr << __PRETTY_FUNCTION__ << " bdbootCF("
|
||||
<< bootstrapfile << ").open(...) fail: "
|
||||
<< bdbootRF.errorString().toStdString() << std::endl;
|
||||
else
|
||||
{
|
||||
bdbootCF.write(bdbootRF.readAll());
|
||||
bdbootCF.close();
|
||||
std::cerr << "Installed DHT bootstrap file not in ConfigDir: "
|
||||
<< bootstrapfile << std::endl;
|
||||
}
|
||||
RS_INFO("DHT bootstrap file not in ConfigDir: ", bootstrapfile);
|
||||
|
||||
bdbootRF.close();
|
||||
}
|
||||
#else
|
||||
#ifdef __ANDROID__
|
||||
auto uenv = jni::GetAttachedEnv(RsJni::getVM());
|
||||
JNIEnv& env = *uenv;
|
||||
|
||||
using AContext = RetroShareServiceAndroid::Context;
|
||||
|
||||
auto& assetHelperClass = jni::Class<RsJni::AssetHelper>::Singleton(env);
|
||||
|
||||
static auto copyAsset =
|
||||
assetHelperClass.GetStaticMethod<
|
||||
jni::jboolean(jni::Object<AContext>, jni::String, jni::String)>(
|
||||
env, "copyAsset" );
|
||||
|
||||
auto androidContext = RetroShareServiceAndroid::getAndroidContext(env);
|
||||
|
||||
jni::jboolean result = assetHelperClass.Call(
|
||||
env, copyAsset,
|
||||
androidContext,
|
||||
jni::Make<jni::String>(env, "values/bdboot.txt"),
|
||||
jni::Make<jni::String>(env, bootstrapfile) );
|
||||
|
||||
if(!result) RS_ERR("Failure installing ", bootstrapfile);
|
||||
|
||||
#else // def __ANDROID__
|
||||
std::cerr << "Checking for Installation DHT bootstrap file " << installfile << std::endl;
|
||||
if ((installfile != "") && (RsDirUtil::checkFile(installfile,tmp_size)))
|
||||
{
|
||||
@ -1615,7 +1616,8 @@ int RsServer::StartupRetroShare()
|
||||
|
||||
//mConfigMgr->addConfiguration("ftserver.cfg", ftserver);
|
||||
//
|
||||
mConfigMgr->addConfiguration("gpg_prefs.cfg" , AuthGPG::getAuthGPG());
|
||||
AuthPGP::registerToConfigMgr(std::string("gpg_prefs.cfg"),mConfigMgr);
|
||||
|
||||
mConfigMgr->addConfiguration("gxsnettunnel.cfg", mGxsNetTunnel);
|
||||
mConfigMgr->addConfiguration("peers.cfg" , mPeerMgr);
|
||||
mConfigMgr->addConfiguration("general.cfg" , mGeneralConfig);
|
||||
@ -1801,7 +1803,7 @@ int RsServer::StartupRetroShare()
|
||||
/* Add AuthGPG services */
|
||||
/**************************************************************************/
|
||||
|
||||
//AuthGPG::getAuthGPG()->addService(mDisc);
|
||||
//AuthGPG::addService(mDisc);
|
||||
|
||||
/**************************************************************************/
|
||||
/* Force Any Last Configuration Options */
|
||||
|
@ -60,8 +60,7 @@ bool RsLoginHandler::checkAndStoreSSLPasswdIntoGPGFile(
|
||||
return true ;
|
||||
}
|
||||
|
||||
bool ok = AuthGPG::getAuthGPG()->encryptTextToFile(
|
||||
ssl_passwd, getSSLPasswdFileName(ssl_id));
|
||||
bool ok = AuthPGP::encryptTextToFile( ssl_passwd, getSSLPasswdFileName(ssl_id));
|
||||
|
||||
if (!ok) std::cerr << "Encrypting went wrong !" << std::endl;
|
||||
|
||||
@ -90,7 +89,7 @@ bool RsLoginHandler::getSSLPasswdFromGPGFile(const RsPeerId& ssl_id,std::string&
|
||||
#endif
|
||||
|
||||
std::string plain;
|
||||
if ( AuthGPG::getAuthGPG()->decryptTextFromFile( plain, getSSLPasswdFileName(ssl_id)) )
|
||||
if ( AuthPGP::decryptTextFromFile( plain, getSSLPasswdFileName(ssl_id)) )
|
||||
{
|
||||
sslPassword = plain;
|
||||
#ifdef DEBUG_RSLOGINHANDLER
|
||||
|
@ -3,7 +3,9 @@
|
||||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright 2007-2008 by Robert Fernie <retroshare@lunamutt.com> *
|
||||
* Copyright (C) 2007-2008 Robert Fernie <retroshare@lunamutt.com> *
|
||||
* Copyright (C) 2021 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
@ -20,21 +22,20 @@
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
#include "serialiser/rsbaseserial.h"
|
||||
|
||||
#include "util/rsthreads.h"
|
||||
#include "util/rsstring.h"
|
||||
#include "util/rsprint.h"
|
||||
|
||||
#include "rsitems/rsitem.h"
|
||||
#include "rsitems/itempriorities.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <typeinfo>
|
||||
|
||||
#include "serialiser/rsbaseserial.h"
|
||||
#include "util/cxx23retrocompat.h"
|
||||
#include "util/rsthreads.h"
|
||||
#include "util/rsstring.h"
|
||||
#include "util/rsprint.h"
|
||||
#include "rsitems/rsitem.h"
|
||||
#include "rsitems/itempriorities.h"
|
||||
|
||||
|
||||
/***
|
||||
* #define RSSERIAL_DEBUG 1
|
||||
@ -166,11 +167,17 @@ uint8_t RsItem::PacketSubType() const
|
||||
/* For Service Packets */
|
||||
RsItem::RsItem(uint8_t ver, uint16_t service, uint8_t subtype)
|
||||
{
|
||||
_priority_level = QOS_PRIORITY_UNKNOWN ; // This value triggers PQIInterface to complain about undefined priorities
|
||||
// This value triggers PQIInterface to complain about undefined priorities
|
||||
_priority_level = QOS_PRIORITY_UNKNOWN;
|
||||
type = (ver << 24) + (service << 8) + subtype;
|
||||
return;
|
||||
}
|
||||
|
||||
RsItem::RsItem( uint8_t ver, RsServiceType service, uint8_t subtype,
|
||||
RsItemPriority prio ):
|
||||
type(static_cast<uint32_t>(
|
||||
(ver << 24) + (std::to_underlying(service) << 8) + subtype )),
|
||||
_priority_level(prio) {}
|
||||
|
||||
uint16_t RsItem::PacketService() const
|
||||
{
|
||||
return (type >> 8) & 0xFFFF;
|
||||
|
@ -1,7 +1,8 @@
|
||||
/*******************************************************************************
|
||||
* RetroShare Broadcast Domain Discovery *
|
||||
* *
|
||||
* Copyright (C) 2019 Gioacchino Mazzurco <gio@altermundi.net> *
|
||||
* Copyright (C) 2019-2021 Gioacchino Mazzurco <gio@altermundi.net> *
|
||||
* Copyright (C) 2019-2021 Asociación Civil Altermundi <info@altermundi.net> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
@ -25,16 +26,17 @@
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
#ifdef __ANDROID__
|
||||
# include <QtAndroid>
|
||||
#endif // def __ANDROID__
|
||||
|
||||
#include "services/broadcastdiscoveryservice.h"
|
||||
#include "retroshare/rspeers.h"
|
||||
#include "serialiser/rsserializable.h"
|
||||
#include "serialiser/rsserializer.h"
|
||||
#include "retroshare/rsevents.h"
|
||||
|
||||
#ifdef __ANDROID__
|
||||
# include "rs_android/retroshareserviceandroid.hpp"
|
||||
#endif // def __ANDROID__
|
||||
|
||||
|
||||
/*extern*/ RsBroadcastDiscovery* rsBroadcastDiscovery = nullptr;
|
||||
|
||||
struct BroadcastDiscoveryPack : RsSerializable
|
||||
@ -99,7 +101,7 @@ BroadcastDiscoveryService::BroadcastDiscoveryService(
|
||||
if(mRsPeers.isHiddenNode(mRsPeers.getOwnId())) return;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
createMulticastLock();
|
||||
createAndroidMulticastLock();
|
||||
#endif // def __ANDROID__
|
||||
|
||||
enableMulticastListening();
|
||||
@ -228,19 +230,47 @@ RsBroadcastDiscoveryResult BroadcastDiscoveryService::createResult(
|
||||
bool BroadcastDiscoveryService::isMulticastListeningEnabled()
|
||||
{
|
||||
#ifdef __ANDROID__
|
||||
return assertMulticastLockIsvalid() &&
|
||||
mWifiMulticastLock.callMethod<jboolean>("isHeld");
|
||||
#endif // def __ANDROID__
|
||||
if(!mAndroidWifiMulticastLock)
|
||||
{
|
||||
RS_ERR("Android multicast lock not initialized!");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto uenv = jni::GetAttachedEnv(RsJni::getVM());
|
||||
JNIEnv& env = *uenv;
|
||||
auto& multicastLockClass = jni::Class<AndroidMulticastLock>::Singleton(env);
|
||||
|
||||
auto isHeld =
|
||||
multicastLockClass.GetMethod<jni::jboolean()>(
|
||||
env, "isHeld" );
|
||||
|
||||
return mAndroidWifiMulticastLock.Call(env, isHeld);
|
||||
#else // def __ANDROID__
|
||||
return true;
|
||||
#endif // def __ANDROID__
|
||||
}
|
||||
|
||||
bool BroadcastDiscoveryService::enableMulticastListening()
|
||||
{
|
||||
#ifdef __ANDROID__
|
||||
if(assertMulticastLockIsvalid() && !isMulticastListeningEnabled())
|
||||
if(!mAndroidWifiMulticastLock)
|
||||
{
|
||||
mWifiMulticastLock.callMethod<void>("acquire");
|
||||
RS_ERR("Android multicast lock not initialized!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!isMulticastListeningEnabled())
|
||||
{
|
||||
auto uenv = jni::GetAttachedEnv(RsJni::getVM());
|
||||
JNIEnv& env = *uenv;
|
||||
auto& multicastLockClass = jni::Class<AndroidMulticastLock>::Singleton(env);
|
||||
|
||||
auto acquire =
|
||||
multicastLockClass.GetMethod<void()>(
|
||||
env, "acquire" );
|
||||
|
||||
mAndroidWifiMulticastLock.Call(env, acquire);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif // def __ANDROID__
|
||||
@ -251,9 +281,24 @@ bool BroadcastDiscoveryService::enableMulticastListening()
|
||||
bool BroadcastDiscoveryService::disableMulticastListening()
|
||||
{
|
||||
#ifdef __ANDROID__
|
||||
if(assertMulticastLockIsvalid() && isMulticastListeningEnabled())
|
||||
if(!mAndroidWifiMulticastLock)
|
||||
{
|
||||
mWifiMulticastLock.callMethod<void>("release");
|
||||
RS_ERR("Android multicast lock not initialized!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(isMulticastListeningEnabled())
|
||||
{
|
||||
auto uenv = jni::GetAttachedEnv(RsJni::getVM());
|
||||
JNIEnv& env = *uenv;
|
||||
auto& multicastLockClass = jni::Class<AndroidMulticastLock>::Singleton(env);
|
||||
|
||||
auto release =
|
||||
multicastLockClass.GetMethod<void()>(
|
||||
env, "release" );
|
||||
|
||||
mAndroidWifiMulticastLock.Call(env, release);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif // def __ANDROID__
|
||||
@ -262,56 +307,57 @@ bool BroadcastDiscoveryService::disableMulticastListening()
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
bool BroadcastDiscoveryService::createMulticastLock()
|
||||
|
||||
bool BroadcastDiscoveryService::createAndroidMulticastLock()
|
||||
{
|
||||
Dbg2() << __PRETTY_FUNCTION__ << std::endl;
|
||||
|
||||
constexpr auto fname = __PRETTY_FUNCTION__;
|
||||
const auto failure = [&](const std::string& err)
|
||||
if(mAndroidWifiMulticastLock)
|
||||
{
|
||||
RsErr() << fname << " " << err << std::endl;
|
||||
return false;
|
||||
};
|
||||
|
||||
if(mWifiMulticastLock.isValid())
|
||||
return failure("mWifiMulticastLock is already initialized");
|
||||
|
||||
QAndroidJniObject context = QtAndroid::androidContext();
|
||||
if(!context.isValid())
|
||||
return failure("Cannot retrieve Android context");
|
||||
|
||||
QAndroidJniObject WIFI_SERVICE = QAndroidJniObject::getStaticObjectField(
|
||||
"android.content.Context", "WIFI_SERVICE", "Ljava/lang/String;");
|
||||
if(!WIFI_SERVICE.isValid())
|
||||
return failure("Cannot retrieve Context.WIFI_SERVICE value");
|
||||
|
||||
QAndroidJniObject wifiManager = context.callObjectMethod(
|
||||
"getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;",
|
||||
WIFI_SERVICE.object<jstring>() );
|
||||
if(!wifiManager.isValid())
|
||||
return failure("Cannot retrieve Android Wifi Manager");
|
||||
|
||||
mWifiMulticastLock = wifiManager.callObjectMethod(
|
||||
"createMulticastLock",
|
||||
"(Ljava/lang/String;)Landroid/net/wifi/WifiManager$MulticastLock;",
|
||||
QAndroidJniObject::fromString(fname).object<jstring>() );
|
||||
if(!mWifiMulticastLock.isValid())
|
||||
return failure("Cannot create WifiManager.MulticastLock");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BroadcastDiscoveryService::assertMulticastLockIsvalid()
|
||||
{
|
||||
if(!mWifiMulticastLock.isValid())
|
||||
{
|
||||
RsErr() << __PRETTY_FUNCTION__ << " mWifiMulticastLock is invalid!"
|
||||
<< std::endl;
|
||||
RS_ERR("Android multicast lock is already initialized");
|
||||
print_stacktrace();
|
||||
return false;
|
||||
}
|
||||
|
||||
auto uenv = jni::GetAttachedEnv(RsJni::getVM());
|
||||
JNIEnv& env = *uenv;
|
||||
|
||||
using AContextTag = RetroShareServiceAndroid::Context;
|
||||
using AContext = jni::Class<AContextTag>;
|
||||
static auto& contextClass = AContext::Singleton(env);
|
||||
|
||||
auto wifiServiceField = jni::StaticField<AContextTag, jni::String>(
|
||||
env, contextClass, "WIFI_SERVICE");
|
||||
|
||||
jni::Local<jni::String> WIFI_SERVICE = contextClass.Get(
|
||||
env, wifiServiceField );
|
||||
|
||||
auto androidContext = RetroShareServiceAndroid::getAndroidContext(env);
|
||||
|
||||
auto getSystemService =
|
||||
contextClass.GetMethod<jni::Object<jni::ObjectTag> (jni::String)>(
|
||||
env, "getSystemService" );
|
||||
|
||||
struct WifiManager
|
||||
{ static constexpr auto Name() { return "android/net/wifi/WifiManager"; } };
|
||||
|
||||
auto& wifiManagerClass = jni::Class<WifiManager>::Singleton(env);
|
||||
|
||||
auto wifiManager = jni::Cast<WifiManager>(
|
||||
env, wifiManagerClass,
|
||||
androidContext.Call(env, getSystemService, WIFI_SERVICE) );
|
||||
|
||||
auto createMulticastLock =
|
||||
wifiManagerClass.GetMethod<jni::Object<AndroidMulticastLock>(jni::String)>(
|
||||
env, "createMulticastLock" );
|
||||
|
||||
mAndroidWifiMulticastLock = jni::NewGlobal(
|
||||
env, wifiManager.Call(
|
||||
env, createMulticastLock,
|
||||
jni::Make<jni::String>(
|
||||
env, "RetroShare BroadcastDiscoveryService" ) ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // def __ANDROID__
|
||||
|
||||
RsBroadcastDiscovery::~RsBroadcastDiscovery() = default;
|
||||
|
@ -1,7 +1,8 @@
|
||||
/*******************************************************************************
|
||||
* RetroShare Broadcast Domain Discovery *
|
||||
* *
|
||||
* Copyright (C) 2019 Gioacchino Mazzurco <gio@altermundi.net> *
|
||||
* Copyright (C) 2019-2021 Gioacchino Mazzurco <gio@altermundi.net> *
|
||||
* Copyright (C) 2019-2021 Asociación Civil Altermundi <info@altermundi.net> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
@ -27,14 +28,16 @@
|
||||
|
||||
#include <udp_discovery_peer.hpp>
|
||||
|
||||
#ifdef __ANDROID__
|
||||
# include <QtAndroidExtras/QAndroidJniObject>
|
||||
#endif // def __ANDROID__
|
||||
|
||||
#include "retroshare/rsbroadcastdiscovery.h"
|
||||
#include "util/rsthreads.h"
|
||||
#include "util/rsdebug.h"
|
||||
|
||||
#ifdef __ANDROID__
|
||||
# include <jni/jni.hpp>
|
||||
# include "rs_android/rsjni.hpp"
|
||||
#endif // def __ANDROID__
|
||||
|
||||
|
||||
namespace UDC = udpdiscovery;
|
||||
class RsPeers;
|
||||
|
||||
@ -42,7 +45,7 @@ class BroadcastDiscoveryService :
|
||||
public RsBroadcastDiscovery, public RsTickingThread
|
||||
{
|
||||
public:
|
||||
BroadcastDiscoveryService(RsPeers& pRsPeers);
|
||||
explicit BroadcastDiscoveryService(RsPeers& pRsPeers);
|
||||
~BroadcastDiscoveryService() override;
|
||||
|
||||
/// @see RsBroadcastDiscovery
|
||||
@ -71,26 +74,27 @@ protected:
|
||||
std::map<UDC::IpPort, std::string> mDiscoveredData;
|
||||
RsMutex mDiscoveredDataMutex;
|
||||
|
||||
RsPeers& mRsPeers; // TODO: std::shared_ptr<RsPeers> mRsPeers;
|
||||
RsPeers& mRsPeers;
|
||||
|
||||
RsBroadcastDiscoveryResult createResult(
|
||||
const UDC::IpPort& ipp, const std::string& uData );
|
||||
|
||||
#ifdef __ANDROID__
|
||||
/** Android WifiManager.MulticastLock */
|
||||
QAndroidJniObject mWifiMulticastLock;
|
||||
struct AndroidMulticastLock
|
||||
{
|
||||
static constexpr auto Name()
|
||||
{ return "android/net/wifi/WifiManager$MulticastLock"; }
|
||||
};
|
||||
|
||||
jni::Global<jni::Object<AndroidMulticastLock>> mAndroidWifiMulticastLock;
|
||||
|
||||
/** Initialize the wifi multicast lock without acquiring it
|
||||
* Needed to enable multicast listening in Android, for RetroShare broadcast
|
||||
* discovery inspired by:
|
||||
* https://github.com/flutter/flutter/issues/16335#issuecomment-420547860
|
||||
*/
|
||||
bool createMulticastLock();
|
||||
|
||||
/** Return false if mWifiMulticastLock is invalid and print error messages */
|
||||
bool assertMulticastLockIsvalid();
|
||||
|
||||
#endif // def __ANDROID__
|
||||
bool createAndroidMulticastLock();
|
||||
#endif
|
||||
|
||||
RS_SET_CONTEXT_DEBUG_LEVEL(3)
|
||||
};
|
||||
|
@ -900,10 +900,19 @@ bool p3GxsForums::markRead(const RsGxsGrpMsgIdPair& msgId, bool read)
|
||||
bool p3GxsForums::subscribeToForum(const RsGxsGroupId& groupId, bool subscribe )
|
||||
{
|
||||
uint32_t token;
|
||||
if( !RsGenExchange::subscribeToGroup(token, groupId, subscribe) || waitToken(token) != RsTokenService::COMPLETE ) return false;
|
||||
if( !RsGenExchange::subscribeToGroup(token, groupId, subscribe) ||
|
||||
waitToken(token) != RsTokenService::COMPLETE ) return false;
|
||||
|
||||
RsGxsGroupId grp;
|
||||
acknowledgeGrp(token,grp);
|
||||
RsGxsGroupId grp;
|
||||
acknowledgeGrp(token, grp);
|
||||
|
||||
/* Since subscribe has been requested, the caller is most probably
|
||||
* interested in getting the group messages ASAP so check updates from peers
|
||||
* without waiting GXS sync timer.
|
||||
* Do it here as this is meaningful or not depending on the service.
|
||||
* Do it only after the token has been completed otherwise the pull have no
|
||||
* effect. */
|
||||
if(subscribe) RsGenExchange::netService()->checkUpdatesFromPeers();
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1150,6 +1159,13 @@ std::error_condition p3GxsForums::setPostKeepForever(
|
||||
}
|
||||
}
|
||||
|
||||
std::error_condition p3GxsForums::requestSynchronization()
|
||||
{
|
||||
auto errc = RsGenExchange::netService()->checkUpdatesFromPeers();
|
||||
if(errc) return errc;
|
||||
return RsGenExchange::netService()->requestPull();
|
||||
}
|
||||
|
||||
/* so we need the same tick idea as wiki for generating dummy forums
|
||||
*/
|
||||
|
||||
|
@ -175,6 +175,8 @@ public:
|
||||
rs_owner_ptr<uint8_t>& resultData, uint32_t& resultSize ) override;
|
||||
#endif
|
||||
|
||||
std::error_condition requestSynchronization() override;
|
||||
|
||||
/// implementation of rsGxsGorums
|
||||
///
|
||||
bool getGroupData(const uint32_t &token, std::vector<RsGxsForumGroup> &groups) override;
|
||||
|
@ -1067,7 +1067,7 @@ bool p3IdService::createIdentity(uint32_t& token, RsIdentityParameters ¶ms)
|
||||
|
||||
if(params.isPgpLinked)
|
||||
{
|
||||
ssdata.pgp.pgpId = AuthGPG::getAuthGPG()->getGPGOwnId();
|
||||
ssdata.pgp.pgpId = AuthPGP::getPgpOwnId();
|
||||
ssdata.pgp.lastCheckTs = time(nullptr);
|
||||
}
|
||||
|
||||
@ -3619,7 +3619,7 @@ RsGenExchange::ServiceCreate_Return p3IdService::service_CreateGroup(
|
||||
unsigned int sign_size = MAX_SIGN_SIZE;
|
||||
memset(signarray,0,MAX_SIGN_SIZE) ; // just in case.
|
||||
|
||||
int result = AuthGPG::getAuthGPG()->SignDataBin(
|
||||
int result = AuthPGP::SignDataBin(
|
||||
static_cast<const void*>(hash.toByteArray()),
|
||||
hash.SIZE_IN_BYTES, signarray, &sign_size,
|
||||
__PRETTY_FUNCTION__ )
|
||||
@ -4096,7 +4096,7 @@ void p3IdService::getPgpIdList()
|
||||
#endif // DEBUG_IDS
|
||||
|
||||
std::list<RsPgpId> list;
|
||||
mPgpUtils->getGPGAllList(list);
|
||||
mPgpUtils->getPgpAllList(list);
|
||||
|
||||
RsStackMutex stack(mIdMtx); /********** STACK LOCKED MTX ******/
|
||||
|
||||
@ -4593,7 +4593,7 @@ void p3IdService::generateDummy_FriendPGP()
|
||||
// Now Generate for friends.
|
||||
std::list<RsPgpId> gpgids;
|
||||
std::list<RsPgpId>::const_iterator it;
|
||||
mPgpUtils->getGPGAllList(gpgids);
|
||||
mPgpUtils->getPgpAllList(gpgids);
|
||||
|
||||
RsGxsIdGroup id;
|
||||
|
||||
|
@ -111,11 +111,7 @@ PRE_TARGETDEPS += $$pretargetStaticLibs(sLibs)
|
||||
LIBS += $$linkDynamicLibs(dLibs)
|
||||
|
||||
android-* {
|
||||
## ifaddrs is missing on Android to add them don't use the one from
|
||||
## https://github.com/morristech/android-ifaddrs
|
||||
## because it crash, use QNetworkInterface from Qt instead
|
||||
CONFIG *= qt
|
||||
QT *= network
|
||||
INCLUDEPATH *= $$clean_path($${RS_SRC_PATH}/supportlibs/jni.hpp/include/)
|
||||
}
|
||||
|
||||
################################### Pkg-Config Stuff #############################
|
||||
|
34
libretroshare/src/util/cxx23retrocompat.h
Normal file
34
libretroshare/src/util/cxx23retrocompat.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*******************************************************************************
|
||||
* RetroShare C++23 backwards compatibility utilities *
|
||||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright (C) 2021 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public License *
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
|
||||
#if ! defined(__cpp_lib_to_underlying)
|
||||
namespace std
|
||||
{
|
||||
template <class Enum>
|
||||
constexpr underlying_type_t<Enum> to_underlying(Enum e) noexcept
|
||||
{ return static_cast<std::underlying_type_t<Enum>>(e); }
|
||||
}
|
||||
#endif // ! defined(__cpp_lib_to_underlying)
|
27
openpgpsdk/CMakeLists.txt
Normal file
27
openpgpsdk/CMakeLists.txt
Normal file
@ -0,0 +1,27 @@
|
||||
# RetroShare decentralized communication platform
|
||||
#
|
||||
# Copyright (C) 2021 Gioacchino Mazzurco <gio@eigenlab.org>
|
||||
# Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net>
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
cmake_minimum_required (VERSION 3.12.0)
|
||||
project(openpgpsdk)
|
||||
|
||||
find_package(ZLIB REQUIRED)
|
||||
find_package(BZip2 REQUIRED)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
|
||||
file(GLOB SOURCES src/openpgpsdk/*.c)
|
||||
add_library(${PROJECT_NAME} ${SOURCES})
|
||||
|
||||
target_include_directories(
|
||||
${PROJECT_NAME}
|
||||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
PRIVATE ${OPENSSL_INCLUDE_DIR}
|
||||
PRIVATE ${BZIP2_INCLUDE_DIRS}
|
||||
PRIVATE ${ZLIB_INCLUDE_DIRS} )
|
||||
|
||||
target_link_libraries(
|
||||
${PROJECT_NAME}
|
||||
OpenSSL::SSL OpenSSL::Crypto BZip2::BZip2 ZLIB::ZLIB )
|
@ -104,8 +104,8 @@ AudioWizard::AudioWizard(QWidget *p) : QWizard(p) {
|
||||
iMaxPeak = 0;
|
||||
iTicks = 0;
|
||||
|
||||
qpTalkingOn = QPixmap::fromImage(QImage(QLatin1String("skin:talking_on.svg")).scaled(64,64));
|
||||
qpTalkingOff = QPixmap::fromImage(QImage(QLatin1String("skin:talking_off.svg")).scaled(64,64));
|
||||
qpTalkingOn = QPixmap::fromImage(QImage(QLatin1String(":/images/talking_on.svg")).scaled(64,64));
|
||||
qpTalkingOff = QPixmap::fromImage(QImage(QLatin1String(":/images/talking_off.svg")).scaled(64,64));
|
||||
|
||||
bInit = false;
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <QColorDialog>
|
||||
#include <QDesktopServices>
|
||||
#include <QIcon>
|
||||
#include <QInputDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QPixmap>
|
||||
#include <QStatusBar>
|
||||
@ -1689,3 +1690,19 @@ void MainWindow::setCompactStatusMode(bool compact)
|
||||
ratesstatus->setCompactMode(compact);
|
||||
//opModeStatus: TODO Show only ???
|
||||
}
|
||||
|
||||
Gui_InputDialogReturn MainWindow::guiInputDialog(const QString& windowTitle, const QString& labelText, QLineEdit::EchoMode textEchoMode, bool modal)
|
||||
{
|
||||
|
||||
QInputDialog dialog(this);
|
||||
dialog.setWindowTitle(windowTitle);
|
||||
dialog.setLabelText(labelText);
|
||||
dialog.setTextEchoMode(textEchoMode);
|
||||
dialog.setModal(modal);
|
||||
|
||||
Gui_InputDialogReturn ret;
|
||||
ret.execReturn = dialog.exec();
|
||||
ret.textValue = dialog.textValue();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
#ifndef _MainWindow_H
|
||||
#define _MainWindow_H
|
||||
|
||||
#include <QLineEdit>
|
||||
#include <QSystemTrayIcon>
|
||||
#include <set>
|
||||
|
||||
@ -74,6 +75,14 @@ class MessengerWindow;
|
||||
class ApplicationWindow;
|
||||
#endif
|
||||
|
||||
|
||||
struct Gui_InputDialogReturn
|
||||
{
|
||||
int execReturn;
|
||||
QString textValue;
|
||||
};
|
||||
Q_DECLARE_METATYPE(Gui_InputDialogReturn);
|
||||
|
||||
class MainWindow : public RWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -192,7 +201,7 @@ public:
|
||||
}
|
||||
|
||||
static bool hiddenmode;
|
||||
|
||||
|
||||
public slots:
|
||||
void receiveNewArgs(QStringList args);
|
||||
void displayErrorMessage(int,int,const QString&) ;
|
||||
@ -210,9 +219,35 @@ public slots:
|
||||
void showBandwidthGraph();
|
||||
|
||||
void toggleStatusToolTip(bool toggle);
|
||||
|
||||
/**
|
||||
* @brief Create a QInputDialog. This must be called in MainWindow thread because Widgets must be created in the GUI thread.
|
||||
* Here an exemple how to call it:
|
||||
*
|
||||
* bool sameThread = QThread::currentThread() == qApp->thread();
|
||||
* Gui_InputDialogReturn ret;
|
||||
* qRegisterMetaType<Gui_InputDialogReturn>("Gui_InputDialogReturn");
|
||||
* QMetaObject::invokeMethod( MainWindow::getInstance()
|
||||
* , "guiInputDialog"
|
||||
* , sameThread ? Qt::DirectConnection : Qt::BlockingQueuedConnection
|
||||
* , Q_RETURN_ARG(Gui_InputDialogReturn, ret)
|
||||
* , Q_ARG(QString, windowTitle)
|
||||
* , Q_ARG(QString, labelText)
|
||||
* , Q_ARG(QLineEdit::EchoMode, textEchoMode)
|
||||
* , Q_ARG(bool, modal)
|
||||
* );
|
||||
*
|
||||
* @param windowTitle: the window title (caption).
|
||||
* @param labelText: label's text which describes what needs to be input.
|
||||
* @param textEchoMode: the echo mode for the text value.
|
||||
* @param modal: pop up the dialog as modal or modeless.
|
||||
* @return Gui_InputDialogReturn ( Accepted(1)|Rejected(0), text value for the input dialog)
|
||||
*/
|
||||
Gui_InputDialogReturn guiInputDialog(const QString& windowTitle, const QString& labelText, QLineEdit::EchoMode textEchoMode, bool modal);
|
||||
|
||||
protected:
|
||||
/** Default Constructor */
|
||||
MainWindow(QWidget *parent = 0, Qt::WindowFlags flags = 0);
|
||||
MainWindow(QWidget *parent = nullptr, Qt::WindowFlags flags = Qt::WindowFlags());
|
||||
|
||||
void closeEvent(QCloseEvent *);
|
||||
|
||||
|
@ -122,14 +122,14 @@ void BoardPostDisplayWidgetBase::setReadStatus(bool isNew, bool isUnread)
|
||||
void BoardPostDisplayWidget_compact::doExpand(bool e)
|
||||
{
|
||||
#ifdef DEBUG_BOARDPOSTDISPLAYWIDGET
|
||||
std::cerr << "Expanding" << std::endl;
|
||||
std::cerr << "Expanding" << std::endl;
|
||||
#endif
|
||||
if(e)
|
||||
ui->frame_notes->show();
|
||||
else
|
||||
ui->frame_notes->hide();
|
||||
if(e)
|
||||
ui->frame_notes->show();
|
||||
else
|
||||
ui->frame_notes->hide();
|
||||
|
||||
emit expand(mPost.mMeta.mMsgId,e);
|
||||
emit expand(mPost.mMeta.mMsgId,e);
|
||||
}
|
||||
|
||||
void BoardPostDisplayWidgetBase::loadComments(bool e)
|
||||
@ -144,7 +144,7 @@ void BoardPostDisplayWidgetBase::readToggled()
|
||||
emit changeReadStatusRequested(mPost.mMeta.mMsgId,s);
|
||||
}
|
||||
|
||||
void BoardPostDisplayWidgetBase::setup()
|
||||
void BoardPostDisplayWidgetBase::baseSetup()
|
||||
{
|
||||
// show/hide things based on the view type
|
||||
|
||||
@ -166,8 +166,6 @@ void BoardPostDisplayWidgetBase::setup()
|
||||
QAction *CopyLinkAction = new QAction(QIcon(""),tr("Copy RetroShare Link"), this);
|
||||
connect(CopyLinkAction, SIGNAL(triggered()), this, SLOT(handleCopyLinkClicked()));
|
||||
|
||||
int S = QFontMetricsF(font()).height() ;
|
||||
|
||||
readButton()->setChecked(false);
|
||||
|
||||
QMenu *menu = new QMenu();
|
||||
@ -184,6 +182,7 @@ void BoardPostDisplayWidgetBase::setup()
|
||||
if(redacted)
|
||||
{
|
||||
commentButton()->setDisabled(true);
|
||||
shareButton()->setDisabled(true);
|
||||
voteUpButton()->setDisabled(true);
|
||||
voteDownButton()->setDisabled(true);
|
||||
fromLabel()->setId(mPost.mMeta.mAuthorId);
|
||||
@ -196,8 +195,6 @@ void BoardPostDisplayWidgetBase::setup()
|
||||
}
|
||||
else
|
||||
{
|
||||
QPixmap sqpixmap2 = FilesDefs::getPixmapFromQtResourcePath(":/images/thumb-default.png");
|
||||
|
||||
QDateTime qtime;
|
||||
qtime.setTime_t(mPost.mMeta.mPublishTs);
|
||||
QString timestamp = qtime.toString("hh:mm dd-MMM-yyyy");
|
||||
@ -295,16 +292,7 @@ BoardPostDisplayWidget_compact::BoardPostDisplayWidget_compact(const RsPostedPos
|
||||
: BoardPostDisplayWidgetBase(post,display_flags,parent), ui(new Ui::BoardPostDisplayWidget_compact())
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setup();
|
||||
|
||||
ui->right_VL->addStretch();
|
||||
ui->right_VL->setAlignment(Qt::AlignTop);
|
||||
ui->topLayout->setAlignment(Qt::AlignTop);
|
||||
ui->arrowsLayout->addStretch();
|
||||
ui->arrowsLayout->setAlignment(Qt::AlignTop);
|
||||
ui->feedFrame_VL->addStretch();
|
||||
|
||||
adjustSize();
|
||||
BoardPostDisplayWidget_compact::setup();
|
||||
}
|
||||
|
||||
BoardPostDisplayWidget_compact::~BoardPostDisplayWidget_compact()
|
||||
@ -314,7 +302,7 @@ BoardPostDisplayWidget_compact::~BoardPostDisplayWidget_compact()
|
||||
|
||||
void BoardPostDisplayWidget_compact::setup()
|
||||
{
|
||||
BoardPostDisplayWidgetBase::setup();
|
||||
baseSetup();
|
||||
|
||||
// show/hide things based on the view type
|
||||
|
||||
@ -356,7 +344,7 @@ void BoardPostDisplayWidget_compact::setup()
|
||||
QObject::connect(ui->expandButton, SIGNAL(toggled(bool)), this, SLOT(doExpand(bool)));
|
||||
|
||||
QTextDocument doc;
|
||||
doc.setHtml(notes()->text());
|
||||
doc.setHtml(BoardPostDisplayWidget_compact::notes()->text());
|
||||
|
||||
if(mDisplayFlags & SHOW_NOTES)
|
||||
{
|
||||
@ -427,16 +415,7 @@ BoardPostDisplayWidget_card::BoardPostDisplayWidget_card(const RsPostedPost& pos
|
||||
: BoardPostDisplayWidgetBase(post,display_flags,parent), ui(new Ui::BoardPostDisplayWidget_card())
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setup();
|
||||
|
||||
ui->right_VL->addStretch();
|
||||
ui->right_VL->setAlignment(Qt::AlignTop);
|
||||
ui->topLayout->setAlignment(Qt::AlignTop);
|
||||
ui->arrowsLayout->addStretch();
|
||||
ui->arrowsLayout->setAlignment(Qt::AlignTop);
|
||||
ui->feedFrame_VL->addStretch();
|
||||
|
||||
adjustSize();
|
||||
BoardPostDisplayWidget_card::setup();
|
||||
}
|
||||
|
||||
BoardPostDisplayWidget_card::~BoardPostDisplayWidget_card()
|
||||
@ -446,7 +425,7 @@ BoardPostDisplayWidget_card::~BoardPostDisplayWidget_card()
|
||||
|
||||
void BoardPostDisplayWidget_card::setup()
|
||||
{
|
||||
BoardPostDisplayWidgetBase::setup();
|
||||
baseSetup();
|
||||
|
||||
RsReputationLevel overall_reputation = rsReputations->overallReputationLevel(mPost.mMeta.mAuthorId);
|
||||
bool redacted = (overall_reputation == RsReputationLevel::LOCALLY_NEGATIVE);
|
||||
@ -463,7 +442,6 @@ void BoardPostDisplayWidget_card::setup()
|
||||
GxsIdDetails::loadPixmapFromData(mPost.mImage.mData, mPost.mImage.mSize, pixmap,GxsIdDetails::ORIGINAL);
|
||||
// Wiping data - as its been passed to thumbnail.
|
||||
|
||||
QPixmap scaledpixmap;
|
||||
if(pixmap.width() > 800){
|
||||
QPixmap scaledpixmap = pixmap.scaledToWidth(800, Qt::SmoothTransformation);
|
||||
ui->pictureLabel->setPixmap(scaledpixmap);
|
||||
@ -478,10 +456,10 @@ void BoardPostDisplayWidget_card::setup()
|
||||
}
|
||||
|
||||
QTextDocument doc;
|
||||
doc.setHtml(notes()->text());
|
||||
doc.setHtml(BoardPostDisplayWidget_card::notes()->text());
|
||||
|
||||
if(doc.toPlainText().trimmed().isEmpty())
|
||||
notes()->hide();
|
||||
BoardPostDisplayWidget_card::notes()->hide();
|
||||
}
|
||||
|
||||
QToolButton *BoardPostDisplayWidget_card::voteUpButton() { return ui->voteUpButton; }
|
||||
|
@ -62,10 +62,11 @@ public:
|
||||
|
||||
static const char *DEFAULT_BOARD_IMAGE;
|
||||
|
||||
protected slots:
|
||||
protected:
|
||||
/* GxsGroupFeedItem */
|
||||
|
||||
virtual void setup(); // to be overloaded by the different views
|
||||
void baseSetup();
|
||||
virtual void setup() =0; // to be overloaded by the different views
|
||||
|
||||
virtual QToolButton *voteUpButton() =0;
|
||||
virtual QToolButton *commentButton() =0;
|
||||
@ -81,6 +82,7 @@ protected slots:
|
||||
virtual QToolButton *shareButton() =0;
|
||||
virtual QFrame *feedFrame() =0;
|
||||
|
||||
protected slots:
|
||||
void loadComments(bool e);
|
||||
void readToggled();
|
||||
void setReadStatus(bool isNew, bool isUnread) ;
|
||||
|
@ -90,7 +90,10 @@
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="voteFrame">
|
||||
<layout class="QVBoxLayout" name="arrowsLayout">
|
||||
<layout class="QVBoxLayout" name="voteFrame_VL">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
@ -173,6 +176,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="voteFrame_VS">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@ -277,7 +287,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="from_HSpacer">
|
||||
<spacer name="from_HS">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
@ -340,7 +350,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="pictureLabel_HSpacer">
|
||||
<spacer name="pictureLabel_HS">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
@ -401,16 +411,16 @@
|
||||
<iconset resource="Posted_images.qrc">
|
||||
<normaloff>:/images/share.png</normaloff>:/images/share.png</iconset>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="buttons_HSpacer">
|
||||
<spacer name="buttons_HS">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
@ -424,10 +434,30 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="right_VS">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="feedFrame_VS">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>542</width>
|
||||
<height>150</height>
|
||||
<height>151</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@ -90,7 +90,22 @@
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="voteFrame">
|
||||
<layout class="QVBoxLayout" name="arrowsLayout">
|
||||
<layout class="QVBoxLayout" name="voteFrame_VL">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QToolButton" name="voteUpButton">
|
||||
<property name="sizePolicy">
|
||||
@ -161,6 +176,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="voteFrame_VS">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@ -287,7 +309,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="from_HSpacer">
|
||||
<spacer name="from_HS">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
@ -305,7 +327,7 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="buttons_HM">
|
||||
<layout class="QHBoxLayout" name="buttons_HL">
|
||||
<item>
|
||||
<widget class="QToolButton" name="commentButton">
|
||||
<property name="text">
|
||||
@ -400,7 +422,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="buttons_HSpacer">
|
||||
<spacer name="buttons_HS">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
@ -414,6 +436,13 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="right_VS">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
@ -473,6 +502,13 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="feedFrame_VS">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>614</width>
|
||||
<height>182</height>
|
||||
<height>198</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -16,7 +16,7 @@
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<layout class="QGridLayout" name="PostedCardView_GL">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
@ -118,7 +118,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<layout class="QHBoxLayout" name="from_HL">
|
||||
<property name="spacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
@ -216,7 +216,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<spacer name="from_HS">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
@ -241,30 +241,27 @@
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<layout class="QVBoxLayout" name="voteFrame_VL">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>3</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>3</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>3</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>3</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QToolButton" name="voteUpButton">
|
||||
@ -337,26 +334,20 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<spacer name="voteFrame_VS">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>5</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<layout class="QHBoxLayout" name="buttons_HL">
|
||||
<item>
|
||||
<widget class="QToolButton" name="commentButton">
|
||||
<property name="text">
|
||||
@ -389,7 +380,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<spacer name="buttons_HS">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
@ -461,7 +452,7 @@
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QFrame" name="picture_frame">
|
||||
<layout class="QHBoxLayout" name="horizontalPictureLayout">
|
||||
<layout class="QHBoxLayout" name="picture_frame_HL">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
@ -485,7 +476,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<spacer name="picture_frame_HS">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
@ -513,9 +504,9 @@
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../images.qrc"/>
|
||||
<include location="../icons.qrc"/>
|
||||
<include location="Posted_images.qrc"/>
|
||||
<include location="../icons.qrc"/>
|
||||
<include location="../images.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
@ -41,9 +41,12 @@
|
||||
#include "gui/common/FilesDefs.h"
|
||||
|
||||
/* View Page */
|
||||
#define VIEW_POST 1
|
||||
#define VIEW_IMAGE 2
|
||||
#define VIEW_LINK 3
|
||||
#define VIEW_POST 0
|
||||
#define VIEW_IMAGE 1
|
||||
#define VIEW_LINK 2
|
||||
/* View Image */
|
||||
#define IMG_ATTACH 0
|
||||
#define IMG_PICTURE 1
|
||||
|
||||
PostedCreatePostDialog::PostedCreatePostDialog(RsPosted *posted, const RsGxsGroupId& grpId, const RsGxsId& default_author, QWidget *parent):
|
||||
QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint),
|
||||
@ -54,7 +57,6 @@ PostedCreatePostDialog::PostedCreatePostDialog(RsPosted *posted, const RsGxsGrou
|
||||
Settings->loadWidgetInformation(this);
|
||||
|
||||
connect(ui->postButton, SIGNAL(clicked()), this, SLOT(createPost()));
|
||||
connect(ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
|
||||
connect(ui->addPicButton, SIGNAL(clicked() ), this , SLOT(addPicture()));
|
||||
connect(ui->RichTextEditWidget, SIGNAL(textSizeOk(bool)),ui->postButton, SLOT(setEnabled(bool)));
|
||||
|
||||
@ -84,6 +86,7 @@ PostedCreatePostDialog::PostedCreatePostDialog(RsPosted *posted, const RsGxsGrou
|
||||
connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(setPage(int)));
|
||||
|
||||
ui->removeButton->hide();
|
||||
ui->stackedWidgetPicture->setCurrentIndex(IMG_ATTACH);
|
||||
|
||||
/* load settings */
|
||||
processSettings(true);
|
||||
@ -202,7 +205,6 @@ void PostedCreatePostDialog::addPicture()
|
||||
|
||||
// select a picture file
|
||||
if (misc::getOpenFileName(window(), RshareSettings::LASTDIR_IMAGES, tr("Load Picture File"), "Pictures (*.png *.xpm *.jpg *.jpeg *.gif *.webp )", imagefilename)) {
|
||||
QString encodedImage;
|
||||
QImage image;
|
||||
if (image.load(imagefilename) == false) {
|
||||
fprintf (stderr, "RsHtml::makeEmbeddedImage() - image \"%s\" can't be load\n", imagefilename.toLatin1().constData());
|
||||
@ -213,7 +215,7 @@ void PostedCreatePostDialog::addPicture()
|
||||
QImage opt;
|
||||
if(ImageUtil::optimizeSizeBytes(imagebytes, image, opt, 640*480, MAXMESSAGESIZE - 2000)) { //Leave space for other stuff
|
||||
ui->imageLabel->setPixmap(QPixmap::fromImage(opt));
|
||||
ui->stackedWidgetPicture->setCurrentIndex(1);
|
||||
ui->stackedWidgetPicture->setCurrentIndex(IMG_PICTURE);
|
||||
ui->removeButton->show();
|
||||
} else {
|
||||
imagefilename = "";
|
||||
@ -259,45 +261,24 @@ int PostedCreatePostDialog::viewMode()
|
||||
|
||||
void PostedCreatePostDialog::setPage(int viewMode)
|
||||
{
|
||||
switch (viewMode) {
|
||||
case VIEW_POST:
|
||||
ui->stackedWidget->setCurrentIndex(0);
|
||||
if( (viewMode < 0) || (viewMode > ui->stackedWidget->count()-1) )
|
||||
viewMode = VIEW_POST;
|
||||
|
||||
ui->viewPostButton->setChecked(true);
|
||||
ui->viewImageButton->setChecked(false);
|
||||
ui->viewLinkButton->setChecked(false);
|
||||
ui->stackedWidget->setCurrentIndex(viewMode);
|
||||
|
||||
break;
|
||||
case VIEW_IMAGE:
|
||||
ui->stackedWidget->setCurrentIndex(1);
|
||||
ui->viewPostButton ->setChecked(viewMode==VIEW_POST);
|
||||
ui->viewImageButton->setChecked(viewMode==VIEW_IMAGE);
|
||||
ui->viewLinkButton ->setChecked(viewMode==VIEW_LINK);
|
||||
|
||||
ui->viewImageButton->setChecked(true);
|
||||
ui->viewPostButton->setChecked(false);
|
||||
ui->viewLinkButton->setChecked(false);
|
||||
|
||||
break;
|
||||
case VIEW_LINK:
|
||||
ui->stackedWidget->setCurrentIndex(2);
|
||||
|
||||
ui->viewLinkButton->setChecked(true);
|
||||
ui->viewPostButton->setChecked(false);
|
||||
ui->viewImageButton->setChecked(false);
|
||||
|
||||
break;
|
||||
default:
|
||||
setPage(VIEW_POST);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void PostedCreatePostDialog::on_removeButton_clicked()
|
||||
{
|
||||
imagefilename = "";
|
||||
imagebytes.clear();
|
||||
QPixmap empty;
|
||||
ui->imageLabel->setPixmap(empty);
|
||||
ui->imageLabel->setPixmap(QPixmap());
|
||||
ui->removeButton->hide();
|
||||
ui->stackedWidgetPicture->setCurrentIndex(0);
|
||||
ui->stackedWidgetPicture->setCurrentIndex(IMG_ATTACH);
|
||||
}
|
||||
|
||||
void PostedCreatePostDialog::reject()
|
||||
|
@ -52,7 +52,7 @@ private slots:
|
||||
void addPicture();
|
||||
void on_removeButton_clicked();
|
||||
void fileHashingFinished(QList<HashedFile> hashedFiles);
|
||||
void reject();
|
||||
void reject() override; //QDialog
|
||||
|
||||
void setPage(int viewMode);
|
||||
private:
|
||||
|
@ -143,7 +143,7 @@
|
||||
<item row="0" column="1">
|
||||
<widget class="QStackedWidget" name="stackedWidgetPicture">
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="PageAttach">
|
||||
<layout class="QGridLayout" name="PageAttach_GL">
|
||||
|
@ -16,7 +16,7 @@
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<layout class="QGridLayout" name="PostedItem_GL">
|
||||
<property name="leftMargin">
|
||||
<number>1</number>
|
||||
</property>
|
||||
@ -82,21 +82,21 @@
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<layout class="QVBoxLayout" name="voteFrame_VL">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>3</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>3</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>3</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>3</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QToolButton" name="voteUpButton">
|
||||
@ -169,26 +169,20 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<spacer name="voteFrame_VS">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>5</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" rowspan="2">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<layout class="QVBoxLayout" name="thumbnail_VL">
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
@ -233,7 +227,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<spacer name="thumbnail_VS">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
@ -248,7 +242,7 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<layout class="QVBoxLayout" name="title_VL">
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
@ -286,7 +280,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="newCommHLayout">
|
||||
<layout class="QHBoxLayout" name="newComm_HL">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
@ -312,7 +306,7 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<layout class="QVBoxLayout" name="from_VL">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
@ -320,7 +314,7 @@
|
||||
<enum>QLayout::SetDefaultConstraint</enum>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<layout class="QHBoxLayout" name="from_HL">
|
||||
<property name="spacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
@ -416,7 +410,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<spacer name="from_HS">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
@ -434,7 +428,7 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="buttonHLayout">
|
||||
<layout class="QHBoxLayout" name="buttons_HL">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
@ -567,7 +561,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<spacer name="buttons_HS">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
@ -631,9 +625,9 @@
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<layout class="QHBoxLayout" name="frame_picture_HL">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<spacer name="frame_picture_LHS">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
@ -659,7 +653,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<spacer name="frame_picture_RHS">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
@ -685,7 +679,7 @@
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<layout class="QGridLayout" name="frame_notes_GL">
|
||||
<property name="leftMargin">
|
||||
<number>3</number>
|
||||
</property>
|
||||
@ -726,17 +720,17 @@
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>GxsIdLabel</class>
|
||||
<extends>QLabel</extends>
|
||||
<header>gui/gxs/GxsIdLabel.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ElidedLabel</class>
|
||||
<extends>QLabel</extends>
|
||||
<header>gui/common/ElidedLabel.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>GxsIdLabel</class>
|
||||
<extends>QLabel</extends>
|
||||
<header>gui/gxs/GxsIdLabel.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ClickableLabel</class>
|
||||
<extends>QLabel</extends>
|
||||
|
@ -58,9 +58,7 @@
|
||||
// number of posts to show at once.
|
||||
#define POSTS_CHUNK_SIZE 25
|
||||
|
||||
/****
|
||||
* #define DEBUG_POSTED
|
||||
***/
|
||||
//#define DEBUG_POSTED
|
||||
|
||||
static const int POSTED_TABS_POSTS = 1;
|
||||
|
||||
@ -87,8 +85,12 @@ std::ostream& operator<<(std::ostream& o,const QSize& s) { return o << s.width()
|
||||
|
||||
void PostedPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const
|
||||
{
|
||||
#ifdef DEBUG_POSTED
|
||||
if(option.state & QStyle::State_Selected) RS_DBG("Selected");
|
||||
#endif
|
||||
|
||||
if((option.state & QStyle::State_Selected)) // Avoids double display. The selected widget is never exactly the size of the rendered one,
|
||||
return; // so when selected, we only draw the selected one.
|
||||
return; // so when selected, we only draw the selected one.
|
||||
|
||||
// prepare
|
||||
painter->save();
|
||||
@ -98,7 +100,7 @@ void PostedPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem &
|
||||
|
||||
painter->save();
|
||||
|
||||
painter->fillRect( option.rect, option.palette.background());
|
||||
painter->fillRect( option.rect, option.palette.window());
|
||||
painter->restore();
|
||||
|
||||
QPixmap pixmap(option.rect.size());
|
||||
@ -109,9 +111,9 @@ void PostedPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem &
|
||||
BoardPostDisplayWidget_compact w(post,displayFlags(post.mMeta.mMsgId),nullptr);
|
||||
|
||||
w.setFixedSize(option.rect.size());
|
||||
|
||||
w.updateGeometry();
|
||||
w.adjustSize();
|
||||
|
||||
w.render(&pixmap,QPoint(0,0),QRegion(),QWidget::DrawChildren );// draw the widgets, not the background
|
||||
}
|
||||
else
|
||||
@ -121,6 +123,7 @@ void PostedPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem &
|
||||
w.setFixedSize(option.rect.size());
|
||||
w.updateGeometry();
|
||||
w.adjustSize();
|
||||
|
||||
w.render(&pixmap,QPoint(0,0),QRegion(),QWidget::DrawChildren );// draw the widgets, not the background
|
||||
}
|
||||
|
||||
@ -145,6 +148,10 @@ void PostedPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem &
|
||||
|
||||
painter->save();
|
||||
painter->drawPixmap(option.rect.topLeft(), pixmap /*,.scaled(option.rect.width(),option.rect.width()*w.height()/(float)w.width(),Qt::KeepAspectRatio,Qt::SmoothTransformation)*/);
|
||||
#ifdef DEBUG_POSTED
|
||||
painter->drawText(option.rect.bottomLeft(),QString::number(time(nullptr)));
|
||||
RS_DBG("DisplayMode=", mDisplayMode == BoardPostDisplayWidget_compact::DISPLAY_MODE_COMPACT? "Compact":"Card", " Title:", post.mMeta.mMsgName.c_str());
|
||||
#endif
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
@ -193,40 +200,46 @@ uint8_t PostedPostDelegate::displayFlags(const RsGxsMessageId &id) const
|
||||
|
||||
QWidget *PostedPostDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex& index) const
|
||||
{
|
||||
RsPostedPost post = index.data(Qt::UserRole).value<RsPostedPost>() ;
|
||||
|
||||
if(index.column() == RsPostedPostsModel::COLUMN_POSTS)
|
||||
{
|
||||
QWidget *w ;
|
||||
if (!index.isValid())
|
||||
return nullptr;
|
||||
|
||||
if(mDisplayMode==BoardPostDisplayWidget_compact::DISPLAY_MODE_COMPACT)
|
||||
w = new BoardPostDisplayWidget_compact(post,displayFlags(post.mMeta.mMsgId),parent);
|
||||
else
|
||||
w = new BoardPostDisplayWidget_card(post,displayFlags(post.mMeta.mMsgId),parent);
|
||||
if(index.column() != RsPostedPostsModel::COLUMN_POSTS)
|
||||
return nullptr;
|
||||
|
||||
QObject::connect(w,SIGNAL(vote(RsGxsGrpMsgIdPair,bool)),mPostListWidget,SLOT(voteMsg(RsGxsGrpMsgIdPair,bool)));
|
||||
QObject::connect(w,SIGNAL(expand(RsGxsMessageId,bool)),this,SLOT(expandItem(RsGxsMessageId,bool)));
|
||||
QObject::connect(w,SIGNAL(commentsRequested(const RsGxsMessageId&,bool)),mPostListWidget,SLOT(openComments(const RsGxsMessageId&)));
|
||||
QObject::connect(w,SIGNAL(changeReadStatusRequested(const RsGxsMessageId&,bool)),mPostListWidget,SLOT(changeReadStatus(const RsGxsMessageId&,bool)));
|
||||
QWidget *w ;
|
||||
RsPostedPost post = index.data(Qt::UserRole).value<RsPostedPost>() ;
|
||||
|
||||
// All other interactions with the widget should cause the msg to be set as read.
|
||||
QObject::connect(w,SIGNAL(thumbnailOpenned()),mPostListWidget,SLOT(markCurrentPostAsRead()));
|
||||
QObject::connect(w,SIGNAL(vote(RsGxsGrpMsgIdPair,bool)),mPostListWidget,SLOT(markCurrentPostAsRead()));
|
||||
QObject::connect(w,SIGNAL(expand(RsGxsMessageId,bool)),this,SLOT(markCurrentPostAsRead()));
|
||||
QObject::connect(w,SIGNAL(commentsRequested(const RsGxsMessageId&,bool)),mPostListWidget,SLOT(markCurrentPostAsRead()));
|
||||
QObject::connect(w,SIGNAL(shareButtonClicked()),mPostListWidget,SLOT(markCurrentPostAsRead()));
|
||||
QObject::connect(w,SIGNAL(copylinkClicked()),mPostListWidget,SLOT(copyMessageLink()));
|
||||
#ifdef DEBUG_POSTED
|
||||
RS_DBG("Title:", post.mMeta.mMsgName.c_str());
|
||||
#endif
|
||||
|
||||
w->setFixedSize(option.rect.size());
|
||||
w->adjustSize();
|
||||
w->updateGeometry();
|
||||
w->adjustSize();
|
||||
if(mDisplayMode==BoardPostDisplayWidget_compact::DISPLAY_MODE_COMPACT)
|
||||
w = new BoardPostDisplayWidget_compact(post,displayFlags(post.mMeta.mMsgId),parent);
|
||||
else
|
||||
w = new BoardPostDisplayWidget_card(post,displayFlags(post.mMeta.mMsgId),parent);
|
||||
|
||||
return w;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
QObject::connect(w,SIGNAL(vote(RsGxsGrpMsgIdPair,bool)),mPostListWidget,SLOT(voteMsg(RsGxsGrpMsgIdPair,bool)));
|
||||
QObject::connect(w,SIGNAL(expand(RsGxsMessageId,bool)),this,SLOT(expandItem(RsGxsMessageId,bool)));
|
||||
QObject::connect(w,SIGNAL(commentsRequested(RsGxsMessageId,bool)),mPostListWidget,SLOT(openComments(RsGxsMessageId)));
|
||||
QObject::connect(w,SIGNAL(changeReadStatusRequested(RsGxsMessageId,bool)),mPostListWidget,SLOT(changeReadStatus(RsGxsMessageId,bool)));
|
||||
|
||||
// All other interactions with the widget should cause the msg to be set as read.
|
||||
QObject::connect(w,SIGNAL(thumbnailOpenned()),mPostListWidget,SLOT(markCurrentPostAsRead()));
|
||||
QObject::connect(w,SIGNAL(vote(RsGxsGrpMsgIdPair,bool)),mPostListWidget,SLOT(markCurrentPostAsRead()));
|
||||
QObject::connect(w,SIGNAL(expand(RsGxsMessageId,bool)),this,SLOT(markCurrentPostAsRead()));
|
||||
QObject::connect(w,SIGNAL(commentsRequested(RsGxsMessageId,bool)),mPostListWidget,SLOT(markCurrentPostAsRead()));
|
||||
QObject::connect(w,SIGNAL(shareButtonClicked()),mPostListWidget,SLOT(markCurrentPostAsRead()));
|
||||
QObject::connect(w,SIGNAL(copylinkClicked()),mPostListWidget,SLOT(copyMessageLink()));
|
||||
|
||||
w->setGeometry(option.rect);
|
||||
w->adjustSize();
|
||||
w->updateGeometry();
|
||||
w->adjustSize();
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
void PostedPostDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const
|
||||
{
|
||||
editor->setGeometry(option.rect);
|
||||
@ -264,13 +277,11 @@ PostedListWidgetWithModel::PostedListWidgetWithModel(const RsGxsGroupId& postedI
|
||||
connect(ui->nextButton,SIGNAL(clicked()),this,SLOT(nextPosts()));
|
||||
connect(ui->prevButton,SIGNAL(clicked()),this,SLOT(prevPosts()));
|
||||
|
||||
connect(ui->postsTree,SIGNAL(customContextMenuRequested(const QPoint&)),this,SLOT(postContextMenu(const QPoint&)));
|
||||
connect(ui->postsTree,SIGNAL(customContextMenuRequested(QPoint)),this,SLOT(postContextMenu(QPoint)));
|
||||
connect(ui->viewModeButton,SIGNAL(clicked()),this,SLOT(switchDisplayMode()));
|
||||
|
||||
connect(mPostedPostsModel,SIGNAL(boardPostsLoaded()),this,SLOT(postPostLoad()));
|
||||
|
||||
QFontMetricsF fm(font());
|
||||
|
||||
/* Setup UI helper */
|
||||
|
||||
/* Connect signals */
|
||||
@ -374,23 +385,20 @@ void PostedListWidgetWithModel::filterItems(QString text)
|
||||
|
||||
void PostedListWidgetWithModel::nextPosts()
|
||||
{
|
||||
ui->postsTree->selectionModel()->clear();
|
||||
if(mPostedPostsModel->displayedStartPostIndex() + POSTS_CHUNK_SIZE < mPostedPostsModel->filteredPostsCount())
|
||||
{
|
||||
mPostedPostsModel->setPostsInterval(POSTS_CHUNK_SIZE+mPostedPostsModel->displayedStartPostIndex(),POSTS_CHUNK_SIZE);
|
||||
if(mPostedPostsModel->displayedStartPostIndex() + POSTS_CHUNK_SIZE < mPostedPostsModel->filteredPostsCount())
|
||||
{
|
||||
mPostedPostsModel->setPostsInterval(POSTS_CHUNK_SIZE+mPostedPostsModel->displayedStartPostIndex(),POSTS_CHUNK_SIZE);
|
||||
updateShowLabel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PostedListWidgetWithModel::prevPosts()
|
||||
{
|
||||
ui->postsTree->selectionModel()->clear();
|
||||
|
||||
if((int)mPostedPostsModel->displayedStartPostIndex() > 0)
|
||||
{
|
||||
mPostedPostsModel->setPostsInterval((int)mPostedPostsModel->displayedStartPostIndex()-POSTS_CHUNK_SIZE,POSTS_CHUNK_SIZE);
|
||||
updateShowLabel();
|
||||
}
|
||||
if((int)mPostedPostsModel->displayedStartPostIndex() > 0)
|
||||
{
|
||||
mPostedPostsModel->setPostsInterval((int)mPostedPostsModel->displayedStartPostIndex()-POSTS_CHUNK_SIZE,POSTS_CHUNK_SIZE);
|
||||
updateShowLabel();
|
||||
}
|
||||
}
|
||||
|
||||
void PostedListWidgetWithModel::showAuthorInPeople()
|
||||
@ -490,29 +498,30 @@ void PostedListWidgetWithModel::handleEvent_main_thread(std::shared_ptr<const Rs
|
||||
|
||||
switch(e->mPostedEventCode)
|
||||
{
|
||||
case RsPostedEventCode::NEW_COMMENT: // [[fallthrough]];
|
||||
case RsPostedEventCode::NEW_VOTE: // [[fallthrough]];
|
||||
{
|
||||
// special treatment here because the message might be a comment, so we need to refresh the comment tab if openned
|
||||
case RsPostedEventCode::NEW_COMMENT: [[fallthrough]];
|
||||
case RsPostedEventCode::NEW_VOTE:
|
||||
{
|
||||
// special treatment here because the message might be a comment, so we need to refresh the comment tab if openned
|
||||
|
||||
for(int i=2;i<ui->tabWidget->count();++i)
|
||||
{
|
||||
auto *t = dynamic_cast<GxsCommentDialog*>(ui->tabWidget->widget(i));
|
||||
for(int i=2;i<ui->tabWidget->count();++i)
|
||||
{
|
||||
auto *t = dynamic_cast<GxsCommentDialog*>(ui->tabWidget->widget(i));
|
||||
|
||||
if(t->groupId() == e->mPostedGroupId)
|
||||
t->refresh();
|
||||
}
|
||||
}
|
||||
case RsPostedEventCode::NEW_MESSAGE: // [[fallthrough]];
|
||||
case RsPostedEventCode::NEW_POSTED_GROUP: // [[fallthrough]];
|
||||
case RsPostedEventCode::UPDATED_POSTED_GROUP: // [[fallthrough]];
|
||||
case RsPostedEventCode::UPDATED_MESSAGE:
|
||||
case RsPostedEventCode::BOARD_DELETED:
|
||||
case RsPostedEventCode::SYNC_PARAMETERS_UPDATED:
|
||||
{
|
||||
if(t->groupId() == e->mPostedGroupId)
|
||||
t->refresh();
|
||||
}
|
||||
}
|
||||
[[clang::fallthrough]];
|
||||
case RsPostedEventCode::NEW_MESSAGE: [[fallthrough]];
|
||||
case RsPostedEventCode::NEW_POSTED_GROUP: [[fallthrough]];
|
||||
case RsPostedEventCode::UPDATED_POSTED_GROUP: [[fallthrough]];
|
||||
case RsPostedEventCode::UPDATED_MESSAGE: [[fallthrough]];
|
||||
case RsPostedEventCode::BOARD_DELETED: [[fallthrough]];
|
||||
case RsPostedEventCode::SYNC_PARAMETERS_UPDATED:
|
||||
{
|
||||
if(e->mPostedGroupId == groupId())
|
||||
updateDisplay(true);
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
|
@ -251,7 +251,7 @@ p, li { white-space: pre-wrap; }
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Preferred</enum>
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
@ -310,7 +310,7 @@ p, li { white-space: pre-wrap; }
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>11</pointsize>
|
||||
<pointsize>25</pointsize>
|
||||
<weight>75</weight>
|
||||
<italic>true</italic>
|
||||
<bold>true</bold>
|
||||
|
@ -381,7 +381,7 @@ void ChatWidget::init(const ChatId &chat_id, const QString &title)
|
||||
hist_chat_type = RS_HISTORY_TYPE_PUBLIC;
|
||||
messageCount = Settings->getPublicChatHistoryCount();
|
||||
|
||||
ui->titleBarFrame->setVisible(false);
|
||||
ui->headerBFrame->setVisible(false);
|
||||
}
|
||||
|
||||
if (rsHistory->getEnable(hist_chat_type))
|
||||
|
@ -32,7 +32,7 @@
|
||||
<enum>QLayout::SetMaximumSize</enum>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="titleBarFrame">
|
||||
<widget class="QFrame" name="headerBFrame">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
@ -51,7 +51,7 @@
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="titleBarFrameHLayout">
|
||||
<layout class="QHBoxLayout" name="headerBFrameHLayout">
|
||||
<property name="leftMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
|
@ -18,42 +18,73 @@
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
#include <QPainter>
|
||||
#include <QResizeEvent>
|
||||
#include "RSTreeView.h"
|
||||
|
||||
RSTreeView::RSTreeView(QWidget *parent) : QTreeView(parent)
|
||||
#include "util/rsdebug.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QResizeEvent>
|
||||
|
||||
//#define DEBUG_RSTREEVIEW
|
||||
|
||||
RSTreeView::RSTreeView(QWidget *parent)
|
||||
: QTreeView(parent), autoSelect(false)
|
||||
{
|
||||
setMouseTracking(false); // normally the default, but who knows if it's not goign to change in the future.
|
||||
setMouseTracking(false); // normally the default, but who knows if it's not going to change in the future.
|
||||
}
|
||||
|
||||
void RSTreeView::wheelEvent(QWheelEvent *e)
|
||||
{
|
||||
if(e->modifiers() == Qt::ControlModifier)
|
||||
{
|
||||
emit zoomRequested(e->delta() > 0);
|
||||
return;
|
||||
}
|
||||
else
|
||||
QTreeView::wheelEvent(e);
|
||||
if(e->modifiers() == Qt::ControlModifier)
|
||||
{
|
||||
emit zoomRequested(e->angleDelta().y() > 0);
|
||||
return;
|
||||
}
|
||||
else
|
||||
QTreeView::wheelEvent(e);
|
||||
}
|
||||
|
||||
void RSTreeView::mouseMoveEvent(QMouseEvent *e)
|
||||
{
|
||||
QModelIndex idx = indexAt(e->pos());
|
||||
#ifdef DEBUG_RSTREEVIEW
|
||||
RS_DBG(e->localPos().x(), ":", e->localPos().y());
|
||||
#endif
|
||||
if (autoSelect)
|
||||
{
|
||||
QModelIndex idx = indexAt(e->pos());
|
||||
|
||||
if(idx.isValid() && idx != selectionModel()->currentIndex())
|
||||
selectionModel()->setCurrentIndex(idx,QItemSelectionModel::ClearAndSelect);
|
||||
if(idx.isValid() && idx != selectionModel()->currentIndex())
|
||||
{
|
||||
#ifdef DEBUG_RSTREEVIEW
|
||||
RS_DBG("Selection changed");
|
||||
#endif
|
||||
selectionModel()->setCurrentIndex(idx,QItemSelectionModel::ClearAndSelect);
|
||||
}
|
||||
}
|
||||
|
||||
QTreeView::mouseMoveEvent(e);
|
||||
QTreeView::mouseMoveEvent(e);
|
||||
}
|
||||
|
||||
void RSTreeView::leaveEvent(QEvent *e)
|
||||
{
|
||||
#ifdef DEBUG_RSTREEVIEW
|
||||
RS_DBG("");
|
||||
#endif
|
||||
if (autoSelect)
|
||||
{
|
||||
auto fp = focusPolicy();
|
||||
setFocusPolicy(Qt::NoFocus); // To not select first index when resetting current index.
|
||||
selectionModel()->setCurrentIndex(QModelIndex(),QItemSelectionModel::Clear); // Close editor
|
||||
setFocusPolicy(fp);
|
||||
}
|
||||
|
||||
QTreeView::leaveEvent(e);
|
||||
}
|
||||
|
||||
void RSTreeView::setAutoSelect(bool b)
|
||||
{
|
||||
if(b)
|
||||
setMouseTracking(true);
|
||||
else
|
||||
setMouseTracking(false);
|
||||
autoSelect = b; // Keep this because setMouseTracking can be called outside.
|
||||
setMouseTracking(b);
|
||||
}
|
||||
|
||||
void RSTreeView::resizeEvent(QResizeEvent *e)
|
||||
|
@ -29,26 +29,34 @@ class RSTreeView : public QTreeView
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
RSTreeView(QWidget *parent = 0);
|
||||
RSTreeView(QWidget *parent = nullptr);
|
||||
|
||||
/**
|
||||
* @brief set Placeholder Text
|
||||
* @param text
|
||||
*/
|
||||
void setPlaceholderText(const QString &text);
|
||||
|
||||
// Use this to make selection automatic based on mouse position. This is useful to trigger selection and therefore editing mode
|
||||
// in trees that show editing widgets using a QStyledItemDelegate
|
||||
|
||||
void setAutoSelect(bool b);
|
||||
/**
|
||||
* @brief Use this to make selection automatic based on mouse position.
|
||||
* This is useful to trigger selection and therefore editing mode in trees that show editing widgets using a QStyledItemDelegate.
|
||||
* @param b
|
||||
*/
|
||||
void setAutoSelect(bool b);
|
||||
|
||||
signals:
|
||||
void sizeChanged(QSize);
|
||||
void zoomRequested(bool zoom_or_unzoom);
|
||||
void sizeChanged(QSize);
|
||||
void zoomRequested(bool zoom_or_unzoom);
|
||||
|
||||
protected:
|
||||
virtual void mouseMoveEvent(QMouseEvent *e) override; // overriding so as to manage auto-selection
|
||||
virtual void leaveEvent(QEvent *e) override; // overriding so as to manage auto-selection clear
|
||||
virtual void wheelEvent(QWheelEvent *e) override; // overriding so as to manage zoom
|
||||
virtual void resizeEvent(QResizeEvent *e) override;
|
||||
virtual void resizeEvent(QResizeEvent *e) override;
|
||||
virtual void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
QString placeholderText;
|
||||
bool autoSelect;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "ConnectFriendWizard.h"
|
||||
#include "ui_ConnectFriendWizard.h"
|
||||
#include "gui/common/PeerDefs.h"
|
||||
#include "gui/connect/ConfCertDialog.h"
|
||||
#include "gui/notifyqt.h"
|
||||
#include "gui/common/GroupDefs.h"
|
||||
#include "gui/msgs/MessageComposer.h"
|
||||
@ -572,6 +573,16 @@ void ConnectFriendWizard::initializePage(int id)
|
||||
ui->ipEdit->setText(s);
|
||||
ui->signersEdit->setPlainText(ts);
|
||||
|
||||
ui->knownIpLabel->setHidden(peerDetails.ipAddressList.empty());
|
||||
ui->knownIpEdit->setHidden(peerDetails.ipAddressList.empty());
|
||||
{
|
||||
QString ipList;
|
||||
for(auto& it : peerDetails.ipAddressList)
|
||||
ipList.append(QString::fromStdString(it) + "\n");
|
||||
|
||||
ui->knownIpEdit->setPlainText(ipList);
|
||||
}
|
||||
|
||||
fillGroups(this, ui->groupComboBox, groupId);
|
||||
|
||||
if(peerDetails.isHiddenNode)
|
||||
@ -587,15 +598,16 @@ void ConnectFriendWizard::initializePage(int id)
|
||||
}
|
||||
if(mIsShortInvite)
|
||||
{
|
||||
ui->nameEdit->setText(tr("[Unknown]"));
|
||||
ui->addKeyToKeyring_CB->setChecked(false);
|
||||
ui->addKeyToKeyring_CB->setEnabled(false);
|
||||
if(ui->nameEdit->text().isEmpty())
|
||||
ui->nameEdit->setText(tr("[Unknown]"));
|
||||
ui->addKeyToKeyring_CB->setChecked(false);
|
||||
ui->addKeyToKeyring_CB->setEnabled(false);
|
||||
ui->signersEdit->hide();
|
||||
ui->signersLabel->hide();
|
||||
ui->signGPGCheckBox->setChecked(false);
|
||||
ui->signGPGCheckBox->setEnabled(false);
|
||||
ui->acceptNoSignGPGCheckBox->setChecked(true);
|
||||
ui->acceptNoSignGPGCheckBox->setEnabled(false);
|
||||
ui->signGPGCheckBox->setChecked(false);
|
||||
ui->signGPGCheckBox->setEnabled(false);
|
||||
ui->acceptNoSignGPGCheckBox->setChecked(true);
|
||||
ui->acceptNoSignGPGCheckBox->setEnabled(false);
|
||||
}
|
||||
|
||||
ui->ipEdit->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
||||
@ -856,30 +868,30 @@ void ConnectFriendWizard::cleanFriendCert()
|
||||
{
|
||||
bool certValid = false;
|
||||
QString errorMsg ;
|
||||
QString certDetail;
|
||||
std::string cert = ui->friendCertEdit->toPlainText().toUtf8().constData();
|
||||
|
||||
if (cert.empty()) {
|
||||
ui->friendCertCleanLabel->setPixmap(FilesDefs::getPixmapFromQtResourcePath(":/images/delete.png"));
|
||||
ui->friendCertCleanLabel->setToolTip("");
|
||||
ui->friendCertCleanLabel->setStyleSheet("");
|
||||
errorMsg = tr("");
|
||||
|
||||
} else {
|
||||
std::string cleanCert;
|
||||
uint32_t error_code;
|
||||
RsPeerDetails details;
|
||||
|
||||
if (rsPeers->cleanCertificate(cert, cleanCert, mIsShortInvite, error_code))
|
||||
{
|
||||
if (rsPeers->cleanCertificate(cert, cleanCert, mIsShortInvite, error_code, details))
|
||||
{
|
||||
certValid = true;
|
||||
|
||||
if (cert != cleanCert)
|
||||
{
|
||||
{
|
||||
QTextCursor textCursor = ui->friendCertEdit->textCursor();
|
||||
|
||||
whileBlocking(ui->friendCertEdit)->setPlainText(QString::fromUtf8(cleanCert.c_str()));
|
||||
whileBlocking(ui->friendCertEdit)->setTextCursor(textCursor);
|
||||
|
||||
ui->friendCertCleanLabel->setStyleSheet("");
|
||||
certDetail = ConfCertDialog::getCertificateDescription(details,false,mIsShortInvite,!details.ipAddressList.empty());
|
||||
}
|
||||
|
||||
if (mIsShortInvite)
|
||||
@ -887,7 +899,7 @@ void ConnectFriendWizard::cleanFriendCert()
|
||||
else
|
||||
errorMsg = tr("Valid certificate") ;
|
||||
|
||||
ui->friendCertCleanLabel->setPixmap(FilesDefs::getPixmapFromQtResourcePath(":/images/accepted16.png"));
|
||||
ui->friendCertCleanLabel->setPixmap(FilesDefs::getPixmapFromQtResourcePath(":/images/accepted16.png"));
|
||||
} else {
|
||||
if (error_code > 0) {
|
||||
switch (error_code) {
|
||||
@ -903,16 +915,17 @@ void ConnectFriendWizard::cleanFriendCert()
|
||||
|
||||
default:
|
||||
errorMsg = tr("Not a valid Retroshare certificate!") ;
|
||||
ui->friendCertCleanLabel->setStyleSheet("QLabel#friendCertCleanLabel {border: 1px solid #DCDC41; border-radius: 6px; background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #FFFFD7, stop:1 #FFFFB2);}");
|
||||
}
|
||||
}
|
||||
ui->friendCertCleanLabel->setPixmap(FilesDefs::getPixmapFromQtResourcePath(":/images/delete.png"));
|
||||
}
|
||||
}
|
||||
|
||||
ui->friendCertCleanLabel->setPixmap(certValid ? FilesDefs::getPixmapFromQtResourcePath(":/images/accepted16.png") : FilesDefs::getPixmapFromQtResourcePath(":/images/delete.png"));
|
||||
ui->friendCertCleanLabel->setToolTip(errorMsg);
|
||||
ui->friendCertCleanLabel->setPixmap(certValid ? FilesDefs::getPixmapFromQtResourcePath(":/images/accepted16.png") : FilesDefs::getPixmapFromQtResourcePath(":/images/delete.png"));
|
||||
ui->friendCertCleanLabel->setToolTip("<p>" + errorMsg + (certValid ? "\n" + certDetail : "") + "</p>");
|
||||
ui->friendCertCleanLabel->setText(errorMsg);
|
||||
ui->friendCertCleanLabel->setProperty("WrongValue", !certValid && !errorMsg.isEmpty());
|
||||
ui->friendCertCleanLabel->style()->unpolish(ui->friendCertCleanLabel);
|
||||
ui->friendCertCleanLabel->style()->polish( ui->friendCertCleanLabel);
|
||||
|
||||
ui->TextPage->setComplete(certValid);
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user