diff --git a/.gitmodules b/.gitmodules index 2f69bb7b2..5199bdb4d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -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 diff --git a/build_scripts/Android/Dockerfile b/build_scripts/Android/Dockerfile index 2e4b8c762..490a247c9 100644 --- a/build_scripts/Android/Dockerfile +++ b/build_scripts/Android/Dockerfile @@ -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/ diff --git a/build_scripts/Android/prepare-toolchain-clang.sh b/build_scripts/Android/prepare-toolchain-clang.sh index 25fefccba..510b04855 100755 --- a/build_scripts/Android/prepare-toolchain-clang.sh +++ b/build_scripts/Android/prepare-toolchain-clang.sh @@ -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 $? } diff --git a/build_scripts/GitlabCI/Android.Dockerfile b/build_scripts/GitlabCI/Android.Dockerfile index a0844972d..bc4bd0755 100644 --- a/build_scripts/GitlabCI/Android.Dockerfile +++ b/build_scripts/GitlabCI/Android.Dockerfile @@ -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 diff --git a/build_scripts/OBS b/build_scripts/OBS index b260e5834..df16cb915 160000 --- a/build_scripts/OBS +++ b/build_scripts/OBS @@ -1 +1 @@ -Subproject commit b260e58346b1eec782bdf88a7e8f3c9d36fd3ecb +Subproject commit df16cb915465d058c75277678799ce4dadeae287 diff --git a/jsonapi-generator/README.adoc b/jsonapi-generator/README.adoc index 64284b85c..cea59a117 100644 --- a/jsonapi-generator/README.adoc +++ b/jsonapi-generator/README.adoc @@ -1,447 +1,10 @@ -// SPDX-FileCopyrightText: (C) 2004-2019 Retroshare Team +// SPDX-FileCopyrightText: (C) 2021 Retroshare Team // 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+. 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& 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+ 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. diff --git a/jsonapi-generator/src/async-method-wrapper-template.cpp.tmpl b/jsonapi-generator/src/async-method-wrapper-template.cpp.tmpl deleted file mode 100644 index 29f53ad48..000000000 --- a/jsonapi-generator/src/async-method-wrapper-template.cpp.tmpl +++ /dev/null @@ -1,80 +0,0 @@ -/******************************************************************************* - * RetroShare JSON API * - * * - * Copyright (C) 2018-2019 Gioacchino Mazzurco * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU Affero General Public License 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 . * - * * - *******************************************************************************/ - -registerHandler( "$%apiPath%$", - [this](const std::shared_ptr session) -{ - const std::multimap headers - { - { "Connection", "keep-alive" }, - { "Content-Type", "text/event-stream" } - }; - session->yield(rb::OK, headers); - - size_t reqSize = session->get_request()->get_header("Content-Length", 0); - session->fetch( reqSize, [this]( - const std::shared_ptr session, - const rb::Bytes& body ) - { - INITIALIZE_API_CALL_JSON_CONTEXT; - - if( !checkRsServicePtrReady( - $%instanceName%$, "$%instanceName%$", cAns, session ) ) - return; - -$%paramsDeclaration%$ - -$%inputParamsDeserialization%$ - - const std::weak_ptr weakService(mService); - const std::weak_ptr 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%$ ); diff --git a/jsonapi-generator/src/async-method-wrapper-template.cpp.tmpl b/jsonapi-generator/src/async-method-wrapper-template.cpp.tmpl new file mode 120000 index 000000000..1ae671997 --- /dev/null +++ b/jsonapi-generator/src/async-method-wrapper-template.cpp.tmpl @@ -0,0 +1 @@ +../../libretroshare/src/jsonapi/async-method-wrapper-template.cpp.tmpl \ No newline at end of file diff --git a/jsonapi-generator/src/jsonapi-generator-doxygen.conf b/jsonapi-generator/src/jsonapi-generator-doxygen.conf deleted file mode 100644 index 0edd1de3e..000000000 --- a/jsonapi-generator/src/jsonapi-generator-doxygen.conf +++ /dev/null @@ -1,230 +0,0 @@ -DOXYFILE_ENCODING = UTF-8 -PROJECT_NAME = "libretroshare" - -ALIASES += jsonapi{1}="\xmlonly\endxmlonly" -ALIASES += jsonapi{2}="\xmlonly\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 - diff --git a/jsonapi-generator/src/jsonapi-generator-doxygen.conf b/jsonapi-generator/src/jsonapi-generator-doxygen.conf new file mode 120000 index 000000000..9aff33c39 --- /dev/null +++ b/jsonapi-generator/src/jsonapi-generator-doxygen.conf @@ -0,0 +1 @@ +../../libretroshare/src/jsonapi/jsonapi-generator-doxygen.conf \ No newline at end of file diff --git a/jsonapi-generator/src/method-wrapper-template.cpp.tmpl b/jsonapi-generator/src/method-wrapper-template.cpp.tmpl deleted file mode 100644 index a3927fba9..000000000 --- a/jsonapi-generator/src/method-wrapper-template.cpp.tmpl +++ /dev/null @@ -1,50 +0,0 @@ -/******************************************************************************* - * RetroShare JSON API * - * * - * Copyright (C) 2018-2019 Gioacchino Mazzurco * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU Affero General Public License as * - * published by the Free Software Foundation, either version 3 of the * - * License, or (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU Affero General Public License for more details. * - * * - * You should have received a copy of the GNU Affero General Public License * - * along with this program. If not, see . * - * * - *******************************************************************************/ - -registerHandler( "$%apiPath%$", - [](const std::shared_ptr session) -{ - size_t reqSize = session->get_request()->get_header("Content-Length", 0); - session->fetch( reqSize, []( - const std::shared_ptr 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%$ ); - diff --git a/jsonapi-generator/src/method-wrapper-template.cpp.tmpl b/jsonapi-generator/src/method-wrapper-template.cpp.tmpl new file mode 120000 index 000000000..717044ed2 --- /dev/null +++ b/jsonapi-generator/src/method-wrapper-template.cpp.tmpl @@ -0,0 +1 @@ +../../libretroshare/src/jsonapi/method-wrapper-template.cpp.tmpl \ No newline at end of file diff --git a/libbitdht/CMakeLists.txt b/libbitdht/CMakeLists.txt new file mode 100644 index 000000000..af352651c --- /dev/null +++ b/libbitdht/CMakeLists.txt @@ -0,0 +1,19 @@ +# RetroShare decentralized communication platform +# +# Copyright (C) 2021 Gioacchino Mazzurco +# Copyright (C) 2021 Asociación Civil Altermundi +# +# 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 ) diff --git a/libretroshare/CMakeLists.txt b/libretroshare/CMakeLists.txt new file mode 100644 index 000000000..93c8b04a5 --- /dev/null +++ b/libretroshare/CMakeLists.txt @@ -0,0 +1,411 @@ +# RetroShare decentralized communication platform +# +# Copyright (C) 2021 Gioacchino Mazzurco +# Copyright (C) 2021 Asociación Civil Altermundi +# +# 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) diff --git a/libretroshare/src/CMakeLists.txt b/libretroshare/src/CMakeLists.txt new file mode 100644 index 000000000..d3ceffecf --- /dev/null +++ b/libretroshare/src/CMakeLists.txt @@ -0,0 +1,408 @@ +# RetroShare decentralized communication platform +# +# Copyright (C) 2021 Gioacchino Mazzurco +# Copyright (C) 2021 Asociación Civil Altermundi +# +# 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 diff --git a/libretroshare/src/deep_search/forumsindex.cpp b/libretroshare/src/deep_search/forumsindex.cpp index acc7aed9a..a04f2ecac 100644 --- a/libretroshare/src/deep_search/forumsindex.cpp +++ b/libretroshare/src/deep_search/forumsindex.cpp @@ -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); diff --git a/libretroshare/src/gossipdiscovery/p3gossipdiscovery.cc b/libretroshare/src/gossipdiscovery/p3gossipdiscovery.cc index 732967f44..948fa3ccc 100644 --- a/libretroshare/src/gossipdiscovery/p3gossipdiscovery.cc +++ b/libretroshare/src/gossipdiscovery/p3gossipdiscovery.cc @@ -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::iterator lit; std::map::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::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 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 *******************/ diff --git a/libretroshare/src/gxs/rsgenexchange.cc b/libretroshare/src/gxs/rsgenexchange.cc index da8973eb1..fb1b4c295 100644 --- a/libretroshare/src/gxs/rsgenexchange.cc +++ b/libretroshare/src/gxs/rsgenexchange.cc @@ -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 groups_to_subscribe ; + bool atLeastOneGroupCreatedSuccessfully = false; + std::list 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::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() diff --git a/libretroshare/src/gxs/rsgxsnetservice.cc b/libretroshare/src/gxs/rsgxsnetservice.cc index e664b580c..9d9437991 100644 --- a/libretroshare/src/gxs/rsgxsnetservice.cc +++ b/libretroshare/src/gxs/rsgxsnetservice.cc @@ -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 > // // 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 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 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 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 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 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::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(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(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(item->PacketSubType())) + { + case RsNxsSubtype::PULL_REQUEST: + std::unique_ptr pullItem( + static_cast(item) ); + handlePullRequest(std::move(pullItem)); + continue; + } + // RsNxsItem needs dynamic_cast, since they have derived siblings. // RsNxsItem *ni = dynamic_cast(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 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 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(mServType) ); + item->PeerId(peerId); + generic_sendItem(item); + } + + return std::error_condition(); +} + +void RsGxsNetService::handlePullRequest( + std::unique_ptr item ) +{ + checkUpdatesFromPeers(std::set{item->PeerId()}); +} + bool RsGxsNetService::getGroupServerUpdateTS(const RsGxsGroupId& gid,rstime_t& group_server_update_TS, rstime_t& msg_server_update_TS) { RS_STACK_MUTEX(mNxsMutex) ; diff --git a/libretroshare/src/gxs/rsgxsnetservice.h b/libretroshare/src/gxs/rsgxsnetservice.h index a4b448003..0baee2a2f 100644 --- a/libretroshare/src/gxs/rsgxsnetservice.h +++ b/libretroshare/src/gxs/rsgxsnetservice.h @@ -250,6 +250,15 @@ public: void threadTick() override; /// @see RsTickingThread + + /// @see RsNetworkExchangeService + std::error_condition checkUpdatesFromPeers( + std::set peers = std::set() ) override; + + /// @see RsNetworkExchangeService + std::error_condition requestPull( + std::set peers = std::set() ) override; + private: /*! @@ -423,6 +432,8 @@ private: */ void handleRecvPublishKeys(RsNxsGroupPublishKeyItem*) ; + void handlePullRequest(std::unique_ptr item); + /** E: item handlers **/ @@ -459,7 +470,7 @@ private: void locked_pushMsgRespFromList(std::list& 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 si); RsItem *generic_recvItem(); private: diff --git a/libretroshare/src/gxs/rsgxsnetutils.cc b/libretroshare/src/gxs/rsgxsnetutils.cc index b74abcb0f..6d759da7e 100644 --- a/libretroshare/src/gxs/rsgxsnetutils.cc +++ b/libretroshare/src/gxs/rsgxsnetutils.cc @@ -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 diff --git a/libretroshare/src/gxs/rsnxs.h b/libretroshare/src/gxs/rsnxs.h index 2f9bb25a6..2197d0e7a 100644 --- a/libretroshare/src/gxs/rsnxs.h +++ b/libretroshare/src/gxs/rsnxs.h @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include @@ -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 peers = std::set() ) = 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 peers = std::set() ) = 0; }; diff --git a/libretroshare/src/jsonapi/README.adoc b/libretroshare/src/jsonapi/README.adoc new file mode 100644 index 000000000..64284b85c --- /dev/null +++ b/libretroshare/src/jsonapi/README.adoc @@ -0,0 +1,447 @@ +// SPDX-FileCopyrightText: (C) 2004-2019 Retroshare Team +// 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+. 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& 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+ 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 diff --git a/libretroshare/src/jsonapi/async-method-wrapper-template.cpp.tmpl b/libretroshare/src/jsonapi/async-method-wrapper-template.cpp.tmpl new file mode 100644 index 000000000..29f53ad48 --- /dev/null +++ b/libretroshare/src/jsonapi/async-method-wrapper-template.cpp.tmpl @@ -0,0 +1,80 @@ +/******************************************************************************* + * RetroShare JSON API * + * * + * Copyright (C) 2018-2019 Gioacchino Mazzurco * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License 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 . * + * * + *******************************************************************************/ + +registerHandler( "$%apiPath%$", + [this](const std::shared_ptr session) +{ + const std::multimap headers + { + { "Connection", "keep-alive" }, + { "Content-Type", "text/event-stream" } + }; + session->yield(rb::OK, headers); + + size_t reqSize = session->get_request()->get_header("Content-Length", 0); + session->fetch( reqSize, [this]( + const std::shared_ptr session, + const rb::Bytes& body ) + { + INITIALIZE_API_CALL_JSON_CONTEXT; + + if( !checkRsServicePtrReady( + $%instanceName%$, "$%instanceName%$", cAns, session ) ) + return; + +$%paramsDeclaration%$ + +$%inputParamsDeserialization%$ + + const std::weak_ptr weakService(mService); + const std::weak_ptr 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%$ ); diff --git a/libretroshare/src/jsonapi/jsonapi-generator-doxygen.conf b/libretroshare/src/jsonapi/jsonapi-generator-doxygen.conf new file mode 100644 index 000000000..0edd1de3e --- /dev/null +++ b/libretroshare/src/jsonapi/jsonapi-generator-doxygen.conf @@ -0,0 +1,230 @@ +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = "libretroshare" + +ALIASES += jsonapi{1}="\xmlonly\endxmlonly" +ALIASES += jsonapi{2}="\xmlonly\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 + diff --git a/libretroshare/src/jsonapi/jsonapi-generator.py b/libretroshare/src/jsonapi/jsonapi-generator.py new file mode 100755 index 000000000..accf9a0cd --- /dev/null +++ b/libretroshare/src/jsonapi/jsonapi-generator.py @@ -0,0 +1,365 @@ +#!/usr/bin/python3 + +# RetroShare JSON API generator +# +# Copyright (C) 2019 selankon +# Copyright (C) 2021 Gioacchino Mazzurco +# Copyright (C) 2021 Asociación Civil Altermundi +# +# 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 +# +# SPDX-FileCopyrightText: Retroshare Team +# 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\$\%) | # Escape sequence of two delimiters + (?P[_a-z][_a-z0-9]*)%\$ | # delimiter and a Python identifier + {(?P[_a-z][_a-z0-9]*)} | # delimiter and a braced identifier + (?P) # 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) diff --git a/libretroshare/src/jsonapi/jsonapi.cpp b/libretroshare/src/jsonapi/jsonapi.cpp index 4b003f225..2f2ded30c 100644 --- a/libretroshare/src/jsonapi/jsonapi.cpp +++ b/libretroshare/src/jsonapi/jsonapi.cpp @@ -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; } diff --git a/libretroshare/src/jsonapi/method-wrapper-template.cpp.tmpl b/libretroshare/src/jsonapi/method-wrapper-template.cpp.tmpl new file mode 100644 index 000000000..a3927fba9 --- /dev/null +++ b/libretroshare/src/jsonapi/method-wrapper-template.cpp.tmpl @@ -0,0 +1,50 @@ +/******************************************************************************* + * RetroShare JSON API * + * * + * Copyright (C) 2018-2019 Gioacchino Mazzurco * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +registerHandler( "$%apiPath%$", + [](const std::shared_ptr session) +{ + size_t reqSize = session->get_request()->get_header("Content-Length", 0); + session->fetch( reqSize, []( + const std::shared_ptr 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%$ ); + diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index e3bc28006..5ebb64290 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: (C) 2004-2019 Retroshare Team +# SPDX-FileCopyrightText: (C) 2004-2021 Retroshare Team # 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 } diff --git a/libretroshare/src/pgp/openpgpsdkhandler.cc b/libretroshare/src/pgp/openpgpsdkhandler.cc new file mode 100644 index 000000000..4b587563d --- /dev/null +++ b/libretroshare/src/pgp/openpgpsdkhandler.cc @@ -0,0 +1,1810 @@ +/******************************************************************************* + * libretroshare/src/pgp: pgphandler.cc * + * * + * libretroshare: retroshare core library * + * * + * Copyright 2018 Cyril Soler * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ +#include +#include +#include +#include +#include +#include +#include + +#ifdef WINDOWS_SYS +#include +#include "util/rsstring.h" +#include "util/rswin.h" +#endif + +extern "C" { +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +} +#include "openpgpsdkhandler.h" + +#include "util/rsdir.h" +#include "util/rsdiscspace.h" +#include "util/rsmemory.h" +#include "pgp/pgpkeyutil.h" +#include "retroshare/rspeers.h" + +static const uint32_t PGP_CERTIFICATE_LIMIT_MAX_NAME_SIZE = 64 ; +static const uint32_t PGP_CERTIFICATE_LIMIT_MAX_EMAIL_SIZE = 64 ; +static const uint32_t PGP_CERTIFICATE_LIMIT_MAX_PASSWD_SIZE = 1024 ; + +//#define DEBUG_PGPHANDLER 1 +//#define PGPHANDLER_DSA_SUPPORT + +ops_keyring_t *OpenPGPSDKHandler::allocateOPSKeyring() +{ + ops_keyring_t *kr = (ops_keyring_t*)rs_malloc(sizeof(ops_keyring_t)) ; + + if(kr == NULL) + return NULL ; + + kr->nkeys = 0 ; + kr->nkeys_allocated = 0 ; + kr->keys = 0 ; + + return kr ; +} + +ops_parse_cb_return_t cb_get_passphrase(const ops_parser_content_t *content_,ops_parse_cb_info_t *cbinfo)// __attribute__((unused))) +{ + const ops_parser_content_union_t *content=&content_->content; + bool prev_was_bad = false ; + + switch(content_->tag) + { + case OPS_PARSER_CMD_GET_SK_PASSPHRASE_PREV_WAS_BAD: prev_was_bad = true ; + /* fallthrough */ + case OPS_PARSER_CMD_GET_SK_PASSPHRASE: + { + std::string passwd; + std::string uid_hint ; + + if(cbinfo->cryptinfo.keydata->nuids > 0) + uid_hint = std::string((const char *)cbinfo->cryptinfo.keydata->uids[0].user_id) ; + uid_hint += "(" + RsPgpId(cbinfo->cryptinfo.keydata->key_id).toStdString()+")" ; + + bool cancelled = false ; + passwd = PGPHandler::passphraseCallback()(NULL,"",uid_hint.c_str(),NULL,prev_was_bad,&cancelled) ; + + if(cancelled) + *(unsigned char *)cbinfo->arg = 1; + + *(content->secret_key_passphrase.passphrase)= (char *)ops_mallocz(passwd.length()+1) ; + memcpy(*(content->secret_key_passphrase.passphrase),passwd.c_str(),passwd.length()) ; + return OPS_KEEP_MEMORY; + } + break; + + default: + break; + } + + return OPS_RELEASE_MEMORY; +} + +OpenPGPSDKHandler::OpenPGPSDKHandler(const std::string& pubring, const std::string& secring,const std::string& trustdb,const std::string& pgp_lock_filename) + : PGPHandler(pubring,secring,trustdb,pgp_lock_filename) +{ + RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. + + // Allocate public and secret keyrings. + // + _pubring = allocateOPSKeyring() ; + _secring = allocateOPSKeyring() ; + + // Check that the file exists. If not, create a void keyring. + + FILE *ftest ; + ftest = RsDirUtil::rs_fopen(pubring.c_str(),"rb") ; + bool pubring_exist = (ftest != NULL) ; + if(ftest != NULL) + fclose(ftest) ; + ftest = RsDirUtil::rs_fopen(secring.c_str(),"rb") ; + bool secring_exist = (ftest != NULL) ; + if(ftest != NULL) + fclose(ftest) ; + + // Read public and secret keyrings from supplied files. + // + if(pubring_exist) + { + if(ops_false == ops_keyring_read_from_file(_pubring, false, pubring.c_str())) + throw std::runtime_error("OpenPGPSDKHandler::readKeyRing(): cannot read pubring. File corrupted.") ; + } + else + RsErr() << "pubring file \"" << pubring << "\" not found. Creating a void keyring." ; + + const ops_keydata_t *keydata ; + int i=0 ; + while( (keydata = ops_keyring_get_key_by_index(_pubring,i)) != NULL ) + { + PGPCertificateInfo& cert(_public_keyring_map[ RsPgpId(keydata->key_id) ]) ; + + // Init all certificates. + + initCertificateInfo(cert,keydata,i) ; + + // Validate signatures. + + validateAndUpdateSignatures(cert,keydata) ; + + ++i ; + } + _pubring_last_update_time = time(NULL) ; + RsErr() << "Pubring read successfully." ; + + if(secring_exist) + { + if(ops_false == ops_keyring_read_from_file(_secring, false, secring.c_str())) + throw std::runtime_error("OpenPGPSDKHandler::readKeyRing(): cannot read secring. File corrupted.") ; + } + else + RsErr() << "secring file \"" << secring << "\" not found. Creating a void keyring." ; + + i=0 ; + while( (keydata = ops_keyring_get_key_by_index(_secring,i)) != NULL ) + { + initCertificateInfo(_secret_keyring_map[ RsPgpId(keydata->key_id) ],keydata,i) ; + ++i ; + } + _secring_last_update_time = time(NULL) ; + + RsErr() << "Secring read successfully." ; + + locked_readPrivateTrustDatabase() ; + _trustdb_last_update_time = time(NULL) ; +} + +void OpenPGPSDKHandler::initCertificateInfo(PGPCertificateInfo& cert,const ops_keydata_t *keydata,uint32_t index) +{ + // Parse certificate name + // + + if(keydata->uids != NULL) + { + std::string namestring( (char *)keydata->uids[0].user_id ) ; + + cert._name = "" ; + uint32_t i=0; + while(i < namestring.length() && namestring[i] != '(' && namestring[i] != '<') { cert._name += namestring[i] ; ++i ;} + + // trim right spaces + std::string::size_type found = cert._name.find_last_not_of(' '); + if (found != std::string::npos) + cert._name.erase(found + 1); + else + cert._name.clear(); // all whitespace + + std::string& next = (namestring[i] == '(')?cert._comment:cert._email ; + ++i ; + next = "" ; + while(i < namestring.length() && namestring[i] != ')' && namestring[i] != '>') { next += namestring[i] ; ++i ;} + + while(i < namestring.length() && namestring[i] != '(' && namestring[i] != '<') { next += namestring[i] ; ++i ;} + + if(i< namestring.length()) + { + std::string& next2 = (namestring[i] == '(')?cert._comment:cert._email ; + ++i ; + next2 = "" ; + while(i < namestring.length() && namestring[i] != ')' && namestring[i] != '>') { next2 += namestring[i] ; ++i ;} + } + } + + cert._trustLvl = 1 ; // to be setup accordingly + cert._validLvl = 1 ; // to be setup accordingly + cert._key_index = index ; + cert._flags = 0 ; + cert._time_stamp = 0 ;// "never" by default. Will be updated by trust database, and effective key usage. + + switch(keydata->key.pkey.algorithm) + { + case OPS_PKA_RSA: cert._type = PGPCertificateInfo::PGP_CERTIFICATE_TYPE_RSA ; + break ; + case OPS_PKA_DSA: cert._type = PGPCertificateInfo::PGP_CERTIFICATE_TYPE_DSA ; + cert._flags |= PGPCertificateInfo::PGP_CERTIFICATE_FLAG_UNSUPPORTED_ALGORITHM ; + break ; + default: cert._type = PGPCertificateInfo::PGP_CERTIFICATE_TYPE_UNKNOWN ; + cert._flags |= PGPCertificateInfo::PGP_CERTIFICATE_FLAG_UNSUPPORTED_ALGORITHM ; + break ; + } + + ops_fingerprint_t f ; + ops_fingerprint(&f,&keydata->key.pkey) ; + + cert._fpr = PGPFingerprintType(f.fingerprint) ; +} + +bool OpenPGPSDKHandler::validateAndUpdateSignatures(PGPCertificateInfo& cert,const ops_keydata_t *keydata) +{ + ops_validate_result_t* result=(ops_validate_result_t*)ops_mallocz(sizeof *result); + ops_boolean_t res = ops_validate_key_signatures(result,keydata,_pubring,cb_get_passphrase) ; + + if(res == ops_false) + { + static ops_boolean_t already = 0 ; + if(!already) + { + RsErr() << "(WW) Error in OpenPGPSDKHandler::validateAndUpdateSignatures(). Validation failed for at least some signatures." ; + already = 1 ; + } + } + + bool ret = false ; + + // Parse signers. + // + + if(result != NULL) + for(size_t i=0;ivalid_count;++i) + { + RsPgpId signer_id(result->valid_sigs[i].signer_id); + + if(cert.signers.find(signer_id) == cert.signers.end()) + { + cert.signers.insert(signer_id) ; + ret = true ; + } + } + + ops_validate_result_free(result) ; + + return ret ; +} + +OpenPGPSDKHandler::~OpenPGPSDKHandler() +{ + RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. +#ifdef DEBUG_PGPHANDLER + RsErr() << "Freeing OpenPGPSDKHandler. Deleting keyrings." ; +#endif + + // no need to free the the _map_ elements. They will be freed by the following calls: + // + ops_keyring_free(_pubring) ; + ops_keyring_free(_secring) ; + + free(_pubring) ; + free(_secring) ; +} + +void OpenPGPSDKHandler::printOPSKeys() const +{ + RsErr() << "Public keyring list from OPS:" ; + ops_keyring_list(_pubring) ; +} + +bool OpenPGPSDKHandler::haveSecretKey(const RsPgpId& id) const +{ + RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. + + return locked_getSecretKey(id) != NULL ; +} + +bool OpenPGPSDKHandler::availableGPGCertificatesWithPrivateKeys(std::list& ids) +{ + RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. + // go through secret keyring, and check that we have the pubkey as well. + // + + const ops_keydata_t *keydata = NULL ; + int i=0 ; + + while( (keydata = ops_keyring_get_key_by_index(_secring,i++)) != NULL ) + if(ops_keyring_find_key_by_id(_pubring,keydata->key_id) != NULL) // check that the key is in the pubring as well + { +#ifdef PGPHANDLER_DSA_SUPPORT + if(keydata->key.pkey.algorithm == OPS_PKA_RSA || keydata->key.pkey.algorithm == OPS_PKA_DSA) +#else + if(keydata->key.pkey.algorithm == OPS_PKA_RSA) +#endif + ids.push_back(RsPgpId(keydata->key_id)) ; +#ifdef DEBUG_PGPHANDLER + else + RsErr() << "Skipping keypair " << RsPgpId(keydata->key_id).toStdString() << ", unsupported algorithm: " << keydata->key.pkey.algorithm ; +#endif + } + + return true ; +} + +bool OpenPGPSDKHandler::GeneratePGPCertificate(const std::string& name, const std::string& email, const std::string& passphrase, RsPgpId& pgpId, const int keynumbits, std::string& errString) +{ + // Some basic checks + + if(!RsDiscSpace::checkForDiscSpace(RS_PGP_DIRECTORY)) + { + errString = std::string("(EE) low disc space in pgp directory. Can't write safely to keyring.") ; + return false ; + } + if(name.length() > PGP_CERTIFICATE_LIMIT_MAX_NAME_SIZE) + { + errString = std::string("(EE) name in certificate exceeds the maximum allowed name size") ; + return false ; + } + if(email.length() > PGP_CERTIFICATE_LIMIT_MAX_EMAIL_SIZE) + { + errString = std::string("(EE) email in certificate exceeds the maximum allowed email size") ; + return false ; + } + if(passphrase.length() > PGP_CERTIFICATE_LIMIT_MAX_PASSWD_SIZE) + { + errString = std::string("(EE) passphrase in certificate exceeds the maximum allowed passphrase size") ; + return false ; + } + if(keynumbits % 1024 != 0) + { + errString = std::string("(EE) RSA key length is not a multiple of 1024") ; + return false ; + } + + // Now the real thing + RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. + RsStackFileLock flck(_pgp_lock_filename) ; // lock access to PGP directory. + + // 1 - generate keypair - RSA-2048 + // + ops_user_id_t uid ; + char *s = strdup((name + " (Generated by RetroShare) <" + email + ">" ).c_str()) ; + uid.user_id = (unsigned char *)s ; + unsigned long int e = 65537 ; // some prime number + + ops_keydata_t *key = ops_rsa_create_selfsigned_keypair(keynumbits, e, &uid) ; + + free(s) ; + + if(!key) + return false ; + + // 2 - save the private key encrypted to a temporary memory buffer, so as to read an encrypted key to memory + + ops_create_info_t *cinfo = NULL ; + ops_memory_t *buf = NULL ; + ops_setup_memory_write(&cinfo, &buf, 0); + + if(!ops_write_transferable_secret_key(key,(unsigned char *)passphrase.c_str(),passphrase.length(),ops_false,cinfo)) + { + errString = std::string("(EE) Cannot encode secret key to memory!!") ; + return false ; + } + + // 3 - read the memory chunk into an encrypted keyring + + ops_keyring_t *tmp_secring = allocateOPSKeyring() ; + + if(! ops_keyring_read_from_mem(tmp_secring, ops_false, buf)) + { + errString = std::string("(EE) Cannot re-read key from memory!!") ; + return false ; + } + ops_teardown_memory_write(cinfo,buf); // cleanup memory + + // 4 - copy the encrypted private key to the private keyring + + pgpId = RsPgpId(tmp_secring->keys[0].key_id) ; + addNewKeyToOPSKeyring(_secring,tmp_secring->keys[0]) ; + initCertificateInfo(_secret_keyring_map[ pgpId ],&tmp_secring->keys[0],_secring->nkeys-1) ; + +#ifdef DEBUG_PGPHANDLER + RsErr() << "Added new secret key with id " << pgpId.toStdString() << " to secret keyring." ; +#endif + ops_keyring_free(tmp_secring) ; + free(tmp_secring) ; + + // 5 - add key to secret keyring on disk. + + cinfo = NULL ; + std::string secring_path_tmp = _secring_path + ".tmp" ; + + if(RsDirUtil::fileExists(_secring_path) && !RsDirUtil::copyFile(_secring_path,secring_path_tmp)) + { + errString= std::string("Cannot copy secret keyring !! Disk full? Out of disk quota?") ; + return false ; + } + int fd=ops_setup_file_append(&cinfo, secring_path_tmp.c_str()); + + if(!ops_write_transferable_secret_key(key,(unsigned char *)passphrase.c_str(),passphrase.length(),ops_false,cinfo)) + { + errString= std::string("Cannot encode secret key to disk!! Disk full? Out of disk quota?") ; + return false ; + } + ops_teardown_file_write(cinfo,fd) ; + + if(!RsDirUtil::renameFile(secring_path_tmp,_secring_path)) + { + errString= std::string("Cannot rename tmp secret key file ") + secring_path_tmp + " into " + _secring_path +". Disk error?" ; + return false ; + } + + // 6 - copy the public key to the public keyring on disk + + cinfo = NULL ; + std::string pubring_path_tmp = _pubring_path + ".tmp" ; + + if(RsDirUtil::fileExists(_pubring_path) && !RsDirUtil::copyFile(_pubring_path,pubring_path_tmp)) + { + errString= std::string("Cannot encode secret key to disk!! Disk full? Out of disk quota?") ; + return false ; + } + fd=ops_setup_file_append(&cinfo, pubring_path_tmp.c_str()); + + if(!ops_write_transferable_public_key(key, ops_false, cinfo)) + { + errString=std::string("Cannot encode secret key to memory!!") ; + return false ; + } + ops_teardown_file_write(cinfo,fd) ; + + if(!RsDirUtil::renameFile(pubring_path_tmp,_pubring_path)) + { + errString= std::string("Cannot rename tmp public key file ") + pubring_path_tmp + " into " + _pubring_path +". Disk error?" ; + return false ; + } + // 7 - clean + ops_keydata_free(key) ; + + // 8 - re-read the key from the public keyring, and add it to memory. + + _pubring_last_update_time = 0 ; // force update pubring from disk. + locked_syncPublicKeyring() ; + +#ifdef DEBUG_PGPHANDLER + RsErr() << "Added new public key with id " << pgpId.toStdString() << " to public keyring." ; +#endif + + // 9 - Update some flags. + + privateTrustCertificate(pgpId,PGPCertificateInfo::PGP_CERTIFICATE_TRUST_ULTIMATE) ; + + return true ; +} + +std::string OpenPGPSDKHandler::makeRadixEncodedPGPKey(const ops_keydata_t *key,bool include_signatures) +{ + ops_create_info_t* cinfo; + ops_memory_t *buf = NULL ; + ops_setup_memory_write(&cinfo, &buf, 0); + ops_boolean_t armoured = ops_true ; + + if(key->type == OPS_PTAG_CT_PUBLIC_KEY) + { + if(ops_write_transferable_public_key_from_packet_data(key,armoured,cinfo) != ops_true) + return "ERROR: This key cannot be processed by RetroShare because\nDSA certificates are not yet handled." ; + } + else if(key->type == OPS_PTAG_CT_ENCRYPTED_SECRET_KEY) + { + if(ops_write_transferable_secret_key_from_packet_data(key,armoured,cinfo) != ops_true) + return "ERROR: This key cannot be processed by RetroShare because\nDSA certificates are not yet handled." ; + } + else + { + ops_create_info_delete(cinfo); + RsErr() << "Unhandled key type " << key->type ; + return "ERROR: Cannot write key. Unhandled key type. " ; + } + + ops_writer_close(cinfo) ; + + std::string res((char *)ops_memory_get_data(buf),ops_memory_get_length(buf)) ; + ops_teardown_memory_write(cinfo,buf); + + if(!include_signatures) + { + std::string tmp ; + if(PGPKeyManagement::createMinimalKey(res,tmp) ) + res = tmp ; + } + + return res ; +} + +const ops_keydata_t *OpenPGPSDKHandler::locked_getSecretKey(const RsPgpId& id) const +{ + std::map::const_iterator res = _secret_keyring_map.find(id) ; + + if(res == _secret_keyring_map.end()) + return NULL ; + else + return ops_keyring_get_key_by_index(_secring,res->second._key_index) ; +} +const ops_keydata_t *OpenPGPSDKHandler::locked_getPublicKey(const RsPgpId& id,bool stamp_the_key) const +{ + std::map::const_iterator res = _public_keyring_map.find(id) ; + + if(res == _public_keyring_map.end()) + return NULL ; + else + { + if(stamp_the_key) // Should we stamp the key as used? + { + static rstime_t last_update_db_because_of_stamp = 0 ; + rstime_t now = time(NULL) ; + + res->second._time_stamp = now ; + + if(now > last_update_db_because_of_stamp + 3600) // only update database once every hour. No need to do it more often. + { + _trustdb_changed = true ; + last_update_db_because_of_stamp = now ; + } + } + return ops_keyring_get_key_by_index(_pubring,res->second._key_index) ; + } +} + +std::string OpenPGPSDKHandler::SaveCertificateToString(const RsPgpId& id,bool include_signatures) const +{ + RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. + const ops_keydata_t *key = locked_getPublicKey(id,false) ; + + if(key == NULL) + { + RsErr() << "Cannot output key " << id.toStdString() << ": not found in keyring." ; + return "" ; + } + + return makeRadixEncodedPGPKey(key,include_signatures) ; +} + +bool OpenPGPSDKHandler::exportPublicKey( const RsPgpId& id, unsigned char*& mem_block, size_t& mem_size, bool armoured, bool include_signatures ) const +{ + mem_block = nullptr; mem_size = 0; // clear just in case + + if(armoured) + { + RsErr() << __PRETTY_FUNCTION__ << " should not be used with " + << "armoured=true, because there's a bug in the armoured export" + << " of OPS" ; + print_stacktrace(); + return false; + } + + RS_STACK_MUTEX(pgphandlerMtx); + const ops_keydata_t* key = locked_getPublicKey(id,false); + + if(!key) + { + RsErr() << __PRETTY_FUNCTION__ << " key id: " << id + << " not found in keyring." ; + return false; + } + + ops_create_info_t* cinfo; + ops_memory_t *buf = nullptr; + ops_setup_memory_write(&cinfo, &buf, 0); + + if(ops_write_transferable_public_key_from_packet_data( + key, armoured, cinfo ) != ops_true) + { + RsErr() << __PRETTY_FUNCTION__ << " This key id " << id + << " cannot be processed by RetroShare because DSA certificates" + << " support is not implemented yet." ; + return false; + } + + ops_writer_close(cinfo); + + mem_size = ops_memory_get_length(buf); + mem_block = reinterpret_cast(malloc(mem_size)); + memcpy(mem_block,ops_memory_get_data(buf),mem_size); + + ops_teardown_memory_write(cinfo,buf); + + if(!include_signatures) + { + size_t new_size; + PGPKeyManagement::findLengthOfMinimalKey(mem_block, mem_size, new_size); + mem_size = new_size; + } + + return true; +} + +bool OpenPGPSDKHandler::exportGPGKeyPair(const std::string& filename,const RsPgpId& exported_key_id) const +{ + RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. + + const ops_keydata_t *pubkey = locked_getPublicKey(exported_key_id,false) ; + + if(pubkey == NULL) + { + RsErr() << "Cannot output key " << exported_key_id.toStdString() << ": not found in public keyring." ; + return false ; + } + const ops_keydata_t *seckey = locked_getSecretKey(exported_key_id) ; + + if(seckey == NULL) + { + RsErr() << "Cannot output key " << exported_key_id.toStdString() << ": not found in secret keyring." ; + return false ; + } + + FILE *f = RsDirUtil::rs_fopen(filename.c_str(),"w") ; + if(f == NULL) + { + RsErr() << "Cannot output key " << exported_key_id.toStdString() << ": file " << filename << " cannot be written. Please check for permissions, quotas, disk space." ; + return false ; + } + + fprintf(f,"%s\n", makeRadixEncodedPGPKey(pubkey,true).c_str()) ; + fprintf(f,"%s\n", makeRadixEncodedPGPKey(seckey,true).c_str()) ; + + fclose(f) ; + return true ; +} + +bool OpenPGPSDKHandler::exportGPGKeyPairToString( std::string& data, const RsPgpId& exportedKeyId, bool includeSignatures, std::string& errorMsg ) const +{ + RS_STACK_MUTEX(pgphandlerMtx); + + const ops_keydata_t *pubkey = locked_getPublicKey(exportedKeyId,false); + + if(!pubkey) + { + errorMsg = "Cannot output key " + exportedKeyId.toStdString() + + ": not found in public keyring."; + return false; + } + const ops_keydata_t *seckey = locked_getSecretKey(exportedKeyId); + + if(!seckey) + { + errorMsg = "Cannot output key " + exportedKeyId.toStdString() + + ": not found in secret keyring."; + return false; + } + + data = makeRadixEncodedPGPKey(pubkey, includeSignatures); + data += "\n"; + data += makeRadixEncodedPGPKey(seckey, includeSignatures); + data += "\n"; + return true; +} + +bool OpenPGPSDKHandler::getGPGDetailsFromBinaryBlock(const unsigned char *mem_block,size_t mem_size,RsPgpId& key_id, std::string& name, std::list& signers) const +{ + ops_keyring_t *tmp_keyring = allocateOPSKeyring(); + ops_memory_t *mem = ops_memory_new() ; + ops_memory_add(mem,mem_block,mem_size); + + if(!ops_keyring_read_from_mem(tmp_keyring,ops_false,mem)) + { + ops_keyring_free(tmp_keyring) ; + free(tmp_keyring) ; + ops_memory_release(mem) ; + free(mem) ; + + RsErr() << "Could not read key. Format error?" ; + //error_string = std::string("Could not read key. Format error?") ; + return false ; + } + ops_memory_release(mem) ; + free(mem) ; + //error_string.clear() ; + + if(tmp_keyring->nkeys != 1) + { + RsErr() << "No or incomplete/invalid key in supplied pgp block." ; + return false ; + } + if(tmp_keyring->keys[0].uids == NULL) + { + RsErr() << "No uid in supplied key." ; + return false ; + } + + key_id = RsPgpId(tmp_keyring->keys[0].key_id) ; + name = std::string((char *)tmp_keyring->keys[0].uids[0].user_id) ; + + // now parse signatures. + // + ops_validate_result_t* result=(ops_validate_result_t*)ops_mallocz(sizeof *result); + ops_boolean_t res ; + + { + RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. + res = ops_validate_key_signatures(result,&tmp_keyring->keys[0],_pubring,cb_get_passphrase) ; + } + + if(res == ops_false) + RsErr() << "(WW) Error in OpenPGPSDKHandler::validateAndUpdateSignatures(). Validation failed for at least some signatures." ; + + // also add self-signature if any (there should be!). + // + res = ops_validate_key_signatures(result,&tmp_keyring->keys[0],tmp_keyring,cb_get_passphrase) ; + + if(res == ops_false) + RsErr() << "(WW) Error in OpenPGPSDKHandler::validateAndUpdateSignatures(). Validation failed for at least some signatures." ; + + // Parse signers. + // + + std::set signers_set ; // Use a set to remove duplicates. + + if(result != NULL) + for(size_t i=0;ivalid_count;++i) + signers_set.insert(RsPgpId(result->valid_sigs[i].signer_id)) ; + + ops_validate_result_free(result) ; + + ops_keyring_free(tmp_keyring) ; + free(tmp_keyring) ; + + // write to the output variable + + signers.clear() ; + + for(std::set::const_iterator it(signers_set.begin());it!=signers_set.end();++it) + signers.push_back(*it) ; + + return true ; +} + +bool OpenPGPSDKHandler::importGPGKeyPair(const std::string& filename,RsPgpId& imported_key_id,std::string& import_error) +{ + import_error = "" ; + + // 1 - Test for file existance + // + FILE *ftest = RsDirUtil::rs_fopen(filename.c_str(),"r") ; + + if(ftest == NULL) + { + import_error = "Cannot open file " + filename + " for read. Please check access permissions." ; + return false ; + } + + fclose(ftest) ; + + // 2 - Read keyring from supplied file. + // + ops_keyring_t *tmp_keyring = allocateOPSKeyring(); + + if(ops_false == ops_keyring_read_from_file(tmp_keyring, ops_true, filename.c_str())) + { + import_error = "OpenPGPSDKHandler::readKeyRing(): cannot read key file. File corrupted?" ; + free(tmp_keyring); + return false ; + } + + return checkAndImportKeyPair(tmp_keyring, imported_key_id, import_error); +} + +bool OpenPGPSDKHandler::importGPGKeyPairFromString(const std::string &data, RsPgpId &imported_key_id, std::string &import_error) +{ + import_error = "" ; + + ops_memory_t* mem = ops_memory_new(); + ops_memory_add(mem, (unsigned char*)data.data(), data.length()); + + ops_keyring_t *tmp_keyring = allocateOPSKeyring(); + + if(ops_false == ops_keyring_read_from_mem(tmp_keyring, ops_true, mem)) + { + import_error = "OpenPGPSDKHandler::importGPGKeyPairFromString(): cannot parse key data" ; + free(tmp_keyring); + return false ; + } + return checkAndImportKeyPair(tmp_keyring, imported_key_id, import_error); +} + +bool OpenPGPSDKHandler::checkAndImportKeyPair(ops_keyring_t *tmp_keyring, RsPgpId &imported_key_id, std::string &import_error) +{ + if(tmp_keyring == 0) + { + import_error = "OpenPGPSDKHandler::checkAndImportKey(): keyring is null" ; + return false; + } + + if(tmp_keyring->nkeys != 2) + { + import_error = "OpenPGPSDKHandler::importKeyPair(): file does not contain a valid keypair." ; + if(tmp_keyring->nkeys > 2) + import_error += "\nMake sure that your key is a RSA key (DSA is not yet supported) and does not contain subkeys (not supported yet)."; + return false ; + } + + // 3 - Test that keyring contains a valid keypair. + // + const ops_keydata_t *pubkey = NULL ; + const ops_keydata_t *seckey = NULL ; + + if(tmp_keyring->keys[0].type == OPS_PTAG_CT_PUBLIC_KEY) + pubkey = &tmp_keyring->keys[0] ; + else if(tmp_keyring->keys[0].type == OPS_PTAG_CT_ENCRYPTED_SECRET_KEY) + seckey = &tmp_keyring->keys[0] ; + else + { + import_error = "Unrecognised key type in key file for key #0. Giving up." ; + RsErr() << "Unrecognised key type " << tmp_keyring->keys[0].type << " in key file for key #0. Giving up." ; + return false ; + } + if(tmp_keyring->keys[1].type == OPS_PTAG_CT_PUBLIC_KEY) + pubkey = &tmp_keyring->keys[1] ; + else if(tmp_keyring->keys[1].type == OPS_PTAG_CT_ENCRYPTED_SECRET_KEY) + seckey = &tmp_keyring->keys[1] ; + else + { + import_error = "Unrecognised key type in key file for key #1. Giving up." ; + RsErr() << "Unrecognised key type " << tmp_keyring->keys[1].type << " in key file for key #1. Giving up." ; + return false ; + } + + if(pubkey == nullptr || seckey == nullptr || pubkey == seckey) + { + import_error = "File does not contain a public and a private key. Sorry." ; + return false ; + } + if(memcmp( pubkey->fingerprint.fingerprint, + seckey->fingerprint.fingerprint, + RsPgpFingerprint::SIZE_IN_BYTES ) != 0) + { + import_error = "Public and private keys do nt have the same fingerprint. Sorry!" ; + return false ; + } + if(pubkey->key.pkey.version != 4) + { + import_error = "Public key is not version 4. Rejected!" ; + return false ; + } + + // 4 - now check self-signature for this keypair. For this we build a dummy keyring containing only the key. + // + ops_validate_result_t *result=(ops_validate_result_t*)ops_mallocz(sizeof *result); + + ops_keyring_t dummy_keyring ; + dummy_keyring.nkeys=1 ; + dummy_keyring.nkeys_allocated=1 ; + dummy_keyring.keys=const_cast(pubkey) ; + + ops_validate_key_signatures(result, const_cast(pubkey), &dummy_keyring, cb_get_passphrase) ; + + // Check that signatures contain at least one certification from the user id. + // + bool found = false ; + + for(uint32_t i=0;ivalid_count;++i) + if(!memcmp( + static_cast(result->valid_sigs[i].signer_id), + pubkey->key_id, + RsPgpId::SIZE_IN_BYTES )) + { + found = true ; + break ; + } + + if(!found) + { + import_error = "Cannot validate self signature for the imported key. Sorry." ; + return false ; + } + ops_validate_result_free(result); + + if(!RsDiscSpace::checkForDiscSpace(RS_PGP_DIRECTORY)) + { + import_error = std::string("(EE) low disc space in pgp directory. Can't write safely to keyring.") ; + return false ; + } + // 5 - All test passed. Adding key to keyring. + // + { + RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. + + imported_key_id = RsPgpId(pubkey->key_id) ; + + if(locked_getSecretKey(imported_key_id) == NULL) + { + RsStackFileLock flck(_pgp_lock_filename) ; // lock access to PGP directory. + + ops_create_info_t *cinfo = NULL ; + + // Make a copy of the secret keyring + // + std::string secring_path_tmp = _secring_path + ".tmp" ; + if(RsDirUtil::fileExists(_secring_path) && !RsDirUtil::copyFile(_secring_path,secring_path_tmp)) + { + import_error = "(EE) Cannot write secret key to disk!! Disk full? Out of disk quota. Keyring will be left untouched." ; + return false ; + } + + // Append the new key + + int fd=ops_setup_file_append(&cinfo, secring_path_tmp.c_str()); + + if(!ops_write_transferable_secret_key_from_packet_data(seckey,ops_false,cinfo)) + { + import_error = "(EE) Cannot encode secret key to disk!! Disk full? Out of disk quota?" ; + return false ; + } + ops_teardown_file_write(cinfo,fd) ; + + // Rename the new keyring to overwrite the old one. + // + if(!RsDirUtil::renameFile(secring_path_tmp,_secring_path)) + { + import_error = " (EE) Cannot move temp file " + secring_path_tmp + ". Bad write permissions?" ; + return false ; + } + + addNewKeyToOPSKeyring(_secring,*seckey) ; + initCertificateInfo(_secret_keyring_map[ imported_key_id ],seckey,_secring->nkeys-1) ; + } + else + import_error = "Private key already exists! Not importing it again." ; + + if(locked_addOrMergeKey(_pubring,_public_keyring_map,pubkey)) + _pubring_changed = true ; + } + + // 6 - clean + // + ops_keyring_free(tmp_keyring) ; + free(tmp_keyring); + + // write public key to disk + syncDatabase(); + + return true ; +} + +void OpenPGPSDKHandler::addNewKeyToOPSKeyring(ops_keyring_t *kr,const ops_keydata_t& key) +{ + if(kr->nkeys >= kr->nkeys_allocated) + { + kr->keys = (ops_keydata_t *)realloc(kr->keys,(kr->nkeys+1)*sizeof(ops_keydata_t)) ; + kr->nkeys_allocated = kr->nkeys+1; + } + memset(&kr->keys[kr->nkeys],0,sizeof(ops_keydata_t)) ; + ops_keydata_copy(&kr->keys[kr->nkeys],&key) ; + kr->nkeys++ ; +} + +bool OpenPGPSDKHandler::LoadCertificateFromBinaryData(const unsigned char *data,uint32_t data_len,RsPgpId& id,std::string& error_string) +{ + return LoadCertificate(data,data_len,ops_false,id,error_string); +} + +bool OpenPGPSDKHandler::LoadCertificateFromString(const std::string& pgp_cert,RsPgpId& id,std::string& error_string) +{ + return LoadCertificate((unsigned char*)(pgp_cert.c_str()),pgp_cert.length(),ops_true,id,error_string); +} + +bool OpenPGPSDKHandler::LoadCertificate(const unsigned char *data,uint32_t data_len,bool armoured,RsPgpId& id,std::string& error_string) +{ + RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. +#ifdef DEBUG_PGPHANDLER + RsErr() << "Reading new key from string: " ; +#endif + + ops_keyring_t *tmp_keyring = allocateOPSKeyring(); + ops_memory_t *mem = ops_memory_new() ; + ops_memory_add(mem,data,data_len) ; + + if(!ops_keyring_read_from_mem(tmp_keyring,armoured,mem)) + { + ops_keyring_free(tmp_keyring) ; + free(tmp_keyring) ; + ops_memory_release(mem) ; + free(mem) ; + + RsErr() << "Could not read key. Format error?" ; + error_string = std::string("Could not read key. Format error?") ; + return false ; + } + ops_memory_release(mem) ; + free(mem) ; + error_string.clear() ; + + // Check that there is exactly one key in this data packet. + // + if(tmp_keyring->nkeys != 1) + { + RsErr() << "Loaded certificate contains more than one PGP key. This is not allowed." ; + error_string = "Loaded certificate contains more than one PGP key. This is not allowed." ; + return false ; + } + + const ops_keydata_t *keydata = ops_keyring_get_key_by_index(tmp_keyring,0); + + // Check that the key is a version 4 key + // + if(keydata->key.pkey.version != 4) + { + error_string = "Public key is not version 4. Rejected!" ; + RsErr() << "Received a key with unhandled version number (" << keydata->key.pkey.version << ")" ; + return false ; + } + + // Check that the key is correctly self-signed. + // + ops_validate_result_t* result=(ops_validate_result_t*)ops_mallocz(sizeof *result); + + ops_validate_key_signatures(result,keydata,tmp_keyring,cb_get_passphrase) ; + + bool found = false ; + + for(uint32_t i=0;ivalid_count;++i) + if(!memcmp( + static_cast(result->valid_sigs[i].signer_id), + keydata->key_id, + RsPgpId::SIZE_IN_BYTES )) + { + found = true ; + break ; + } + + if(!found) + { + error_string = "This key is not self-signed. This is required by Retroshare." ; + RsErr() << "This key is not self-signed. This is required by Retroshare." ; + ops_validate_result_free(result); + return false ; + } + ops_validate_result_free(result); + +#ifdef DEBUG_PGPHANDLER + RsErr() << " Key read correctly: " ; + ops_keyring_list(tmp_keyring) ; +#endif + + int i=0 ; + + while( (keydata = ops_keyring_get_key_by_index(tmp_keyring,i++)) != NULL ) + if(locked_addOrMergeKey(_pubring,_public_keyring_map,keydata)) + { + _pubring_changed = true ; +#ifdef DEBUG_PGPHANDLER + RsErr() << " Added the key in the main public keyring." ; +#endif + } + else + RsErr() << "Key already in public keyring." ; + + if(tmp_keyring->nkeys > 0) + id = RsPgpId(tmp_keyring->keys[0].key_id) ; + else + return false ; + + ops_keyring_free(tmp_keyring) ; + free(tmp_keyring) ; + + _pubring_changed = true ; + + return true ; +} + +bool OpenPGPSDKHandler::locked_addOrMergeKey(ops_keyring_t *keyring,std::map& kmap,const ops_keydata_t *keydata) +{ + bool ret = false ; + RsPgpId id(keydata->key_id) ; + +#ifdef DEBUG_PGPHANDLER + RsErr() << "AddOrMergeKey():" ; + RsErr() << " id: " << id.toStdString() ; +#endif + + // See if the key is already in the keyring + const ops_keydata_t *existing_key = NULL; + std::map::const_iterator res = kmap.find(id) ; + + // Checks that + // - the key is referenced by keyid + // - the map is initialized + // - the fingerprint matches! + // + if(res == kmap.end() || (existing_key = ops_keyring_get_key_by_index(keyring,res->second._key_index)) == NULL) + { +#ifdef DEBUG_PGPHANDLER + RsErr() << " Key is new. Adding it to keyring" ; +#endif + addNewKeyToOPSKeyring(keyring,*keydata) ; // the key is new. + initCertificateInfo(kmap[id],keydata,keyring->nkeys-1) ; + existing_key = &(keyring->keys[keyring->nkeys-1]) ; + ret = true ; + } + else + { + if(memcmp( existing_key->fingerprint.fingerprint, + keydata->fingerprint.fingerprint, + RsPgpFingerprint::SIZE_IN_BYTES )) + { + RsErr() << "(EE) attempt to merge key with identical id, but different fingerprint!" ; + return false ; + } + +#ifdef DEBUG_PGPHANDLER + RsErr() << " Key exists. Merging signatures." ; +#endif + ret = mergeKeySignatures(const_cast(existing_key),keydata) ; + + if(ret) + initCertificateInfo(kmap[id],existing_key,res->second._key_index) ; + } + + if(ret) + { + validateAndUpdateSignatures(kmap[id],existing_key) ; + kmap[id]._time_stamp = time(NULL) ; + } + + return ret ; +} + +bool OpenPGPSDKHandler::encryptTextToFile(const RsPgpId& key_id,const std::string& text,const std::string& outfile) +{ + RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. + + const ops_keydata_t *public_key = locked_getPublicKey(key_id,true) ; + + if(public_key == NULL) + { + RsErr() << "Cannot get public key of id " << key_id.toStdString() ; + return false ; + } + + if(public_key->type != OPS_PTAG_CT_PUBLIC_KEY) + { + RsErr() << "OpenPGPSDKHandler::encryptTextToFile(): ERROR: supplied id did not return a public key!" ; + return false ; + } + + std::string outfile_tmp = outfile + ".tmp" ; + + ops_create_info_t *info; + int fd = ops_setup_file_write(&info, outfile_tmp.c_str(), ops_true); + + if (fd < 0) + { + RsErr() << "OpenPGPSDKHandler::encryptTextToFile(): ERROR: Cannot write to " << outfile_tmp ; + return false ; + } + + if(!ops_encrypt_stream(info, public_key, NULL, ops_false, ops_true)) + { + RsErr() << "OpenPGPSDKHandler::encryptTextToFile(): ERROR: encryption failed." ; + return false ; + } + + ops_write(text.c_str(), text.length(), info); + ops_teardown_file_write(info, fd); + + if(!RsDirUtil::renameFile(outfile_tmp,outfile)) + { + RsErr() << "OpenPGPSDKHandler::encryptTextToFile(): ERROR: Cannot rename " + outfile_tmp + " to " + outfile + ". Disk error?" ; + return false ; + } + + return true ; +} + +bool OpenPGPSDKHandler::encryptDataBin(const RsPgpId& key_id,const void *data, const uint32_t len, unsigned char *encrypted_data, unsigned int *encrypted_data_len) +{ + RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. + + const ops_keydata_t *public_key = locked_getPublicKey(key_id,true) ; + + if(public_key == NULL) + { + RsErr() << "Cannot get public key of id " << key_id.toStdString() ; + return false ; + } + + if(public_key->type != OPS_PTAG_CT_PUBLIC_KEY) + { + RsErr() << "OpenPGPSDKHandler::encryptTextToFile(): ERROR: supplied id did not return a public key!" ; + return false ; + } + if(public_key->key.pkey.algorithm != OPS_PKA_RSA) + { + RsErr() << "OpenPGPSDKHandler::encryptTextToFile(): ERROR: supplied key id " << key_id.toStdString() << " is not an RSA key (DSA for instance, is not supported)!" ; + return false ; + } + ops_create_info_t *info; + ops_memory_t *buf = NULL ; + ops_setup_memory_write(&info, &buf, 0); + bool res = true; + + if(!ops_encrypt_stream(info, public_key, NULL, ops_false, ops_false)) + { + RsErr() << "Encryption failed." ; + res = false ; + } + + ops_write(data,len,info); + ops_writer_close(info); + ops_create_info_delete(info); + + int tlen = ops_memory_get_length(buf) ; + + if( (int)*encrypted_data_len >= tlen) + { + if(res) + { + memcpy(encrypted_data,ops_memory_get_data(buf),tlen) ; + *encrypted_data_len = tlen ; + res = true ; + } + } + else + { + RsErr() << "Not enough room to fit encrypted data. Size given=" << *encrypted_data_len << ", required=" << tlen ; + res = false ; + } + + ops_memory_release(buf) ; + free(buf) ; + + return res ; +} + +bool OpenPGPSDKHandler::decryptDataBin(const RsPgpId& /*key_id*/,const void *encrypted_data, const uint32_t encrypted_len, unsigned char *data, unsigned int *data_len) +{ + int out_length ; + unsigned char *out ; + ops_boolean_t res = ops_decrypt_memory((const unsigned char *)encrypted_data,encrypted_len,&out,&out_length,_secring,ops_false,cb_get_passphrase) ; + + if(*data_len < (unsigned int)out_length) + { + RsErr() << "Not enough room to store decrypted data! Please give more."; + return false ; + } + + *data_len = (unsigned int)out_length ; + memcpy(data,out,out_length) ; + free(out) ; + + return (bool)res ; +} + +bool OpenPGPSDKHandler::decryptTextFromFile(const RsPgpId&,std::string& text,const std::string& inputfile) +{ + RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. + + unsigned char *out_buf = NULL ; + std::string buf ; + + FILE *f = RsDirUtil::rs_fopen(inputfile.c_str(),"rb") ; + + if (f == NULL) + { + RsErr() << "Cannot open file " << inputfile << " for read." ; + return false; + } + + int c ; + while( (c = fgetc(f))!= EOF) + buf += (unsigned char)c; + + fclose(f) ; + +#ifdef DEBUG_PGPHANDLER + RsErr() << "OpenPGPSDKHandler::decryptTextFromFile: read a file of length " << std::dec << buf.length() ; + RsErr() << "buf=\"" << buf << "\"" ; +#endif + + int out_length ; + ops_boolean_t res = ops_decrypt_memory((const unsigned char *)buf.c_str(),buf.length(),&out_buf,&out_length,_secring,ops_true,cb_get_passphrase) ; + + text = std::string((char *)out_buf,out_length) ; + free (out_buf); + return (bool)res ; +} + +bool OpenPGPSDKHandler::SignDataBin(const RsPgpId& id,const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen,bool use_raw_signature, std::string reason /* = "" */) +{ + // need to find the key and to decrypt it. + ops_keydata_t *key = nullptr; + { + RS_STACK_MUTEX(pgphandlerMtx); // lock access to PGP memory structures. + const ops_keydata_t *test_key = locked_getSecretKey(id); + if(!test_key) + { + RsErr("Cannot sign: no secret key with id ", id.toStdString() ); + return false ; + } + // Copy key as it may take time for user to respond. + key = ops_keydata_new(); + ops_keydata_copy(key, test_key); + } + + std::string uid_hint ; + if(key->nuids > 0) + uid_hint = std::string((const char *)key->uids[0].user_id) ; + uid_hint += "(" + RsPgpId(key->key_id).toStdString()+")" ; + +#ifdef DEBUG_PGPHANDLER + ops_fingerprint_t f ; + ops_fingerprint(&f,&key->key.pkey) ; + + PGPFingerprintType fp(f.fingerprint) ; +#endif + + bool last_passwd_was_wrong = false ; + ops_secret_key_t *secret_key = nullptr ; + + for(int i=0;i<3;++i) + { + bool cancelled =false; + // Need to be outside of mutex to not block GUI. + std::string passphrase = _passphrase_callback(NULL,reason.c_str(),uid_hint.c_str(),"Please enter password for encrypting your key : ",last_passwd_was_wrong,&cancelled) ;//TODO reason + + secret_key = ops_decrypt_secret_key_from_data(key,passphrase.c_str()) ; + + if(cancelled) + { + RsErr() << "Key entering cancelled" ; + ops_keydata_free(key); + return false ; + } + if(secret_key) + break ; + + RsErr() << "Key decryption went wrong. Wrong password?" ; + last_passwd_was_wrong = true ; + } + // No more need of key, free it. + ops_keydata_free(key); + + if(!secret_key) + { + RsErr() << "Could not obtain secret key. Signature cancelled." ; + return false ; + } + + // then do the signature. + + RS_STACK_MUTEX(pgphandlerMtx); // lock access to PGP memory structures. + + ops_boolean_t not_raw = !use_raw_signature ; +#ifdef V07_NON_BACKWARD_COMPATIBLE_CHANGE_002 + ops_memory_t *memres = ops_sign_buf(data,len,OPS_SIG_BINARY,OPS_HASH_SHA256,secret_key,ops_false,ops_false,not_raw,not_raw) ; +#else + ops_memory_t *memres = ops_sign_buf(data,len,OPS_SIG_BINARY,OPS_HASH_SHA1,secret_key,ops_false,ops_false,not_raw,not_raw) ; +#endif + + if(!memres) + return false ; + + bool res ; + uint32_t slen = (uint32_t)ops_memory_get_length(memres); + + if(*signlen >= slen) + { + *signlen = slen ; + + memcpy(sign,ops_memory_get_data(memres),*signlen) ; + res = true ; + } + else + { + RsErr() << "(EE) memory chunk is not large enough for signature packet. Requred size: " << slen << " bytes." ; + res = false ; + } + + ops_memory_release(memres) ; + free(memres) ; + ops_secret_key_free(secret_key) ; + free(secret_key) ; + +#ifdef DEBUG_PGPHANDLER + RsErr() << "Signed with fingerprint " << fp.toStdString() << ", length " << std::dec << *signlen << ", literal data length = " << len ; + RsErr() << "Signature body: " ; + hexdump( (unsigned char *)data, len) ; + RsErr() ; + RsErr() << "Data: " ; + hexdump( (unsigned char *)sign,*signlen) ; + RsErr() ; +#endif + return res ; +} + +bool OpenPGPSDKHandler::privateSignCertificate(const RsPgpId& ownId,const RsPgpId& id_of_key_to_sign) +{ + RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. + + ops_keydata_t *key_to_sign = const_cast(locked_getPublicKey(id_of_key_to_sign,true)) ; + + if(key_to_sign == NULL) + { + RsErr() << "Cannot sign: no public key with id " << id_of_key_to_sign.toStdString() ; + return false ; + } + + // 1 - get decrypted secret key + // + const ops_keydata_t *skey = locked_getSecretKey(ownId) ; + + if(!skey) + { + RsErr() << "Cannot sign: no secret key with id " << ownId.toStdString() ; + return false ; + } + const ops_keydata_t *pkey = locked_getPublicKey(ownId,true) ; + + if(!pkey) + { + RsErr() << "Cannot sign: no public key with id " << ownId.toStdString() ; + return false ; + } + + bool cancelled = false; + std::string passphrase = _passphrase_callback(NULL,"",RsPgpId(skey->key_id).toStdString().c_str(),"Please enter passwd for encrypting your key : ",false,&cancelled) ; + + ops_secret_key_t *secret_key = ops_decrypt_secret_key_from_data(skey,passphrase.c_str()) ; + + if(cancelled) + { + RsErr() << "Key cancelled by used." ; + return false ; + } + if(!secret_key) + { + RsErr() << "Key decryption went wrong. Wrong passwd?" ; + return false ; + } + + // 2 - then do the signature. + + if(!ops_sign_key(key_to_sign,pkey->key_id,secret_key)) + { + RsErr() << "Key signature went wrong. Wrong passwd?" ; + return false ; + } + + // 3 - free memory + // + ops_secret_key_free(secret_key) ; + free(secret_key) ; + + _pubring_changed = true ; + + // 4 - update signatures. + // + PGPCertificateInfo& cert(_public_keyring_map[ id_of_key_to_sign ]) ; + validateAndUpdateSignatures(cert,key_to_sign) ; + cert._flags |= PGPCertificateInfo::PGP_CERTIFICATE_FLAG_HAS_OWN_SIGNATURE ; + + return true ; +} + +bool OpenPGPSDKHandler::getKeyFingerprint(const RsPgpId& id, RsPgpFingerprint& fp) const +{ + RS_STACK_MUTEX(pgphandlerMtx); + + const ops_keydata_t *key = locked_getPublicKey(id,false) ; + + if(!key) return false; + + ops_fingerprint_t f ; + ops_fingerprint(&f,&key->key.pkey) ; + + fp = RsPgpFingerprint::fromBufferUnsafe(f.fingerprint); + + return true ; +} + +bool OpenPGPSDKHandler::VerifySignBin(const void *literal_data, uint32_t literal_data_length, unsigned char *sign, unsigned int sign_len, const PGPFingerprintType& key_fingerprint) +{ + RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. + + RsPgpId id = RsPgpId(key_fingerprint.toByteArray() + PGPFingerprintType::SIZE_IN_BYTES - RsPgpId::SIZE_IN_BYTES) ; + const ops_keydata_t *key = locked_getPublicKey(id,true) ; + + if(key == NULL) + { + RsErr() << "No key returned by fingerprint " << key_fingerprint.toStdString() << ", and ID " << id.toStdString() << ", signature verification failed!" ; + return false ; + } + + // Check that fingerprint is the same. + const ops_public_key_t *pkey = &key->key.pkey ; + ops_fingerprint_t fp ; + ops_fingerprint(&fp,pkey) ; + + if(key_fingerprint != PGPFingerprintType(fp.fingerprint)) + { + RsErr() << "Key fingerprint does not match " << key_fingerprint.toStdString() << ", for ID " << id.toStdString() << ", signature verification failed!" ; + return false ; + } + +#ifdef DEBUG_PGPHANDLER + RsErr() << "Verifying signature from fingerprint " << key_fingerprint.toStdString() << ", length " << std::dec << sign_len << ", literal data length = " << literal_data_length ; + RsErr() << "Signature body: " ; + hexdump( (unsigned char *)sign,sign_len) ; + RsErr() ; + RsErr() << "Signed data: " ; + hexdump( (unsigned char *)literal_data, literal_data_length) ; + RsErr() ; +#endif + + return ops_validate_detached_signature(literal_data,literal_data_length,sign,sign_len,key) ; +} + +// Lexicographic order on signature packets +// +bool operator<(const ops_packet_t& p1,const ops_packet_t& p2) +{ + if(p1.length < p2.length) + return true ; + if(p1.length > p2.length) + return false ; + + for(uint32_t i=0;i p2.raw[i]) + return false ; + } + return false ; +} + +bool OpenPGPSDKHandler::mergeKeySignatures(ops_keydata_t *dst,const ops_keydata_t *src) +{ + // First sort all signatures into lists to see which is new, which is not new + +#ifdef DEBUG_PGPHANDLER + RsErr() << "Merging signatures for key " << RsPgpId(dst->key_id).toStdString() ; +#endif + std::set dst_packets ; + + for(uint32_t i=0;inpackets;++i) dst_packets.insert(dst->packets[i]) ; + + std::set to_add ; + + for(uint32_t i=0;inpackets;++i) + if(dst_packets.find(src->packets[i]) == dst_packets.end()) + { + uint8_t tag ; + uint32_t length ; + unsigned char *tmp_data = src->packets[i].raw ; // put it in a tmp variable because read_packetHeader() will modify it!! + + PGPKeyParser::read_packetHeader(tmp_data,tag,length) ; + + if(tag == PGPKeyParser::PGP_PACKET_TAG_SIGNATURE) + to_add.insert(src->packets[i]) ; +#ifdef DEBUG_PGPHANDLER + else + RsErr() << " Packet with tag 0x" << std::hex << (int)(src->packets[i].raw[0]) << std::dec << " not merged, because it is not a signature." ; +#endif + } + + for(std::set::const_iterator it(to_add.begin());it!=to_add.end();++it) + { +#ifdef DEBUG_PGPHANDLER + RsErr() << " Adding packet with tag 0x" << std::hex << (int)(*it).raw[0] << std::dec ; +#endif + ops_add_packet_to_keydata(dst,&*it) ; + } + return to_add.size() > 0 ; +} + +bool OpenPGPSDKHandler::syncDatabase() +{ + RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. + RsStackFileLock flck(_pgp_lock_filename) ; // lock access to PGP directory. + +#ifdef DEBUG_PGPHANDLER + RsErr() << "Sync-ing keyrings." ; +#endif + locked_syncPublicKeyring() ; + //locked_syncSecretKeyring() ; + + // Now sync the trust database as well. + // + locked_syncTrustDatabase() ; + +#ifdef DEBUG_PGPHANDLER + RsErr() << "Done. " ; +#endif + return true ; +} + +bool OpenPGPSDKHandler::locked_syncPublicKeyring() +{ + struct stat64 buf ; +#ifdef WINDOWS_SYS + std::wstring wfullname; + librs::util::ConvertUtf8ToUtf16(_pubring_path, wfullname); + if(-1 == _wstati64(wfullname.c_str(), &buf)) +#else + if(-1 == stat64(_pubring_path.c_str(), &buf)) +#endif + RsErr() << "OpenPGPSDKHandler::syncDatabase(): can't stat file " << _pubring_path << ". Can't sync public keyring." ; + + if(_pubring_last_update_time < buf.st_mtime) + { + RsErr() << "Detected change on disk of public keyring. Merging!" << std::endl ; + + locked_mergeKeyringFromDisk(_pubring,_public_keyring_map,_pubring_path) ; + _pubring_last_update_time = buf.st_mtime ; + } + + // Now check if the pubring was locally modified, which needs saving it again + if(_pubring_changed && RsDiscSpace::checkForDiscSpace(RS_PGP_DIRECTORY)) + { + std::string tmp_keyring_file = _pubring_path + ".tmp" ; + + RsErr() << "Local changes in public keyring. Writing to disk..." ; + if(!ops_write_keyring_to_file(_pubring,ops_false,tmp_keyring_file.c_str(),ops_true)) + { + RsErr() << "Cannot write public keyring tmp file. Disk full? Disk quota exceeded?" ; + return false ; + } + if(!RsDirUtil::renameFile(tmp_keyring_file,_pubring_path)) + { + RsErr() << "Cannot rename tmp pubring file " << tmp_keyring_file << " into actual pubring file " << _pubring_path << ". Check writing permissions?!?" ; + return false ; + } + + RsErr() << "Done." ; + _pubring_last_update_time = time(NULL) ; // should we get this value from the disk instead?? + _pubring_changed = false ; + } + return true ; +} + +void OpenPGPSDKHandler::locked_mergeKeyringFromDisk(ops_keyring_t *keyring, + std::map& kmap, + const std::string& keyring_file) +{ +#ifdef DEBUG_PGPHANDLER + RsErr() << "Merging keyring " << keyring_file << " from disk to memory." ; +#endif + + // 1 - load keyring into a temporary keyring list. + ops_keyring_t *tmp_keyring = OpenPGPSDKHandler::allocateOPSKeyring() ; + + if(ops_false == ops_keyring_read_from_file(tmp_keyring, false, keyring_file.c_str())) + { + RsErr() << "OpenPGPSDKHandler::locked_mergeKeyringFromDisk(): cannot read keyring. File corrupted?" ; + ops_keyring_free(tmp_keyring) ; + return ; + } + + // 2 - load new keys and merge existing key signatures + + for(int i=0;inkeys;++i) + locked_addOrMergeKey(keyring,kmap,&tmp_keyring->keys[i]) ;// we dont' account for the return value. This is disk merging, not local changes. + + // 4 - clean + ops_keyring_free(tmp_keyring) ; +} + +bool OpenPGPSDKHandler::removeKeysFromPGPKeyring(const std::set& keys_to_remove,std::string& backup_file,uint32_t& error_code) +{ + // 1 - lock everything. + // + RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. + RsStackFileLock flck(_pgp_lock_filename) ; // lock access to PGP directory. + + error_code = PGP_KEYRING_REMOVAL_ERROR_NO_ERROR ; + + for(std::set::const_iterator it(keys_to_remove.begin());it!=keys_to_remove.end();++it) + if(locked_getSecretKey(*it) != NULL) + { + RsErr() << "(EE) OpenPGPSDKHandler:: can't remove key " << (*it).toStdString() << " since its shared by a secret key! Operation cancelled." ; + error_code = PGP_KEYRING_REMOVAL_ERROR_CANT_REMOVE_SECRET_KEYS ; + return false ; + } + + // 2 - sync everything. + // + locked_syncPublicKeyring() ; + + // 3 - make a backup of the public keyring + // + char template_name[_pubring_path.length()+8] ; + sprintf(template_name,"%s.XXXXXX",_pubring_path.c_str()) ; + +#if defined __USE_XOPEN_EXTENDED || defined __USE_XOPEN2K8 + int fd_keyring_backup(mkstemp(template_name)); + if (fd_keyring_backup == -1) +#else + if(mktemp(template_name) == NULL) +#endif + { + RsErr() << "OpenPGPSDKHandler::removeKeysFromPGPKeyring(): cannot create keyring backup file. Giving up." ; + error_code = PGP_KEYRING_REMOVAL_ERROR_CANNOT_CREATE_BACKUP ; + return false ; + } +#if defined __USE_XOPEN_EXTENDED || defined __USE_XOPEN2K8 + close(fd_keyring_backup); // TODO: keep the file open and use the fd +#endif + + if(!ops_write_keyring_to_file(_pubring,ops_false,template_name,ops_true)) + { + RsErr() << "OpenPGPSDKHandler::removeKeysFromPGPKeyring(): cannot write keyring backup file. Giving up." ; + error_code = PGP_KEYRING_REMOVAL_ERROR_CANNOT_WRITE_BACKUP ; + return false ; + } + backup_file = std::string(template_name,_pubring_path.length()+7) ; + + RsErr() << "Keyring was backed up to file " << backup_file ; + + // Remove keys from the keyring, and update the keyring map. + // + for(std::set::const_iterator it(keys_to_remove.begin());it!=keys_to_remove.end();++it) + { + if(locked_getSecretKey(*it) != NULL) + { + RsErr() << "(EE) OpenPGPSDKHandler:: can't remove key " << (*it).toStdString() << " since its shared by a secret key!" ; + continue ; + } + + std::map::iterator res = _public_keyring_map.find(*it) ; + + if(res == _public_keyring_map.end()) + { + RsErr() << "(EE) OpenPGPSDKHandler:: can't remove key " << (*it).toStdString() << " from keyring: key not found." ; + continue ; + } + + if(res->second._key_index >= (unsigned int)_pubring->nkeys || RsPgpId(_pubring->keys[res->second._key_index].key_id) != *it) + { + RsErr() << "(EE) OpenPGPSDKHandler:: can't remove key " << (*it).toStdString() << ". Inconsistency found." ; + error_code = PGP_KEYRING_REMOVAL_ERROR_DATA_INCONSISTENCY ; + return false ; + } + + // Move the last key to the freed place. This deletes the key in place. + // + ops_keyring_remove_key(_pubring,res->second._key_index) ; + + // Erase the info from the keyring map. + // + _public_keyring_map.erase(res) ; + + // now update all indices back. This internal look is very costly, but it avoids deleting the wrong keys, since the keyring structure is + // changed by ops_keyring_remove_key and therefore indices don't point to the correct location anymore. + + int i=0 ; + const ops_keydata_t *keydata ; + while( (keydata = ops_keyring_get_key_by_index(_pubring,i)) != NULL ) + { + PGPCertificateInfo& cert(_public_keyring_map[ RsPgpId(keydata->key_id) ]) ; + cert._key_index = i ; + ++i ; + } + } + + // Everything went well, sync back the keyring on disk + + _pubring_changed = true ; + _trustdb_changed = true ; + + locked_syncPublicKeyring() ; + locked_syncTrustDatabase() ; + + return true ; +} diff --git a/libretroshare/src/pgp/openpgpsdkhandler.h b/libretroshare/src/pgp/openpgpsdkhandler.h new file mode 100644 index 000000000..8aff1459b --- /dev/null +++ b/libretroshare/src/pgp/openpgpsdkhandler.h @@ -0,0 +1,116 @@ +/******************************************************************************* + * libretroshare/src/pgp: pgphandler.h * + * * + * libretroshare: retroshare core library * + * * + * Copyright 2018 Cyril Soler * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ +#pragma once + +#include +#include +#include +#include +#include + +#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& key_ids,std::string& backup_file,uint32_t& error_code) override; + virtual bool availableGPGCertificatesWithPrivateKeys(std::list& 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& 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& kmap, const std::string& keyring_file) ; + bool locked_addOrMergeKey(ops_keyring_t *keyring,std::map& 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 +}; diff --git a/libretroshare/src/pgp/pgpauxutils.cc b/libretroshare/src/pgp/pgpauxutils.cc index d7229e848..c87985fab 100644 --- a/libretroshare/src/pgp/pgpauxutils.cc +++ b/libretroshare/src/pgp/pgpauxutils.cc @@ -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 &ids) +bool PgpAuxUtilsImpl::getPgpAllList(std::list &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); } diff --git a/libretroshare/src/pgp/pgpauxutils.h b/libretroshare/src/pgp/pgpauxutils.h index 4b188e3ae..aa897c0e1 100644 --- a/libretroshare/src/pgp/pgpauxutils.h +++ b/libretroshare/src/pgp/pgpauxutils.h @@ -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 &ids) = 0; + virtual RsPgpId getPgpId(const RsPeerId& sslid) = 0; + virtual bool getPgpAllList(std::list &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 &ids); + virtual bool getPgpAllList(std::list &ids); }; diff --git a/libretroshare/src/pgp/pgphandler.cc b/libretroshare/src/pgp/pgphandler.cc index b1e96b00b..850338868 100644 --- a/libretroshare/src/pgp/pgphandler.cc +++ b/libretroshare/src/pgp/pgphandler.cc @@ -33,15 +33,6 @@ #include "util/rswin.h" #endif -extern "C" { -#include -#include -#include -#include -#include -#include -#include -} #include "pgphandler.h" #include "retroshare/rsiface.h" // For rsicontrol. #include "retroshare/rspeers.h" // For rsicontrol. @@ -59,56 +50,6 @@ static const uint32_t PGP_CERTIFICATE_LIMIT_MAX_PASSWD_SIZE = 1024 ; PassphraseCallback PGPHandler::_passphrase_callback = NULL ; -ops_keyring_t *PGPHandler::allocateOPSKeyring() -{ - ops_keyring_t *kr = (ops_keyring_t*)rs_malloc(sizeof(ops_keyring_t)) ; - - if(kr == NULL) - return NULL ; - - kr->nkeys = 0 ; - kr->nkeys_allocated = 0 ; - kr->keys = 0 ; - - return kr ; -} - -ops_parse_cb_return_t cb_get_passphrase(const ops_parser_content_t *content_,ops_parse_cb_info_t *cbinfo)// __attribute__((unused))) -{ - const ops_parser_content_union_t *content=&content_->content; - bool prev_was_bad = false ; - - switch(content_->tag) - { - case OPS_PARSER_CMD_GET_SK_PASSPHRASE_PREV_WAS_BAD: prev_was_bad = true ; - /* fallthrough */ - case OPS_PARSER_CMD_GET_SK_PASSPHRASE: - { - std::string passwd; - std::string uid_hint ; - - if(cbinfo->cryptinfo.keydata->nuids > 0) - uid_hint = std::string((const char *)cbinfo->cryptinfo.keydata->uids[0].user_id) ; - uid_hint += "(" + RsPgpId(cbinfo->cryptinfo.keydata->key_id).toStdString()+")" ; - - bool cancelled = false ; - passwd = PGPHandler::passphraseCallback()(NULL,"",uid_hint.c_str(),NULL,prev_was_bad,&cancelled) ; - - if(cancelled) - *(unsigned char *)cbinfo->arg = 1; - - *(content->secret_key_passphrase.passphrase)= (char *)ops_mallocz(passwd.length()+1) ; - memcpy(*(content->secret_key_passphrase.passphrase),passwd.c_str(),passwd.length()) ; - return OPS_KEEP_MEMORY; - } - break; - - default: - break; - } - - return OPS_RELEASE_MEMORY; -} void PGPHandler::setPassphraseCallback(PassphraseCallback cb) { _passphrase_callback = cb ; @@ -117,242 +58,47 @@ void PGPHandler::setPassphraseCallback(PassphraseCallback cb) PGPHandler::PGPHandler(const std::string& pubring, const std::string& secring,const std::string& trustdb,const std::string& pgp_lock_filename) : pgphandlerMtx(std::string("PGPHandler")), _pubring_path(pubring),_secring_path(secring),_trustdb_path(trustdb),_pgp_lock_filename(pgp_lock_filename) { - RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. - - _pubring_changed = false ; - _trustdb_changed = false ; - - RsStackFileLock flck(_pgp_lock_filename) ; // lock access to PGP directory. - - if(_passphrase_callback == NULL) - std::cerr << "WARNING: before created a PGPHandler, you need to init the passphrase callback using PGPHandler::setPassphraseCallback()" << std::endl; - - // Allocate public and secret keyrings. - // - _pubring = allocateOPSKeyring() ; - _secring = allocateOPSKeyring() ; - - // Check that the file exists. If not, create a void keyring. - - FILE *ftest ; - ftest = RsDirUtil::rs_fopen(pubring.c_str(),"rb") ; - bool pubring_exist = (ftest != NULL) ; - if(ftest != NULL) - fclose(ftest) ; - ftest = RsDirUtil::rs_fopen(secring.c_str(),"rb") ; - bool secring_exist = (ftest != NULL) ; - if(ftest != NULL) - fclose(ftest) ; - - // Read public and secret keyrings from supplied files. - // - if(pubring_exist) - { - if(ops_false == ops_keyring_read_from_file(_pubring, false, pubring.c_str())) - throw std::runtime_error("PGPHandler::readKeyRing(): cannot read pubring. File corrupted.") ; - } - else - std::cerr << "pubring file \"" << pubring << "\" not found. Creating a void keyring." << std::endl; - - const ops_keydata_t *keydata ; - int i=0 ; - while( (keydata = ops_keyring_get_key_by_index(_pubring,i)) != NULL ) - { - PGPCertificateInfo& cert(_public_keyring_map[ RsPgpId(keydata->key_id) ]) ; - - // Init all certificates. - - initCertificateInfo(cert,keydata,i) ; - - // Validate signatures. - - validateAndUpdateSignatures(cert,keydata) ; - - ++i ; - } - _pubring_last_update_time = time(NULL) ; - std::cerr << "Pubring read successfully." << std::endl; - - if(secring_exist) - { - if(ops_false == ops_keyring_read_from_file(_secring, false, secring.c_str())) - throw std::runtime_error("PGPHandler::readKeyRing(): cannot read secring. File corrupted.") ; - } - else - std::cerr << "secring file \"" << secring << "\" not found. Creating a void keyring." << std::endl; - - i=0 ; - while( (keydata = ops_keyring_get_key_by_index(_secring,i)) != NULL ) - { - initCertificateInfo(_secret_keyring_map[ RsPgpId(keydata->key_id) ],keydata,i) ; - ++i ; - } - _secring_last_update_time = time(NULL) ; - - std::cerr << "Secring read successfully." << std::endl; - - locked_readPrivateTrustDatabase() ; - _trustdb_last_update_time = time(NULL) ; -} - -void PGPHandler::initCertificateInfo(PGPCertificateInfo& cert,const ops_keydata_t *keydata,uint32_t index) -{ - // Parse certificate name - // - - if(keydata->uids != NULL) - { - std::string namestring( (char *)keydata->uids[0].user_id ) ; - - cert._name = "" ; - uint32_t i=0; - while(i < namestring.length() && namestring[i] != '(' && namestring[i] != '<') { cert._name += namestring[i] ; ++i ;} - - // trim right spaces - std::string::size_type found = cert._name.find_last_not_of(' '); - if (found != std::string::npos) - cert._name.erase(found + 1); - else - cert._name.clear(); // all whitespace - - std::string& next = (namestring[i] == '(')?cert._comment:cert._email ; - ++i ; - next = "" ; - while(i < namestring.length() && namestring[i] != ')' && namestring[i] != '>') { next += namestring[i] ; ++i ;} - - while(i < namestring.length() && namestring[i] != '(' && namestring[i] != '<') { next += namestring[i] ; ++i ;} - - if(i< namestring.length()) - { - std::string& next2 = (namestring[i] == '(')?cert._comment:cert._email ; - ++i ; - next2 = "" ; - while(i < namestring.length() && namestring[i] != ')' && namestring[i] != '>') { next2 += namestring[i] ; ++i ;} - } - } - - cert._trustLvl = 1 ; // to be setup accordingly - cert._validLvl = 1 ; // to be setup accordingly - cert._key_index = index ; - cert._flags = 0 ; - cert._time_stamp = 0 ;// "never" by default. Will be updated by trust database, and effective key usage. - - switch(keydata->key.pkey.algorithm) - { - case OPS_PKA_RSA: cert._type = PGPCertificateInfo::PGP_CERTIFICATE_TYPE_RSA ; - break ; - case OPS_PKA_DSA: cert._type = PGPCertificateInfo::PGP_CERTIFICATE_TYPE_DSA ; - cert._flags |= PGPCertificateInfo::PGP_CERTIFICATE_FLAG_UNSUPPORTED_ALGORITHM ; - break ; - default: cert._type = PGPCertificateInfo::PGP_CERTIFICATE_TYPE_UNKNOWN ; - cert._flags |= PGPCertificateInfo::PGP_CERTIFICATE_FLAG_UNSUPPORTED_ALGORITHM ; - break ; - } - - ops_fingerprint_t f ; - ops_fingerprint(&f,&keydata->key.pkey) ; - - cert._fpr = PGPFingerprintType(f.fingerprint) ; -} - -bool PGPHandler::validateAndUpdateSignatures(PGPCertificateInfo& cert,const ops_keydata_t *keydata) -{ - ops_validate_result_t* result=(ops_validate_result_t*)ops_mallocz(sizeof *result); - ops_boolean_t res = ops_validate_key_signatures(result,keydata,_pubring,cb_get_passphrase) ; - - if(res == ops_false) - { - static ops_boolean_t already = 0 ; - if(!already) - { - std::cerr << "(WW) Error in PGPHandler::validateAndUpdateSignatures(). Validation failed for at least some signatures." << std::endl; - already = 1 ; - } - } - - bool ret = false ; - - // Parse signers. - // - - if(result != NULL) - for(size_t i=0;ivalid_count;++i) - { - RsPgpId signer_id(result->valid_sigs[i].signer_id); - - if(cert.signers.find(signer_id) == cert.signers.end()) - { - cert.signers.insert(signer_id) ; - ret = true ; - } - } - - ops_validate_result_free(result) ; - - return ret ; } PGPHandler::~PGPHandler() { - RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. -#ifdef DEBUG_PGPHANDLER - std::cerr << "Freeing PGPHandler. Deleting keyrings." << std::endl; -#endif - - // no need to free the the _map_ elements. They will be freed by the following calls: - // - ops_keyring_free(_pubring) ; - ops_keyring_free(_secring) ; - - free(_pubring) ; - free(_secring) ; } bool PGPHandler::printKeys() const { #ifdef DEBUG_PGPHANDLER - std::cerr << "Printing details of all " << std::dec << _public_keyring_map.size() << " keys: " << std::endl; + RsErr() << "Printing details of all " << std::dec << _public_keyring_map.size() << " keys: " ; #endif for(std::map::const_iterator it(_public_keyring_map.begin()); it != _public_keyring_map.end(); ++it) { - std::cerr << "PGP Key: " << it->first.toStdString() << std::endl; + RsErr() << "PGP Key: " << it->first.toStdString() ; - std::cerr << "\tName : " << it->second._name << std::endl; - std::cerr << "\tEmail : " << it->second._email << std::endl; - std::cerr << "\tOwnSign : " << (it->second._flags & PGPCertificateInfo::PGP_CERTIFICATE_FLAG_HAS_OWN_SIGNATURE) << std::endl; - std::cerr << "\tAccept Connect: " << (it->second._flags & PGPCertificateInfo::PGP_CERTIFICATE_FLAG_ACCEPT_CONNEXION) << std::endl; - std::cerr << "\ttrustLvl : " << it->second._trustLvl << std::endl; - std::cerr << "\tvalidLvl : " << it->second._validLvl << std::endl; - std::cerr << "\tUse time stamp: " << it->second._time_stamp << std::endl; - std::cerr << "\tfingerprint : " << it->second._fpr.toStdString() << std::endl; - std::cerr << "\tSigners : " << it->second.signers.size() << std::endl; + RsErr() << "\tName : " << it->second._name ; + RsErr() << "\tEmail : " << it->second._email ; + RsErr() << "\tOwnSign : " << (it->second._flags & PGPCertificateInfo::PGP_CERTIFICATE_FLAG_HAS_OWN_SIGNATURE) ; + RsErr() << "\tAccept Connect: " << (it->second._flags & PGPCertificateInfo::PGP_CERTIFICATE_FLAG_ACCEPT_CONNEXION) ; + RsErr() << "\ttrustLvl : " << it->second._trustLvl ; + RsErr() << "\tvalidLvl : " << it->second._validLvl ; + RsErr() << "\tUse time stamp: " << it->second._time_stamp ; + RsErr() << "\tfingerprint : " << it->second._fpr.toStdString() ; + RsErr() << "\tSigners : " << it->second.signers.size() ; std::set::const_iterator sit; for(sit = it->second.signers.begin(); sit != it->second.signers.end(); ++sit) { - std::cerr << "\t\tSigner ID:" << (*sit).toStdString() << ", Name: " ; + RsErr() << "\t\tSigner ID:" << (*sit).toStdString() << ", Name: " ; const PGPCertificateInfo *info = PGPHandler::getCertificateInfo(*sit) ; if(info != NULL) - std::cerr << info->_name ; + RsErr() << info->_name ; - std::cerr << std::endl ; + RsErr() << std::endl ; } } - std::cerr << "Public keyring list from OPS:" << std::endl; - ops_keyring_list(_pubring) ; - return true ; } -bool PGPHandler::haveSecretKey(const RsPgpId& id) const -{ - RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. - - return locked_getSecretKey(id) != NULL ; -} - const PGPCertificateInfo *PGPHandler::getCertificateInfo(const RsPgpId& id) const { RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. @@ -365,1193 +111,13 @@ const PGPCertificateInfo *PGPHandler::getCertificateInfo(const RsPgpId& id) cons return NULL ; } -bool PGPHandler::availableGPGCertificatesWithPrivateKeys(std::list& ids) -{ - RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. - // go through secret keyring, and check that we have the pubkey as well. - // - - const ops_keydata_t *keydata = NULL ; - int i=0 ; - - while( (keydata = ops_keyring_get_key_by_index(_secring,i++)) != NULL ) - if(ops_keyring_find_key_by_id(_pubring,keydata->key_id) != NULL) // check that the key is in the pubring as well - { -#ifdef PGPHANDLER_DSA_SUPPORT - if(keydata->key.pkey.algorithm == OPS_PKA_RSA || keydata->key.pkey.algorithm == OPS_PKA_DSA) -#else - if(keydata->key.pkey.algorithm == OPS_PKA_RSA) -#endif - ids.push_back(RsPgpId(keydata->key_id)) ; -#ifdef DEBUG_PGPHANDLER - else - std::cerr << "Skipping keypair " << RsPgpId(keydata->key_id).toStdString() << ", unsupported algorithm: " << keydata->key.pkey.algorithm << std::endl; -#endif - } - - return true ; -} - -bool PGPHandler::GeneratePGPCertificate(const std::string& name, const std::string& email, const std::string& passphrase, RsPgpId& pgpId, const int keynumbits, std::string& errString) -{ - // Some basic checks - - if(!RsDiscSpace::checkForDiscSpace(RS_PGP_DIRECTORY)) - { - errString = std::string("(EE) low disc space in pgp directory. Can't write safely to keyring.") ; - return false ; - } - if(name.length() > PGP_CERTIFICATE_LIMIT_MAX_NAME_SIZE) - { - errString = std::string("(EE) name in certificate exceeds the maximum allowed name size") ; - return false ; - } - if(email.length() > PGP_CERTIFICATE_LIMIT_MAX_EMAIL_SIZE) - { - errString = std::string("(EE) email in certificate exceeds the maximum allowed email size") ; - return false ; - } - if(passphrase.length() > PGP_CERTIFICATE_LIMIT_MAX_PASSWD_SIZE) - { - errString = std::string("(EE) passphrase in certificate exceeds the maximum allowed passphrase size") ; - return false ; - } - if(keynumbits % 1024 != 0) - { - errString = std::string("(EE) RSA key length is not a multiple of 1024") ; - return false ; - } - - // Now the real thing - RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. - RsStackFileLock flck(_pgp_lock_filename) ; // lock access to PGP directory. - - // 1 - generate keypair - RSA-2048 - // - ops_user_id_t uid ; - char *s = strdup((name + " (Generated by RetroShare) <" + email + ">" ).c_str()) ; - uid.user_id = (unsigned char *)s ; - unsigned long int e = 65537 ; // some prime number - - ops_keydata_t *key = ops_rsa_create_selfsigned_keypair(keynumbits, e, &uid) ; - - free(s) ; - - if(!key) - return false ; - - // 2 - save the private key encrypted to a temporary memory buffer, so as to read an encrypted key to memory - - ops_create_info_t *cinfo = NULL ; - ops_memory_t *buf = NULL ; - ops_setup_memory_write(&cinfo, &buf, 0); - - if(!ops_write_transferable_secret_key(key,(unsigned char *)passphrase.c_str(),passphrase.length(),ops_false,cinfo)) - { - errString = std::string("(EE) Cannot encode secret key to memory!!") ; - return false ; - } - - // 3 - read the memory chunk into an encrypted keyring - - ops_keyring_t *tmp_secring = allocateOPSKeyring() ; - - if(! ops_keyring_read_from_mem(tmp_secring, ops_false, buf)) - { - errString = std::string("(EE) Cannot re-read key from memory!!") ; - return false ; - } - ops_teardown_memory_write(cinfo,buf); // cleanup memory - - // 4 - copy the encrypted private key to the private keyring - - pgpId = RsPgpId(tmp_secring->keys[0].key_id) ; - addNewKeyToOPSKeyring(_secring,tmp_secring->keys[0]) ; - initCertificateInfo(_secret_keyring_map[ pgpId ],&tmp_secring->keys[0],_secring->nkeys-1) ; - -#ifdef DEBUG_PGPHANDLER - std::cerr << "Added new secret key with id " << pgpId.toStdString() << " to secret keyring." << std::endl; -#endif - ops_keyring_free(tmp_secring) ; - free(tmp_secring) ; - - // 5 - add key to secret keyring on disk. - - cinfo = NULL ; - std::string secring_path_tmp = _secring_path + ".tmp" ; - - if(RsDirUtil::fileExists(_secring_path) && !RsDirUtil::copyFile(_secring_path,secring_path_tmp)) - { - errString= std::string("Cannot copy secret keyring !! Disk full? Out of disk quota?") ; - return false ; - } - int fd=ops_setup_file_append(&cinfo, secring_path_tmp.c_str()); - - if(!ops_write_transferable_secret_key(key,(unsigned char *)passphrase.c_str(),passphrase.length(),ops_false,cinfo)) - { - errString= std::string("Cannot encode secret key to disk!! Disk full? Out of disk quota?") ; - return false ; - } - ops_teardown_file_write(cinfo,fd) ; - - if(!RsDirUtil::renameFile(secring_path_tmp,_secring_path)) - { - errString= std::string("Cannot rename tmp secret key file ") + secring_path_tmp + " into " + _secring_path +". Disk error?" ; - return false ; - } - - // 6 - copy the public key to the public keyring on disk - - cinfo = NULL ; - std::string pubring_path_tmp = _pubring_path + ".tmp" ; - - if(RsDirUtil::fileExists(_pubring_path) && !RsDirUtil::copyFile(_pubring_path,pubring_path_tmp)) - { - errString= std::string("Cannot encode secret key to disk!! Disk full? Out of disk quota?") ; - return false ; - } - fd=ops_setup_file_append(&cinfo, pubring_path_tmp.c_str()); - - if(!ops_write_transferable_public_key(key, ops_false, cinfo)) - { - errString=std::string("Cannot encode secret key to memory!!") ; - return false ; - } - ops_teardown_file_write(cinfo,fd) ; - - if(!RsDirUtil::renameFile(pubring_path_tmp,_pubring_path)) - { - errString= std::string("Cannot rename tmp public key file ") + pubring_path_tmp + " into " + _pubring_path +". Disk error?" ; - return false ; - } - // 7 - clean - ops_keydata_free(key) ; - - // 8 - re-read the key from the public keyring, and add it to memory. - - _pubring_last_update_time = 0 ; // force update pubring from disk. - locked_syncPublicKeyring() ; - -#ifdef DEBUG_PGPHANDLER - std::cerr << "Added new public key with id " << pgpId.toStdString() << " to public keyring." << std::endl; -#endif - - // 9 - Update some flags. - - privateTrustCertificate(pgpId,PGPCertificateInfo::PGP_CERTIFICATE_TRUST_ULTIMATE) ; - - return true ; -} - -std::string PGPHandler::makeRadixEncodedPGPKey(const ops_keydata_t *key,bool include_signatures) -{ - ops_create_info_t* cinfo; - ops_memory_t *buf = NULL ; - ops_setup_memory_write(&cinfo, &buf, 0); - ops_boolean_t armoured = ops_true ; - - if(key->type == OPS_PTAG_CT_PUBLIC_KEY) - { - if(ops_write_transferable_public_key_from_packet_data(key,armoured,cinfo) != ops_true) - return "ERROR: This key cannot be processed by RetroShare because\nDSA certificates are not yet handled." ; - } - else if(key->type == OPS_PTAG_CT_ENCRYPTED_SECRET_KEY) - { - if(ops_write_transferable_secret_key_from_packet_data(key,armoured,cinfo) != ops_true) - return "ERROR: This key cannot be processed by RetroShare because\nDSA certificates are not yet handled." ; - } - else - { - ops_create_info_delete(cinfo); - std::cerr << "Unhandled key type " << key->type << std::endl; - return "ERROR: Cannot write key. Unhandled key type. " ; - } - - ops_writer_close(cinfo) ; - - std::string res((char *)ops_memory_get_data(buf),ops_memory_get_length(buf)) ; - ops_teardown_memory_write(cinfo,buf); - - if(!include_signatures) - { - std::string tmp ; - if(PGPKeyManagement::createMinimalKey(res,tmp) ) - res = tmp ; - } - - return res ; -} - -const ops_keydata_t *PGPHandler::locked_getSecretKey(const RsPgpId& id) const -{ - std::map::const_iterator res = _secret_keyring_map.find(id) ; - - if(res == _secret_keyring_map.end()) - return NULL ; - else - return ops_keyring_get_key_by_index(_secring,res->second._key_index) ; -} -const ops_keydata_t *PGPHandler::locked_getPublicKey(const RsPgpId& id,bool stamp_the_key) const -{ - std::map::const_iterator res = _public_keyring_map.find(id) ; - - if(res == _public_keyring_map.end()) - return NULL ; - else - { - if(stamp_the_key) // Should we stamp the key as used? - { - static rstime_t last_update_db_because_of_stamp = 0 ; - rstime_t now = time(NULL) ; - - res->second._time_stamp = now ; - - if(now > last_update_db_because_of_stamp + 3600) // only update database once every hour. No need to do it more often. - { - _trustdb_changed = true ; - last_update_db_because_of_stamp = now ; - } - } - return ops_keyring_get_key_by_index(_pubring,res->second._key_index) ; - } -} - -std::string PGPHandler::SaveCertificateToString(const RsPgpId& id,bool include_signatures) const -{ - RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. - const ops_keydata_t *key = locked_getPublicKey(id,false) ; - - if(key == NULL) - { - std::cerr << "Cannot output key " << id.toStdString() << ": not found in keyring." << std::endl; - return "" ; - } - - return makeRadixEncodedPGPKey(key,include_signatures) ; -} - -bool PGPHandler::exportPublicKey( - const RsPgpId& id, - unsigned char*& mem_block, size_t& mem_size, - bool armoured, bool include_signatures ) const -{ - mem_block = nullptr; mem_size = 0; // clear just in case - - if(armoured) - { - RsErr() << __PRETTY_FUNCTION__ << " should not be used with " - << "armoured=true, because there's a bug in the armoured export" - << " of OPS" << std::endl; - print_stacktrace(); - return false; - } - - RS_STACK_MUTEX(pgphandlerMtx); - const ops_keydata_t* key = locked_getPublicKey(id,false); - - if(!key) - { - RsErr() << __PRETTY_FUNCTION__ << " key id: " << id - << " not found in keyring." << std::endl; - return false; - } - - ops_create_info_t* cinfo; - ops_memory_t *buf = nullptr; - ops_setup_memory_write(&cinfo, &buf, 0); - - if(ops_write_transferable_public_key_from_packet_data( - key, armoured, cinfo ) != ops_true) - { - RsErr() << __PRETTY_FUNCTION__ << " This key id " << id - << " cannot be processed by RetroShare because DSA certificates" - << " support is not implemented yet." << std::endl; - return false; - } - - ops_writer_close(cinfo); - - mem_size = ops_memory_get_length(buf); - mem_block = reinterpret_cast(malloc(mem_size)); - memcpy(mem_block,ops_memory_get_data(buf),mem_size); - - ops_teardown_memory_write(cinfo,buf); - - if(!include_signatures) - { - size_t new_size; - PGPKeyManagement::findLengthOfMinimalKey(mem_block, mem_size, new_size); - mem_size = new_size; - } - - return true; -} - -bool PGPHandler::exportGPGKeyPair(const std::string& filename,const RsPgpId& exported_key_id) const -{ - RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. - - const ops_keydata_t *pubkey = locked_getPublicKey(exported_key_id,false) ; - - if(pubkey == NULL) - { - std::cerr << "Cannot output key " << exported_key_id.toStdString() << ": not found in public keyring." << std::endl; - return false ; - } - const ops_keydata_t *seckey = locked_getSecretKey(exported_key_id) ; - - if(seckey == NULL) - { - std::cerr << "Cannot output key " << exported_key_id.toStdString() << ": not found in secret keyring." << std::endl; - return false ; - } - - FILE *f = RsDirUtil::rs_fopen(filename.c_str(),"w") ; - if(f == NULL) - { - std::cerr << "Cannot output key " << exported_key_id.toStdString() << ": file " << filename << " cannot be written. Please check for permissions, quotas, disk space." << std::endl; - return false ; - } - - fprintf(f,"%s\n", makeRadixEncodedPGPKey(pubkey,true).c_str()) ; - fprintf(f,"%s\n", makeRadixEncodedPGPKey(seckey,true).c_str()) ; - - fclose(f) ; - return true ; -} - -bool PGPHandler::exportGPGKeyPairToString( - std::string& data, const RsPgpId& exportedKeyId, - bool includeSignatures, std::string& errorMsg ) const -{ - RS_STACK_MUTEX(pgphandlerMtx); - - const ops_keydata_t *pubkey = locked_getPublicKey(exportedKeyId,false); - - if(!pubkey) - { - errorMsg = "Cannot output key " + exportedKeyId.toStdString() + - ": not found in public keyring."; - return false; - } - const ops_keydata_t *seckey = locked_getSecretKey(exportedKeyId); - - if(!seckey) - { - errorMsg = "Cannot output key " + exportedKeyId.toStdString() + - ": not found in secret keyring."; - return false; - } - - data = makeRadixEncodedPGPKey(pubkey, includeSignatures); - data += "\n"; - data += makeRadixEncodedPGPKey(seckey, includeSignatures); - data += "\n"; - return true; -} - -bool PGPHandler::getGPGDetailsFromBinaryBlock(const unsigned char *mem_block,size_t mem_size,RsPgpId& key_id, std::string& name, std::list& signers) const -{ - ops_keyring_t *tmp_keyring = allocateOPSKeyring(); - ops_memory_t *mem = ops_memory_new() ; - ops_memory_add(mem,mem_block,mem_size); - - if(!ops_keyring_read_from_mem(tmp_keyring,ops_false,mem)) - { - ops_keyring_free(tmp_keyring) ; - free(tmp_keyring) ; - ops_memory_release(mem) ; - free(mem) ; - - std::cerr << "Could not read key. Format error?" << std::endl; - //error_string = std::string("Could not read key. Format error?") ; - return false ; - } - ops_memory_release(mem) ; - free(mem) ; - //error_string.clear() ; - - if(tmp_keyring->nkeys != 1) - { - std::cerr << "No or incomplete/invalid key in supplied pgp block." << std::endl; - return false ; - } - if(tmp_keyring->keys[0].uids == NULL) - { - std::cerr << "No uid in supplied key." << std::endl; - return false ; - } - - key_id = RsPgpId(tmp_keyring->keys[0].key_id) ; - name = std::string((char *)tmp_keyring->keys[0].uids[0].user_id) ; - - // now parse signatures. - // - ops_validate_result_t* result=(ops_validate_result_t*)ops_mallocz(sizeof *result); - ops_boolean_t res ; - - { - RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. - res = ops_validate_key_signatures(result,&tmp_keyring->keys[0],_pubring,cb_get_passphrase) ; - } - - if(res == ops_false) - std::cerr << "(WW) Error in PGPHandler::validateAndUpdateSignatures(). Validation failed for at least some signatures." << std::endl; - - // also add self-signature if any (there should be!). - // - res = ops_validate_key_signatures(result,&tmp_keyring->keys[0],tmp_keyring,cb_get_passphrase) ; - - if(res == ops_false) - std::cerr << "(WW) Error in PGPHandler::validateAndUpdateSignatures(). Validation failed for at least some signatures." << std::endl; - - // Parse signers. - // - - std::set signers_set ; // Use a set to remove duplicates. - - if(result != NULL) - for(size_t i=0;ivalid_count;++i) - signers_set.insert(RsPgpId(result->valid_sigs[i].signer_id)) ; - - ops_validate_result_free(result) ; - - ops_keyring_free(tmp_keyring) ; - free(tmp_keyring) ; - - // write to the output variable - - signers.clear() ; - - for(std::set::const_iterator it(signers_set.begin());it!=signers_set.end();++it) - signers.push_back(*it) ; - - return true ; -} - -bool PGPHandler::importGPGKeyPair(const std::string& filename,RsPgpId& imported_key_id,std::string& import_error) -{ - import_error = "" ; - - // 1 - Test for file existance - // - FILE *ftest = RsDirUtil::rs_fopen(filename.c_str(),"r") ; - - if(ftest == NULL) - { - import_error = "Cannot open file " + filename + " for read. Please check access permissions." ; - return false ; - } - - fclose(ftest) ; - - // 2 - Read keyring from supplied file. - // - ops_keyring_t *tmp_keyring = allocateOPSKeyring(); - - if(ops_false == ops_keyring_read_from_file(tmp_keyring, ops_true, filename.c_str())) - { - import_error = "PGPHandler::readKeyRing(): cannot read key file. File corrupted?" ; - free(tmp_keyring); - return false ; - } - - return checkAndImportKeyPair(tmp_keyring, imported_key_id, import_error); -} - -bool PGPHandler::importGPGKeyPairFromString(const std::string &data, RsPgpId &imported_key_id, std::string &import_error) -{ - import_error = "" ; - - ops_memory_t* mem = ops_memory_new(); - ops_memory_add(mem, (unsigned char*)data.data(), data.length()); - - ops_keyring_t *tmp_keyring = allocateOPSKeyring(); - - if(ops_false == ops_keyring_read_from_mem(tmp_keyring, ops_true, mem)) - { - import_error = "PGPHandler::importGPGKeyPairFromString(): cannot parse key data" ; - free(tmp_keyring); - return false ; - } - return checkAndImportKeyPair(tmp_keyring, imported_key_id, import_error); -} - -bool PGPHandler::checkAndImportKeyPair(ops_keyring_t *tmp_keyring, RsPgpId &imported_key_id, std::string &import_error) -{ - if(tmp_keyring == 0) - { - import_error = "PGPHandler::checkAndImportKey(): keyring is null" ; - return false; - } - - if(tmp_keyring->nkeys != 2) - { - import_error = "PGPHandler::importKeyPair(): file does not contain a valid keypair." ; - if(tmp_keyring->nkeys > 2) - import_error += "\nMake sure that your key is a RSA key (DSA is not yet supported) and does not contain subkeys (not supported yet)."; - return false ; - } - - // 3 - Test that keyring contains a valid keypair. - // - const ops_keydata_t *pubkey = NULL ; - const ops_keydata_t *seckey = NULL ; - - if(tmp_keyring->keys[0].type == OPS_PTAG_CT_PUBLIC_KEY) - pubkey = &tmp_keyring->keys[0] ; - else if(tmp_keyring->keys[0].type == OPS_PTAG_CT_ENCRYPTED_SECRET_KEY) - seckey = &tmp_keyring->keys[0] ; - else - { - import_error = "Unrecognised key type in key file for key #0. Giving up." ; - std::cerr << "Unrecognised key type " << tmp_keyring->keys[0].type << " in key file for key #0. Giving up." << std::endl; - return false ; - } - if(tmp_keyring->keys[1].type == OPS_PTAG_CT_PUBLIC_KEY) - pubkey = &tmp_keyring->keys[1] ; - else if(tmp_keyring->keys[1].type == OPS_PTAG_CT_ENCRYPTED_SECRET_KEY) - seckey = &tmp_keyring->keys[1] ; - else - { - import_error = "Unrecognised key type in key file for key #1. Giving up." ; - std::cerr << "Unrecognised key type " << tmp_keyring->keys[1].type << " in key file for key #1. Giving up." << std::endl; - return false ; - } - - if(pubkey == nullptr || seckey == nullptr || pubkey == seckey) - { - import_error = "File does not contain a public and a private key. Sorry." ; - return false ; - } - if(memcmp( pubkey->fingerprint.fingerprint, - seckey->fingerprint.fingerprint, - RsPgpFingerprint::SIZE_IN_BYTES ) != 0) - { - import_error = "Public and private keys do nt have the same fingerprint. Sorry!" ; - return false ; - } - if(pubkey->key.pkey.version != 4) - { - import_error = "Public key is not version 4. Rejected!" ; - return false ; - } - - // 4 - now check self-signature for this keypair. For this we build a dummy keyring containing only the key. - // - ops_validate_result_t *result=(ops_validate_result_t*)ops_mallocz(sizeof *result); - - ops_keyring_t dummy_keyring ; - dummy_keyring.nkeys=1 ; - dummy_keyring.nkeys_allocated=1 ; - dummy_keyring.keys=const_cast(pubkey) ; - - ops_validate_key_signatures(result, const_cast(pubkey), &dummy_keyring, cb_get_passphrase) ; - - // Check that signatures contain at least one certification from the user id. - // - bool found = false ; - - for(uint32_t i=0;ivalid_count;++i) - if(!memcmp( - static_cast(result->valid_sigs[i].signer_id), - pubkey->key_id, - RsPgpId::SIZE_IN_BYTES )) - { - found = true ; - break ; - } - - if(!found) - { - import_error = "Cannot validate self signature for the imported key. Sorry." ; - return false ; - } - ops_validate_result_free(result); - - if(!RsDiscSpace::checkForDiscSpace(RS_PGP_DIRECTORY)) - { - import_error = std::string("(EE) low disc space in pgp directory. Can't write safely to keyring.") ; - return false ; - } - // 5 - All test passed. Adding key to keyring. - // - { - RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. - - imported_key_id = RsPgpId(pubkey->key_id) ; - - if(locked_getSecretKey(imported_key_id) == NULL) - { - RsStackFileLock flck(_pgp_lock_filename) ; // lock access to PGP directory. - - ops_create_info_t *cinfo = NULL ; - - // Make a copy of the secret keyring - // - std::string secring_path_tmp = _secring_path + ".tmp" ; - if(RsDirUtil::fileExists(_secring_path) && !RsDirUtil::copyFile(_secring_path,secring_path_tmp)) - { - import_error = "(EE) Cannot write secret key to disk!! Disk full? Out of disk quota. Keyring will be left untouched." ; - return false ; - } - - // Append the new key - - int fd=ops_setup_file_append(&cinfo, secring_path_tmp.c_str()); - - if(!ops_write_transferable_secret_key_from_packet_data(seckey,ops_false,cinfo)) - { - import_error = "(EE) Cannot encode secret key to disk!! Disk full? Out of disk quota?" ; - return false ; - } - ops_teardown_file_write(cinfo,fd) ; - - // Rename the new keyring to overwrite the old one. - // - if(!RsDirUtil::renameFile(secring_path_tmp,_secring_path)) - { - import_error = " (EE) Cannot move temp file " + secring_path_tmp + ". Bad write permissions?" ; - return false ; - } - - addNewKeyToOPSKeyring(_secring,*seckey) ; - initCertificateInfo(_secret_keyring_map[ imported_key_id ],seckey,_secring->nkeys-1) ; - } - else - import_error = "Private key already exists! Not importing it again." ; - - if(locked_addOrMergeKey(_pubring,_public_keyring_map,pubkey)) - _pubring_changed = true ; - } - - // 6 - clean - // - ops_keyring_free(tmp_keyring) ; - free(tmp_keyring); - - // write public key to disk - syncDatabase(); - - return true ; -} - -void PGPHandler::addNewKeyToOPSKeyring(ops_keyring_t *kr,const ops_keydata_t& key) -{ - if(kr->nkeys >= kr->nkeys_allocated) - { - kr->keys = (ops_keydata_t *)realloc(kr->keys,(kr->nkeys+1)*sizeof(ops_keydata_t)) ; - kr->nkeys_allocated = kr->nkeys+1; - } - memset(&kr->keys[kr->nkeys],0,sizeof(ops_keydata_t)) ; - ops_keydata_copy(&kr->keys[kr->nkeys],&key) ; - kr->nkeys++ ; -} - -bool PGPHandler::LoadCertificateFromBinaryData(const unsigned char *data,uint32_t data_len,RsPgpId& id,std::string& error_string) -{ - return LoadCertificate(data,data_len,ops_false,id,error_string); -} - -bool PGPHandler::LoadCertificateFromString(const std::string& pgp_cert,RsPgpId& id,std::string& error_string) -{ - return LoadCertificate((unsigned char*)(pgp_cert.c_str()),pgp_cert.length(),ops_true,id,error_string); -} - -bool PGPHandler::LoadCertificate(const unsigned char *data,uint32_t data_len,bool armoured,RsPgpId& id,std::string& error_string) -{ - RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. -#ifdef DEBUG_PGPHANDLER - std::cerr << "Reading new key from string: " << std::endl; -#endif - - ops_keyring_t *tmp_keyring = allocateOPSKeyring(); - ops_memory_t *mem = ops_memory_new() ; - ops_memory_add(mem,data,data_len) ; - - if(!ops_keyring_read_from_mem(tmp_keyring,armoured,mem)) - { - ops_keyring_free(tmp_keyring) ; - free(tmp_keyring) ; - ops_memory_release(mem) ; - free(mem) ; - - std::cerr << "Could not read key. Format error?" << std::endl; - error_string = std::string("Could not read key. Format error?") ; - return false ; - } - ops_memory_release(mem) ; - free(mem) ; - error_string.clear() ; - - // Check that there is exactly one key in this data packet. - // - if(tmp_keyring->nkeys != 1) - { - std::cerr << "Loaded certificate contains more than one PGP key. This is not allowed." << std::endl; - error_string = "Loaded certificate contains more than one PGP key. This is not allowed." ; - return false ; - } - - const ops_keydata_t *keydata = ops_keyring_get_key_by_index(tmp_keyring,0); - - // Check that the key is a version 4 key - // - if(keydata->key.pkey.version != 4) - { - error_string = "Public key is not version 4. Rejected!" ; - std::cerr << "Received a key with unhandled version number (" << keydata->key.pkey.version << ")" << std::endl; - return false ; - } - - // Check that the key is correctly self-signed. - // - ops_validate_result_t* result=(ops_validate_result_t*)ops_mallocz(sizeof *result); - - ops_validate_key_signatures(result,keydata,tmp_keyring,cb_get_passphrase) ; - - bool found = false ; - - for(uint32_t i=0;ivalid_count;++i) - if(!memcmp( - static_cast(result->valid_sigs[i].signer_id), - keydata->key_id, - RsPgpId::SIZE_IN_BYTES )) - { - found = true ; - break ; - } - - if(!found) - { - error_string = "This key is not self-signed. This is required by Retroshare." ; - std::cerr << "This key is not self-signed. This is required by Retroshare." << std::endl; - ops_validate_result_free(result); - return false ; - } - ops_validate_result_free(result); - -#ifdef DEBUG_PGPHANDLER - std::cerr << " Key read correctly: " << std::endl; - ops_keyring_list(tmp_keyring) ; -#endif - - int i=0 ; - - while( (keydata = ops_keyring_get_key_by_index(tmp_keyring,i++)) != NULL ) - if(locked_addOrMergeKey(_pubring,_public_keyring_map,keydata)) - { - _pubring_changed = true ; -#ifdef DEBUG_PGPHANDLER - std::cerr << " Added the key in the main public keyring." << std::endl; -#endif - } - else - std::cerr << "Key already in public keyring." << std::endl; - - if(tmp_keyring->nkeys > 0) - id = RsPgpId(tmp_keyring->keys[0].key_id) ; - else - return false ; - - ops_keyring_free(tmp_keyring) ; - free(tmp_keyring) ; - - _pubring_changed = true ; - - return true ; -} - -bool PGPHandler::locked_addOrMergeKey(ops_keyring_t *keyring,std::map& kmap,const ops_keydata_t *keydata) -{ - bool ret = false ; - RsPgpId id(keydata->key_id) ; - -#ifdef DEBUG_PGPHANDLER - std::cerr << "AddOrMergeKey():" << std::endl; - std::cerr << " id: " << id.toStdString() << std::endl; -#endif - - // See if the key is already in the keyring - const ops_keydata_t *existing_key = NULL; - std::map::const_iterator res = kmap.find(id) ; - - // Checks that - // - the key is referenced by keyid - // - the map is initialized - // - the fingerprint matches! - // - if(res == kmap.end() || (existing_key = ops_keyring_get_key_by_index(keyring,res->second._key_index)) == NULL) - { -#ifdef DEBUG_PGPHANDLER - std::cerr << " Key is new. Adding it to keyring" << std::endl; -#endif - addNewKeyToOPSKeyring(keyring,*keydata) ; // the key is new. - initCertificateInfo(kmap[id],keydata,keyring->nkeys-1) ; - existing_key = &(keyring->keys[keyring->nkeys-1]) ; - ret = true ; - } - else - { - if(memcmp( existing_key->fingerprint.fingerprint, - keydata->fingerprint.fingerprint, - RsPgpFingerprint::SIZE_IN_BYTES )) - { - std::cerr << "(EE) attempt to merge key with identical id, but different fingerprint!" << std::endl; - return false ; - } - -#ifdef DEBUG_PGPHANDLER - std::cerr << " Key exists. Merging signatures." << std::endl; -#endif - ret = mergeKeySignatures(const_cast(existing_key),keydata) ; - - if(ret) - initCertificateInfo(kmap[id],existing_key,res->second._key_index) ; - } - - if(ret) - { - validateAndUpdateSignatures(kmap[id],existing_key) ; - kmap[id]._time_stamp = time(NULL) ; - } - - return ret ; -} - -bool PGPHandler::encryptTextToFile(const RsPgpId& key_id,const std::string& text,const std::string& outfile) -{ - RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. - - const ops_keydata_t *public_key = locked_getPublicKey(key_id,true) ; - - if(public_key == NULL) - { - std::cerr << "Cannot get public key of id " << key_id.toStdString() << std::endl; - return false ; - } - - if(public_key->type != OPS_PTAG_CT_PUBLIC_KEY) - { - std::cerr << "PGPHandler::encryptTextToFile(): ERROR: supplied id did not return a public key!" << std::endl; - return false ; - } - - std::string outfile_tmp = outfile + ".tmp" ; - - ops_create_info_t *info; - int fd = ops_setup_file_write(&info, outfile_tmp.c_str(), ops_true); - - if (fd < 0) - { - std::cerr << "PGPHandler::encryptTextToFile(): ERROR: Cannot write to " << outfile_tmp << std::endl; - return false ; - } - - if(!ops_encrypt_stream(info, public_key, NULL, ops_false, ops_true)) - { - std::cerr << "PGPHandler::encryptTextToFile(): ERROR: encryption failed." << std::endl; - return false ; - } - - ops_write(text.c_str(), text.length(), info); - ops_teardown_file_write(info, fd); - - if(!RsDirUtil::renameFile(outfile_tmp,outfile)) - { - std::cerr << "PGPHandler::encryptTextToFile(): ERROR: Cannot rename " + outfile_tmp + " to " + outfile + ". Disk error?" << std::endl; - return false ; - } - - return true ; -} - -bool PGPHandler::encryptDataBin(const RsPgpId& key_id,const void *data, const uint32_t len, unsigned char *encrypted_data, unsigned int *encrypted_data_len) -{ - RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. - - const ops_keydata_t *public_key = locked_getPublicKey(key_id,true) ; - - if(public_key == NULL) - { - std::cerr << "Cannot get public key of id " << key_id.toStdString() << std::endl; - return false ; - } - - if(public_key->type != OPS_PTAG_CT_PUBLIC_KEY) - { - std::cerr << "PGPHandler::encryptTextToFile(): ERROR: supplied id did not return a public key!" << std::endl; - return false ; - } - if(public_key->key.pkey.algorithm != OPS_PKA_RSA) - { - std::cerr << "PGPHandler::encryptTextToFile(): ERROR: supplied key id " << key_id.toStdString() << " is not an RSA key (DSA for instance, is not supported)!" << std::endl; - return false ; - } - ops_create_info_t *info; - ops_memory_t *buf = NULL ; - ops_setup_memory_write(&info, &buf, 0); - bool res = true; - - if(!ops_encrypt_stream(info, public_key, NULL, ops_false, ops_false)) - { - std::cerr << "Encryption failed." << std::endl; - res = false ; - } - - ops_write(data,len,info); - ops_writer_close(info); - ops_create_info_delete(info); - - int tlen = ops_memory_get_length(buf) ; - - if( (int)*encrypted_data_len >= tlen) - { - if(res) - { - memcpy(encrypted_data,ops_memory_get_data(buf),tlen) ; - *encrypted_data_len = tlen ; - res = true ; - } - } - else - { - std::cerr << "Not enough room to fit encrypted data. Size given=" << *encrypted_data_len << ", required=" << tlen << std::endl; - res = false ; - } - - ops_memory_release(buf) ; - free(buf) ; - - return res ; -} - -bool PGPHandler::decryptDataBin(const RsPgpId& /*key_id*/,const void *encrypted_data, const uint32_t encrypted_len, unsigned char *data, unsigned int *data_len) -{ - int out_length ; - unsigned char *out ; - ops_boolean_t res = ops_decrypt_memory((const unsigned char *)encrypted_data,encrypted_len,&out,&out_length,_secring,ops_false,cb_get_passphrase) ; - - if(*data_len < (unsigned int)out_length) - { - std::cerr << "Not enough room to store decrypted data! Please give more."<< std::endl; - return false ; - } - - *data_len = (unsigned int)out_length ; - memcpy(data,out,out_length) ; - free(out) ; - - return (bool)res ; -} - -bool PGPHandler::decryptTextFromFile(const RsPgpId&,std::string& text,const std::string& inputfile) -{ - RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. - - unsigned char *out_buf = NULL ; - std::string buf ; - - FILE *f = RsDirUtil::rs_fopen(inputfile.c_str(),"rb") ; - - if (f == NULL) - { - std::cerr << "Cannot open file " << inputfile << " for read." << std::endl; - return false; - } - - int c ; - while( (c = fgetc(f))!= EOF) - buf += (unsigned char)c; - - fclose(f) ; - -#ifdef DEBUG_PGPHANDLER - std::cerr << "PGPHandler::decryptTextFromFile: read a file of length " << std::dec << buf.length() << std::endl; - std::cerr << "buf=\"" << buf << "\"" << std::endl; -#endif - - int out_length ; - ops_boolean_t res = ops_decrypt_memory((const unsigned char *)buf.c_str(),buf.length(),&out_buf,&out_length,_secring,ops_true,cb_get_passphrase) ; - - text = std::string((char *)out_buf,out_length) ; - free (out_buf); - return (bool)res ; -} - -bool PGPHandler::SignDataBin(const RsPgpId& id,const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen,bool use_raw_signature, std::string reason /* = "" */) -{ - RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. - // need to find the key and to decrypt it. - - const ops_keydata_t *key = locked_getSecretKey(id) ; - - if(!key) - { - std::cerr << "Cannot sign: no secret key with id " << id.toStdString() << std::endl; - return false ; - } - - std::string uid_hint ; - if(key->nuids > 0) - uid_hint = std::string((const char *)key->uids[0].user_id) ; - uid_hint += "(" + RsPgpId(key->key_id).toStdString()+")" ; - -#ifdef DEBUG_PGPHANDLER - ops_fingerprint_t f ; - ops_fingerprint(&f,&key->key.pkey) ; - - PGPFingerprintType fp(f.fingerprint) ; -#endif - - bool last_passwd_was_wrong = false ; -ops_secret_key_t *secret_key = NULL ; - - for(int i=0;i<3;++i) - { - bool cancelled =false; - std::string passphrase = _passphrase_callback(NULL,reason.c_str(),uid_hint.c_str(),"Please enter passwd for encrypting your key : ",last_passwd_was_wrong,&cancelled) ;//TODO reason - - secret_key = ops_decrypt_secret_key_from_data(key,passphrase.c_str()) ; - - if(cancelled) - { - std::cerr << "Key entering cancelled" << std::endl; - return false ; - } - if(secret_key) - break ; - - std::cerr << "Key decryption went wrong. Wrong passwd?" << std::endl; - last_passwd_was_wrong = true ; - } - if(!secret_key) - { - std::cerr << "Could not obtain secret key. Signature cancelled." << std::endl; - return false ; - } - - // then do the signature. - - ops_boolean_t not_raw = !use_raw_signature ; -#ifdef V07_NON_BACKWARD_COMPATIBLE_CHANGE_002 - ops_memory_t *memres = ops_sign_buf(data,len,OPS_SIG_BINARY,OPS_HASH_SHA256,secret_key,ops_false,ops_false,not_raw,not_raw) ; -#else - ops_memory_t *memres = ops_sign_buf(data,len,OPS_SIG_BINARY,OPS_HASH_SHA1,secret_key,ops_false,ops_false,not_raw,not_raw) ; -#endif - - if(!memres) - return false ; - - bool res ; - uint32_t slen = (uint32_t)ops_memory_get_length(memres); - - if(*signlen >= slen) - { - *signlen = slen ; - - memcpy(sign,ops_memory_get_data(memres),*signlen) ; - res = true ; - } - else - { - std::cerr << "(EE) memory chunk is not large enough for signature packet. Requred size: " << slen << " bytes." << std::endl; - res = false ; - } - - ops_memory_release(memres) ; - free(memres) ; - ops_secret_key_free(secret_key) ; - free(secret_key) ; - -#ifdef DEBUG_PGPHANDLER - std::cerr << "Signed with fingerprint " << fp.toStdString() << ", length " << std::dec << *signlen << ", literal data length = " << len << std::endl; - std::cerr << "Signature body: " << std::endl; - hexdump( (unsigned char *)data, len) ; - std::cerr << std::endl; - std::cerr << "Data: " << std::endl; - hexdump( (unsigned char *)sign,*signlen) ; - std::cerr << std::endl; -#endif - return res ; -} - -bool PGPHandler::privateSignCertificate(const RsPgpId& ownId,const RsPgpId& id_of_key_to_sign) -{ - RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. - - ops_keydata_t *key_to_sign = const_cast(locked_getPublicKey(id_of_key_to_sign,true)) ; - - if(key_to_sign == NULL) - { - std::cerr << "Cannot sign: no public key with id " << id_of_key_to_sign.toStdString() << std::endl; - return false ; - } - - // 1 - get decrypted secret key - // - const ops_keydata_t *skey = locked_getSecretKey(ownId) ; - - if(!skey) - { - std::cerr << "Cannot sign: no secret key with id " << ownId.toStdString() << std::endl; - return false ; - } - const ops_keydata_t *pkey = locked_getPublicKey(ownId,true) ; - - if(!pkey) - { - std::cerr << "Cannot sign: no public key with id " << ownId.toStdString() << std::endl; - return false ; - } - - bool cancelled = false; - std::string passphrase = _passphrase_callback(NULL,"",RsPgpId(skey->key_id).toStdString().c_str(),"Please enter passwd for encrypting your key : ",false,&cancelled) ; - - ops_secret_key_t *secret_key = ops_decrypt_secret_key_from_data(skey,passphrase.c_str()) ; - - if(cancelled) - { - std::cerr << "Key cancelled by used." << std::endl; - return false ; - } - if(!secret_key) - { - std::cerr << "Key decryption went wrong. Wrong passwd?" << std::endl; - return false ; - } - - // 2 - then do the signature. - - if(!ops_sign_key(key_to_sign,pkey->key_id,secret_key)) - { - std::cerr << "Key signature went wrong. Wrong passwd?" << std::endl; - return false ; - } - - // 3 - free memory - // - ops_secret_key_free(secret_key) ; - free(secret_key) ; - - _pubring_changed = true ; - - // 4 - update signatures. - // - PGPCertificateInfo& cert(_public_keyring_map[ id_of_key_to_sign ]) ; - validateAndUpdateSignatures(cert,key_to_sign) ; - cert._flags |= PGPCertificateInfo::PGP_CERTIFICATE_FLAG_HAS_OWN_SIGNATURE ; - - return true ; -} - void PGPHandler::updateOwnSignatureFlag(const RsPgpId& own_id) { RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. if(_public_keyring_map.find(own_id)==_public_keyring_map.end()) { - std::cerr << __func__ << ": key with id=" << own_id.toStdString() << " not in keyring." << std::endl; + RsErr() << __func__ << ": key with id=" << own_id.toStdString() << " not in keyring." ; // return now, because the following operation would add an entry to _public_keyring_map return; } @@ -1569,7 +135,7 @@ void PGPHandler::updateOwnSignatureFlag(const RsPgpId& cert_id,const RsPgpId& ow if(it == _public_keyring_map.end()) { - std::cerr << "updateOwnSignatureFlag: Cannot get certificate for string " << cert_id.toStdString() << ". This is probably a bug." << std::endl; + RsErr() << "updateOwnSignatureFlag: Cannot get certificate for string " << cert_id.toStdString() << ". This is probably a bug." ; return ; } @@ -1599,59 +165,6 @@ void PGPHandler::locked_updateOwnSignatureFlag(PGPCertificateInfo& cert,const Rs RsPgpFingerprint::SIZE_IN_BYTES - RsPgpId::SIZE_IN_BYTES ); } -bool PGPHandler::getKeyFingerprint(const RsPgpId& id, RsPgpFingerprint& fp) const -{ - RS_STACK_MUTEX(pgphandlerMtx); - - const ops_keydata_t *key = locked_getPublicKey(id,false) ; - - if(!key) return false; - - ops_fingerprint_t f ; - ops_fingerprint(&f,&key->key.pkey) ; - - fp = RsPgpFingerprint::fromBufferUnsafe(f.fingerprint); - - return true ; -} - -bool PGPHandler::VerifySignBin(const void *literal_data, uint32_t literal_data_length, unsigned char *sign, unsigned int sign_len, const PGPFingerprintType& key_fingerprint) -{ - RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. - - RsPgpId id = RsPgpId(key_fingerprint.toByteArray() + PGPFingerprintType::SIZE_IN_BYTES - RsPgpId::SIZE_IN_BYTES) ; - const ops_keydata_t *key = locked_getPublicKey(id,true) ; - - if(key == NULL) - { - std::cerr << "No key returned by fingerprint " << key_fingerprint.toStdString() << ", and ID " << id.toStdString() << ", signature verification failed!" << std::endl; - return false ; - } - - // Check that fingerprint is the same. - const ops_public_key_t *pkey = &key->key.pkey ; - ops_fingerprint_t fp ; - ops_fingerprint(&fp,pkey) ; - - if(key_fingerprint != PGPFingerprintType(fp.fingerprint)) - { - std::cerr << "Key fingerprint does not match " << key_fingerprint.toStdString() << ", for ID " << id.toStdString() << ", signature verification failed!" << std::endl; - return false ; - } - -#ifdef DEBUG_PGPHANDLER - std::cerr << "Verifying signature from fingerprint " << key_fingerprint.toStdString() << ", length " << std::dec << sign_len << ", literal data length = " << literal_data_length << std::endl; - std::cerr << "Signature body: " << std::endl; - hexdump( (unsigned char *)sign,sign_len) ; - std::cerr << std::endl; - std::cerr << "Signed data: " << std::endl; - hexdump( (unsigned char *)literal_data, literal_data_length) ; - std::cerr << std::endl; -#endif - - return ops_validate_detached_signature(literal_data,literal_data_length,sign,sign_len,key) ; -} - void PGPHandler::setAcceptConnexion(const RsPgpId& id,bool b) { RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. @@ -1699,65 +212,6 @@ bool PGPHandler::isGPGAccepted(const RsPgpId &id) return (res != _public_keyring_map.end()) && (res->second._flags & PGPCertificateInfo::PGP_CERTIFICATE_FLAG_ACCEPT_CONNEXION) ; } -// Lexicographic order on signature packets -// -bool operator<(const ops_packet_t& p1,const ops_packet_t& p2) -{ - if(p1.length < p2.length) - return true ; - if(p1.length > p2.length) - return false ; - - for(uint32_t i=0;i p2.raw[i]) - return false ; - } - return false ; -} - -bool PGPHandler::mergeKeySignatures(ops_keydata_t *dst,const ops_keydata_t *src) -{ - // First sort all signatures into lists to see which is new, which is not new - -#ifdef DEBUG_PGPHANDLER - std::cerr << "Merging signatures for key " << RsPgpId(dst->key_id).toStdString() << std::endl; -#endif - std::set dst_packets ; - - for(uint32_t i=0;inpackets;++i) dst_packets.insert(dst->packets[i]) ; - - std::set to_add ; - - for(uint32_t i=0;inpackets;++i) - if(dst_packets.find(src->packets[i]) == dst_packets.end()) - { - uint8_t tag ; - uint32_t length ; - unsigned char *tmp_data = src->packets[i].raw ; // put it in a tmp variable because read_packetHeader() will modify it!! - - PGPKeyParser::read_packetHeader(tmp_data,tag,length) ; - - if(tag == PGPKeyParser::PGP_PACKET_TAG_SIGNATURE) - to_add.insert(src->packets[i]) ; -#ifdef DEBUG_PGPHANDLER - else - std::cerr << " Packet with tag 0x" << std::hex << (int)(src->packets[i].raw[0]) << std::dec << " not merged, because it is not a signature." << std::endl; -#endif - } - - for(std::set::const_iterator it(to_add.begin());it!=to_add.end();++it) - { -#ifdef DEBUG_PGPHANDLER - std::cerr << " Adding packet with tag 0x" << std::hex << (int)(*it).raw[0] << std::dec << std::endl; -#endif - ops_add_packet_to_keydata(dst,&*it) ; - } - return to_add.size() > 0 ; -} - bool PGPHandler::parseSignature(unsigned char *sign, unsigned int signlen,RsPgpId& issuer_id) { PGPSignatureInfo info ; @@ -1780,7 +234,7 @@ bool PGPHandler::privateTrustCertificate(const RsPgpId& id,int trustlvl) { if(trustlvl < 0 || trustlvl >= 6 || trustlvl == 1) { - std::cerr << "Invalid trust level " << trustlvl << " passed to privateTrustCertificate." << std::endl; + RsErr() << "Invalid trust level " << trustlvl << " passed to privateTrustCertificate." ; return false ; } @@ -1788,7 +242,7 @@ bool PGPHandler::privateTrustCertificate(const RsPgpId& id,int trustlvl) if(it == _public_keyring_map.end()) { - std::cerr << "(EE) Key id " << id.toStdString() << " not in the keyring. Can't setup trust level." << std::endl; + RsErr() << "(EE) Key id " << id.toStdString() << " not in the keyring. Can't setup trust level." ; return false ; } @@ -1812,12 +266,12 @@ void PGPHandler::locked_readPrivateTrustDatabase() { FILE *fdb = RsDirUtil::rs_fopen(_trustdb_path.c_str(),"rb") ; #ifdef DEBUG_PGPHANDLER - std::cerr << "PGPHandler: Reading private trust database." << std::endl; + RsErr() << "PGPHandler: Reading private trust database." ; #endif if(fdb == NULL) { - std::cerr << " private trust database not found. No trust info loaded." << std::endl ; + RsErr() << " private trust database not found. No trust info loaded." << std::endl ; return ; } std::map::iterator it ; @@ -1830,12 +284,12 @@ void PGPHandler::locked_readPrivateTrustDatabase() if(it == _public_keyring_map.end()) { - std::cerr << " (WW) Trust packet found for unknown key id " << RsPgpId(trustpacket.user_id).toStdString() << std::endl; + RsErr() << " (WW) Trust packet found for unknown key id " << RsPgpId(trustpacket.user_id).toStdString() ; continue ; } if(trustpacket.trust_level > 6) { - std::cerr << " (WW) Trust packet found with unexpected trust level " << trustpacket.trust_level << std::endl; + RsErr() << " (WW) Trust packet found with unexpected trust level " << trustpacket.trust_level ; continue ; } @@ -1848,19 +302,19 @@ void PGPHandler::locked_readPrivateTrustDatabase() fclose(fdb) ; - std::cerr << "PGPHandler: Successfully read " << std::hex << n_packets << std::dec << " trust packets." << std::endl; + RsErr() << "PGPHandler: Successfully read " << std::hex << n_packets << std::dec << " trust packets." ; } bool PGPHandler::locked_writePrivateTrustDatabase() { FILE *fdb = RsDirUtil::rs_fopen((_trustdb_path+".tmp").c_str(),"wb") ; #ifdef DEBUG_PGPHANDLER - std::cerr << "PGPHandler: Reading private trust database." << std::endl; + RsErr() << "PGPHandler: Reading private trust database." ; #endif if(fdb == NULL) { - std::cerr << " (EE) Can't open private trust database file " << _trustdb_path << " for write. Giving up!" << std::endl ; + RsErr() << " (EE) Can't open private trust database file " << _trustdb_path << " for write. Giving up!" << std::endl ; return false; } PrivateTrustPacket trustpacket ; @@ -1878,7 +332,7 @@ bool PGPHandler::locked_writePrivateTrustDatabase() if(fwrite((void*)&trustpacket,sizeof(PrivateTrustPacket),1,fdb) != 1) { - std::cerr << " (EE) Cannot write to trust database " << _trustdb_path << ". Disc full, or quota exceeded ? Leaving database untouched." << std::endl; + RsErr() << " (EE) Cannot write to trust database " << _trustdb_path << ". Disc full, or quota exceeded ? Leaving database untouched." ; fclose(fdb) ; return false; } @@ -1888,78 +342,13 @@ bool PGPHandler::locked_writePrivateTrustDatabase() if(!RsDirUtil::renameFile(_trustdb_path+".tmp",_trustdb_path)) { - std::cerr << " (EE) Cannot move temp file " << _trustdb_path+".tmp" << ". Bad write permissions?" << std::endl; + RsErr() << " (EE) Cannot move temp file " << _trustdb_path+".tmp" << ". Bad write permissions?" ; return false ; } else return true ; } -bool PGPHandler::syncDatabase() -{ - RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. - RsStackFileLock flck(_pgp_lock_filename) ; // lock access to PGP directory. - -#ifdef DEBUG_PGPHANDLER - std::cerr << "Sync-ing keyrings." << std::endl; -#endif - locked_syncPublicKeyring() ; - //locked_syncSecretKeyring() ; - - // Now sync the trust database as well. - // - locked_syncTrustDatabase() ; - -#ifdef DEBUG_PGPHANDLER - std::cerr << "Done. " << std::endl; -#endif - return true ; -} - -bool PGPHandler::locked_syncPublicKeyring() -{ - struct stat64 buf ; -#ifdef WINDOWS_SYS - std::wstring wfullname; - librs::util::ConvertUtf8ToUtf16(_pubring_path, wfullname); - if(-1 == _wstati64(wfullname.c_str(), &buf)) -#else - if(-1 == stat64(_pubring_path.c_str(), &buf)) -#endif - std::cerr << "PGPHandler::syncDatabase(): can't stat file " << _pubring_path << ". Can't sync public keyring." << std::endl; - - if(_pubring_last_update_time < buf.st_mtime) - { - std::cerr << "Detected change on disk of public keyring. Merging!" << std::endl ; - - locked_mergeKeyringFromDisk(_pubring,_public_keyring_map,_pubring_path) ; - _pubring_last_update_time = buf.st_mtime ; - } - - // Now check if the pubring was locally modified, which needs saving it again - if(_pubring_changed && RsDiscSpace::checkForDiscSpace(RS_PGP_DIRECTORY)) - { - std::string tmp_keyring_file = _pubring_path + ".tmp" ; - - std::cerr << "Local changes in public keyring. Writing to disk..." << std::endl; - if(!ops_write_keyring_to_file(_pubring,ops_false,tmp_keyring_file.c_str(),ops_true)) - { - std::cerr << "Cannot write public keyring tmp file. Disk full? Disk quota exceeded?" << std::endl; - return false ; - } - if(!RsDirUtil::renameFile(tmp_keyring_file,_pubring_path)) - { - std::cerr << "Cannot rename tmp pubring file " << tmp_keyring_file << " into actual pubring file " << _pubring_path << ". Check writing permissions?!?" << std::endl; - return false ; - } - - std::cerr << "Done." << std::endl; - _pubring_last_update_time = time(NULL) ; // should we get this value from the disk instead?? - _pubring_changed = false ; - } - return true ; -} - bool PGPHandler::locked_syncTrustDatabase() { struct stat64 buf ; @@ -1971,13 +360,13 @@ bool PGPHandler::locked_syncTrustDatabase() if(-1 == stat64(_trustdb_path.c_str(), &buf)) #endif { - std::cerr << "PGPHandler::syncDatabase(): can't stat file " << _trustdb_path << ". Will force write it." << std::endl; + RsErr() << "PGPHandler::syncDatabase(): can't stat file " << _trustdb_path << ". Will force write it." ; _trustdb_changed = true ; // we force write of trust database if it does not exist. } if(_trustdb_last_update_time < buf.st_mtime) { - std::cerr << "Detected change on disk of trust database. " << std::endl ; + RsErr() << "Detected change on disk of trust database. " << std::endl ; locked_readPrivateTrustDatabase(); _trustdb_last_update_time = time(NULL) ; @@ -1985,149 +374,18 @@ bool PGPHandler::locked_syncTrustDatabase() if(_trustdb_changed) { - std::cerr << "Local changes in trust database. Writing to disk..." << std::endl; + RsErr() << "Local changes in trust database. Writing to disk..." ; if(!locked_writePrivateTrustDatabase()) - std::cerr << "Cannot write trust database. Disk full? Disk quota exceeded?" << std::endl; + RsErr() << "Cannot write trust database. Disk full? Disk quota exceeded?" ; else { - std::cerr << "Done." << std::endl; + RsErr() << "Done." ; _trustdb_last_update_time = time(NULL) ; _trustdb_changed = false ; } } return true ; } -void PGPHandler::locked_mergeKeyringFromDisk( ops_keyring_t *keyring, - std::map& kmap, - const std::string& keyring_file) -{ -#ifdef DEBUG_PGPHANDLER - std::cerr << "Merging keyring " << keyring_file << " from disk to memory." << std::endl; -#endif - // 1 - load keyring into a temporary keyring list. - ops_keyring_t *tmp_keyring = PGPHandler::allocateOPSKeyring() ; - if(ops_false == ops_keyring_read_from_file(tmp_keyring, false, keyring_file.c_str())) - { - std::cerr << "PGPHandler::locked_mergeKeyringFromDisk(): cannot read keyring. File corrupted?" ; - ops_keyring_free(tmp_keyring) ; - return ; - } - // 2 - load new keys and merge existing key signatures - - for(int i=0;inkeys;++i) - locked_addOrMergeKey(keyring,kmap,&tmp_keyring->keys[i]) ;// we dont' account for the return value. This is disk merging, not local changes. - - // 4 - clean - ops_keyring_free(tmp_keyring) ; -} - -bool PGPHandler::removeKeysFromPGPKeyring(const std::set& keys_to_remove,std::string& backup_file,uint32_t& error_code) -{ - // 1 - lock everything. - // - RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. - RsStackFileLock flck(_pgp_lock_filename) ; // lock access to PGP directory. - - error_code = PGP_KEYRING_REMOVAL_ERROR_NO_ERROR ; - - for(std::set::const_iterator it(keys_to_remove.begin());it!=keys_to_remove.end();++it) - if(locked_getSecretKey(*it) != NULL) - { - std::cerr << "(EE) PGPHandler:: can't remove key " << (*it).toStdString() << " since its shared by a secret key! Operation cancelled." << std::endl; - error_code = PGP_KEYRING_REMOVAL_ERROR_CANT_REMOVE_SECRET_KEYS ; - return false ; - } - - // 2 - sync everything. - // - locked_syncPublicKeyring() ; - - // 3 - make a backup of the public keyring - // - char template_name[_pubring_path.length()+8] ; - sprintf(template_name,"%s.XXXXXX",_pubring_path.c_str()) ; - -#if defined __USE_XOPEN_EXTENDED || defined __USE_XOPEN2K8 - int fd_keyring_backup(mkstemp(template_name)); - if (fd_keyring_backup == -1) -#else - if(mktemp(template_name) == NULL) -#endif - { - std::cerr << "PGPHandler::removeKeysFromPGPKeyring(): cannot create keyring backup file. Giving up." << std::endl; - error_code = PGP_KEYRING_REMOVAL_ERROR_CANNOT_CREATE_BACKUP ; - return false ; - } -#if defined __USE_XOPEN_EXTENDED || defined __USE_XOPEN2K8 - close(fd_keyring_backup); // TODO: keep the file open and use the fd -#endif - - if(!ops_write_keyring_to_file(_pubring,ops_false,template_name,ops_true)) - { - std::cerr << "PGPHandler::removeKeysFromPGPKeyring(): cannot write keyring backup file. Giving up." << std::endl; - error_code = PGP_KEYRING_REMOVAL_ERROR_CANNOT_WRITE_BACKUP ; - return false ; - } - backup_file = std::string(template_name,_pubring_path.length()+7) ; - - std::cerr << "Keyring was backed up to file " << backup_file << std::endl; - - // Remove keys from the keyring, and update the keyring map. - // - for(std::set::const_iterator it(keys_to_remove.begin());it!=keys_to_remove.end();++it) - { - if(locked_getSecretKey(*it) != NULL) - { - std::cerr << "(EE) PGPHandler:: can't remove key " << (*it).toStdString() << " since its shared by a secret key!" << std::endl; - continue ; - } - - std::map::iterator res = _public_keyring_map.find(*it) ; - - if(res == _public_keyring_map.end()) - { - std::cerr << "(EE) PGPHandler:: can't remove key " << (*it).toStdString() << " from keyring: key not found." << std::endl; - continue ; - } - - if(res->second._key_index >= (unsigned int)_pubring->nkeys || RsPgpId(_pubring->keys[res->second._key_index].key_id) != *it) - { - std::cerr << "(EE) PGPHandler:: can't remove key " << (*it).toStdString() << ". Inconsistency found." << std::endl; - error_code = PGP_KEYRING_REMOVAL_ERROR_DATA_INCONSISTENCY ; - return false ; - } - - // Move the last key to the freed place. This deletes the key in place. - // - ops_keyring_remove_key(_pubring,res->second._key_index) ; - - // Erase the info from the keyring map. - // - _public_keyring_map.erase(res) ; - - // now update all indices back. This internal look is very costly, but it avoids deleting the wrong keys, since the keyring structure is - // changed by ops_keyring_remove_key and therefore indices don't point to the correct location anymore. - - int i=0 ; - const ops_keydata_t *keydata ; - while( (keydata = ops_keyring_get_key_by_index(_pubring,i)) != NULL ) - { - PGPCertificateInfo& cert(_public_keyring_map[ RsPgpId(keydata->key_id) ]) ; - cert._key_index = i ; - ++i ; - } - } - - // Everything went well, sync back the keyring on disk - - _pubring_changed = true ; - _trustdb_changed = true ; - - locked_syncPublicKeyring() ; - locked_syncTrustDatabase() ; - - return true ; -} diff --git a/libretroshare/src/pgp/pgphandler.h b/libretroshare/src/pgp/pgphandler.h index 5d7eb82f8..19323b142 100644 --- a/libretroshare/src/pgp/pgphandler.h +++ b/libretroshare/src/pgp/pgphandler.h @@ -29,12 +29,6 @@ #include #include -extern "C" { -#include -#include -#include -} - 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& 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& 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& 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& 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& 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& 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& 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& kmap, const std::string& keyring_file) ; - bool locked_addOrMergeKey(ops_keyring_t *keyring,std::map& kmap,const ops_keydata_t *keydata) ; + bool locked_syncTrustDatabase() ; // Members. // mutable RsMutex pgphandlerMtx ; - ops_keyring_t *_pubring ; - ops_keyring_t *_secring ; - std::map _public_keyring_map ; // used for fast access to keys. Gives the index in the keyring. std::map _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 }; diff --git a/libretroshare/src/pgp/rscertificate.cc b/libretroshare/src/pgp/rscertificate.cc index f3007bb01..23c7f2dab 100644 --- a/libretroshare/src/pgp/rscertificate.cc +++ b/libretroshare/src/pgp/rscertificate.cc @@ -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(errCode); - return crt != nullptr; + return rsPeers->loadDetailsFromStringCert(input,details,error_code); } return false; diff --git a/libretroshare/src/pgp/rscertificate.h b/libretroshare/src/pgp/rscertificate.h index 1ba3db633..977493e69 100644 --- a/libretroshare/src/pgp/rscertificate.h +++ b/libretroshare/src/pgp/rscertificate.h @@ -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& locators() const { return mLocators; } diff --git a/libretroshare/src/pqi/authgpg.cc b/libretroshare/src/pqi/authgpg.cc index b41084cf0..f7a6fb6c3 100644 --- a/libretroshare/src/pqi/authgpg.cc +++ b/libretroshare/src/pqi/authgpg.cc @@ -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& 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& 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& pgp_ids,std::string& backup_file,uint32_t& error_code) +bool AuthPGP::removeKeysFromPGPKeyring(const std::set& pgp_ids,std::string& backup_file,uint32_t& error_code) { // std::list pids ; // // for(std::list::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 pids ; // -// PGPHandler::availableGPGCertificatesWithPrivateKeys(pids) ; +// mPgpHandler->availableGPGCertificatesWithPrivateKeys(pids) ; // // for(std::list::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 &ids) +bool AuthPGP::getPgpAllList(std::list &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& list,bool (*filter)(const PGPCertificateInfo&)) +bool AuthPGP::getGPGFilteredList(std::list& 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 &ids) +bool AuthPGP::getPgpValidList(std::list &ids) { return getGPGFilteredList(ids,&filter_Validity); } -bool AuthGPG::getGPGAcceptedList(std::list &ids) +bool AuthPGP::getPgpAcceptedList(std::list &ids) { return getGPGFilteredList(ids,&filter_Accepted); } -bool AuthGPG::getGPGSignedList(std::list &ids) +bool AuthPGP::getPgpSignedList(std::list &ids) { return getGPGFilteredList(ids,&filter_OwnSigned); } @@ -504,9 +529,9 @@ bool AuthGPG::getGPGSignedList(std::list &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 &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& lst) +bool AuthPGP::saveList(bool& cleanup, std::list& lst) { #ifdef GPG_DEBUG std::cerr << "AuthGPG::saveList() called" << std::endl ; #endif std::list 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& lst) return true; } -bool AuthGPG::loadList(std::list& load) +bool AuthPGP::loadList(std::list& load) { #ifdef GPG_DEBUG std::cerr << "AuthGPG::loadList() Item Count: " << load.size() << std::endl; @@ -745,7 +787,7 @@ bool AuthGPG::loadList(std::list& load) std::list::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& 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; } diff --git a/libretroshare/src/pqi/authgpg.h b/libretroshare/src/pqi/authgpg.h index 4fe76194c..1db1ad482 100644 --- a/libretroshare/src/pqi/authgpg.h +++ b/libretroshare/src/pqi/authgpg.h @@ -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& signers) ; + static int availablePgpCertificatesWithPrivateKeys(std::list& 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 &ids); - virtual bool getGPGValidList(std::list &ids); - virtual bool getGPGAcceptedList(std::list &ids); - virtual bool getGPGSignedList(std::list &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 &ids); + static bool getPgpValidList(std::list &ids); + static bool getPgpAcceptedList(std::list &ids); + static bool getPgpSignedList(std::list &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 &pgp_ids,std::string& backup_file,uint32_t& error_code) ; + static bool removeKeysFromPGPKeyring(const std::set &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& list,bool (*filter)(const PGPCertificateInfo&) = NULL) ; + static bool getGPGFilteredList(std::list& 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&); - virtual bool loadList(std::list& load); + virtual RsSerialiser *setupSerialiser() override; + virtual bool saveList(bool &cleanup, std::list&) override; + virtual bool loadList(std::list& 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 services ; - static AuthGPG *_instance ; + static AuthPGP *_instance ; }; #endif diff --git a/libretroshare/src/pqi/authssl.cc b/libretroshare/src/pqi/authssl.cc index eb89a1ed5..9d70121a3 100644 --- a/libretroshare/src/pqi/authssl.cc +++ b/libretroshare/src/pqi/authssl.cc @@ -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(signature->length), pd.fpr )) + if (!AuthPGP::VerifySignBin( signed_data, signed_data_length, signature->data, static_cast(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 <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" diff --git a/libretroshare/src/pqi/p3peermgr.cc b/libretroshare/src/pqi/p3peermgr.cc index 83c4d9366..d4ff9f95d 100644 --- a/libretroshare/src/pqi/p3peermgr.cc +++ b/libretroshare/src/pqi/p3peermgr.cc @@ -812,11 +812,11 @@ int p3PeerMgrIMPL::getFriendCount(bool ssl, bool online) // count all gpg id's std::list gpgIds; - AuthGPG::getAuthGPG()->getGPGAcceptedList(gpgIds); + AuthPGP::getPgpAcceptedList(gpgIds); // add own gpg id, if we have more than one location std::list 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& 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& load) #endif for(uint32_t i=0;ipgp_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& 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 { diff --git a/libretroshare/src/pqi/pqifdbin.cc b/libretroshare/src/pqi/pqifdbin.cc index a3ed6db16..255e65b77 100644 --- a/libretroshare/src/pqi/pqifdbin.cc +++ b/libretroshare/src/pqi/pqifdbin.cc @@ -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 diff --git a/libretroshare/src/pqi/pqinetwork.cc b/libretroshare/src/pqi/pqinetwork.cc index a5ca76035..2b786f488 100644 --- a/libretroshare/src/pqi/pqinetwork.cc +++ b/libretroshare/src/pqi/pqinetwork.cc @@ -21,15 +21,6 @@ * along with this program. If not, see . * * * *******************************************************************************/ -#ifdef WINDOWS_SYS -# include "util/rswin.h" -# include "util/rsmemory.h" -# include -#endif // WINDOWS_SYS - -#ifdef __ANDROID__ -# include -#endif // def __ANDROID__ #include #include @@ -43,6 +34,28 @@ #include "util/rsnet.h" #include "util/stacktrace.h" +#ifdef WINDOWS_SYS +# include "util/rswin.h" +# include "util/rsmemory.h" +# include +#endif // WINDOWS_SYS + +/// @See: android_ifaddrs/README.adoc +#ifdef __ANDROID__ +# include +#endif // def __ANDROID__ + +#ifdef WINDOWS_SYS /* Windows - define errno */ +int errno; +#else /* Windows - define errno */ +#include +#endif + +#ifdef __HAIKU__ +# include +# 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 - -#endif - -#ifdef __HAIKU__ - #include - #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 #ifdef WINDOWS_SYS # include # include # pragma comment(lib, "IPHLPAPI.lib") #elif defined(__ANDROID__) && __ANDROID_API__ < 24 -# include -# include -# include -# include -#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 # include #endif // WINDOWS_SYS @@ -324,20 +320,12 @@ bool getLocalAddresses(std::vector& 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& addrs) { sockaddr_storage tmp; sockaddr_storage_clear(tmp); - if (sockaddr_storage_copyip(tmp, *reinterpret_cast(ifa->ifa_addr))) + if(sockaddr_storage_copyip( + tmp, + *reinterpret_cast(ifa->ifa_addr) )) addrs.push_back(tmp); } freeifaddrs(ifsaddrs); #endif // WINDOWS_SYS #ifdef NET_DEBUG - std::list::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(); diff --git a/libretroshare/src/pqi/pqinetwork.h b/libretroshare/src/pqi/pqinetwork.h index e4238ee5e..9519bf197 100644 --- a/libretroshare/src/pqi/pqinetwork.h +++ b/libretroshare/src/pqi/pqinetwork.h @@ -4,7 +4,8 @@ * libretroshare: retroshare core library * * * * Copyright (C) 2004-2006 Robert Fernie * - * Copyright (C) 2015-2018 Gioacchino Mazzurco * + * Copyright (C) 2015-2021 Gioacchino Mazzurco * + * Copyright (C) 2021 Asociación Civil Altermundi * * * * 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 . * * * *******************************************************************************/ -#ifndef MRK_PQI_NETWORKING_HEADER -#define MRK_PQI_NETWORKING_HEADER +#pragma once #include @@ -86,9 +86,13 @@ extern int errno; /* Define extern errno, to duplicate unix behaviour */ #include #include +#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 & 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 - diff --git a/libretroshare/src/pqi/pqissl.cc b/libretroshare/src/pqi/pqissl.cc index 1cfff8fbd..6a455dfeb 100644 --- a/libretroshare/src/pqi/pqissl.cc +++ b/libretroshare/src/pqi/pqissl.cc @@ -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 " diff --git a/libretroshare/src/pqi/pqissllistener.cc b/libretroshare/src/pqi/pqissllistener.cc index fa25bfe0b..ad2129928 100644 --- a/libretroshare/src/pqi/pqissllistener.cc +++ b/libretroshare/src/pqi/pqissllistener.cc @@ -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 " diff --git a/libretroshare/src/retroshare/rsgxsforums.h b/libretroshare/src/retroshare/rsgxsforums.h index 4967d46c5..ba13bd16e 100644 --- a/libretroshare/src/retroshare/rsgxsforums.h +++ b/libretroshare/src/retroshare/rsgxsforums.h @@ -450,6 +450,17 @@ public: const std::string& matchString, std::vector& 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 diff --git a/libretroshare/src/retroshare/rspeers.h b/libretroshare/src/retroshare/rspeers.h index f49ef7fc2..e00576908 100644 --- a/libretroshare/src/retroshare/rspeers.h +++ b/libretroshare/src/retroshare/rspeers.h @@ -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; diff --git a/libretroshare/src/rs_android/LocalArray.h b/libretroshare/src/rs_android/LocalArray.h new file mode 100644 index 000000000..2ab708aff --- /dev/null +++ b/libretroshare/src/rs_android/LocalArray.h @@ -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 +#include + +/** + * 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 +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 diff --git a/libretroshare/src/rs_android/README-ifaddrs-android.adoc b/libretroshare/src/rs_android/README-ifaddrs-android.adoc new file mode 100644 index 000000000..0c0065f92 --- /dev/null +++ b/libretroshare/src/rs_android/README-ifaddrs-android.adoc @@ -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. + diff --git a/libretroshare/src/rs_android/ScopedFd.h b/libretroshare/src/rs_android/ScopedFd.h new file mode 100644 index 000000000..d2b7935fa --- /dev/null +++ b/libretroshare/src/rs_android/ScopedFd.h @@ -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 + +// 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 diff --git a/libretroshare/src/util/androiddebug.h b/libretroshare/src/rs_android/androidcoutcerrcatcher.hpp similarity index 83% rename from libretroshare/src/util/androiddebug.h rename to libretroshare/src/rs_android/androidcoutcerrcatcher.hpp index c358be553..43cf16dd7 100644 --- a/libretroshare/src/util/androiddebug.h +++ b/libretroshare/src/rs_android/androidcoutcerrcatcher.hpp @@ -1,9 +1,9 @@ /******************************************************************************* - * libretroshare/src/util: androiddebug.h * * * * libretroshare: retroshare core library * * * - * Copyright (C) 2016 Gioacchino Mazzurco * + * Copyright (C) 2016-2021 Gioacchino Mazzurco * + * Copyright (C) 2021 Asociación Civil Altermundi * * * * 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 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(instance); + AndroidCoutCerrCatcher &i = *static_cast(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; } }; diff --git a/libretroshare/src/rs_android/errorconditionwrap.cpp b/libretroshare/src/rs_android/errorconditionwrap.cpp new file mode 100644 index 000000000..e27495878 --- /dev/null +++ b/libretroshare/src/rs_android/errorconditionwrap.cpp @@ -0,0 +1,42 @@ +/******************************************************************************* + * * + * libretroshare: retroshare core library * + * * + * Copyright (C) 2021 Gioacchino Mazzurco * + * Copyright (C) 2021 Asociación Civil Altermundi * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +#include "rs_android/rsjni.hpp" + +namespace jni +{ +Local> MakeAnything( + ThingToMake, JNIEnv& env, + const std::error_condition& ec ) +{ + auto& clazz = jni::Class::Singleton(env); + + static auto method = + clazz.GetConstructor(env); + + jni::jint value = ec.value(); + auto message = jni::Make(env, ec.message()); + auto category = jni::Make(env, ec.category().name()); + + return clazz.New(env, method, value, message, category); +} +} diff --git a/libretroshare/src/rs_android/ifaddrs-android.h b/libretroshare/src/rs_android/ifaddrs-android.h new file mode 100644 index 000000000..446d8d2be --- /dev/null +++ b/libretroshare/src/rs_android/ifaddrs-android.h @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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(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(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(ss); + return reinterpret_cast(&ss4->sin_addr); + } else if (family == AF_INET6) { + sockaddr_in6* ss6 = reinterpret_cast(ss); + return reinterpret_cast(&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(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(&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(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 diff --git a/libretroshare/src/rs_android/org/retroshare/service/AssetHelper.java b/libretroshare/src/rs_android/org/retroshare/service/AssetHelper.java new file mode 100644 index 000000000..c32aa5b5d --- /dev/null +++ b/libretroshare/src/rs_android/org/retroshare/service/AssetHelper.java @@ -0,0 +1,98 @@ +/* + * RetroShare + * Copyright (C) 2021 Gioacchino Mazzurco + * Copyright (C) 2021 Asociación Civil Altermundi + * + * 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 . + * + * SPDX-FileCopyrightText: Retroshare Team + * 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"; +} diff --git a/libretroshare/src/rs_android/org/retroshare/service/ErrorConditionWrap.java b/libretroshare/src/rs_android/org/retroshare/service/ErrorConditionWrap.java new file mode 100644 index 000000000..c0830f5d2 --- /dev/null +++ b/libretroshare/src/rs_android/org/retroshare/service/ErrorConditionWrap.java @@ -0,0 +1,48 @@ +/* + * RetroShare + * Copyright (C) 2021 Gioacchino Mazzurco + * Copyright (C) 2021 Asociación Civil Altermundi + * + * 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 . + * + * SPDX-FileCopyrightText: Retroshare Team + * 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; +} diff --git a/libretroshare/src/rs_android/org/retroshare/service/RetroShareServiceAndroid.java b/libretroshare/src/rs_android/org/retroshare/service/RetroShareServiceAndroid.java new file mode 100644 index 000000000..818f06348 --- /dev/null +++ b/libretroshare/src/rs_android/org/retroshare/service/RetroShareServiceAndroid.java @@ -0,0 +1,141 @@ +/* + * RetroShare + * Copyright (C) 2016-2021 Gioacchino Mazzurco + * Copyright (C) 2021 Asociación Civil Altermundi + * + * 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 . + * + * SPDX-FileCopyrightText: Retroshare Team + * 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(); +} diff --git a/libretroshare/src/rs_android/retroshareserviceandroid.cpp b/libretroshare/src/rs_android/retroshareserviceandroid.cpp new file mode 100644 index 000000000..6e156edca --- /dev/null +++ b/libretroshare/src/rs_android/retroshareserviceandroid.cpp @@ -0,0 +1,103 @@ +/* + * RetroShare Service Android + * Copyright (C) 2016-2021 Gioacchino Mazzurco + * Copyright (C) 2021 Asociación Civil Altermundi + * + * 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 . + * + * SPDX-FileCopyrightText: Retroshare Team + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include +#include + +#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 +RetroShareServiceAndroid::sAndroidCoutCerrCatcher = nullptr; + +using ErrorConditionWrap = RsJni::ErrorConditionWrap; + +/*static*/ jni::Local> +RetroShareServiceAndroid::start( + JNIEnv& env, jni::Class&, + jni::jint jsonApiPort, const jni::String& jsonApiBindAddress ) +{ + if(jsonApiPort < 0 || jsonApiPort > std::numeric_limits::max()) + { + RS_ERR("Got invalid JSON API port: ", jsonApiPort); + return jni::Make(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(); + + RsInit::InitRsConfig(); + RsControl::earlyInitNotificationSystem(); + + RsConfigOptions conf; + conf.jsonApiPort = static_cast(jsonApiPort); + conf.jsonApiBindAddress = jni::Make(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(env, std::errc::no_child_process); + } + + return jni::Make(env, std::error_condition()); +} + +jni::Local> RetroShareServiceAndroid::stop( + JNIEnv& env, jni::Class& ) +{ + if(RsControl::instance()->isReady()) + { + RsControl::instance()->rsGlobalShutDown(); + return jni::Make(env, std::error_condition()); + } + + sAndroidCoutCerrCatcher.reset(); + + return jni::Make(env, std::errc::no_such_process); +} + +jni::Local > +RetroShareServiceAndroid::getAndroidContext(JNIEnv& env) +{ + auto& clazz = jni::Class::Singleton(env); + static auto method = + clazz.GetStaticMethod()>( + env, "getServiceContext" ); + return clazz.Call(env, method); +} diff --git a/libretroshare/src/rs_android/retroshareserviceandroid.hpp b/libretroshare/src/rs_android/retroshareserviceandroid.hpp new file mode 100644 index 000000000..bd8f88f31 --- /dev/null +++ b/libretroshare/src/rs_android/retroshareserviceandroid.hpp @@ -0,0 +1,84 @@ +/* + * RetroShare Service Android + * Copyright (C) 2016-2021 Gioacchino Mazzurco + * Copyright (C) 2021 Asociación Civil Altermundi + * + * 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 . + * + * SPDX-FileCopyrightText: Retroshare Team + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +#pragma once + +#include +#include + +#include + +#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> start( + JNIEnv& env, jni::Class& 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> stop( + JNIEnv& env, jni::Class& ); + + struct Context + { + /// JNI parafernalia + static constexpr auto Name() { return "android/content/Context"; } + }; + + /// Return RetroShare Service Android Context + static jni::Local> 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 sAndroidCoutCerrCatcher; +}; diff --git a/libretroshare/src/rs_android/rsjni.cpp b/libretroshare/src/rs_android/rsjni.cpp new file mode 100644 index 000000000..c9fc2c8ed --- /dev/null +++ b/libretroshare/src/rs_android/rsjni.cpp @@ -0,0 +1,70 @@ +/******************************************************************************* + * RetroShare JNI utilities * + * * + * libretroshare: retroshare core library * + * * + * Copyright (C) 2021 Gioacchino Mazzurco * + * Copyright (C) 2021 Asociación Civil Altermundi * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +#include "rs_android/rsjni.hpp" +#include "rs_android/retroshareserviceandroid.hpp" + +rs_view_ptr 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::Singleton(env); + jni::Class::Singleton(env); + + jni::RegisterNatives( + env, *jni::Class::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 diff --git a/libretroshare/src/rs_android/rsjni.hpp b/libretroshare/src/rs_android/rsjni.hpp new file mode 100644 index 000000000..339dfd5c7 --- /dev/null +++ b/libretroshare/src/rs_android/rsjni.hpp @@ -0,0 +1,90 @@ +/******************************************************************************* + * RetroShare JNI utilities * + * * + * libretroshare: retroshare core library * + * * + * Copyright (C) 2021 Gioacchino Mazzurco * + * Copyright (C) 2021 Asociación Civil Altermundi * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ +#pragma once + +#include +#include + +#include + +#include "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 mJvm; +}; + + +namespace jni +{ +/** Provides idiomatic way of creating instances via +@code{.cpp} + jni::Make(env, std::error_condition()); +@endcode */ +jni::Local> +MakeAnything( + jni::ThingToMake, JNIEnv& env, + const std::error_condition& ec ); +} diff --git a/libretroshare/src/rsitems/itempriorities.h b/libretroshare/src/rsitems/itempriorities.h index a376a9d64..7c2b92cb6 100644 --- a/libretroshare/src/rsitems/itempriorities.h +++ b/libretroshare/src/rsitems/itempriorities.h @@ -3,7 +3,9 @@ * * * libretroshare: retroshare core library * * * - * Copyright 2011-2011 by Cyril Soler * + * Copyright (C) 2011-2018 Cyril Soler * + * Copyright (C) 2021 Gioacchino Mazzurco * + * Copyright (C) 2021 Asociación Civil Altermundi * * * * 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 +#include + +using RsItemPriority = uint8_t; // This file centralises QoS priorities for all transfer RsItems // diff --git a/libretroshare/src/rsitems/rsitem.h b/libretroshare/src/rsitems/rsitem.h index 3ef44f859..70844f840 100644 --- a/libretroshare/src/rsitems/rsitem.h +++ b/libretroshare/src/rsitems/rsitem.h @@ -3,7 +3,8 @@ * * * libretroshare: retroshare core library * * * - * Copyright (C) 2018 Gioacchino Mazzurco * + * Copyright (C) 2018-2021 Gioacchino Mazzurco * + * Copyright (C) 2021 Asociación Civil Altermundi * * * * 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 @@ -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; diff --git a/libretroshare/src/rsitems/rsnxsitems.cc b/libretroshare/src/rsitems/rsnxsitems.cc index e8178e045..94409bc19 100644 --- a/libretroshare/src/rsitems/rsnxsitems.cc +++ b/libretroshare/src/rsitems/rsnxsitems.cc @@ -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(item_subtype)) + { + case RsNxsSubtype::PULL_REQUEST: + return new RsNxsPullRequestItem(static_cast(service_id)); + } + switch(item_subtype) { case RS_PKT_SUBTYPE_NXS_SYNC_GRP_REQ_ITEM: return new RsNxsSyncGrpReqItem(SERVICE_TYPE) ; diff --git a/libretroshare/src/rsitems/rsnxsitems.h b/libretroshare/src/rsitems/rsnxsitems.h index 2b6731bfc..c7b6c58e3 100644 --- a/libretroshare/src/rsitems/rsnxsitems.h +++ b/libretroshare/src/rsitems/rsnxsitems.h @@ -3,7 +3,10 @@ * * * libretroshare: retroshare core library * * * - * Copyright 2012 Christopher Evi-Parker,Robert Fernie* + * Copyright (C) 2012 Christopher Evi-Parker * + * Copyright (C) 2012 Robert Fernie * + * Copyright (C) 2021 Gioacchino Mazzurco * + * Copyright (C) 2021 Asociación Civil Altermundi * * * * 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 . * * * *******************************************************************************/ -#ifndef RSNXSITEMS_H -#define RSNXSITEMS_H +#pragma once #include #include @@ -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(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 diff --git a/libretroshare/src/rsserver/p3face-config.cc b/libretroshare/src/rsserver/p3face-config.cc index 3251f33eb..62c60815b 100644 --- a/libretroshare/src/rsserver/p3face-config.cc +++ b/libretroshare/src/rsserver/p3face-config.cc @@ -118,7 +118,7 @@ void RsServer::rsGlobalShutDown() // if(mWire) mWire->join(); // #endif - AuthGPG::exit(); + AuthPGP::exit(); mShutdownCallback(0); } diff --git a/libretroshare/src/rsserver/p3peers.cc b/libretroshare/src/rsserver/p3peers.cc index 7011d7aef..2ca178c0a 100644 --- a/libretroshare/src/rsserver/p3peers.cc +++ b/libretroshare/src/rsserver/p3peers.cc @@ -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 &ids) #endif /* get from mAuthMgr */ - AuthGPG::getAuthGPG()->getGPGAllList(ids); + AuthPGP::getPgpAllList(ids); return true; } @@ -628,7 +628,7 @@ bool p3Peers::getGPGValidList(std::list &ids) #endif /* get from mAuthMgr */ - AuthGPG::getAuthGPG()->getGPGValidList(ids); + AuthPGP::getPgpValidList(ids); return true; } @@ -639,14 +639,14 @@ bool p3Peers::getGPGSignedList(std::list &ids) #endif /* get from mAuthMgr */ - AuthGPG::getAuthGPG()->getGPGSignedList(ids); + AuthPGP::getPgpSignedList(ids); return true; } bool p3Peers::getPgpFriendList(std::vector& pgpIds) { std::list 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 &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 &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& 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 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 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 */ diff --git a/libretroshare/src/rsserver/p3peers.h b/libretroshare/src/rsserver/p3peers.h index c2ff96d10..91630e12d 100644 --- a/libretroshare/src/rsserver/p3peers.h +++ b/libretroshare/src/rsserver/p3peers.h @@ -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; diff --git a/libretroshare/src/rsserver/p3serverconfig.cc b/libretroshare/src/rsserver/p3serverconfig.cc index 6d3343dc7..c50eb2c89 100644 --- a/libretroshare/src/rsserver/p3serverconfig.cc +++ b/libretroshare/src/rsserver/p3serverconfig.cc @@ -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; diff --git a/libretroshare/src/rsserver/rsaccounts.cc b/libretroshare/src/rsserver/rsaccounts.cc index 8be56073c..5d848571a 100644 --- a/libretroshare/src/rsserver/rsaccounts.cc +++ b/libretroshare/src/rsserver/rsaccounts.cc @@ -32,12 +32,12 @@ #include #include - +#include #include #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 +#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::Singleton(env); + + auto& applicationInfoClass = jni::Class::Singleton(env); + + auto getApplicationInfo = + contextClass.GetMethod ()>( + env, "getApplicationInfo" ); + + auto applicationInfo = androidContext.Call(env, getApplicationInfo); + + auto dataDirField = jni::Field( + env, applicationInfoClass, "dataDir" ); + + jni::Local dataDir = applicationInfo.Get( + env, dataDirField ); + + basedir = jni::Make(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 &pgpIds) { - AuthGPG::getAuthGPG()->availableGPGCertificatesWithPrivateKeys(pgpIds); - return 1; +int RsAccountsDetail::GetPGPLogins(std::list& 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::mapexportProfile(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"); diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index 8383a8eda..53d2b3a52 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -32,8 +32,9 @@ #endif #ifdef __ANDROID__ -# include // To install bdboot.txt -# include // for QString::fromStdString(...) +# include +# 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::Singleton(env); + + static auto copyAsset = + assetHelperClass.GetStaticMethod< + jni::jboolean(jni::Object, jni::String, jni::String)>( + env, "copyAsset" ); + + auto androidContext = RetroShareServiceAndroid::getAndroidContext(env); + + jni::jboolean result = assetHelperClass.Call( + env, copyAsset, + androidContext, + jni::Make(env, "values/bdboot.txt"), + jni::Make(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 */ diff --git a/libretroshare/src/rsserver/rsloginhandler.cc b/libretroshare/src/rsserver/rsloginhandler.cc index dbe023235..a0834b0af 100644 --- a/libretroshare/src/rsserver/rsloginhandler.cc +++ b/libretroshare/src/rsserver/rsloginhandler.cc @@ -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 diff --git a/libretroshare/src/serialiser/rsserial.cc b/libretroshare/src/serialiser/rsserial.cc index 52123abf1..4d3cda811 100644 --- a/libretroshare/src/serialiser/rsserial.cc +++ b/libretroshare/src/serialiser/rsserial.cc @@ -3,7 +3,9 @@ * * * libretroshare: retroshare core library * * * - * Copyright 2007-2008 by Robert Fernie * + * Copyright (C) 2007-2008 Robert Fernie * + * Copyright (C) 2021 Gioacchino Mazzurco * + * Copyright (C) 2021 Asociación Civil Altermundi * * * * 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 +#include #include #include #include #include +#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( + (ver << 24) + (std::to_underlying(service) << 8) + subtype )), + _priority_level(prio) {} + uint16_t RsItem::PacketService() const { return (type >> 8) & 0xFFFF; diff --git a/libretroshare/src/services/broadcastdiscoveryservice.cc b/libretroshare/src/services/broadcastdiscoveryservice.cc index 076244b44..380cf8e5d 100644 --- a/libretroshare/src/services/broadcastdiscoveryservice.cc +++ b/libretroshare/src/services/broadcastdiscoveryservice.cc @@ -1,7 +1,8 @@ /******************************************************************************* * RetroShare Broadcast Domain Discovery * * * - * Copyright (C) 2019 Gioacchino Mazzurco * + * Copyright (C) 2019-2021 Gioacchino Mazzurco * + * Copyright (C) 2019-2021 Asociación Civil Altermundi * * * * 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 #include -#ifdef __ANDROID__ -# include -#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("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::Singleton(env); + + auto isHeld = + multicastLockClass.GetMethod( + 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("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::Singleton(env); + + auto acquire = + multicastLockClass.GetMethod( + 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("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::Singleton(env); + + auto release = + multicastLockClass.GetMethod( + 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() ); - 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() ); - 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; + static auto& contextClass = AContext::Singleton(env); + + auto wifiServiceField = jni::StaticField( + env, contextClass, "WIFI_SERVICE"); + + jni::Local WIFI_SERVICE = contextClass.Get( + env, wifiServiceField ); + + auto androidContext = RetroShareServiceAndroid::getAndroidContext(env); + + auto getSystemService = + contextClass.GetMethod (jni::String)>( + env, "getSystemService" ); + + struct WifiManager + { static constexpr auto Name() { return "android/net/wifi/WifiManager"; } }; + + auto& wifiManagerClass = jni::Class::Singleton(env); + + auto wifiManager = jni::Cast( + env, wifiManagerClass, + androidContext.Call(env, getSystemService, WIFI_SERVICE) ); + + auto createMulticastLock = + wifiManagerClass.GetMethod(jni::String)>( + env, "createMulticastLock" ); + + mAndroidWifiMulticastLock = jni::NewGlobal( + env, wifiManager.Call( + env, createMulticastLock, + jni::Make( + env, "RetroShare BroadcastDiscoveryService" ) ) ); + return true; } + #endif // def __ANDROID__ RsBroadcastDiscovery::~RsBroadcastDiscovery() = default; diff --git a/libretroshare/src/services/broadcastdiscoveryservice.h b/libretroshare/src/services/broadcastdiscoveryservice.h index ebbec04c1..f4204c324 100644 --- a/libretroshare/src/services/broadcastdiscoveryservice.h +++ b/libretroshare/src/services/broadcastdiscoveryservice.h @@ -1,7 +1,8 @@ /******************************************************************************* * RetroShare Broadcast Domain Discovery * * * - * Copyright (C) 2019 Gioacchino Mazzurco * + * Copyright (C) 2019-2021 Gioacchino Mazzurco * + * Copyright (C) 2019-2021 Asociación Civil Altermundi * * * * 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 -#ifdef __ANDROID__ -# include -#endif // def __ANDROID__ - #include "retroshare/rsbroadcastdiscovery.h" #include "util/rsthreads.h" #include "util/rsdebug.h" +#ifdef __ANDROID__ +# include +# 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 mDiscoveredData; RsMutex mDiscoveredDataMutex; - RsPeers& mRsPeers; // TODO: std::shared_ptr 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> 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) }; diff --git a/libretroshare/src/services/p3gxsforums.cc b/libretroshare/src/services/p3gxsforums.cc index 6cb3ae5c6..97d880880 100644 --- a/libretroshare/src/services/p3gxsforums.cc +++ b/libretroshare/src/services/p3gxsforums.cc @@ -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 */ diff --git a/libretroshare/src/services/p3gxsforums.h b/libretroshare/src/services/p3gxsforums.h index b499e7b0d..9400de652 100644 --- a/libretroshare/src/services/p3gxsforums.h +++ b/libretroshare/src/services/p3gxsforums.h @@ -175,6 +175,8 @@ public: rs_owner_ptr& resultData, uint32_t& resultSize ) override; #endif + std::error_condition requestSynchronization() override; + /// implementation of rsGxsGorums /// bool getGroupData(const uint32_t &token, std::vector &groups) override; diff --git a/libretroshare/src/services/p3idservice.cc b/libretroshare/src/services/p3idservice.cc index 7182b6a25..bf034bcb2 100644 --- a/libretroshare/src/services/p3idservice.cc +++ b/libretroshare/src/services/p3idservice.cc @@ -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(hash.toByteArray()), hash.SIZE_IN_BYTES, signarray, &sign_size, __PRETTY_FUNCTION__ ) @@ -4096,7 +4096,7 @@ void p3IdService::getPgpIdList() #endif // DEBUG_IDS std::list 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 gpgids; std::list::const_iterator it; - mPgpUtils->getGPGAllList(gpgids); + mPgpUtils->getPgpAllList(gpgids); RsGxsIdGroup id; diff --git a/libretroshare/src/use_libretroshare.pri b/libretroshare/src/use_libretroshare.pri index 0cca29150..7ceda74ba 100644 --- a/libretroshare/src/use_libretroshare.pri +++ b/libretroshare/src/use_libretroshare.pri @@ -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 ############################# diff --git a/libretroshare/src/util/cxx23retrocompat.h b/libretroshare/src/util/cxx23retrocompat.h new file mode 100644 index 000000000..cd96b7cbf --- /dev/null +++ b/libretroshare/src/util/cxx23retrocompat.h @@ -0,0 +1,34 @@ +/******************************************************************************* + * RetroShare C++23 backwards compatibility utilities * + * * + * libretroshare: retroshare core library * + * * + * Copyright (C) 2021 Gioacchino Mazzurco * + * Copyright (C) 2021 Asociación Civil Altermundi * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ +#pragma once + +#include + +#if ! defined(__cpp_lib_to_underlying) +namespace std +{ +template +constexpr underlying_type_t to_underlying(Enum e) noexcept +{ return static_cast>(e); } +} +#endif // ! defined(__cpp_lib_to_underlying) diff --git a/openpgpsdk/CMakeLists.txt b/openpgpsdk/CMakeLists.txt new file mode 100644 index 000000000..32dd86c6a --- /dev/null +++ b/openpgpsdk/CMakeLists.txt @@ -0,0 +1,27 @@ +# RetroShare decentralized communication platform +# +# Copyright (C) 2021 Gioacchino Mazzurco +# Copyright (C) 2021 Asociación Civil Altermundi +# +# 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 ) diff --git a/plugins/VOIP/gui/AudioWizard.cpp b/plugins/VOIP/gui/AudioWizard.cpp index cbf24d9b4..8c0841d1f 100644 --- a/plugins/VOIP/gui/AudioWizard.cpp +++ b/plugins/VOIP/gui/AudioWizard.cpp @@ -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; diff --git a/retroshare-gui/src/gui/MainWindow.cpp b/retroshare-gui/src/gui/MainWindow.cpp index bf5dc6230..207fc5130 100644 --- a/retroshare-gui/src/gui/MainWindow.cpp +++ b/retroshare-gui/src/gui/MainWindow.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -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; +} diff --git a/retroshare-gui/src/gui/MainWindow.h b/retroshare-gui/src/gui/MainWindow.h index e34fda42a..b4f3cccd5 100644 --- a/retroshare-gui/src/gui/MainWindow.h +++ b/retroshare-gui/src/gui/MainWindow.h @@ -21,6 +21,7 @@ #ifndef _MainWindow_H #define _MainWindow_H +#include #include #include @@ -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"); + * 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 *); diff --git a/retroshare-gui/src/gui/Posted/BoardPostDisplayWidget.cpp b/retroshare-gui/src/gui/Posted/BoardPostDisplayWidget.cpp index 241c713d1..da47d7596 100644 --- a/retroshare-gui/src/gui/Posted/BoardPostDisplayWidget.cpp +++ b/retroshare-gui/src/gui/Posted/BoardPostDisplayWidget.cpp @@ -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; } diff --git a/retroshare-gui/src/gui/Posted/BoardPostDisplayWidget.h b/retroshare-gui/src/gui/Posted/BoardPostDisplayWidget.h index a6d4a04d6..189f83ae5 100644 --- a/retroshare-gui/src/gui/Posted/BoardPostDisplayWidget.h +++ b/retroshare-gui/src/gui/Posted/BoardPostDisplayWidget.h @@ -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) ; diff --git a/retroshare-gui/src/gui/Posted/BoardPostDisplayWidget_card.ui b/retroshare-gui/src/gui/Posted/BoardPostDisplayWidget_card.ui index 28ce4fd1d..85eb14906 100644 --- a/retroshare-gui/src/gui/Posted/BoardPostDisplayWidget_card.ui +++ b/retroshare-gui/src/gui/Posted/BoardPostDisplayWidget_card.ui @@ -90,7 +90,10 @@ - + + + 0 + 0 @@ -173,6 +176,13 @@ + + + + Qt::Vertical + + + @@ -277,7 +287,7 @@ - + Qt::Horizontal @@ -340,7 +350,7 @@ - + Qt::Horizontal @@ -401,16 +411,16 @@ :/images/share.png:/images/share.png - - true - Qt::ToolButtonTextBesideIcon + + true + - + Qt::Horizontal @@ -424,10 +434,30 @@ + + + + Qt::Vertical + + + + 0 + 0 + + + + + + + + Qt::Vertical + + + diff --git a/retroshare-gui/src/gui/Posted/BoardPostDisplayWidget_compact.ui b/retroshare-gui/src/gui/Posted/BoardPostDisplayWidget_compact.ui index f27524f08..8c6e89748 100644 --- a/retroshare-gui/src/gui/Posted/BoardPostDisplayWidget_compact.ui +++ b/retroshare-gui/src/gui/Posted/BoardPostDisplayWidget_compact.ui @@ -7,7 +7,7 @@ 0 0 542 - 150 + 151 @@ -90,7 +90,22 @@ - + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + @@ -161,6 +176,13 @@ + + + + Qt::Vertical + + + @@ -287,7 +309,7 @@ - + Qt::Horizontal @@ -305,7 +327,7 @@ - + @@ -400,7 +422,7 @@ - + Qt::Horizontal @@ -414,6 +436,13 @@ + + + + Qt::Vertical + + + @@ -473,6 +502,13 @@ + + + + Qt::Vertical + + + diff --git a/retroshare-gui/src/gui/Posted/PostedCardView.ui b/retroshare-gui/src/gui/Posted/PostedCardView.ui index a55acad24..dba517263 100644 --- a/retroshare-gui/src/gui/Posted/PostedCardView.ui +++ b/retroshare-gui/src/gui/Posted/PostedCardView.ui @@ -7,7 +7,7 @@ 0 0 614 - 182 + 198 @@ -16,7 +16,7 @@ - + 0 @@ -118,7 +118,7 @@ - + 5 @@ -216,7 +216,7 @@ - + Qt::Horizontal @@ -241,30 +241,27 @@ 0 - - - QFrame::NoFrame QFrame::Plain - + 0 - 3 + 0 - 3 + 0 - 3 + 0 - 3 + 0 @@ -337,26 +334,20 @@ - + Qt::Vertical QSizePolicy::Expanding - - - 20 - 5 - - - + @@ -389,7 +380,7 @@ - + Qt::Horizontal @@ -461,7 +452,7 @@ - + 0 @@ -485,7 +476,7 @@ - + Qt::Horizontal @@ -513,9 +504,9 @@ - - + + diff --git a/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.cpp b/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.cpp index 9c08c8169..ce22fa7f3 100644 --- a/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.cpp +++ b/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.cpp @@ -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() diff --git a/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.h b/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.h index a62fe46c6..48ae3cbd4 100644 --- a/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.h +++ b/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.h @@ -52,7 +52,7 @@ private slots: void addPicture(); void on_removeButton_clicked(); void fileHashingFinished(QList hashedFiles); - void reject(); + void reject() override; //QDialog void setPage(int viewMode); private: diff --git a/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.ui b/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.ui index a9ae69b46..a44f226b1 100644 --- a/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.ui +++ b/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.ui @@ -143,7 +143,7 @@ - 1 + 0 diff --git a/retroshare-gui/src/gui/Posted/PostedItem.ui b/retroshare-gui/src/gui/Posted/PostedItem.ui index fc316a632..6c6b290f8 100644 --- a/retroshare-gui/src/gui/Posted/PostedItem.ui +++ b/retroshare-gui/src/gui/Posted/PostedItem.ui @@ -16,7 +16,7 @@ - + 1 @@ -82,21 +82,21 @@ QFrame::Plain - + 0 - 3 + 0 - 3 + 0 - 3 + 0 - 3 + 0 @@ -169,26 +169,20 @@ - + Qt::Vertical QSizePolicy::Expanding - - - 20 - 5 - - - + 9 @@ -233,7 +227,7 @@ - + Qt::Vertical @@ -248,7 +242,7 @@ - + 6 @@ -286,7 +280,7 @@ - + 0 @@ -312,7 +306,7 @@ - + 0 @@ -320,7 +314,7 @@ QLayout::SetDefaultConstraint - + 5 @@ -416,7 +410,7 @@ - + Qt::Horizontal @@ -434,7 +428,7 @@ - + 6 @@ -567,7 +561,7 @@ - + Qt::Horizontal @@ -631,9 +625,9 @@ QFrame::Raised - + - + Qt::Horizontal @@ -659,7 +653,7 @@ - + Qt::Horizontal @@ -685,7 +679,7 @@ QFrame::Sunken - + 3 @@ -726,17 +720,17 @@ + + GxsIdLabel + QLabel +
gui/gxs/GxsIdLabel.h
+
ElidedLabel QLabel
gui/common/ElidedLabel.h
1
- - GxsIdLabel - QLabel -
gui/gxs/GxsIdLabel.h
-
ClickableLabel QLabel diff --git a/retroshare-gui/src/gui/Posted/PostedListWidgetWithModel.cpp b/retroshare-gui/src/gui/Posted/PostedListWidgetWithModel.cpp index 087eebe3c..7dcc767b8 100644 --- a/retroshare-gui/src/gui/Posted/PostedListWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/Posted/PostedListWidgetWithModel.cpp @@ -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() ; - 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() ; - // 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_ptrmPostedEventCode) { - 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;itabWidget->count();++i) - { - auto *t = dynamic_cast(ui->tabWidget->widget(i)); + for(int i=2;itabWidget->count();++i) + { + auto *t = dynamic_cast(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; diff --git a/retroshare-gui/src/gui/Posted/PostedListWidgetWithModel.ui b/retroshare-gui/src/gui/Posted/PostedListWidgetWithModel.ui index 0433fe838..9ed0fc3db 100644 --- a/retroshare-gui/src/gui/Posted/PostedListWidgetWithModel.ui +++ b/retroshare-gui/src/gui/Posted/PostedListWidgetWithModel.ui @@ -251,7 +251,7 @@ p, li { white-space: pre-wrap; } Qt::Vertical - QSizePolicy::Preferred + QSizePolicy::Expanding @@ -310,7 +310,7 @@ p, li { white-space: pre-wrap; } - 11 + 25 75 true true diff --git a/retroshare-gui/src/gui/chat/ChatWidget.cpp b/retroshare-gui/src/gui/chat/ChatWidget.cpp index d4a20fe74..a909e3e27 100644 --- a/retroshare-gui/src/gui/chat/ChatWidget.cpp +++ b/retroshare-gui/src/gui/chat/ChatWidget.cpp @@ -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)) diff --git a/retroshare-gui/src/gui/chat/ChatWidget.ui b/retroshare-gui/src/gui/chat/ChatWidget.ui index 88e501335..879c99d00 100644 --- a/retroshare-gui/src/gui/chat/ChatWidget.ui +++ b/retroshare-gui/src/gui/chat/ChatWidget.ui @@ -32,7 +32,7 @@ QLayout::SetMaximumSize - + 0 @@ -51,7 +51,7 @@ QFrame::Plain - + 2 diff --git a/retroshare-gui/src/gui/common/RSTreeView.cpp b/retroshare-gui/src/gui/common/RSTreeView.cpp index 624021f2f..454ab250e 100644 --- a/retroshare-gui/src/gui/common/RSTreeView.cpp +++ b/retroshare-gui/src/gui/common/RSTreeView.cpp @@ -18,42 +18,73 @@ * * *******************************************************************************/ -#include -#include #include "RSTreeView.h" -RSTreeView::RSTreeView(QWidget *parent) : QTreeView(parent) +#include "util/rsdebug.h" + +#include +#include + +//#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) diff --git a/retroshare-gui/src/gui/common/RSTreeView.h b/retroshare-gui/src/gui/common/RSTreeView.h index 116ccac31..0ccd34134 100644 --- a/retroshare-gui/src/gui/common/RSTreeView.h +++ b/retroshare-gui/src/gui/common/RSTreeView.h @@ -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 diff --git a/retroshare-gui/src/gui/connect/ConnectFriendWizard.cpp b/retroshare-gui/src/gui/connect/ConnectFriendWizard.cpp index c3463a79b..15456bbd5 100755 --- a/retroshare-gui/src/gui/connect/ConnectFriendWizard.cpp +++ b/retroshare-gui/src/gui/connect/ConnectFriendWizard.cpp @@ -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("

" + errorMsg + (certValid ? "\n" + certDetail : "") + "

"); 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); } diff --git a/retroshare-gui/src/gui/connect/ConnectFriendWizard.ui b/retroshare-gui/src/gui/connect/ConnectFriendWizard.ui index f6ac10b5e..65b736762 100644 --- a/retroshare-gui/src/gui/connect/ConnectFriendWizard.ui +++ b/retroshare-gui/src/gui/connect/ConnectFriendWizard.ui @@ -590,7 +590,7 @@
- Email + ProfilId
@@ -629,7 +629,7 @@ - Signers + Signers:
@@ -675,6 +675,16 @@
+ + + + Known IP: + + + + + +
diff --git a/retroshare-gui/src/gui/notifyqt.cpp b/retroshare-gui/src/gui/notifyqt.cpp index 7bb1b6cf2..d0fcea506 100644 --- a/retroshare-gui/src/gui/notifyqt.cpp +++ b/retroshare-gui/src/gui/notifyqt.cpp @@ -21,12 +21,6 @@ #include "gui/common/FilesDefs.h" #include -#include -#include -#include -//#include -#include - #include "notifyqt.h" #include #include @@ -55,6 +49,13 @@ #include "retroshare/rsplugin.h" +#include +#include +#include +//#include +#include +#include + /***** * #define NOTIFY_DEBUG ****/ @@ -223,37 +224,51 @@ bool NotifyQt::askForPassword(const std::string& title, const std::string& key_d { RsAutoUpdatePage::lockAllEvents() ; - QInputDialog dialog; + QString windowTitle; if (title == "") { - dialog.setWindowTitle(tr("Passphrase required")); + windowTitle = tr("Passphrase required"); } else if (title == "AuthSSLimpl::SignX509ReqWithGPG()") { - dialog.setWindowTitle(tr("You need to sign your node's certificate.")); + windowTitle = tr("You need to sign your node's certificate."); } else if (title == "p3IdService::service_CreateGroup()") { - dialog.setWindowTitle(tr("You need to sign your forum/chatrooms identity.")); + windowTitle = tr("You need to sign your forum/chatrooms identity."); } else { - dialog.setWindowTitle(QString::fromStdString(title)); + windowTitle = QString::fromStdString(title); } - dialog.setLabelText((prev_is_bad ? QString("%1

").arg(tr("Wrong password !")) : QString()) + QString("%1
Profile: %2\n").arg(tr("Please enter your Retroshare passphrase"), QString::fromUtf8(key_details.c_str()))); - dialog.setTextEchoMode(QLineEdit::Password); - dialog.setModal(true); + QString labelText = ( prev_is_bad ? QString("%1

").arg(tr("Wrong password !")) : QString() ) + + QString("%1
Profile: %2\n") + .arg( tr("Please enter your Retroshare passphrase") + , QString::fromUtf8(key_details.c_str()) ); + QLineEdit::EchoMode textEchoMode = QLineEdit::Password; + bool modal = true; - int ret = dialog.exec(); + bool sameThread = QThread::currentThread() == qApp->thread(); + Gui_InputDialogReturn ret; + qRegisterMetaType("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) + ); - cancelled = false ; + cancelled = false ; RsAutoUpdatePage::unlockAllEvents() ; - if (ret == QDialog::Rejected) { - password.clear() ; - cancelled = true ; - return true ; - } + if (ret.execReturn == QDialog::Rejected) { + password.clear() ; + cancelled = true ; + return true ; + } - if (ret == QDialog::Accepted) { - password = dialog.textValue().toUtf8().constData(); - return true; - } + if (ret.execReturn == QDialog::Accepted) { + password = ret.textValue.toUtf8().constData(); + return true; + } return false; } diff --git a/retroshare-gui/src/gui/qss/stylesheet/Standard_Dark.qss b/retroshare-gui/src/gui/qss/stylesheet/Standard_Dark.qss index f2097d0be..536a14061 100644 --- a/retroshare-gui/src/gui/qss/stylesheet/Standard_Dark.qss +++ b/retroshare-gui/src/gui/qss/stylesheet/Standard_Dark.qss @@ -2230,6 +2230,15 @@ PlotWidget { /* RetroShare specific part */ /**********************************/ +/**** Fix QPushButton ****/ + +QPushButton, +QPushButton:disabled, +QPushButton:checked { + padding-left: 6px; + padding-right: 6px; +} + /**** Fix QTreeView Items ****/ QTreeView::item, @@ -2248,13 +2257,13 @@ QTreeView:branch:selected:!active { /**** Fix QSplitter ****/ QSplitter { - background-color: #19232D; + background-color: rgba(0,0,0,0); } - QSplitter::handle { - background-color: #455364; - border: 0px solid #455364; - border-radius: 4px; + background-color: rgba(0,0,0,0); + border: 0px; + border-radius: 2px; + padding: 0px; } @@ -2286,7 +2295,7 @@ QFrame#bottomFrame,/* Frame used at the bottom of dialog*/ QFrame#toasterFrame,/* Frame used in Toasters*/ QFrame#toolBarFrame {/* Frame used for buttons*/ background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #19232D, stop:1 #32414B); - border: 1px solid #CCCCCC; + border: 1px solid #455364; } QFrame#toolBarFrame > LineEditClear { background-color: #29333D; @@ -2316,7 +2325,7 @@ QFrame#titleBarFrame { background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #455364, stop: 0.5 #54687A,stop: 0.6 #44586A, stop:1 #455364); border: 0px; } -QFrame[objectName^="#headerBFrame"] { +QFrame[objectName^="headerBFrame"] { border: 1px; border-radius: 4px; } diff --git a/retroshare-gui/src/gui/qss/stylesheet/Standard_Light.qss b/retroshare-gui/src/gui/qss/stylesheet/Standard_Light.qss index 85f601e3e..a7f1e6c8c 100644 --- a/retroshare-gui/src/gui/qss/stylesheet/Standard_Light.qss +++ b/retroshare-gui/src/gui/qss/stylesheet/Standard_Light.qss @@ -2230,6 +2230,15 @@ PlotWidget { /* RetroShare specific part */ /**********************************/ +/**** Fix QPushButton ****/ + +QPushButton, +QPushButton:disabled, +QPushButton:checked { + padding-left: 6px; + padding-right: 6px; +} + /**** Fix QTreeView Items ****/ QTreeView::item, @@ -2248,13 +2257,13 @@ QTreeView:branch:selected:!active { /**** Fix QSplitter ****/ QSplitter { - background-color: white; + background-color: rgba(0,0,0,0); } - QSplitter::handle { - background-color: #C9CDD0; - border: 0px solid #C9CDD0; - border-radius: 4px; + background-color: rgba(0,0,0,0); + border: 0px; + border-radius: 2px; + padding: 0px; } @@ -2307,25 +2316,34 @@ QLabel#avatarLabel{ } -/* HeaderFrame & TitleBarFrame */ +/* HeaderFrame */ QFrame[objectName^="headerFrame"], QFrame[objectName^="headerBFrame"], -QToolBar#headerToolBar, -QFrame#titleBarFrame { +QToolBar#headerToolBar { background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #9BDBF9, stop:1 #1592CD); border: 0px; } -QFrame[objectName^="#headerBFrame"] { +QFrame[objectName^="headerBFrame"] { border: 1px; border-radius: 4px; } QFrame[objectName^="headerFrame"] > *:!hover, -QFrame[objectName^="headerBFrame"] > *:!hover, -QFrame#titleBarFrame > *:!hover { +QFrame[objectName^="headerBFrame"] > *:!hover { background: transparent; color: white; } + +/* TitleBarFrame */ + +QFrame#titleBarFrame { + background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #F0F8FD, stop:1 #E6F2FD); + border: 0px; +} +QFrame#titleBarFrame > *:!hover { + background: transparent; + color: black; +} QFrame#titleBarFrame QComboBox, QFrame#titleBarFrame QLineEdit, QFrame#titleBarFrame QTextEdit { diff --git a/retroshare-gui/src/gui/qss/stylesheet/default.qss b/retroshare-gui/src/gui/qss/stylesheet/default.qss index 40d0b06ea..d1730bfef 100644 --- a/retroshare-gui/src/gui/qss/stylesheet/default.qss +++ b/retroshare-gui/src/gui/qss/stylesheet/default.qss @@ -418,31 +418,3 @@ OpModeStatus[opMode="Minimal"] { [WrongValue="true"] { background-color: #FF8080; } - -/* HeaderFrame & TitleBarFrame */ - -QFrame[objectName^="headerFrame"], -QFrame[objectName^="headerBFrame"] { - background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #9BDBF9, stop:1 #1592CD); - border: 1px; - border-radius: 4px; -} -QFrame[objectName^="#headerBFrame"] { - border: 1px; - border-radius: 4px; -} -QFrame[objectName^="headerFrame"] > *:!hover, -QFrame[objectName^="headerBFrame"] > *:!hover{ - background: transparent; - color: white; -} - -QFrame#toolBarFrame, QFrame#toolBarFrameTop { - background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #FEFEFE, stop:1 #E8E8E8); - border: 1px solid #CCCCCC; -} - -ChatWidget QFrame#titleBarFrame { - background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #FEFEFE, stop:1 #E8E8E8); - border: 1px solid #CCCCCC; -} diff --git a/retroshare-gui/src/main.cpp b/retroshare-gui/src/main.cpp index 56495d592..d8818db0c 100644 --- a/retroshare-gui/src/main.cpp +++ b/retroshare-gui/src/main.cpp @@ -99,10 +99,6 @@ __declspec(dllexport) __cdecl BOOL _OPENSSL_isservice(void) #endif #endif -/*** WINDOWS DON'T LIKE THIS - REDEFINES VER numbers. -#include -****/ - #include #include #include diff --git a/retroshare-gui/src/qss/retroclassic.qss b/retroshare-gui/src/qss/retroclassic.qss new file mode 100644 index 000000000..eb45b3379 --- /dev/null +++ b/retroshare-gui/src/qss/retroclassic.qss @@ -0,0 +1,21 @@ +/* HeaderFrame & TitleBarFrame */ + +QFrame[objectName^="headerFrame"] { + background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #9BDBF9, stop:1 #1592CD); +} +QFrame[objectName^="headerBFrame"] { + background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #9BDBF9, stop:1 #1592CD); + border: 1px; + border-radius: 4px; +} +QFrame[objectName^="headerFrame"] > *:!hover, +QFrame[objectName^="headerBFrame"] > *:!hover{ + background: transparent; + color: white; +} + +QFrame[objectName^="toolBarFrame"], +QFrame[objectName^="toolBarFrameTop"] { + background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #FEFEFE, stop:1 #E8E8E8); + border: 1px solid #CCCCCC; +} diff --git a/retroshare-gui/src/release/skin/Bliss/maxButton.png b/retroshare-gui/src/release/skin/Bliss/maxButton.png deleted file mode 100644 index 4d83bcd35..000000000 Binary files a/retroshare-gui/src/release/skin/Bliss/maxButton.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Bliss/maxButton1.png b/retroshare-gui/src/release/skin/Bliss/maxButton1.png deleted file mode 100644 index a916ba483..000000000 Binary files a/retroshare-gui/src/release/skin/Bliss/maxButton1.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Bliss/maxButton2.png b/retroshare-gui/src/release/skin/Bliss/maxButton2.png deleted file mode 100644 index aaba43674..000000000 Binary files a/retroshare-gui/src/release/skin/Bliss/maxButton2.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Bliss/minButton.png b/retroshare-gui/src/release/skin/Bliss/minButton.png deleted file mode 100644 index 7f1553a6e..000000000 Binary files a/retroshare-gui/src/release/skin/Bliss/minButton.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Bliss/minButton1.png b/retroshare-gui/src/release/skin/Bliss/minButton1.png deleted file mode 100644 index a3c564cdd..000000000 Binary files a/retroshare-gui/src/release/skin/Bliss/minButton1.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Bliss/minButton2.png b/retroshare-gui/src/release/skin/Bliss/minButton2.png deleted file mode 100644 index 01af810b0..000000000 Binary files a/retroshare-gui/src/release/skin/Bliss/minButton2.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Bliss/quiButton.png b/retroshare-gui/src/release/skin/Bliss/quiButton.png deleted file mode 100644 index 6a657ae1a..000000000 Binary files a/retroshare-gui/src/release/skin/Bliss/quiButton.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Bliss/quiButton1.png b/retroshare-gui/src/release/skin/Bliss/quiButton1.png deleted file mode 100644 index 174c7b2ee..000000000 Binary files a/retroshare-gui/src/release/skin/Bliss/quiButton1.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Bliss/quiButton2.png b/retroshare-gui/src/release/skin/Bliss/quiButton2.png deleted file mode 100644 index f379e9431..000000000 Binary files a/retroshare-gui/src/release/skin/Bliss/quiButton2.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Bliss/sl.png b/retroshare-gui/src/release/skin/Bliss/sl.png deleted file mode 100644 index 851821b6a..000000000 Binary files a/retroshare-gui/src/release/skin/Bliss/sl.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Bliss/so.png b/retroshare-gui/src/release/skin/Bliss/so.png deleted file mode 100644 index 6497639b3..000000000 Binary files a/retroshare-gui/src/release/skin/Bliss/so.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Bliss/sr.png b/retroshare-gui/src/release/skin/Bliss/sr.png deleted file mode 100644 index 6689549b3..000000000 Binary files a/retroshare-gui/src/release/skin/Bliss/sr.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Bliss/su.png b/retroshare-gui/src/release/skin/Bliss/su.png deleted file mode 100644 index 9862742f0..000000000 Binary files a/retroshare-gui/src/release/skin/Bliss/su.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Glassy/maxButton.png b/retroshare-gui/src/release/skin/Glassy/maxButton.png deleted file mode 100644 index 469d21e40..000000000 Binary files a/retroshare-gui/src/release/skin/Glassy/maxButton.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Glassy/minButton.png b/retroshare-gui/src/release/skin/Glassy/minButton.png deleted file mode 100644 index 40c6ba78c..000000000 Binary files a/retroshare-gui/src/release/skin/Glassy/minButton.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Glassy/quiButton.png b/retroshare-gui/src/release/skin/Glassy/quiButton.png deleted file mode 100644 index da6390211..000000000 Binary files a/retroshare-gui/src/release/skin/Glassy/quiButton.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Glassy/sl.png b/retroshare-gui/src/release/skin/Glassy/sl.png deleted file mode 100644 index f259a74c7..000000000 Binary files a/retroshare-gui/src/release/skin/Glassy/sl.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Glassy/so.png b/retroshare-gui/src/release/skin/Glassy/so.png deleted file mode 100644 index 9b554663d..000000000 Binary files a/retroshare-gui/src/release/skin/Glassy/so.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Glassy/sr.png b/retroshare-gui/src/release/skin/Glassy/sr.png deleted file mode 100644 index f259a74c7..000000000 Binary files a/retroshare-gui/src/release/skin/Glassy/sr.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Glassy/su.png b/retroshare-gui/src/release/skin/Glassy/su.png deleted file mode 100644 index 0e96fdbed..000000000 Binary files a/retroshare-gui/src/release/skin/Glassy/su.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Green/maxButton.png b/retroshare-gui/src/release/skin/Green/maxButton.png deleted file mode 100644 index 73f1fc27d..000000000 Binary files a/retroshare-gui/src/release/skin/Green/maxButton.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Green/minButton.png b/retroshare-gui/src/release/skin/Green/minButton.png deleted file mode 100644 index 1c9adaa6c..000000000 Binary files a/retroshare-gui/src/release/skin/Green/minButton.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Green/quiButton.png b/retroshare-gui/src/release/skin/Green/quiButton.png deleted file mode 100644 index 6134015ef..000000000 Binary files a/retroshare-gui/src/release/skin/Green/quiButton.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Green/sl.png b/retroshare-gui/src/release/skin/Green/sl.png deleted file mode 100644 index 06af00e82..000000000 Binary files a/retroshare-gui/src/release/skin/Green/sl.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Green/so.png b/retroshare-gui/src/release/skin/Green/so.png deleted file mode 100644 index 661ffd761..000000000 Binary files a/retroshare-gui/src/release/skin/Green/so.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Green/sr.png b/retroshare-gui/src/release/skin/Green/sr.png deleted file mode 100644 index 7f62f1c0b..000000000 Binary files a/retroshare-gui/src/release/skin/Green/sr.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Green/su.png b/retroshare-gui/src/release/skin/Green/su.png deleted file mode 100644 index 8e04d5077..000000000 Binary files a/retroshare-gui/src/release/skin/Green/su.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Night Vision/maxButton.png b/retroshare-gui/src/release/skin/Night Vision/maxButton.png deleted file mode 100644 index cbb27c3cb..000000000 Binary files a/retroshare-gui/src/release/skin/Night Vision/maxButton.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Night Vision/minButton.png b/retroshare-gui/src/release/skin/Night Vision/minButton.png deleted file mode 100644 index 5892a982c..000000000 Binary files a/retroshare-gui/src/release/skin/Night Vision/minButton.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Night Vision/quiButton.png b/retroshare-gui/src/release/skin/Night Vision/quiButton.png deleted file mode 100644 index 1443caa9d..000000000 Binary files a/retroshare-gui/src/release/skin/Night Vision/quiButton.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Night Vision/sl.png b/retroshare-gui/src/release/skin/Night Vision/sl.png deleted file mode 100644 index acc9db3d1..000000000 Binary files a/retroshare-gui/src/release/skin/Night Vision/sl.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Night Vision/so.png b/retroshare-gui/src/release/skin/Night Vision/so.png deleted file mode 100644 index 900e051a9..000000000 Binary files a/retroshare-gui/src/release/skin/Night Vision/so.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Night Vision/sr.png b/retroshare-gui/src/release/skin/Night Vision/sr.png deleted file mode 100644 index 0d0f296ec..000000000 Binary files a/retroshare-gui/src/release/skin/Night Vision/sr.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Night Vision/su.png b/retroshare-gui/src/release/skin/Night Vision/su.png deleted file mode 100644 index 32b195e0d..000000000 Binary files a/retroshare-gui/src/release/skin/Night Vision/su.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Vista/maxButton.png b/retroshare-gui/src/release/skin/Vista/maxButton.png deleted file mode 100644 index cbb27c3cb..000000000 Binary files a/retroshare-gui/src/release/skin/Vista/maxButton.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Vista/maxButton1.png b/retroshare-gui/src/release/skin/Vista/maxButton1.png deleted file mode 100644 index 1bed27a49..000000000 Binary files a/retroshare-gui/src/release/skin/Vista/maxButton1.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Vista/maxButton2.png b/retroshare-gui/src/release/skin/Vista/maxButton2.png deleted file mode 100644 index a9ece6da2..000000000 Binary files a/retroshare-gui/src/release/skin/Vista/maxButton2.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Vista/minButton.png b/retroshare-gui/src/release/skin/Vista/minButton.png deleted file mode 100644 index 5892a982c..000000000 Binary files a/retroshare-gui/src/release/skin/Vista/minButton.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Vista/minButton1.png b/retroshare-gui/src/release/skin/Vista/minButton1.png deleted file mode 100644 index 79207e5df..000000000 Binary files a/retroshare-gui/src/release/skin/Vista/minButton1.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Vista/minButton2.png b/retroshare-gui/src/release/skin/Vista/minButton2.png deleted file mode 100644 index b52bdb299..000000000 Binary files a/retroshare-gui/src/release/skin/Vista/minButton2.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Vista/quiButton.png b/retroshare-gui/src/release/skin/Vista/quiButton.png deleted file mode 100644 index 1443caa9d..000000000 Binary files a/retroshare-gui/src/release/skin/Vista/quiButton.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Vista/quiButton1.png b/retroshare-gui/src/release/skin/Vista/quiButton1.png deleted file mode 100644 index 008b25e2e..000000000 Binary files a/retroshare-gui/src/release/skin/Vista/quiButton1.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Vista/quiButton2.png b/retroshare-gui/src/release/skin/Vista/quiButton2.png deleted file mode 100644 index 3e79d9f08..000000000 Binary files a/retroshare-gui/src/release/skin/Vista/quiButton2.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Vista/sl.png b/retroshare-gui/src/release/skin/Vista/sl.png deleted file mode 100644 index 05628496b..000000000 Binary files a/retroshare-gui/src/release/skin/Vista/sl.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Vista/so.png b/retroshare-gui/src/release/skin/Vista/so.png deleted file mode 100644 index d9472686c..000000000 Binary files a/retroshare-gui/src/release/skin/Vista/so.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Vista/sr.png b/retroshare-gui/src/release/skin/Vista/sr.png deleted file mode 100644 index 60e8e091f..000000000 Binary files a/retroshare-gui/src/release/skin/Vista/sr.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/Vista/su.png b/retroshare-gui/src/release/skin/Vista/su.png deleted file mode 100644 index c62254cfb..000000000 Binary files a/retroshare-gui/src/release/skin/Vista/su.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/VistaAlpha/bg.png b/retroshare-gui/src/release/skin/VistaAlpha/bg.png deleted file mode 100644 index f7ead614a..000000000 Binary files a/retroshare-gui/src/release/skin/VistaAlpha/bg.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/VistaAlpha/maxButton.png b/retroshare-gui/src/release/skin/VistaAlpha/maxButton.png deleted file mode 100644 index bb1c53ee4..000000000 Binary files a/retroshare-gui/src/release/skin/VistaAlpha/maxButton.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/VistaAlpha/maxButton1.png b/retroshare-gui/src/release/skin/VistaAlpha/maxButton1.png deleted file mode 100644 index 1bed27a49..000000000 Binary files a/retroshare-gui/src/release/skin/VistaAlpha/maxButton1.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/VistaAlpha/maxButton2.png b/retroshare-gui/src/release/skin/VistaAlpha/maxButton2.png deleted file mode 100644 index a9ece6da2..000000000 Binary files a/retroshare-gui/src/release/skin/VistaAlpha/maxButton2.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/VistaAlpha/minButton.png b/retroshare-gui/src/release/skin/VistaAlpha/minButton.png deleted file mode 100644 index 379bfa4cb..000000000 Binary files a/retroshare-gui/src/release/skin/VistaAlpha/minButton.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/VistaAlpha/minButton1.png b/retroshare-gui/src/release/skin/VistaAlpha/minButton1.png deleted file mode 100644 index 79207e5df..000000000 Binary files a/retroshare-gui/src/release/skin/VistaAlpha/minButton1.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/VistaAlpha/minButton2.png b/retroshare-gui/src/release/skin/VistaAlpha/minButton2.png deleted file mode 100644 index b52bdb299..000000000 Binary files a/retroshare-gui/src/release/skin/VistaAlpha/minButton2.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/VistaAlpha/quiButton.png b/retroshare-gui/src/release/skin/VistaAlpha/quiButton.png deleted file mode 100644 index e3882e9ff..000000000 Binary files a/retroshare-gui/src/release/skin/VistaAlpha/quiButton.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/VistaAlpha/quiButton1.png b/retroshare-gui/src/release/skin/VistaAlpha/quiButton1.png deleted file mode 100644 index 008b25e2e..000000000 Binary files a/retroshare-gui/src/release/skin/VistaAlpha/quiButton1.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/VistaAlpha/quiButton2.png b/retroshare-gui/src/release/skin/VistaAlpha/quiButton2.png deleted file mode 100644 index 3e79d9f08..000000000 Binary files a/retroshare-gui/src/release/skin/VistaAlpha/quiButton2.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/VistaAlpha/sl.png b/retroshare-gui/src/release/skin/VistaAlpha/sl.png deleted file mode 100644 index 82deb022e..000000000 Binary files a/retroshare-gui/src/release/skin/VistaAlpha/sl.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/VistaAlpha/so.png b/retroshare-gui/src/release/skin/VistaAlpha/so.png deleted file mode 100644 index 677255b01..000000000 Binary files a/retroshare-gui/src/release/skin/VistaAlpha/so.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/VistaAlpha/sr.png b/retroshare-gui/src/release/skin/VistaAlpha/sr.png deleted file mode 100644 index 22f2e74fe..000000000 Binary files a/retroshare-gui/src/release/skin/VistaAlpha/sr.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/VistaAlpha/su.png b/retroshare-gui/src/release/skin/VistaAlpha/su.png deleted file mode 100644 index 6f19cdc00..000000000 Binary files a/retroshare-gui/src/release/skin/VistaAlpha/su.png and /dev/null differ diff --git a/retroshare-gui/src/release/skin/skin.dat b/retroshare-gui/src/release/skin/skin.dat deleted file mode 100644 index 7a501621c..000000000 --- a/retroshare-gui/src/release/skin/skin.dat +++ /dev/null @@ -1,7 +0,0 @@ -[Skin] -Blur=false -Hintergrundfarbe=@Variant(\0\0\0\x43\x1\xff\xff\xd5\xd5\xd5\xd5\xd5\xd5\0\0) -SkinOn=true -Skinpfad=skin/Vista/ -Titelfarbe=@Variant(\0\0\0\x43\x1\xff\xff\0\0\0\0\0\0\0\0) -Titelschrift=@Variant(\0\0\0@\0\0\0\x1a\0\x43\0o\0m\0i\0\x63\0 \0S\0\x61\0n\0s\0 \0M\0S@$\0\0\0\0\0\0\xff\xff\xff\xff\x5\x1\0K\x10) diff --git a/retroshare-gui/src/retroshare-process.nsi b/retroshare-gui/src/retroshare-process.nsi deleted file mode 100644 index 685f90214..000000000 --- a/retroshare-gui/src/retroshare-process.nsi +++ /dev/null @@ -1,502 +0,0 @@ -; Script generated with the Venis Install Wizard & modified by defnax -; This script need the http://nsis.sourceforge.net/Processes_plug-in -; This script need the http://nsis.sourceforge.net/KillProcDLL_plug-in - -; Define your application name -!define APPNAME "RetroShare" -!define VERSION "0.4.13d" -!define APPNAMEANDVERSION "${APPNAME} ${VERSION}" - - -; Main Install settings -Name "${APPNAMEANDVERSION}" -InstallDir "$PROGRAMFILES\RetroShare" -InstallDirRegKey HKLM "Software\${APPNAME}" "" -OutFile "RetroShare_${VERSION}_setup.exe" -BrandingText "${APPNAMEANDVERSION}" -; Use compression -SetCompressor LZMA - -VAR KILLEXENAME - - -; Modern interface settings -!include Sections.nsh -!include "MUI.nsh" - -;Interface Settings -!define MUI_ABORTWARNING -;!define MUI_HEADERIMAGE -;!define MUI_HEADERIMAGE_BITMAP "retroshare.bmp" ; optional - -# MUI defines -!define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\orange-install.ico" -!define MUI_FINISHPAGE_NOAUTOCLOSE -!define MUI_LICENSEPAGE_RADIOBUTTONS -!define MUI_COMPONENTSPAGE_SMALLDESC -!define MUI_FINISHPAGE_LINK "Visit the RetroShare forum for the latest news and support" -!define MUI_FINISHPAGE_LINK_LOCATION "http://retroshare.sourceforge.net/forum/" -!define MUI_FINISHPAGE_RUN "$INSTDIR\RetroShare.exe" -!define MUI_FINISHPAGE_SHOWREADME $INSTDIR\changelog.txt -!define MUI_FINISHPAGE_SHOWREADME_TEXT changelog.txt -!define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED -!define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\orange-uninstall.ico" -!define MUI_UNFINISHPAGE_NOAUTOCLOSE -!define MUI_LANGDLL_REGISTRY_ROOT HKLM -!define MUI_LANGDLL_REGISTRY_KEY ${REGKEY} -!define MUI_LANGDLL_REGISTRY_VALUENAME InstallerLanguage - -; !define MUI_WELCOMEPAGE_TEXT "This wizard will guide you through the installation of RetroShare. \r\n\r\nIt is recommended that you close all other applications before starting Setup. This will make it possible to update relevant system files without havinf to reboot your computer. \r\n\r\nIMPORTANT: Ensure that RetroShare is NOT RUNNING before continuing (you can exit from the taskbar menu), otherwise the installer cannot update the executables, and the installation will fail. \r\n\r\nClick Next to continue. " - -;!define MUI_WELCOMEPAGE_TEXT "This wizard will guide you through the installation of RetroShare. \r\n\r\nIMPORTANT: Ensure that RetroShare is NOT RUNNING before continuing (you can exit from the taskbar menu), otherwise the installer cannot update the executables, and the installation will fail. \r\n\r\nClick Next to continue. " - - -; Defines the un-/installer logo of RetroShare -!insertmacro MUI_DEFAULT MUI_WELCOMEFINISHPAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Wizard\orange.bmp" -!insertmacro MUI_DEFAULT MUI_UNWELCOMEFINISHPAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Wizard\orange-uninstall.bmp" - -; Set languages (first is default language) -!insertmacro MUI_RESERVEFILE_LANGDLL -ReserveFile "${NSISDIR}\Plugins\AdvSplash.dll" - -;-------------------------------- -;Configuration - - - ;!insertmacro MUI_RESERVEFILE_SPECIALBITMAP - - LicenseLangString myLicenseData 1033 "license\license.txt" - LicenseLangString myLicenseData 1031 "license\license-GER.txt" - LicenseLangString myLicenseData 1036 "license\license-FR.txt" - LicenseLangString myLicenseData 1055 "license\license-TR.txt" - LicenseLangString myLicenseData 2052 "license\license.txt" - LicenseLangString myLicenseData 1045 "license\license.txt" - - LicenseData $(myLicenseData) - -# Installer pages -!insertmacro MUI_PAGE_WELCOME -!insertmacro MUI_PAGE_LICENSE "$(myLicenseData)" -!insertmacro MUI_PAGE_COMPONENTS -!insertmacro MUI_PAGE_DIRECTORY -!insertmacro MUI_PAGE_INSTFILES -!insertmacro MUI_PAGE_FINISH -!insertmacro MUI_UNPAGE_CONFIRM -!insertmacro MUI_UNPAGE_INSTFILES - -# Installer languages -!define MUI_LANGDLL_ALLLANGUAGES - -!insertmacro MUI_LANGUAGE English -!insertmacro MUI_LANGUAGE German -!insertmacro MUI_LANGUAGE French -!insertmacro MUI_LANGUAGE Turkish -!insertmacro MUI_LANGUAGE SimpChinese -!insertmacro MUI_LANGUAGE Polish - - ;Component-selection page - ;Titles - - LangString sec_main ${LANG_ENGLISH} "Program Files" - LangString sec_data ${LANG_ENGLISH} "Program Skins" - LangString sec_shortcuts ${LANG_ENGLISH} "Shortcuts" - LangString sec_link ${LANG_ENGLISH} "File Association" - LangString sec_autostart ${LANG_ENGLISH} "Auto Startup" - LangString DESC_sec_main ${LANG_ENGLISH} "Installs the RetroShare program files." - LangString DESC_sec_data ${LANG_ENGLISH} "Installs RetroShare Skins" - LangString DESC_sec_shortcuts ${LANG_ENGLISH} "Create RetroShare shortcut icons." - LangString DESC_sec_link ${LANG_ENGLISH} "Associate RetroShare with .pqi file extension" - LangString DESC_sec_autostart ${LANG_ENGLISH} "Auto-Run and Login at Startup" - LangString LANGUAGEID ${LANG_ENGLISH} "1033" - - LangString sec_main ${LANG_FRENCH} "RetroShare" - LangString sec_data ${LANG_FRENCH} "Programme de Skins" - LangString sec_shortcuts ${LANG_FRENCH} "Raccourcis" - LangString sec_link ${LANG_FRENCH} "RetroShare fichiers Association" - LangString sec_startmenu ${LANG_FRENCH} "Raccourcis du menu Démarrer" - LangString sec_autostart ${LANG_FRENCH} "Démarrage automatique" - LangString DESC_sec_main ${LANG_FRENCH} "Installe les fichiers du programme." - LangString DESC_sec_data ${LANG_FRENCH} "Installe RetroShare Skins" - LangString DESC_sec_startmenu ${LANG_FRENCH} "Crée les raccourcis du menu Démarrer" - LangString DESC_sec_shortcuts ${LANG_FRENCH} "Crée une icône sur le bureau." - LangString DESC_sec_link ${LANG_FRENCH} "Associate RetroShare with .pqi file extension" - LangString DESC_sec_autostart ${LANG_FRENCH} "Run and Auto-connexion au démarrage" - LangString LANGUAGEID ${LANG_FRENCH} "1036" - - LangString sec_main ${LANG_GERMAN} "Programmdateien" - LangString sec_data ${LANG_GERMAN} "Skins f�r das Programm" - LangString sec_shortcuts ${LANG_GERMAN} "Shortcuts" - LangString sec_link ${LANG_GERMAN} "Dateiverkn�pfungen" - LangString sec_autostart ${LANG_GERMAN} "Auto Startup" - LangString DESC_sec_main ${LANG_GERMAN} "Installiert die erforderlichen Programmdateien." - LangString DESC_sec_data ${LANG_GERMAN} "Installiert RetroShare Skins" - LangString DESC_sec_shortcuts ${LANG_GERMAN} "Erstellt eine RetroShare Verkn�pfung im Startmen�, Desktop oder im Schnellstarter." - LangString DESC_sec_link ${LANG_GERMAN} "RetroShare mit .pqi Dateien verkn�pfen" - LangString DESC_sec_autostart ${LANG_GERMAN} "Beim Neustart automatisch RetroShare starten und sich anmelden" - LangString LANGUAGEID ${LANG_GERMAN} "1031" - - LangString sec_main ${LANG_TURKISH} "Program Dosyalar�" - LangString sec_data ${LANG_TURKISH} "Program Skinleri" - LangString sec_shortcuts ${LANG_TURKISH} "Shortcut'lar" - LangString sec_link ${LANG_TURKISH} ".pqi Dosya Kaydet" - LangString sec_autostart ${LANG_TURKISH} "Otomatik calistir ve baglan" - LangString DESC_sec_main ${LANG_TURKISH} "Program dosyalar�n� kurar." - LangString DESC_sec_data ${LANG_TURKISH} "RetroShare Skin'leri kurar" - LangString DESC_sec_shortcuts ${TURKISH} "Shortcut yap Start menu , Desktop veya Quicklaunchbar icin." - LangString DESC_sec_link ${LANG_TURKISH} "RetroShare .pqi almas� i�in kaydettirir" - LangString DESC_sec_autostart ${LANG_TURKISH} "Isletim sistemi acildiginda Otomatik olarak calistir ve baglan" - LangString LANGUAGEID ${LANG_TURKISH} "1055" - - LangString sec_main ${LANG_SIMPCHINESE} "程序文件" - LangString sec_data ${LANG_SIMPCHINESE} "程序皮肤" - LangString sec_shortcuts ${LANG_SIMPCHINESE} "快捷方式" - LangString sec_link ${LANG_SIMPCHINESE} "RetroShare文件关联" - LangString sec_autostart ${LANG_SIMPCHINESE} "自动启动" - LangString DESC_sec_main ${LANG_SIMPCHINESE} "安装RetroShare程序" - LangString DESC_sec_data ${LANG_SIMPCHINESE} "安装RetroShare皮肤" - LangString DESC_sec_shortcuts ${LANG_SIMPCHINESE} "建RetroShare快捷方式" - LangString DESC_sec_link ${LANG_SIMPCHINESE} "关联.pqi扩展名" - LangString DESC_sec_autostart ${LANG_SIMPCHINESE} "启动时自动运行和登录" - LangString LANGUAGEID ${LANG_SIMPCHINESE} "2052" - - LangString sec_main ${LANG_POLISH} "Pliki programu" - LangString sec_data ${LANG_POLISH} "Skórki" - LangString sec_shortcuts ${LANG_POLISH} "Skróty" - LangString sec_link ${LANG_POLISH} "Skojarz pliki" - LangString sec_autostart ${LANG_POLISH} "Automatyczne uruchamianie" - LangString DESC_sec_main ${LANG_POLISH} "Instaluje pliki programu RetroShare" - LangString DESC_sec_data ${LANG_POLISH} "Instaluje skórki programu RetroShare" - LangString DESC_sec_shortcuts ${LANG_POLISH} "Utwórz ikony skrótów na pulpicie, w menu start oraz na pasku szybkiego uruchamiania." - LangString DESC_sec_link ${LANG_POLISH} "Skojarz pliki o rozszerzeniu .pqi z RetroShare" - LangString DESC_sec_autostart ${LANG_POLISH} "Uruchom i zaloguj podczas startu systemu" - LangString LANGUAGEID ${LANG_POLISH} "1045" - - -!insertmacro MUI_RESERVEFILE_INSTALLOPTIONS - -; CloseRetroShare: this will in a loop send the RetroShare window the WM_CLOSE -; message until it does not find a valid RetroShare window -; - -!macro CloseRetroShare UN -Function ${UN}CloseRetroShare - Push $0 - - IntFmt $R4 "%u" 0 - - goto skip - killloop: - DetailPrint "Killing RetroShare" - KillProcDLL::KillProc "RetroShare.exe" - loop: - Sleep 1000 - IntOp $R4 $R4 + 1 - IntCmp $R4 5 done - skip: - DetailPrint "Looking for running copies of RetroShare" - - ;Push "wxWindowClassNR" # the wcn - ;Push "RetroShare" # the known part of the wt - ;Call ${UN}EnhancedFindWindow - ;Pop $0 # will contain the window's handle - ;Pop $1 # will containg the full wcn - # both will containg "failed", if no matching wcn was found - - ;StrCmp $0 "failed" done - ;StrCmp $0 "0" done - ;DetailPrint "Stopping RetroShare" - ;SendMessage $0 16 0 0 # WM_CLOSE == 16 - Goto loop - done: - - IntFmt $R4 "%u" 0 - Processes::FindProcess "RetroShare.exe" - StrCmp $R0 "1" killloop reallydone - - reallydone: - Pop $0 -FunctionEnd -!macroend - - -!macro CheckForIt UN -Function ${UN}CheckForIt - - Processes::FindProcess $KILLEXENAME - StrCmp $R0 "1" foundit didntfindit - - foundit: - MessageBox MB_OKCANCEL "You must quit ${APPNAME} ($KILLEXENAME) \ - before installing this version.$\r$\nPlease quit it and press \ - OK to continue." IDOK tryagain - Abort - - tryagain: - - Sleep 2000 - Processes::FindProcess $KILLEXENAME - StrCmp $R0 "1" stillthere didntfindit - - stillthere: - MessageBox MB_OKCANCEL "There is still a copy of ${APPNAME} \ - ($KILLEXENAME) running.$\r$\nPress OK to force-quit the application, \ - or Cancel to exit." IDOK killit - Abort - - killit: - KillProcDLL::KillProc $KILLEXENAME - Sleep 1000 - - didntfindit: - -FunctionEnd -!macroend - -!macro QuitIt UN -Function ${UN}QuitIt - - # try nicely first - Call ${UN}CloseRetroShare - - # kill all the old ones - StrCpy $KILLEXENAME "RetroShare.exe" - Call ${UN}CheckForIt - StrCpy $KILLEXENAME "" -FunctionEnd -!macroend - - -; This function automatically uninstalls older versions. -; It is largely copied from: -; http://nsis.sourceforge.net/archive/viewpage.php?pageid=326 - - -Section $(sec_main) sec_main - - ;Set Section required - SectionIn RO - - ; Set Section properties - SetOverwrite on - - ; Clears previous error logs - Delete "$INSTDIR\*.log" - - ; Set Section Files and Shortcuts - SetOutPath "$INSTDIR\" - File /r "release\RetroShare.exe" - File /r "D:\Qt\2009.02\mingw\bin\mingwm10.dll" - File /r "D:\Qt\2009.02\qt\bin\QtCore4.dll" - File /r "D:\Qt\2009.02\qt\bin\QtGui4.dll" - File /r "D:\Qt\2009.02\qt\bin\QtNetwork4.dll" - File /r "D:\Qt\2009.02\qt\bin\QtXml4.dll" - File /r "D:\Qt\2009.02\qt\bin\QtScript4.dll" - File /r "pthreadGCE2.dll" - File /r "pthreadGC2d.dll" - File /r "changelog.txt" - - -SectionEnd - -Section $(sec_data) sec_data - - ; Set Section properties - SetOverwrite on - - ; Set Section Files and Shortcuts - SetOutPath "$APPDATA\RetroShare\" - ;File /r "data\*" - - ; We're not ready for external skins... - ; Set Section qss need to remove svn path - SetOutPath "$INSTDIR\qss\" - File /r qss\*.* - - ; Set Section skin - ; SetOutPath "$INSTDIR\skin\" - ; File /r release\skin\*.* - - ; Add emoticons - SetOutPath "$INSTDIR\emoticons\" - File /r emoticons\*.* - - ; Add Chat Style - SetOutPath "$INSTDIR\style\" - File /r style\*.* - -SectionEnd - -Section $(sec_link) sec_link - ; Delete any existing keys - - - ; Write the file association - WriteRegStr HKCR .pqi "" retroshare - WriteRegStr HKCR retroshare "" "PQI File" - WriteRegBin HKCR retroshare EditFlags 00000100 - WriteRegStr HKCR "retroshare\shell" "" open - WriteRegStr HKCR "retroshare\shell\open\command" "" `"$INSTDIR\RetroShare.exe" "%1"` - -SectionEnd - -SectionGroup $(sec_shortcuts) sec_shortcuts -Section StartMenu SEC0001 - - SetOutPath "$INSTDIR" - CreateDirectory "$SMPROGRAMS\${APPNAME}" - CreateShortCut "$SMPROGRAMS\${APPNAME}\$(^UninstallLink).lnk" "$INSTDIR\uninstall.exe" "" "$INSTDIR\uninstall.exe" 0 - CreateShortCut "$SMPROGRAMS\${APPNAME}\${APPNAME}.lnk" "$INSTDIR\RetroShare.exe" "" "$INSTDIR\RetroShare.exe" 0 - -SectionEnd - -Section Desktop SEC0002 - - - CreateShortCut "$DESKTOP\${APPNAME}.lnk" "$INSTDIR\RetroShare.exe" "" "$INSTDIR\RetroShare.exe" 0 - -SectionEnd - -Section Quicklaunchbar SEC0003 - - - CreateShortCut "$QUICKLAUNCH\${APPNAME}.lnk" "$INSTDIR\RetroShare.exe" "" "$INSTDIR\RetroShare.exe" 0 - -SectionEnd -SectionGroupEnd - -;Section $(sec_autostart) sec_autostart - -; WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Run" "RetroRun" "$INSTDIR\${APPNAME}.exe -a" - -;SectionEnd - -Section $(sec_autostart) sec_autostart - - CreateShortCut "$SMSTARTUP\${APPNAME}.lnk" "$INSTDIR\RetroShare.exe" "" "$INSTDIR\RetroShare.exe" 0 -SectionEnd - - -Section -FinishSection - - WriteRegStr HKLM "Software\${APPNAME}" "" "$INSTDIR" - WriteRegStr HKLM "Software\${APPNAME}" "Version" "${VERSION}" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "DisplayName" "${APPNAME}" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "UninstallString" "$INSTDIR\uninstall.exe" - WriteUninstaller "$INSTDIR\uninstall.exe" - -SectionEnd - - - -;-------------------------------- -;Descriptions - -!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN - !insertmacro MUI_DESCRIPTION_TEXT ${sec_main} $(DESC_sec_main) - !insertmacro MUI_DESCRIPTION_TEXT ${sec_data} $(DESC_sec_data) - !insertmacro MUI_DESCRIPTION_TEXT ${sec_shortcuts} $(DESC_sec_shortcuts) - !insertmacro MUI_DESCRIPTION_TEXT ${sec_link} $(DESC_sec_link) - !insertmacro MUI_DESCRIPTION_TEXT ${sec_autostart} $(DESC_sec_autostart) -!insertmacro MUI_FUNCTION_DESCRIPTION_END - - -;!insertmacro EnhancedFindWindow "" -;!insertmacro EnhancedFindWindow "un." - -!insertmacro CloseRetroShare "" -!insertmacro CloseRetroShare "un." - -!insertmacro CheckForIt "" -!insertmacro CheckForIt "un." - -!insertmacro QuitIt "" -!insertmacro QuitIt "un." - -;Uninstall section -Section "Uninstall" - - Call un.QuitIt - - ; Remove file association registry keys - DeleteRegKey HKCR .pqi - DeleteRegKey HKCR retroshare - - ; Remove program/uninstall regsitry keys - DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" - DeleteRegKey HKLM SOFTWARE\${APPNAME} - - DeleteRegValue HKCU "Software\Microsoft\Windows\CurrentVersion\Run" "RetroRun" - - ; Remove files and uninstaller - Delete $INSTDIR\RetroShare.exe - Delete $INSTDIR\*.dll - Delete $INSTDIR\*.dat - Delete $INSTDIR\*.txt - Delete $INSTDIR\*.ini - Delete $INSTDIR\*.log - - Delete $INSTDIR\uninstall.exe - - ; Remove the kadc.ini file. - ; Don't remove the directory, otherwise - ; we lose the XPGP keys. - ; Should make this an option though... - Delete "$APPDATA\${APPNAME}\kadc.ini" - Delete "$APPDATA\${APPNAME}\*.cfg" - Delete "$APPDATA\${APPNAME}\*.conf" - Delete "$APPDATA\${APPNAME}\*.log-save" - Delete "$APPDATA\${APPNAME}\*.log" - Delete "$APPDATA\${APPNAME}\*.failed" - - RMDir /r "$APPDATA\${APPNAME}\cache" - RMDir /r "$APPDATA\${APPNAME}\Partials" - - ; Remove shortcuts, if any - Delete "$SMPROGRAMS\${APPNAME}\*.*" - - ; Remove desktop shortcut - Delete "$DESKTOP\${APPNAME}.lnk" - - ; Remove Quicklaunch shortcut - Delete "$QUICKLAUNCH\${APPNAME}.lnk" - - ; Remove Autstart - Delete "$SMSTARTUP\${APPNAME}.lnk" - - ; Remove directories used - RMDir "$SMPROGRAMS\${APPNAME}" - RMDir /r "$INSTDIR" - RMDir /r "$INSTDIR\qss" - RMDir /r "$INSTDIR\emoticons" - RMDir /r "$INSTDIR\style" - -SectionEnd - -Function .onInit - - InitPluginsDir - Push $R1 - File /oname=$PLUGINSDIR\spltmp.bmp "gui\images\splash.bmp" - advsplash::show 1200 1000 1000 -1 $PLUGINSDIR\spltmp - Pop $R1 - Pop $R1 - !insertmacro MUI_LANGDLL_DISPLAY - -FunctionEnd - - -# Installer Language Strings -# TODO Update the Language Strings with the appropriate translations. - -LangString ^UninstallLink ${LANG_ENGLISH} "Uninstall" -LangString ^UninstallLink ${LANG_GERMAN} "Deinstallieren" -LangString ^UninstallLink ${LANG_TURKISH} "Kald�r" -LangString ^UninstallLink ${LANG_FRENCH} "Désinstaller" -LangString ^UninstallLink ${LANG_SIMPCHINESE} "卸载" -LangString ^UninstallLink ${LANG_POLISH} "Odinstaluj" - - - - - -; eof diff --git a/retroshare-gui/src/retroshare-ultramodern.nsi b/retroshare-gui/src/retroshare-ultramodern.nsi deleted file mode 100644 index d224cc8f1..000000000 --- a/retroshare-gui/src/retroshare-ultramodern.nsi +++ /dev/null @@ -1,501 +0,0 @@ -; Script generated with the Venis Install Wizard & modified by defnax - -; Define your application name -!define APPNAME "RetroShare" -!define VERSION "0.5.1 4049" -!define APPNAMEANDVERSION "${APPNAME} ${VERSION}" -!define QTBASE "D:\qt\2010.01" - -; Main Install settings -Name "${APPNAMEANDVERSION}" -InstallDir "$PROGRAMFILES\RetroShare" -InstallDirRegKey HKLM "Software\${APPNAME}" "" -OutFile "RetroShare_${VERSION}_setup_ultramodern.exe" -BrandingText "${APPNAMEANDVERSION}" -; Use compression -SetCompressor /SOLID LZMA - -; Modern interface settings -!include Sections.nsh -!include "UMUI.nsh" - -;Interface Settings -!define MUI_ABORTWARNING -;!define MUI_HEADERIMAGE -;!define MUI_HEADERIMAGE_BITMAP "retroshare.bmp" ; optional - -# MUI defines -!define MUI_ICON "${NSISDIR}\Contrib\Graphics\UltraModernUI\Icon.ico" -!define MUI_FINISHPAGE_NOAUTOCLOSE -!define MUI_LICENSEPAGE_RADIOBUTTONS -!define MUI_COMPONENTSPAGE_SMALLDESC -!define MUI_FINISHPAGE_LINK "Visit the RetroShare forum for the latest news and support" -!define MUI_FINISHPAGE_LINK_LOCATION "http://retroshare.sourceforge.net/forum/" -!define MUI_FINISHPAGE_RUN "$INSTDIR\RetroShare.exe" -!define MUI_FINISHPAGE_SHOWREADME $INSTDIR\changelog.txt -!define MUI_FINISHPAGE_SHOWREADME_TEXT changelog.txt -!define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED -!define MUI_UNICON "${NSISDIR}\Contrib\Graphics\UltraModernUI\UnIcon.ico" -!define MUI_UNFINISHPAGE_NOAUTOCLOSE -!define MUI_LANGDLL_REGISTRY_ROOT HKLM -!define MUI_LANGDLL_REGISTRY_KEY ${REGKEY} -!define UMUI_LANGDLL_REGISTRY_VALUENAME InstallerLanguage - -;!define MUI_WELCOMEPAGE_TEXT "This wizard will guide you through the installation of RetroShare. \r\n\r\nIt is recommended that you close all other applications before starting Setup. This will make it possible to update relevant system files without havinf to reboot your computer. \r\n\r\nIMPORTANT: Ensure that RetroShare is NOT RUNNING before continuing (you can exit from the taskbar menu), otherwise the installer cannot update the executables, and the installation will fail. \r\n\r\nClick Next to continue. " - -;!define MUI_WELCOMEPAGE_TEXT "This wizard will guide you through the installation of RetroShare. \r\n\r\nIMPORTANT: Ensure that RetroShare is NOT RUNNING before continuing (you can exit from the taskbar menu), otherwise the installer cannot update the executables, and the installation will fail. \r\n\r\nClick Next to continue. " - - -; Defines the un-/installer logo of RetroShare -!insertmacro MUI_DEFAULT MUI_WELCOMEFINISHPAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Wizard\orange.bmp" -!insertmacro MUI_DEFAULT MUI_UNWELCOMEFINISHPAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Wizard\orange-uninstall.bmp" - -; Set languages (first is default language) -!insertmacro MUI_RESERVEFILE_LANGDLL -ReserveFile "${NSISDIR}\Plugins\AdvSplash.dll" - -;-------------------------------- -;Configuration - - - ;!insertmacro MUI_RESERVEFILE_SPECIALBITMAP - - LicenseLangString myLicenseData 1030 "license\license.txt" - LicenseLangString myLicenseData 1033 "license\license.txt" - LicenseLangString myLicenseData 1031 "license\license-GER.txt" - LicenseLangString myLicenseData 1036 "license\license-FR.txt" - LicenseLangString myLicenseData 1055 "license\license-TR.txt" - LicenseLangString myLicenseData 2052 "license\license.txt" - LicenseLangString myLicenseData 1045 "license\license.txt" - LicenseLangString myLicenseData 1041 "license\license.txt" - LicenseLangString myLicenseData 1042 "license\license.txt" - LicenseLangString myLicenseData 1049 "license\license.txt" - LicenseLangString myLicenseData 1053 "license\license.txt" - - LicenseData $(myLicenseData) - -# Installer pages -!insertmacro MUI_PAGE_WELCOME -!insertmacro MUI_PAGE_LICENSE "$(myLicenseData)" -!insertmacro MUI_PAGE_COMPONENTS -!insertmacro MUI_PAGE_DIRECTORY -!insertmacro MUI_PAGE_INSTFILES -!insertmacro MUI_PAGE_FINISH -!insertmacro MUI_UNPAGE_CONFIRM -!insertmacro MUI_UNPAGE_INSTFILES - -# Installer languages -!define MUI_LANGDLL_ALLLANGUAGES - -!insertmacro MUI_LANGUAGE Danish -!insertmacro MUI_LANGUAGE English -!insertmacro MUI_LANGUAGE French -!insertmacro MUI_LANGUAGE German -!insertmacro MUI_LANGUAGE Japanese -!insertmacro MUI_LANGUAGE Korean -!insertmacro MUI_LANGUAGE Polish -!insertmacro MUI_LANGUAGE Russian -!insertmacro MUI_LANGUAGE Swedish -!insertmacro MUI_LANGUAGE SimpChinese -!insertmacro MUI_LANGUAGE Turkish - - - - ;Component-selection page - ;Titles - - LangString sec_main ${LANG_ENGLISH} "Program Files" - LangString sec_data ${LANG_ENGLISH} "Program Skins" - LangString sec_shortcuts ${LANG_ENGLISH} "Shortcuts" - LangString sec_link ${LANG_ENGLISH} "File Association" - LangString sec_autostart ${LANG_ENGLISH} "Auto Startup" - LangString DESC_sec_main ${LANG_ENGLISH} "Installs the RetroShare program files." - LangString DESC_sec_data ${LANG_ENGLISH} "Installs RetroShare Skins" - LangString DESC_sec_shortcuts ${LANG_ENGLISH} "Create RetroShare shortcut icons." - LangString DESC_sec_link ${LANG_ENGLISH} "Associate RetroShare with .rsc file extension" - LangString LANGUAGEID ${LANG_ENGLISH} "1033" - - - LangString sec_main ${LANG_FRENCH} "RetroShare" - LangString sec_data ${LANG_FRENCH} "Programme de Skins" - LangString sec_shortcuts ${LANG_FRENCH} "Raccourcis" - LangString sec_link ${LANG_FRENCH} "RetroShare fichiers Association" - LangString sec_startmenu ${LANG_FRENCH} "Raccourcis du menu Démarrer" - LangString sec_autostart ${LANG_FRENCH} "Démarrage automatique" - LangString DESC_sec_main ${LANG_FRENCH} "Installe les fichiers du programme." - LangString DESC_sec_data ${LANG_FRENCH} "Installe RetroShare Skins" - LangString DESC_sec_startmenu ${LANG_FRENCH} "Crée les raccourcis du menu Démarrer" - LangString DESC_sec_shortcuts ${LANG_FRENCH} "Crée une icône sur le bureau." - LangString DESC_sec_link ${LANG_FRENCH} "Associate RetroShare with .rsc file extension" - LangString LANGUAGEID ${LANG_FRENCH} "1036" - - - LangString sec_main ${LANG_GERMAN} "Programmdateien" - LangString sec_data ${LANG_GERMAN} "Skins fuer das Programm" - LangString sec_shortcuts ${LANG_GERMAN} "Shortcuts" - LangString sec_link ${LANG_GERMAN} "Dateiverknuepfungen" - LangString sec_autostart ${LANG_GERMAN} "Auto Startup" - LangString DESC_sec_main ${LANG_GERMAN} "Installiert die erforderlichen Programmdateien." - LangString DESC_sec_data ${LANG_GERMAN} "Installiert RetroShare Skins" - LangString DESC_sec_shortcuts ${LANG_GERMAN} "Erstellt eine RetroShare Verkn�pfung im Startmen�, Desktop oder im Schnellstarter." - LangString DESC_sec_link ${LANG_GERMAN} "RetroShare mit .rsc Dateien verkn�pfen" - LangString LANGUAGEID ${LANG_GERMAN} "1031" - - LangString sec_main ${LANG_TURKISH} "Program Dosyalar�" - LangString sec_data ${LANG_TURKISH} "Program Skinleri" - LangString sec_shortcuts ${LANG_TURKISH} "Shortcut'lar" - LangString sec_link ${LANG_TURKISH} ".rsc Dosya Kaydet" - LangString sec_autostart ${LANG_TURKISH} "Otomatik calistir ve baglan" - LangString DESC_sec_main ${LANG_TURKISH} "Program dosyalar�n� kurar." - LangString DESC_sec_data ${LANG_TURKISH} "RetroShare Skin'leri kurar" - LangString DESC_sec_shortcuts ${TURKISH} "Shortcut yap Start menu , Desktop veya Quicklaunchbar icin." - LangString DESC_sec_link ${LANG_TURKISH} "RetroShare .rsc almas� i�in kaydettirir" - LangString LANGUAGEID ${LANG_TURKISH} "1055" - - LangString sec_main ${LANG_SIMPCHINESE} "程序文件" - LangString sec_data ${LANG_SIMPCHINESE} "程序皮肤" - LangString sec_shortcuts ${LANG_SIMPCHINESE} "快捷方式" - LangString sec_link ${LANG_SIMPCHINESE} "RetroShare文件关联" - LangString sec_autostart ${LANG_SIMPCHINESE} "自动启动" - LangString DESC_sec_main ${LANG_SIMPCHINESE} "安装RetroShare程序" - LangString DESC_sec_data ${LANG_SIMPCHINESE} "安装RetroShare皮肤" - LangString DESC_sec_shortcuts ${LANG_SIMPCHINESE} "建RetroShare快捷方式" - LangString DESC_sec_link ${LANG_SIMPCHINESE} "关联.rsc扩" - LangString LANGUAGEID ${LANG_SIMPCHINESE} "2052" - - LangString sec_main ${LANG_POLISH} "Pliki programu" - LangString sec_data ${LANG_POLISH} "Skórki" - LangString sec_shortcuts ${LANG_POLISH} "Skróty" - LangString sec_link ${LANG_POLISH} "Skojarz pliki" - LangString sec_autostart ${LANG_POLISH} "Automatyczne uruchamianie" - LangString DESC_sec_main ${LANG_POLISH} "Instaluje pliki programu RetroShare" - LangString DESC_sec_data ${LANG_POLISH} "Instaluje skórki programu RetroShare" - LangString DESC_sec_shortcuts ${LANG_POLISH} "Utwórz ikony skrótów na pulpicie, w menu start oraz na pasku szybkiego uruchamiania." - LangString DESC_sec_link ${LANG_POLISH} "Skojarz pliki o rozszerzeniu .rsc z RetroShare" - LangString LANGUAGEID ${LANG_POLISH} "1045" - - LangString sec_main ${LANG_DANISH} "Program Files" - LangString sec_data ${LANG_DANISH} "Program Skins" - LangString sec_shortcuts ${LANG_DANISH} "Shortcuts" - LangString sec_link ${LANG_DANISH} "File Association" - LangString sec_autostart ${LANG_DANISH} "Auto Startup" - LangString DESC_sec_main ${LANG_DANISH} "Installs the RetroShare program files." - LangString DESC_sec_data ${LANG_DANISH} "Installs RetroShare Skins" - LangString DESC_sec_shortcuts ${LANG_DANISH} "Create RetroShare shortcut icons." - LangString DESC_sec_link ${LANG_DANISH} "Associate RetroShare with .rsc file extension" - LangString LANGUAGEID ${LANG_DANISH} "1030" - - LangString sec_main ${LANG_RUSSIAN} "Program Files" - LangString sec_data ${LANG_RUSSIAN} "Program Skins" - LangString sec_shortcuts ${LANG_RUSSIAN} "Shortcuts" - LangString sec_link ${LANG_RUSSIAN} "File Association" - LangString sec_autostart ${LANG_RUSSIAN} "Auto Startup" - LangString DESC_sec_main ${LANG_RUSSIAN} "Installs the RetroShare program files." - LangString DESC_sec_data ${LANG_RUSSIAN} "Installs RetroShare Skins" - LangString DESC_sec_shortcuts ${LANG_RUSSIAN} "Create RetroShare shortcut icons." - LangString DESC_sec_link ${LANG_RUSSIAN} "Associate RetroShare with .rsc file extension" - LangString LANGUAGEID ${LANG_RUSSIAN} "1049" - - LangString sec_main ${LANG_SWEDISH} "Program Files" - LangString sec_data ${LANG_SWEDISH} "Program Skins" - LangString sec_shortcuts ${LANG_SWEDISH} "Shortcuts" - LangString sec_link ${LANG_SWEDISH} "File Association" - LangString sec_autostart ${LANG_SWEDISH} "Auto Startup" - LangString DESC_sec_main ${LANG_SWEDISH} "Installs the RetroShare program files." - LangString DESC_sec_data ${LANG_SWEDISH} "Installs RetroShare Skins" - LangString DESC_sec_shortcuts ${LANG_SWEDISH} "Create RetroShare shortcut icons." - LangString DESC_sec_link ${LANG_SWEDISH} "Associate RetroShare with .rsc file extension" - LangString LANGUAGEID ${LANG_SWEDISH} "1053" - - LangString sec_main ${LANG_JAPANESE} "Program Files" - LangString sec_data ${LANG_JAPANESE} "Program Skins" - LangString sec_shortcuts ${LANG_JAPANESE} "Shortcuts" - LangString sec_link ${LANG_JAPANESE} "File Association" - LangString sec_autostart ${LANG_JAPANESE} "Auto Startup" - LangString DESC_sec_main ${LANG_JAPANESE} "Installs the RetroShare program files." - LangString DESC_sec_data ${LANG_JAPANESE} "Installs RetroShare Skins" - LangString DESC_sec_shortcuts ${LANG_JAPANESE} "Create RetroShare shortcut icons." - LangString DESC_sec_link ${LANG_JAPANESE} "Associate RetroShare with .rsc file extension" - LangString LANGUAGEID ${LANG_JAPANESE} "1041" - - LangString sec_main ${LANG_KOREAN} "Program Files" - LangString sec_data ${LANG_KOREAN} "Program Skins" - LangString sec_shortcuts ${LANG_KOREAN} "Shortcuts" - LangString sec_link ${LANG_KOREAN} "File Association" - LangString sec_autostart ${LANG_KOREAN} "Auto Startup" - LangString DESC_sec_main ${LANG_KOREAN} "Installs the RetroShare program files." - LangString DESC_sec_data ${LANG_KOREAN} "Installs RetroShare Skins" - LangString DESC_sec_shortcuts ${LANG_KOREAN} "Create RetroShare shortcut icons." - LangString DESC_sec_link ${LANG_KOREAN} "Associate RetroShare with .rsc file extension" - LangString LANGUAGEID ${LANG_KOREAN} "1042" - - -!insertmacro MUI_RESERVEFILE_INSTALLOPTIONS - -Section $(sec_main) sec_main - - ;Set Section required - SectionIn RO - - ; Set Section properties - SetOverwrite on - - ; Clears previous error logs - Delete "$INSTDIR\*.log" - - ; Set Section Files and Shortcuts - SetOutPath "$INSTDIR\" - File /r "release\RetroShare.exe" - File /r "..\..\retroshare-nogui\src\release\retroshare-nogui.exe" - File /r "D:\Qt\2010.01\mingw\bin\mingwm10.dll" - File /r "D:\Qt\2010.01\qt\bin\QtCore4.dll" - File /r "D:\Qt\2010.01\qt\bin\QtGui4.dll" - File /r "D:\Qt\2010.01\qt\bin\QtNetwork4.dll" - File /r "D:\Qt\2010.01\qt\bin\QtXml4.dll" - File /r "D:\Qt\2010.01\qt\bin\QtScript4.dll" - File /r "D:\Qt\2010.01\qt\bin\libgcc_s_dw2-1.dll" - File /r "D:\Qt\2010.01\qt\plugins\imageformats" - File /r "D:\Development\miniupnpc-1.3\miniupnpc.dll" - File /r ${QTBASE}\qt\qt_*.qm - File /r "release\pthreadGC2d.dll" - File /r "release\libgpg-error-0.dll" - File /r "release\libgpgme-11.dll" - File /r "changelog.txt" - File /r /x Data "release\bdboot.txt" - - -SectionEnd - -Section $(sec_data) sec_data - - ; Set Section properties - SetOverwrite on - - ; Set Section Files and Shortcuts - SetOutPath "$APPDATA\RetroShare\" - ;File /r "data\*" - - ; Set Section Plugins - SetOutPath "$APPDATA\RetroShare\plugins\" - ;File /r "plugins\" - - ; Set Section qss and exclude svn - SetOutPath "$INSTDIR\qss\" - File /r /x .svn qss\*.* - - ; Set Section sounds and exclude svn - SetOutPath "$INSTDIR\sounds\" - File /r /x .svn sounds\*.* - - ; Set Section skin - ; SetOutPath "$INSTDIR\skin\" - ; File /r release\skin\*.* - - ; Add emoticons - ;SetOutPath "$INSTDIR\emoticons\" - ;File /r emoticons\*.* - - ; Add Chat Style - ;SetOutPath "$INSTDIR\style\" - ;File /r style\*.* - -SectionEnd - -; These are the programs that are needed by RetroShare. -Section -Prerequisites - SetOutPath $INSTDIR\Prerequisites - MessageBox MB_YESNO "$(InstallGPG4WIN)" /SD IDYES IDNO leave - File "Prerequisites\gpg4win-1.1.4.exe" - ExecWait "$INSTDIR\Prerequisites\gpg4win-1.1.4.exe" - - leave: -SectionEnd - -Section $(sec_link) sec_link - ; Delete any existing keys - - - ; Write the file association - WriteRegStr HKCR .rsc "" retroshare - WriteRegStr HKCR retroshare "" "RSC File" - WriteRegBin HKCR retroshare EditFlags 00000100 - WriteRegStr HKCR "retroshare\shell" "" open - WriteRegStr HKCR "retroshare\shell\open\command" "" `"$INSTDIR\RetroShare.exe" "%1"` - -SectionEnd - -SectionGroup $(sec_shortcuts) sec_shortcuts -Section StartMenu SEC0001 - - SetOutPath "$INSTDIR" - CreateDirectory "$SMPROGRAMS\${APPNAME}" - CreateShortCut "$SMPROGRAMS\${APPNAME}\${APPNAME}.lnk" "$INSTDIR\RetroShare.exe" "" "$INSTDIR\RetroShare.exe" 0 - CreateShortCut "$SMPROGRAMS\${APPNAME}\$(^UninstallLink).lnk" "$INSTDIR\uninstall.exe" "" "$INSTDIR\uninstall.exe" 0 - -SectionEnd - -Section Desktop SEC0002 - - - CreateShortCut "$DESKTOP\${APPNAME}.lnk" "$INSTDIR\RetroShare.exe" "" "$INSTDIR\RetroShare.exe" 0 - -SectionEnd - -Section Quicklaunchbar SEC0003 - - - CreateShortCut "$QUICKLAUNCH\${APPNAME}.lnk" "$INSTDIR\RetroShare.exe" "" "$INSTDIR\RetroShare.exe" 0 - -SectionEnd -SectionGroupEnd - -;Section $(sec_autostart) sec_autostart - -; WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Run" "RetroRun" "$INSTDIR\${APPNAME}.exe -a" - -;SectionEnd - -;Section $(sec_autostart) sec_autostart - -; CreateShortCut "$SMSTARTUP\${APPNAME}.lnk" "$INSTDIR\RetroShare.exe" "" "$INSTDIR\RetroShare.exe" 0 -;SectionEnd - - -Section -FinishSection - - WriteRegStr HKLM "Software\${APPNAME}" "" "$INSTDIR" - WriteRegStr HKLM "Software\${APPNAME}" "Version" "${VERSION}" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "DisplayName" "${APPNAME}" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "UninstallString" "$INSTDIR\uninstall.exe" - WriteUninstaller "$INSTDIR\uninstall.exe" - -SectionEnd - - - -;-------------------------------- -;Descriptions - -!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN - !insertmacro MUI_DESCRIPTION_TEXT ${sec_main} $(DESC_sec_main) - !insertmacro MUI_DESCRIPTION_TEXT ${sec_data} $(DESC_sec_data) - !insertmacro MUI_DESCRIPTION_TEXT ${sec_shortcuts} $(DESC_sec_shortcuts) - !insertmacro MUI_DESCRIPTION_TEXT ${sec_link} $(DESC_sec_link) - ;!insertmacro MUI_DESCRIPTION_TEXT ${sec_autostart} $(DESC_sec_autostart) -!insertmacro MUI_FUNCTION_DESCRIPTION_END - -;Uninstall section -Section "Uninstall" - - ; Remove file association registry keys - DeleteRegKey HKCR .rsc - DeleteRegKey HKCR retroshare - - ; Remove program/uninstall regsitry keys - DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" - DeleteRegKey HKLM SOFTWARE\${APPNAME} - - DeleteRegValue HKCU "Software\Microsoft\Windows\CurrentVersion\Run" "RetroRun" - - ; Remove files and uninstaller - Delete $INSTDIR\RetroShare.exe - Delete $INSTDIR\*.dll - Delete $INSTDIR\*.dat - Delete $INSTDIR\*.txt - Delete $INSTDIR\*.ini - Delete $INSTDIR\*.log - - Delete $INSTDIR\uninstall.exe - - ; Remove the kadc.ini file. - ; Don't remove the directory, otherwise - ; we lose the XPGP keys. - ; Should make this an option though... - Delete "$APPDATA\${APPNAME}\kadc.ini" - Delete "$APPDATA\${APPNAME}\*.cfg" - Delete "$APPDATA\${APPNAME}\*.conf" - Delete "$APPDATA\${APPNAME}\*.log-save" - Delete "$APPDATA\${APPNAME}\*.log" - Delete "$APPDATA\${APPNAME}\*.failed" - - RMDir /r "$APPDATA\${APPNAME}\cache" - RMDir /r "$APPDATA\${APPNAME}\Partials" - - ; Remove shortcuts, if any - Delete "$SMPROGRAMS\${APPNAME}\*.*" - - ; Remove desktop shortcut - Delete "$DESKTOP\${APPNAME}.lnk" - - ; Remove Quicklaunch shortcut - Delete "$QUICKLAUNCH\${APPNAME}.lnk" - - ; Remove Autostart - ;Delete "$SMSTARTUP\${APPNAME}.lnk" - - ; Remove directories used - RMDir "$SMPROGRAMS\${APPNAME}" - RMDir /r "$INSTDIR" - RMDir /r "$INSTDIR\qss" - RMDir /r "$INSTDIR\emoticons" - RMDir /r "$INSTDIR\style" - RMDir /r "$INSTDIR\translations" - -SectionEnd - -Function .onInit - - InitPluginsDir - Push $R1 - File /oname=$PLUGINSDIR\spltmp.bmp "gui\images\splash.bmp" - advsplash::show 1200 1000 1000 -1 $PLUGINSDIR\spltmp - Pop $R1 - Pop $R1 - !insertmacro MUI_LANGDLL_DISPLAY - - - -FunctionEnd - - -# Installer Language Strings -# TODO Update the Language Strings with the appropriate translations. - -LangString InstallGPG4WIN ${LANG_ENGLISH} "Install Gpg4win ? Gpg4win is required for RetroShare!" -LangString InstallGPG4WIN ${LANG_GERMAN} "Installiere Gpg4win ? Gpg4win ist erforderlich fuer RetroShare!" -LangString InstallGPG4WIN ${LANG_TURKISH} "Gpg4win Yükle? Gpg4win RetroShare için gerekli!" -LangString InstallGPG4WIN ${LANG_FRENCH} "RetroShare a besoin de GPG4win pour fonctionner. Lancer l'installation de GPG4win?" -LangString InstallGPG4WIN ${LANG_SIMPCHINESE} "Install Gpg4win ? Gpg4win是需要Retroshare!" -LangString InstallGPG4WIN ${LANG_POLISH} "Install Gpg4win ? Gpg4win wymagane jest Retroshare!" -LangString InstallGPG4WIN ${LANG_DANISH} "Installer Gpg4win? Gpg4win er nødvendig for RetroShare!" -LangString InstallGPG4WIN ${LANG_JAPANESE} "Install Gpg4win ? Gpg4win is required for RetroShare!" -LangString InstallGPG4WIN ${LANG_KOREAN} "Install Gpg4win ? Gpg4win is required for RetroShare!" -LangString InstallGPG4WIN ${LANG_RUSSIAN} "Install Gpg4win ? Gpg4win is required for RetroShare!" -LangString InstallGPG4WIN ${LANG_SWEDISH} "Installera Gpg4win? Gpg4win krävs för RetroShare!" - -LangString FINISHPAGELINK ${LANG_ENGLISH} "Visit the RetroShare forums for the latest news and support" -LangString FINISHPAGELINK ${LANG_GERMAN} "Besuche RetroShare Support Forum " -LangString FINISHPAGELINK ${LANG_TURKISH} "Destek için Retroshare foruma ziyaret" -LangString FINISHPAGELINK ${LANG_FRENCH} "Consultez le forum RetroShare pour vous tenir au courant des dernieres modifications, et obtenir de l'aide." -LangString FINISHPAGELINK ${LANG_SIMPCHINESE} "帮助论坛" -LangString FINISHPAGELINK ${LANG_POLISH} "Odwiedź forum RetroShare do najświeższych informacji i wsparcia" -LangString FINISHPAGELINK ${LANG_DANISH} "Besøg RetroShare fora for de seneste nyheder og støtte" -LangString FINISHPAGELINK ${LANG_JAPANESE} "Visit the RetroShare forums for the latest news and support" -LangString FINISHPAGELINK ${LANG_KOREAN} "Visit the RetroShare forums for the latest news and support" -LangString FINISHPAGELINK ${LANG_RUSSIAN} "Visit the RetroShare forums for the latest news and support" -LangString FINISHPAGELINK ${LANG_SWEDISH} "Besök RetroShare forum för de senaste nyheterna och stöd" - -LangString ^UninstallLink ${LANG_ENGLISH} "Uninstall" -LangString ^UninstallLink ${LANG_GERMAN} "Deinstallieren" -LangString ^UninstallLink ${LANG_TURKISH} "Kald�r" -LangString ^UninstallLink ${LANG_FRENCH} "Désinstaller" -LangString ^UninstallLink ${LANG_SIMPCHINESE} "卸载" -LangString ^UninstallLink ${LANG_POLISH} "Odinstaluj" -LangString ^UninstallLink ${LANG_DANISH} "Afinstaller" -LangString ^UninstallLink ${LANG_JAPANESE} "Uninstall" -LangString ^UninstallLink ${LANG_KOREAN} "Uninstall" -LangString ^UninstallLink ${LANG_RUSSIAN} "Uninstall" -LangString ^UninstallLink ${LANG_SWEDISH} "Avinstallera" - - -; eof diff --git a/retroshare-gui/src/retroshare.in b/retroshare-gui/src/retroshare.in deleted file mode 100644 index 994d26d7c..000000000 --- a/retroshare-gui/src/retroshare.in +++ /dev/null @@ -1,594 +0,0 @@ -; Script generated with the Venis Install Wizard & modified by defnax - -; Define your application name -!define APPNAME "RetroShare" -!define VERSION "0.5.4e" -!define REVISION "$WCREV$" -!define APPNAMEANDVERSION "${APPNAME} ${VERSION} ${REVISION}" -!define QTBASE "d:\qt\2010.05" -!define RSBASE "d:\Development\retroshare\retroshare-gui\" - -; Main Install settings -Name "${APPNAMEANDVERSION}" -InstallDir "$PROGRAMFILES\RetroShare" -InstallDirRegKey HKLM "Software\${APPNAME}" "" -OutFile "RetroShare_${VERSION}_${REVISION}_setup.exe" -BrandingText "${APPNAMEANDVERSION}" -; Use compression -SetCompressor /SOLID LZMA - -; Modern interface settings -!include Sections.nsh -!include "MUI.nsh" - -;Interface Settings -!define MUI_ABORTWARNING -;!define MUI_HEADERIMAGE -;!define MUI_HEADERIMAGE_BITMAP "retroshare.bmp" ; optional - -# MUI defines -!define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\orange-install.ico" -!define MUI_FINISHPAGE_NOAUTOCLOSE -!define MUI_LICENSEPAGE_RADIOBUTTONS -!define MUI_COMPONENTSPAGE_SMALLDESC -!define MUI_FINISHPAGE_LINK "$(FINISHPAGELINK)" -!define MUI_FINISHPAGE_LINK_LOCATION "http://retroshare.sourceforge.net/forum/" -!define MUI_FINISHPAGE_RUN "$INSTDIR\RetroShare.exe" -!define MUI_FINISHPAGE_SHOWREADME $INSTDIR\changelog.txt -!define MUI_FINISHPAGE_SHOWREADME_TEXT changelog.txt -!define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED -!define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\orange-uninstall.ico" -!define MUI_UNFINISHPAGE_NOAUTOCLOSE -!define MUI_LANGDLL_REGISTRY_ROOT HKLM -!define MUI_LANGDLL_REGISTRY_KEY ${REGKEY} -!define MUI_LANGDLL_REGISTRY_VALUENAME InstallerLanguage - -;!define MUI_WELCOMEPAGE_TEXT "This wizard will guide you through the installation of RetroShare. \r\n\r\nIt is recommended that you close all other applications before starting Setup. This will make it possible to update relevant system files without havinf to reboot your computer. \r\n\r\nIMPORTANT: Ensure that RetroShare is NOT RUNNING before continuing (you can exit from the taskbar menu), otherwise the installer cannot update the executables, and the installation will fail. \r\n\r\nClick Next to continue. " - -;!define MUI_WELCOMEPAGE_TEXT "This wizard will guide you through the installation of RetroShare. \r\n\r\nIMPORTANT: Ensure that RetroShare is NOT RUNNING before continuing (you can exit from the taskbar menu), otherwise the installer cannot update the executables, and the installation will fail. \r\n\r\nClick Next to continue. " - - -; Defines the un-/installer logo of RetroShare -!insertmacro MUI_DEFAULT MUI_WELCOMEFINISHPAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Wizard\orange.bmp" -!insertmacro MUI_DEFAULT MUI_UNWELCOMEFINISHPAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Wizard\orange-uninstall.bmp" - -; Set languages (first is default language) -!insertmacro MUI_RESERVEFILE_LANGDLL -ReserveFile "${NSISDIR}\Plugins\AdvSplash.dll" - -;-------------------------------- -;Configuration - - - ;!insertmacro MUI_RESERVEFILE_SPECIALBITMAP - - LicenseLangString myLicenseData 1030 "license\license.txt" - LicenseLangString myLicenseData 1031 "license\license-GER.txt" - LicenseLangString myLicenseData 1032 "license\license-GR.txt" - LicenseLangString myLicenseData 1033 "license\license.txt" - LicenseLangString myLicenseData 1034 "license\license-SP.txt" - LicenseLangString myLicenseData 1036 "license\license-FR.txt" - LicenseLangString myLicenseData 1040 "license\license-IT.txt" - LicenseLangString myLicenseData 1041 "license\license.txt" - LicenseLangString myLicenseData 1042 "license\license.txt" - LicenseLangString myLicenseData 1045 "license\license.txt" - LicenseLangString myLicenseData 1046 "license\license-PT_BR.txt" - LicenseLangString myLicenseData 1049 "license\license.txt" - LicenseLangString myLicenseData 1053 "license\license.txt" - LicenseLangString myLicenseData 1055 "license\license-TR.txt" - LicenseLangString myLicenseData 2052 "license\license.txt" - - LicenseData $(myLicenseData) - -# Installer pages -!insertmacro MUI_PAGE_WELCOME -!insertmacro MUI_PAGE_LICENSE "$(myLicenseData)" -!insertmacro MUI_PAGE_COMPONENTS -!insertmacro MUI_PAGE_DIRECTORY -!insertmacro MUI_PAGE_INSTFILES -!insertmacro MUI_PAGE_FINISH -!insertmacro MUI_UNPAGE_CONFIRM -!insertmacro MUI_UNPAGE_INSTFILES - -# Installer languages -!define MUI_LANGDLL_ALLLANGUAGES - -!insertmacro MUI_LANGUAGE English -!insertmacro MUI_LANGUAGE Danish -!insertmacro MUI_LANGUAGE French -!insertmacro MUI_LANGUAGE German -!insertmacro MUI_LANGUAGE Greek -!insertmacro MUI_LANGUAGE Italian -!insertmacro MUI_LANGUAGE Japanese -!insertmacro MUI_LANGUAGE Korean -!insertmacro MUI_LANGUAGE Polish -!insertmacro MUI_LANGUAGE PortugueseBR -!insertmacro MUI_LANGUAGE Russian -!insertmacro MUI_LANGUAGE Swedish -!insertmacro MUI_LANGUAGE SimpChinese -!insertmacro MUI_LANGUAGE Spanish -!insertmacro MUI_LANGUAGE Turkish - - - ;Component-selection page - ;Titles - - LangString sec_main ${LANG_ENGLISH} "Program Files" - LangString sec_data ${LANG_ENGLISH} "Program Skins" - LangString sec_shortcuts ${LANG_ENGLISH} "Shortcuts" - LangString sec_plugins ${LANG_ENGLISH} "Plugins" - LangString sec_link ${LANG_ENGLISH} "File Association" - LangString sec_autostart ${LANG_ENGLISH} "Auto Startup" - LangString DESC_sec_main ${LANG_ENGLISH} "Installs the RetroShare program files." - LangString DESC_sec_plugins ${LANG_ENGLISH} "Installs the RetroShare plugins." - LangString DESC_sec_data ${LANG_ENGLISH} "Installs RetroShare Skins" - LangString DESC_sec_shortcuts ${LANG_ENGLISH} "Create RetroShare shortcut icons." - LangString DESC_sec_link ${LANG_ENGLISH} "Associate RetroShare with .rsc file extension" - LangString LANGUAGEID ${LANG_ENGLISH} "1033" - - LangString sec_main ${LANG_FRENCH} "RetroShare" - LangString sec_data ${LANG_FRENCH} "Programme de Skins" - LangString sec_plugins ${LANG_FRENCH} "Plugins" - LangString sec_shortcuts ${LANG_FRENCH} "Raccourcis" - LangString sec_link ${LANG_FRENCH} "Association de fichiers" - LangString sec_startmenu ${LANG_FRENCH} "Raccourcis du menu Démarrer" - LangString sec_autostart ${LANG_FRENCH} "Démarrage automatique" - LangString DESC_sec_main ${LANG_FRENCH} "Installation des fichiers du programme." - LangString DESC_sec_data ${LANG_FRENCH} "Installation des Skins de RetroShare" - LangString DESC_sec_plugins ${LANG_FRENCH} "Installation des extensions de RetroShare " - LangString DESC_sec_startmenu ${LANG_FRENCH} "Création des raccourcis du menu Démarrer" - LangString DESC_sec_shortcuts ${LANG_FRENCH} "Création de l'icône sur le bureau." - LangString DESC_sec_link ${LANG_FRENCH} "Associer RetroShare avec l'extension de fichier .rsc" - LangString LANGUAGEID ${LANG_FRENCH} "1036" - - LangString sec_main ${LANG_GERMAN} "Programme" - LangString sec_data ${LANG_GERMAN} "Programm Skins" - LangString sec_plugins ${LANG_GERMAN} "Plug-ins" - LangString sec_shortcuts ${LANG_GERMAN} "Verknüpfungen" - LangString sec_link ${LANG_GERMAN} "Dateiverknüpfungen" - LangString sec_autostart ${LANG_GERMAN} "Autostart" - LangString DESC_sec_main ${LANG_GERMAN} "Installiert die RetroShare Programmdateien." - LangString DESC_sec_data ${LANG_GERMAN} "Installiert RetroShare Skins" - LangString DESC_sec_plugins ${LANG_GERMAN} "Installiert die RetroShare Erweiterungen." - LangString DESC_sec_shortcuts ${LANG_GERMAN} "RetroShare Verknüpfung im Startmenüe, Desktop oder im Schnellstarter erstellen." - LangString DESC_sec_link ${LANG_GERMAN} "RetroShare mit .rsc Dateiendung verknüpfen" - LangString LANGUAGEID ${LANG_GERMAN} "1031" - - LangString sec_main ${LANG_TURKISH} "Program Dosyalar?" - LangString sec_data ${LANG_TURKISH} "Program Skinleri" - LangString sec_shortcuts ${LANG_TURKISH} "Shortcut'lar" - LangString sec_plugins ${LANG_TURKISH} "Eklentiler" - LangString sec_link ${LANG_TURKISH} ".rsc Dosya Kaydet" - LangString sec_autostart ${LANG_TURKISH} "Otomatik calistir ve baglan" - LangString DESC_sec_main ${LANG_TURKISH} "Program dosyalar?n? kurar." - LangString DESC_sec_data ${LANG_TURKISH} "RetroShare Skin'leri kurar" - LangString DESC_sec_plugins ${LANG_TURKISH} "Installs the RetroShare plugins." - LangString DESC_sec_shortcuts ${TURKISH} "Shortcut yap Start menu , Desktop veya Quicklaunchbar icin." - LangString DESC_sec_link ${LANG_TURKISH} "RetroShare .rsc almas? i?in kaydettirir" - LangString LANGUAGEID ${LANG_TURKISH} "1055" - - LangString sec_main ${LANG_SIMPCHINESE} "程序文件" - LangString sec_data ${LANG_SIMPCHINESE} "程序皮肤" - LangString sec_plugins ${LANG_SIMPCHINESE} "Plugins" - LangString sec_shortcuts ${LANG_SIMPCHINESE} "快捷方式" - LangString sec_link ${LANG_SIMPCHINESE} "RetroShare文件关联" - LangString sec_autostart ${LANG_SIMPCHINESE} "自动启动" - LangString DESC_sec_main ${LANG_SIMPCHINESE} "安装RetroShare程序" - LangString DESC_sec_data ${LANG_SIMPCHINESE} "安装RetroShare皮肤" - LangString DESC_sec_plugins ${LANG_SIMPCHINESE} "Installs the RetroShare plugins." - LangString DESC_sec_shortcuts ${LANG_SIMPCHINESE} "建RetroShare快捷方式" - LangString DESC_sec_link ${LANG_SIMPCHINESE} "关联.rsc扩展名" - LangString LANGUAGEID ${LANG_SIMPCHINESE} "2052" - - LangString sec_main ${LANG_POLISH} "Pliki programu" - LangString sec_data ${LANG_POLISH} "Skórki" - LangString sec_plugins ${LANG_POLISH} "Plugins" - LangString sec_shortcuts ${LANG_POLISH} "Skróty" - LangString sec_link ${LANG_POLISH} "Skojarz pliki" - LangString sec_autostart ${LANG_POLISH} "Automatyczne uruchamianie" - LangString DESC_sec_main ${LANG_POLISH} "Instaluje pliki programu RetroShare" - LangString DESC_sec_data ${LANG_POLISH} "Instaluje skórki programu RetroShare" - LangString DESC_sec_plugins ${LANG_POLISH} "Installs the RetroShare plugins." - LangString DESC_sec_shortcuts ${LANG_POLISH} "Utwórz ikony skrótów na pulpicie, w menu start oraz na pasku szybkiego uruchamiania." - LangString DESC_sec_link ${LANG_POLISH} "Skojarz pliki o rozszerzeniu .rsc z RetroShare" - LangString LANGUAGEID ${LANG_POLISH} "1045" - - LangString sec_main ${LANG_DANISH} "Program Files" - LangString sec_data ${LANG_DANISH} "Program Skins" - LangString sec_plugins ${LANG_DANISH} "Plugins" - LangString sec_shortcuts ${LANG_DANISH} "Shortcuts" - LangString sec_link ${LANG_DANISH} "File Association" - LangString sec_autostart ${LANG_DANISH} "Auto Startup" - LangString DESC_sec_main ${LANG_DANISH} "Installs the RetroShare program files." - LangString DESC_sec_data ${LANG_DANISH} "Installs RetroShare Skins" - LangString DESC_sec_plugins ${LANG_DANISH} "Installs the RetroShare plugins." - LangString DESC_sec_shortcuts ${LANG_DANISH} "Create RetroShare shortcut icons." - LangString DESC_sec_link ${LANG_DANISH} "Associate RetroShare with .rsc file extension" - LangString LANGUAGEID ${LANG_DANISH} "1030" - - LangString sec_main ${LANG_RUSSIAN} "Program Files" - LangString sec_data ${LANG_RUSSIAN} "Program Skins" - LangString sec_plugins ${LANG_RUSSIAN} "Plugins" - LangString sec_shortcuts ${LANG_RUSSIAN} "Shortcuts" - LangString sec_link ${LANG_RUSSIAN} "File Association" - LangString sec_autostart ${LANG_RUSSIAN} "Auto Startup" - LangString DESC_sec_main ${LANG_RUSSIAN} "Installs the RetroShare program files." - LangString DESC_sec_data ${LANG_RUSSIAN} "Installs RetroShare Skins" - LangString DESC_sec_plugins ${LANG_RUSSIAN} "Installs the RetroShare plugins." - LangString DESC_sec_shortcuts ${LANG_RUSSIAN} "Create RetroShare shortcut icons." - LangString DESC_sec_link ${LANG_RUSSIAN} "Associate RetroShare with .rsc file extension" - LangString LANGUAGEID ${LANG_RUSSIAN} "1049" - - LangString sec_main ${LANG_SWEDISH} "Program Files" - LangString sec_data ${LANG_SWEDISH} "Program Skins" - LangString sec_plugins ${LANG_SWEDISH} "Plugins" - LangString sec_shortcuts ${LANG_SWEDISH} "Shortcuts" - LangString sec_link ${LANG_SWEDISH} "File Association" - LangString sec_autostart ${LANG_SWEDISH} "Auto Startup" - LangString DESC_sec_main ${LANG_SWEDISH} "Installs the RetroShare program files." - LangString DESC_sec_data ${LANG_SWEDISH} "Installs RetroShare Skins" - LangString DESC_sec_plugins ${LANG_SWEDISH} "Installs the RetroShare plugins." - LangString DESC_sec_shortcuts ${LANG_SWEDISH} "Create RetroShare shortcut icons." - LangString DESC_sec_link ${LANG_SWEDISH} "Associate RetroShare with .rsc file extension" - LangString LANGUAGEID ${LANG_SWEDISH} "1053" - - LangString sec_main ${LANG_SPANISH} "Archivos de programa" - LangString sec_data ${LANG_SPANISH} "Estilos del programa" - LangString sec_plugins ${LANG_SPANISH} "Plugins" - LangString sec_shortcuts ${LANG_SPANISH} "Accesos directos" - LangString sec_link ${LANG_SPANISH} "Asociación de archivos" - LangString sec_autostart ${LANG_SPANISH} "Inicio automático" - LangString DESC_sec_main ${LANG_SPANISH} "Instala los archivos del programa RetroShare." - LangString DESC_sec_data ${LANG_SPANISH} "Instala los estilos para RetroShare" - LangString DESC_sec_plugins ${LANG_SPANISH} "Installs the RetroShare plugins." - LangString DESC_sec_shortcuts ${LANG_SPANISH} "Crear iconos de acceso directo de RetroShare." - LangString DESC_sec_link ${LANG_SPANISH} "Asociar RetroShare con la extensión de archivo .rsc" - LangString LANGUAGEID ${LANG_SPANISH} "1034" - - LangString sec_main ${LANG_ITALIAN} "Programmi" - LangString sec_data ${LANG_ITALIAN} "Temi del Programma" - LangString sec_plugins ${LANG_ITALIAN} "Plugins" - LangString sec_shortcuts ${LANG_ITALIAN} "Icone" - LangString sec_link ${LANG_ITALIAN} "Associazione dei File" - LangString sec_autostart ${LANG_ITALIAN} "Esecuzione Automatica" - LangString DESC_sec_main ${LANG_ITALIAN} "Installare i file programma di RetroShare." - LangString DESC_sec_data ${LANG_ITALIAN} "Installare i temi di RetroShare" - LangString DESC_sec_plugins ${LANG_ITALIAN} "Installs the RetroShare plugins." - LangString DESC_sec_shortcuts ${LANG_ITALIAN} "Creare le icone per avviare RetroShare." - LangString DESC_sec_link ${LANG_ITALIAN} "Associa a RetroShare i file con estensione .rsc" - LangString LANGUAGEID ${LANG_ITALIAN} "1040" - - LangString sec_main ${LANG_GREEK} "Program Files" - LangString sec_data ${LANG_GREEK} "Program Skins" - LangString sec_plugins ${LANG_GREEK} "Plugins" - LangString sec_shortcuts ${LANG_GREEK} "Shortcuts" - LangString sec_link ${LANG_GREEK} "File Association" - LangString sec_autostart ${LANG_GREEK} "Auto Startup" - LangString DESC_sec_main ${LANG_GREEK} "Installs the RetroShare program files." - LangString DESC_sec_data ${LANG_GREEK} "Installs RetroShare Skins" - LangString DESC_sec_plugins ${LANG_GREEK} "Installs the RetroShare plugins." - LangString DESC_sec_shortcuts ${LANG_GREEK} "Create RetroShare shortcut icons." - LangString DESC_sec_link ${LANG_GREEK} "Associate RetroShare with .rsc file extension" - LangString LANGUAGEID ${LANG_GREEK} "1032" - - LangString sec_main ${LANG_PORTUGUESEBR} "Program Files" - LangString sec_data ${LANG_PORTUGUESEBR} "Program Skins" - LangString sec_plugins ${LANG_PORTUGUESEBR} "Plugins" - LangString sec_shortcuts ${LANG_PORTUGUESEBR} "Shortcuts" - LangString sec_link ${LANG_PORTUGUESEBR} "File Association" - LangString sec_autostart ${LANG_PORTUGUESEBR} "Auto Startup" - LangString DESC_sec_main ${LANG_PORTUGUESEBR} "Installs the RetroShare program files." - LangString DESC_sec_data ${LANG_PORTUGUESEBR} "Installs RetroShare Skins" - LangString DESC_sec_plugins ${LANG_PORTUGUESEBR} "Installs the RetroShare plugins." - LangString DESC_sec_shortcuts ${LANG_PORTUGUESEBR} "Create RetroShare shortcut icons." - LangString DESC_sec_link ${LANG_PORTUGUESEBR} "Associate RetroShare with .rsc file extension" - LangString LANGUAGEID ${LANG_PORTUGUESEBR} "1046" - - LangString sec_main ${LANG_JAPANESE} "Program Files" - LangString sec_data ${LANG_JAPANESE} "Program Skins" - LangString sec_plugins ${LANG_JAPANESE} "Plugins" - LangString sec_shortcuts ${LANG_JAPANESE} "Shortcuts" - LangString sec_link ${LANG_JAPANESE} "File Association" - LangString sec_autostart ${LANG_JAPANESE} "Auto Startup" - LangString DESC_sec_main ${LANG_JAPANESE} "Installs the RetroShare program files." - LangString DESC_sec_data ${LANG_JAPANESE} "Installs RetroShare Skins" - LangString DESC_sec_plugins ${LANG_JAPANESE} "Installs the RetroShare plugins." - LangString DESC_sec_shortcuts ${LANG_JAPANESE} "Create RetroShare shortcut icons." - LangString DESC_sec_link ${LANG_JAPANESE} "Associate RetroShare with .rsc file extension" - LangString LANGUAGEID ${LANG_JAPANESE} "1041" - - LangString sec_main ${LANG_KOREAN} "Program Files" - LangString sec_data ${LANG_KOREAN} "Program Skins" - LangString sec_plugins ${LANG_KOREAN} "Plugins" - LangString sec_shortcuts ${LANG_KOREAN} "Shortcuts" - LangString sec_link ${LANG_KOREAN} "File Association" - LangString sec_autostart ${LANG_KOREAN} "Auto Startup" - LangString DESC_sec_main ${LANG_KOREAN} "Installs the RetroShare program files." - LangString DESC_sec_data ${LANG_KOREAN} "Installs RetroShare Skins" - LangString DESC_sec_plugins ${LANG_KOREAN} "Installs the RetroShare plugins." - LangString DESC_sec_shortcuts ${LANG_KOREAN} "Create RetroShare shortcut icons." - LangString DESC_sec_link ${LANG_KOREAN} "Associate RetroShare with .rsc file extension" - LangString LANGUAGEID ${LANG_KOREAN} "1042" - - -!insertmacro MUI_RESERVEFILE_INSTALLOPTIONS - -Section $(sec_main) sec_main - - ;Set Section required - SectionIn RO - - ; Set Section properties - SetOverwrite on - - ; Clears previous error logs - Delete "$INSTDIR\*.log" - - ; Set Section Files and Shortcuts - SetOutPath "$INSTDIR\" - File /r "release\RetroShare.exe" - File /r "..\..\retroshare-nogui\src\release\retroshare-nogui.exe" - File /r "${QTBASE}\mingw\bin\mingwm10.dll" - File /r "${QTBASE}\qt\bin\QtCore4.dll" - File /r "${QTBASE}\qt\bin\QtGui4.dll" - File /r "${QTBASE}\qt\bin\QtNetwork4.dll" - File /r "${QTBASE}\qt\bin\QtMultimedia4.dll" - File /r "${QTBASE}\qt\bin\QtXml4.dll" - File /r "${QTBASE}\qt\bin\QtScript4.dll" - File /r "${QTBASE}\qt\bin\QtSvg4.dll" - File /r "${QTBASE}\qt\bin\libgcc_s_dw2-1.dll" - File /r "${QTBASE}\qt\plugins\imageformats" - File /r ${QTBASE}\qt\qt_*.qm - File /r ${RSBASE}\src\qt_*.qm - File /r "release\pthreadGC2d.dll" - File /r "d:\Development\lib\libminiupnpc-1.3\miniupnpc.dll" - File /r "changelog.txt" - File /r /x Data "release\bdboot.txt" - - -SectionEnd - -Section $(sec_data) sec_data - - ; Set Section properties - SetOverwrite on - - ; Set Section Files and Shortcuts - SetOutPath "$APPDATA\RetroShare\" - ;File /r "data\*" - - ; Set Section qss and exclude svn - SetOutPath "$INSTDIR\qss\" - File /r /x .svn qss\*.* - - ; Set Section sounds and exclude svn - SetOutPath "$INSTDIR\sounds\" - File /r /x .svn sounds\*.* - - ; Set Section skin - ; SetOutPath "$INSTDIR\skin\" - ; File /r release\skin\*.* - - ; Add emoticons - ;SetOutPath "$INSTDIR\emoticons\" - ;File /r emoticons\*.* - - ; Add Chat Style - SetOutPath "$APPDATA\RetroShare\stylesheets\" - File /r gui\qss\chat\Bubble - File /r gui\qss\chat\Bubble_Compact - - -SectionEnd - -SectionGroup $(sec_plugins) sec_plugins -Section Voip SEC001 - - ; Set Section properties - SetOverwrite on - - ; Set Section Plugins - SetOutPath "$APPDATA\RetroShare\extensions\" - - File /r "..\..\plugins\VOIP\release\VOIP.dll" - -SectionEnd - -Section FeedReader SEC002 - - ; Set Section properties - SetOverwrite on - - ; Set Section Plugins - SetOutPath "$APPDATA\RetroShare\extensions\" - - File /r "..\..\plugins\FeedReader\release\FeedReader.dll" - -SectionEnd -SectionGroupEnd - -Section $(sec_link) sec_link - ; Delete any existing keys - - - ; Write the file association - WriteRegStr HKCR .rsc "" retroshare - WriteRegStr HKCR retroshare "" "RSC File" - WriteRegBin HKCR retroshare EditFlags 00000100 - WriteRegStr HKCR "retroshare\shell" "" open - WriteRegStr HKCR "retroshare\shell\open\command" "" `"$INSTDIR\RetroShare.exe" "%1"` - -SectionEnd - -SectionGroup $(sec_shortcuts) sec_shortcuts -Section StartMenu SEC0001 - - SetOutPath "$INSTDIR" - CreateDirectory "$SMPROGRAMS\${APPNAME}" - CreateShortCut "$SMPROGRAMS\${APPNAME}\${APPNAME}.lnk" "$INSTDIR\RetroShare.exe" "" "$INSTDIR\RetroShare.exe" 0 - CreateShortCut "$SMPROGRAMS\${APPNAME}\$(^UninstallLink).lnk" "$INSTDIR\uninstall.exe" "" "$INSTDIR\uninstall.exe" 0 - -SectionEnd - -Section Desktop SEC0002 - - - CreateShortCut "$DESKTOP\${APPNAME}.lnk" "$INSTDIR\RetroShare.exe" "" "$INSTDIR\RetroShare.exe" 0 - -SectionEnd - -Section Quicklaunchbar SEC0003 - - - CreateShortCut "$QUICKLAUNCH\${APPNAME}.lnk" "$INSTDIR\RetroShare.exe" "" "$INSTDIR\RetroShare.exe" 0 - -SectionEnd -SectionGroupEnd - -;Section $(sec_autostart) sec_autostart - -; WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Run" "RetroRun" "$INSTDIR\${APPNAME}.exe -a" - -;SectionEnd - -;Section $(sec_autostart) sec_autostart - -; CreateShortCut "$SMSTARTUP\${APPNAME}.lnk" "$INSTDIR\RetroShare.exe" "" "$INSTDIR\RetroShare.exe" 0 -;SectionEnd - - -Section -FinishSection - - WriteRegStr HKLM "Software\${APPNAME}" "" "$INSTDIR" - WriteRegStr HKLM "Software\${APPNAME}" "Version" "${VERSION}" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "DisplayName" "${APPNAME}" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "UninstallString" "$INSTDIR\uninstall.exe" - WriteUninstaller "$INSTDIR\uninstall.exe" - -SectionEnd - - - -;-------------------------------- -;Descriptions - -!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN - !insertmacro MUI_DESCRIPTION_TEXT ${sec_main} $(DESC_sec_main) - !insertmacro MUI_DESCRIPTION_TEXT ${sec_data} $(DESC_sec_data) - !insertmacro MUI_DESCRIPTION_TEXT ${sec_plugins} $(DESC_sec_plugins) - !insertmacro MUI_DESCRIPTION_TEXT ${sec_shortcuts} $(DESC_sec_shortcuts) - !insertmacro MUI_DESCRIPTION_TEXT ${sec_link} $(DESC_sec_link) - ;!insertmacro MUI_DESCRIPTION_TEXT ${sec_autostart} $(DESC_sec_autostart) -!insertmacro MUI_FUNCTION_DESCRIPTION_END - -;Uninstall section -Section "Uninstall" - - ; Remove file association registry keys - DeleteRegKey HKCR .rsc - DeleteRegKey HKCR retroshare - - ; Remove program/uninstall regsitry keys - DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" - DeleteRegKey HKLM SOFTWARE\${APPNAME} - - DeleteRegValue HKCU "Software\Microsoft\Windows\CurrentVersion\Run" "RetroRun" - - ; Remove files and uninstaller - Delete $INSTDIR\RetroShare.exe - Delete $INSTDIR\*.dll - Delete $INSTDIR\*.dat - Delete $INSTDIR\*.txt - Delete $INSTDIR\*.ini - Delete $INSTDIR\*.log - - Delete $INSTDIR\uninstall.exe - - ; Remove the kadc.ini file. - ; Don't remove the directory, otherwise - ; we lose the XPGP keys. - ; Should make this an option though... - Delete "$APPDATA\${APPNAME}\kadc.ini" - Delete "$APPDATA\${APPNAME}\*.cfg" - Delete "$APPDATA\${APPNAME}\*.conf" - Delete "$APPDATA\${APPNAME}\*.log-save" - Delete "$APPDATA\${APPNAME}\*.log" - Delete "$APPDATA\${APPNAME}\*.failed" - - RMDir /r "$APPDATA\${APPNAME}\cache" - RMDir /r "$APPDATA\${APPNAME}\Partials" - - ; Remove shortcuts, if any - Delete "$SMPROGRAMS\${APPNAME}\*.*" - - ; Remove desktop shortcut - Delete "$DESKTOP\${APPNAME}.lnk" - - ; Remove Quicklaunch shortcut - Delete "$QUICKLAUNCH\${APPNAME}.lnk" - - ; Remove Autostart - ;Delete "$SMSTARTUP\${APPNAME}.lnk" - - ; Remove directories used - RMDir "$SMPROGRAMS\${APPNAME}" - RMDir /r "$INSTDIR" - RMDir /r "$INSTDIR\qss" - RMDir /r "$INSTDIR\emoticons" - RMDir /r "$INSTDIR\style" - RMDir /r "$INSTDIR\translations" - -SectionEnd - -Function .onInit - - InitPluginsDir - Push $R1 - File /oname=$PLUGINSDIR\spltmp.bmp "gui\images\splash.bmp" - advsplash::show 1200 1000 1000 -1 $PLUGINSDIR\spltmp - Pop $R1 - Pop $R1 - !insertmacro MUI_LANGDLL_DISPLAY - - - -FunctionEnd - - -# Installer Language Strings -# TODO Update the Language Strings with the appropriate translations. - - -LangString FINISHPAGELINK ${LANG_ENGLISH} "Visit the RetroShare forums for the latest news and support" -LangString FINISHPAGELINK ${LANG_GERMAN} "Das RetroShare Support-Forum besuchen, um Neuigkeiten und Unterstützung zu erfahren" -LangString FINISHPAGELINK ${LANG_TURKISH} "Destek için Retroshare foruma ziyaret et" -LangString FINISHPAGELINK ${LANG_FRENCH} "Consultez le forum RetroShare pour vous tenir au courant des dernieres modifications, et obtenir de l'aide." -LangString FINISHPAGELINK ${LANG_SIMPCHINESE} "帮助论坛" -LangString FINISHPAGELINK ${LANG_POLISH} "Odwiedź forum RetroShare do najświeższych informacji i wsparcia" -LangString FINISHPAGELINK ${LANG_DANISH} "Besøg RetroShare fora for de seneste nyheder og støtte" -LangString FINISHPAGELINK ${LANG_JAPANESE} "Visit the RetroShare forums for the latest news and support" -LangString FINISHPAGELINK ${LANG_KOREAN} "Visit the RetroShare forums for the latest news and support" -LangString FINISHPAGELINK ${LANG_RUSSIAN} "Visit the RetroShare forums for the latest news and support" -LangString FINISHPAGELINK ${LANG_SWEDISH} "Besök RetroShare forum för de senaste nyheterna och stöd" -LangString FINISHPAGELINK ${LANG_SPANISH} "Visite los foros de RetroShare para las últimas noticias y soporte" -LangString FINISHPAGELINK ${LANG_ITALIAN} "Visita i forum di RetroShare per le ultime novità ed il supporto" -LangString FINISHPAGELINK ${LANG_GREEK} "Visit the RetroShare forums for the latest news and support" -LangString FINISHPAGELINK ${LANG_PORTUGUESEBR} "Visit the RetroShare forums for the latest news and support" - -LangString ^UninstallLink ${LANG_ENGLISH} "Uninstall" -LangString ^UninstallLink ${LANG_GERMAN} "Deinstallieren" -LangString ^UninstallLink ${LANG_TURKISH} "Kald�r" -LangString ^UninstallLink ${LANG_FRENCH} "Désinstaller" -LangString ^UninstallLink ${LANG_SIMPCHINESE} "卸载" -LangString ^UninstallLink ${LANG_POLISH} "Odinstaluj" -LangString ^UninstallLink ${LANG_DANISH} "Afinstaller" -LangString ^UninstallLink ${LANG_JAPANESE} "Uninstall" -LangString ^UninstallLink ${LANG_KOREAN} "Uninstall" -LangString ^UninstallLink ${LANG_RUSSIAN} "Uninstall" -LangString ^UninstallLink ${LANG_SWEDISH} "Avinstallera" -LangString ^UninstallLink ${LANG_SPANISH} "Desinstalar" -LangString ^UninstallLink ${LANG_ITALIAN} "Disinstallare" -LangString ^UninstallLink ${LANG_GREEK} "Απεγκατάσταση" -LangString ^UninstallLink ${LANG_PORTUGUESEBR} "Desinstalar" - -; eof diff --git a/retroshare-gui/src/retroshare.nsi b/retroshare-gui/src/retroshare.nsi deleted file mode 100644 index 9a604b44a..000000000 --- a/retroshare-gui/src/retroshare.nsi +++ /dev/null @@ -1,595 +0,0 @@ -; Script generated with the Venis Install Wizard & modified by defnax - -; Define your application name -!define APPNAME "RetroShare" -!define VERSION "0.5.5a" -!define REVISION "6725" -!define APPNAMEANDVERSION "${APPNAME} ${VERSION} ${REVISION}" -!define QTBASE "h:\qt\2010.05" -!define RSBASE "h:\Development\retroshare\retroshare-gui\" - -; Main Install settings -Name "${APPNAMEANDVERSION}" -InstallDir "$PROGRAMFILES\RetroShare" -InstallDirRegKey HKLM "Software\${APPNAME}" "" -OutFile "RetroShare_${VERSION}_${REVISION}_setup.exe" -BrandingText "${APPNAMEANDVERSION}" -; Use compression -SetCompressor /SOLID LZMA - -; Modern interface settings -!include Sections.nsh -!include "MUI.nsh" - -;Interface Settings -!define MUI_ABORTWARNING -;!define MUI_HEADERIMAGE -;!define MUI_HEADERIMAGE_BITMAP "retroshare.bmp" ; optional - -# MUI defines -!define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\orange-install.ico" -!define MUI_FINISHPAGE_NOAUTOCLOSE -!define MUI_LICENSEPAGE_RADIOBUTTONS -!define MUI_COMPONENTSPAGE_SMALLDESC -!define MUI_FINISHPAGE_LINK "$(FINISHPAGELINK)" -!define MUI_FINISHPAGE_LINK_LOCATION "http://retroshare.sourceforge.net/forum/" -!define MUI_FINISHPAGE_RUN "$INSTDIR\RetroShare.exe" -!define MUI_FINISHPAGE_SHOWREADME $INSTDIR\changelog.txt -!define MUI_FINISHPAGE_SHOWREADME_TEXT changelog.txt -!define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED -!define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\orange-uninstall.ico" -!define MUI_UNFINISHPAGE_NOAUTOCLOSE -!define MUI_LANGDLL_REGISTRY_ROOT HKLM -!define MUI_LANGDLL_REGISTRY_KEY ${REGKEY} -!define MUI_LANGDLL_REGISTRY_VALUENAME InstallerLanguage - -;!define MUI_WELCOMEPAGE_TEXT "This wizard will guide you through the installation of RetroShare. \r\n\r\nIt is recommended that you close all other applications before starting Setup. This will make it possible to update relevant system files without havinf to reboot your computer. \r\n\r\nIMPORTANT: Ensure that RetroShare is NOT RUNNING before continuing (you can exit from the taskbar menu), otherwise the installer cannot update the executables, and the installation will fail. \r\n\r\nClick Next to continue. " - -;!define MUI_WELCOMEPAGE_TEXT "This wizard will guide you through the installation of RetroShare. \r\n\r\nIMPORTANT: Ensure that RetroShare is NOT RUNNING before continuing (you can exit from the taskbar menu), otherwise the installer cannot update the executables, and the installation will fail. \r\n\r\nClick Next to continue. " - - -; Defines the un-/installer logo of RetroShare -!insertmacro MUI_DEFAULT MUI_WELCOMEFINISHPAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Wizard\orange.bmp" -!insertmacro MUI_DEFAULT MUI_UNWELCOMEFINISHPAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Wizard\orange-uninstall.bmp" - -; Set languages (first is default language) -!insertmacro MUI_RESERVEFILE_LANGDLL -ReserveFile "${NSISDIR}\Plugins\AdvSplash.dll" - -;-------------------------------- -;Configuration - - - ;!insertmacro MUI_RESERVEFILE_SPECIALBITMAP - - LicenseLangString myLicenseData 1030 "license\license.txt" - LicenseLangString myLicenseData 1031 "license\license-GER.txt" - LicenseLangString myLicenseData 1032 "license\license-GR.txt" - LicenseLangString myLicenseData 1033 "license\license.txt" - LicenseLangString myLicenseData 1034 "license\license-SP.txt" - LicenseLangString myLicenseData 1036 "license\license-FR.txt" - LicenseLangString myLicenseData 1040 "license\license-IT.txt" - LicenseLangString myLicenseData 1041 "license\license.txt" - LicenseLangString myLicenseData 1042 "license\license.txt" - LicenseLangString myLicenseData 1045 "license\license.txt" - LicenseLangString myLicenseData 1046 "license\license-PT_BR.txt" - LicenseLangString myLicenseData 1049 "license\license.txt" - LicenseLangString myLicenseData 1053 "license\license.txt" - LicenseLangString myLicenseData 1055 "license\license-TR.txt" - LicenseLangString myLicenseData 2052 "license\license.txt" - - LicenseData $(myLicenseData) - -# Installer pages -!insertmacro MUI_PAGE_WELCOME -!insertmacro MUI_PAGE_LICENSE "$(myLicenseData)" -!insertmacro MUI_PAGE_COMPONENTS -!insertmacro MUI_PAGE_DIRECTORY -!insertmacro MUI_PAGE_INSTFILES -!insertmacro MUI_PAGE_FINISH -!insertmacro MUI_UNPAGE_CONFIRM -!insertmacro MUI_UNPAGE_INSTFILES - -# Installer languages -!define MUI_LANGDLL_ALLLANGUAGES - -!insertmacro MUI_LANGUAGE English -!insertmacro MUI_LANGUAGE Danish -!insertmacro MUI_LANGUAGE French -!insertmacro MUI_LANGUAGE German -!insertmacro MUI_LANGUAGE Greek -!insertmacro MUI_LANGUAGE Italian -!insertmacro MUI_LANGUAGE Japanese -!insertmacro MUI_LANGUAGE Korean -!insertmacro MUI_LANGUAGE Polish -!insertmacro MUI_LANGUAGE PortugueseBR -!insertmacro MUI_LANGUAGE Russian -!insertmacro MUI_LANGUAGE Swedish -!insertmacro MUI_LANGUAGE SimpChinese -!insertmacro MUI_LANGUAGE Spanish -!insertmacro MUI_LANGUAGE Turkish - - - ;Component-selection page - ;Titles - - LangString sec_main ${LANG_ENGLISH} "Program Files" - LangString sec_data ${LANG_ENGLISH} "Program Skins" - LangString sec_shortcuts ${LANG_ENGLISH} "Shortcuts" - LangString sec_plugins ${LANG_ENGLISH} "Plugins" - LangString sec_link ${LANG_ENGLISH} "File Association" - LangString sec_autostart ${LANG_ENGLISH} "Auto Startup" - LangString DESC_sec_main ${LANG_ENGLISH} "Installs the RetroShare program files." - LangString DESC_sec_plugins ${LANG_ENGLISH} "Installs the RetroShare plugins." - LangString DESC_sec_data ${LANG_ENGLISH} "Installs RetroShare Skins" - LangString DESC_sec_shortcuts ${LANG_ENGLISH} "Create RetroShare shortcut icons." - LangString DESC_sec_link ${LANG_ENGLISH} "Associate RetroShare with .rsc file extension" - LangString LANGUAGEID ${LANG_ENGLISH} "1033" - - LangString sec_main ${LANG_FRENCH} "RetroShare" - LangString sec_data ${LANG_FRENCH} "Programme de Skins" - LangString sec_plugins ${LANG_FRENCH} "Plugins" - LangString sec_shortcuts ${LANG_FRENCH} "Raccourcis" - LangString sec_link ${LANG_FRENCH} "Association de fichiers" - LangString sec_startmenu ${LANG_FRENCH} "Raccourcis du menu Démarrer" - LangString sec_autostart ${LANG_FRENCH} "Démarrage automatique" - LangString DESC_sec_main ${LANG_FRENCH} "Installation des fichiers du programme." - LangString DESC_sec_data ${LANG_FRENCH} "Installation des Skins de RetroShare" - LangString DESC_sec_plugins ${LANG_FRENCH} "Installation des extensions de RetroShare " - LangString DESC_sec_startmenu ${LANG_FRENCH} "Création des raccourcis du menu Démarrer" - LangString DESC_sec_shortcuts ${LANG_FRENCH} "Création de l'icône sur le bureau." - LangString DESC_sec_link ${LANG_FRENCH} "Associer RetroShare avec l'extension de fichier .rsc" - LangString LANGUAGEID ${LANG_FRENCH} "1036" - - LangString sec_main ${LANG_GERMAN} "Programme" - LangString sec_data ${LANG_GERMAN} "Programm Skins" - LangString sec_plugins ${LANG_GERMAN} "Plug-ins" - LangString sec_shortcuts ${LANG_GERMAN} "Verknüpfungen" - LangString sec_link ${LANG_GERMAN} "Dateiverknüpfungen" - LangString sec_autostart ${LANG_GERMAN} "Autostart" - LangString DESC_sec_main ${LANG_GERMAN} "Installiert die RetroShare Programmdateien." - LangString DESC_sec_data ${LANG_GERMAN} "Installiert RetroShare Skins" - LangString DESC_sec_plugins ${LANG_GERMAN} "Installiert die RetroShare Erweiterungen." - LangString DESC_sec_shortcuts ${LANG_GERMAN} "RetroShare Verknüpfung im Startmenüe, Desktop oder im Schnellstarter erstellen." - LangString DESC_sec_link ${LANG_GERMAN} "RetroShare mit .rsc Dateiendung verknüpfen" - LangString LANGUAGEID ${LANG_GERMAN} "1031" - - LangString sec_main ${LANG_TURKISH} "Program Dosyalar?" - LangString sec_data ${LANG_TURKISH} "Program Skinleri" - LangString sec_shortcuts ${LANG_TURKISH} "Shortcut'lar" - LangString sec_plugins ${LANG_TURKISH} "Eklentiler" - LangString sec_link ${LANG_TURKISH} ".rsc Dosya Kaydet" - LangString sec_autostart ${LANG_TURKISH} "Otomatik calistir ve baglan" - LangString DESC_sec_main ${LANG_TURKISH} "Program dosyalar?n? kurar." - LangString DESC_sec_data ${LANG_TURKISH} "RetroShare Skin'leri kurar" - LangString DESC_sec_plugins ${LANG_TURKISH} "Installs the RetroShare plugins." - LangString DESC_sec_shortcuts ${TURKISH} "Shortcut yap Start menu , Desktop veya Quicklaunchbar icin." - LangString DESC_sec_link ${LANG_TURKISH} "RetroShare .rsc almas? i?in kaydettirir" - LangString LANGUAGEID ${LANG_TURKISH} "1055" - - LangString sec_main ${LANG_SIMPCHINESE} "程序文件" - LangString sec_data ${LANG_SIMPCHINESE} "程序皮肤" - LangString sec_plugins ${LANG_SIMPCHINESE} "Plugins" - LangString sec_shortcuts ${LANG_SIMPCHINESE} "快捷方式" - LangString sec_link ${LANG_SIMPCHINESE} "RetroShare文件关联" - LangString sec_autostart ${LANG_SIMPCHINESE} "自动启动" - LangString DESC_sec_main ${LANG_SIMPCHINESE} "安装RetroShare程序" - LangString DESC_sec_data ${LANG_SIMPCHINESE} "安装RetroShare皮肤" - LangString DESC_sec_plugins ${LANG_SIMPCHINESE} "Installs the RetroShare plugins." - LangString DESC_sec_shortcuts ${LANG_SIMPCHINESE} "建RetroShare快捷方式" - LangString DESC_sec_link ${LANG_SIMPCHINESE} "关联.rsc扩展名" - LangString LANGUAGEID ${LANG_SIMPCHINESE} "2052" - - LangString sec_main ${LANG_POLISH} "Pliki programu" - LangString sec_data ${LANG_POLISH} "Skórki" - LangString sec_plugins ${LANG_POLISH} "Plugins" - LangString sec_shortcuts ${LANG_POLISH} "Skróty" - LangString sec_link ${LANG_POLISH} "Skojarz pliki" - LangString sec_autostart ${LANG_POLISH} "Automatyczne uruchamianie" - LangString DESC_sec_main ${LANG_POLISH} "Instaluje pliki programu RetroShare" - LangString DESC_sec_data ${LANG_POLISH} "Instaluje skórki programu RetroShare" - LangString DESC_sec_plugins ${LANG_POLISH} "Installs the RetroShare plugins." - LangString DESC_sec_shortcuts ${LANG_POLISH} "Utwórz ikony skrótów na pulpicie, w menu start oraz na pasku szybkiego uruchamiania." - LangString DESC_sec_link ${LANG_POLISH} "Skojarz pliki o rozszerzeniu .rsc z RetroShare" - LangString LANGUAGEID ${LANG_POLISH} "1045" - - LangString sec_main ${LANG_DANISH} "Program Files" - LangString sec_data ${LANG_DANISH} "Program Skins" - LangString sec_plugins ${LANG_DANISH} "Plugins" - LangString sec_shortcuts ${LANG_DANISH} "Shortcuts" - LangString sec_link ${LANG_DANISH} "File Association" - LangString sec_autostart ${LANG_DANISH} "Auto Startup" - LangString DESC_sec_main ${LANG_DANISH} "Installs the RetroShare program files." - LangString DESC_sec_data ${LANG_DANISH} "Installs RetroShare Skins" - LangString DESC_sec_plugins ${LANG_DANISH} "Installs the RetroShare plugins." - LangString DESC_sec_shortcuts ${LANG_DANISH} "Create RetroShare shortcut icons." - LangString DESC_sec_link ${LANG_DANISH} "Associate RetroShare with .rsc file extension" - LangString LANGUAGEID ${LANG_DANISH} "1030" - - LangString sec_main ${LANG_RUSSIAN} "Program Files" - LangString sec_data ${LANG_RUSSIAN} "Program Skins" - LangString sec_plugins ${LANG_RUSSIAN} "Plugins" - LangString sec_shortcuts ${LANG_RUSSIAN} "Shortcuts" - LangString sec_link ${LANG_RUSSIAN} "File Association" - LangString sec_autostart ${LANG_RUSSIAN} "Auto Startup" - LangString DESC_sec_main ${LANG_RUSSIAN} "Installs the RetroShare program files." - LangString DESC_sec_data ${LANG_RUSSIAN} "Installs RetroShare Skins" - LangString DESC_sec_plugins ${LANG_RUSSIAN} "Installs the RetroShare plugins." - LangString DESC_sec_shortcuts ${LANG_RUSSIAN} "Create RetroShare shortcut icons." - LangString DESC_sec_link ${LANG_RUSSIAN} "Associate RetroShare with .rsc file extension" - LangString LANGUAGEID ${LANG_RUSSIAN} "1049" - - LangString sec_main ${LANG_SWEDISH} "Program Files" - LangString sec_data ${LANG_SWEDISH} "Program Skins" - LangString sec_plugins ${LANG_SWEDISH} "Plugins" - LangString sec_shortcuts ${LANG_SWEDISH} "Shortcuts" - LangString sec_link ${LANG_SWEDISH} "File Association" - LangString sec_autostart ${LANG_SWEDISH} "Auto Startup" - LangString DESC_sec_main ${LANG_SWEDISH} "Installs the RetroShare program files." - LangString DESC_sec_data ${LANG_SWEDISH} "Installs RetroShare Skins" - LangString DESC_sec_plugins ${LANG_SWEDISH} "Installs the RetroShare plugins." - LangString DESC_sec_shortcuts ${LANG_SWEDISH} "Create RetroShare shortcut icons." - LangString DESC_sec_link ${LANG_SWEDISH} "Associate RetroShare with .rsc file extension" - LangString LANGUAGEID ${LANG_SWEDISH} "1053" - - LangString sec_main ${LANG_SPANISH} "Archivos de programa" - LangString sec_data ${LANG_SPANISH} "Estilos del programa" - LangString sec_plugins ${LANG_SPANISH} "Plugins" - LangString sec_shortcuts ${LANG_SPANISH} "Accesos directos" - LangString sec_link ${LANG_SPANISH} "Asociación de archivos" - LangString sec_autostart ${LANG_SPANISH} "Inicio automático" - LangString DESC_sec_main ${LANG_SPANISH} "Instala los archivos del programa RetroShare." - LangString DESC_sec_data ${LANG_SPANISH} "Instala los estilos para RetroShare" - LangString DESC_sec_plugins ${LANG_SPANISH} "Installs the RetroShare plugins." - LangString DESC_sec_shortcuts ${LANG_SPANISH} "Crear iconos de acceso directo de RetroShare." - LangString DESC_sec_link ${LANG_SPANISH} "Asociar RetroShare con la extensión de archivo .rsc" - LangString LANGUAGEID ${LANG_SPANISH} "1034" - - LangString sec_main ${LANG_ITALIAN} "Programmi" - LangString sec_data ${LANG_ITALIAN} "Temi del Programma" - LangString sec_plugins ${LANG_ITALIAN} "Plugins" - LangString sec_shortcuts ${LANG_ITALIAN} "Icone" - LangString sec_link ${LANG_ITALIAN} "Associazione dei File" - LangString sec_autostart ${LANG_ITALIAN} "Esecuzione Automatica" - LangString DESC_sec_main ${LANG_ITALIAN} "Installare i file programma di RetroShare." - LangString DESC_sec_data ${LANG_ITALIAN} "Installare i temi di RetroShare" - LangString DESC_sec_plugins ${LANG_ITALIAN} "Installs the RetroShare plugins." - LangString DESC_sec_shortcuts ${LANG_ITALIAN} "Creare le icone per avviare RetroShare." - LangString DESC_sec_link ${LANG_ITALIAN} "Associa a RetroShare i file con estensione .rsc" - LangString LANGUAGEID ${LANG_ITALIAN} "1040" - - LangString sec_main ${LANG_GREEK} "Program Files" - LangString sec_data ${LANG_GREEK} "Program Skins" - LangString sec_plugins ${LANG_GREEK} "Plugins" - LangString sec_shortcuts ${LANG_GREEK} "Shortcuts" - LangString sec_link ${LANG_GREEK} "File Association" - LangString sec_autostart ${LANG_GREEK} "Auto Startup" - LangString DESC_sec_main ${LANG_GREEK} "Installs the RetroShare program files." - LangString DESC_sec_data ${LANG_GREEK} "Installs RetroShare Skins" - LangString DESC_sec_plugins ${LANG_GREEK} "Installs the RetroShare plugins." - LangString DESC_sec_shortcuts ${LANG_GREEK} "Create RetroShare shortcut icons." - LangString DESC_sec_link ${LANG_GREEK} "Associate RetroShare with .rsc file extension" - LangString LANGUAGEID ${LANG_GREEK} "1032" - - LangString sec_main ${LANG_PORTUGUESEBR} "Program Files" - LangString sec_data ${LANG_PORTUGUESEBR} "Program Skins" - LangString sec_plugins ${LANG_PORTUGUESEBR} "Plugins" - LangString sec_shortcuts ${LANG_PORTUGUESEBR} "Shortcuts" - LangString sec_link ${LANG_PORTUGUESEBR} "File Association" - LangString sec_autostart ${LANG_PORTUGUESEBR} "Auto Startup" - LangString DESC_sec_main ${LANG_PORTUGUESEBR} "Installs the RetroShare program files." - LangString DESC_sec_data ${LANG_PORTUGUESEBR} "Installs RetroShare Skins" - LangString DESC_sec_plugins ${LANG_PORTUGUESEBR} "Installs the RetroShare plugins." - LangString DESC_sec_shortcuts ${LANG_PORTUGUESEBR} "Create RetroShare shortcut icons." - LangString DESC_sec_link ${LANG_PORTUGUESEBR} "Associate RetroShare with .rsc file extension" - LangString LANGUAGEID ${LANG_PORTUGUESEBR} "1046" - - LangString sec_main ${LANG_JAPANESE} "Program Files" - LangString sec_data ${LANG_JAPANESE} "Program Skins" - LangString sec_plugins ${LANG_JAPANESE} "Plugins" - LangString sec_shortcuts ${LANG_JAPANESE} "Shortcuts" - LangString sec_link ${LANG_JAPANESE} "File Association" - LangString sec_autostart ${LANG_JAPANESE} "Auto Startup" - LangString DESC_sec_main ${LANG_JAPANESE} "Installs the RetroShare program files." - LangString DESC_sec_data ${LANG_JAPANESE} "Installs RetroShare Skins" - LangString DESC_sec_plugins ${LANG_JAPANESE} "Installs the RetroShare plugins." - LangString DESC_sec_shortcuts ${LANG_JAPANESE} "Create RetroShare shortcut icons." - LangString DESC_sec_link ${LANG_JAPANESE} "Associate RetroShare with .rsc file extension" - LangString LANGUAGEID ${LANG_JAPANESE} "1041" - - LangString sec_main ${LANG_KOREAN} "Program Files" - LangString sec_data ${LANG_KOREAN} "Program Skins" - LangString sec_plugins ${LANG_KOREAN} "Plugins" - LangString sec_shortcuts ${LANG_KOREAN} "Shortcuts" - LangString sec_link ${LANG_KOREAN} "File Association" - LangString sec_autostart ${LANG_KOREAN} "Auto Startup" - LangString DESC_sec_main ${LANG_KOREAN} "Installs the RetroShare program files." - LangString DESC_sec_data ${LANG_KOREAN} "Installs RetroShare Skins" - LangString DESC_sec_plugins ${LANG_KOREAN} "Installs the RetroShare plugins." - LangString DESC_sec_shortcuts ${LANG_KOREAN} "Create RetroShare shortcut icons." - LangString DESC_sec_link ${LANG_KOREAN} "Associate RetroShare with .rsc file extension" - LangString LANGUAGEID ${LANG_KOREAN} "1042" - - -!insertmacro MUI_RESERVEFILE_INSTALLOPTIONS - -Section $(sec_main) sec_main - - ;Set Section required - SectionIn RO - - ; Set Section properties - SetOverwrite on - - ; Clears previous error logs - Delete "$INSTDIR\*.log" - - ; Set Section Files and Shortcuts - SetOutPath "$INSTDIR\" - File /r "release\RetroShare.exe" - File /r "..\..\retroshare-nogui\src\release\retroshare-nogui.exe" - File /r "${QTBASE}\mingw\bin\mingwm10.dll" - File /r "${QTBASE}\qt\bin\QtCore4.dll" - File /r "${QTBASE}\qt\bin\QtGui4.dll" - File /r "${QTBASE}\qt\bin\QtNetwork4.dll" - File /r "${QTBASE}\qt\bin\QtMultimedia4.dll" - File /r "${QTBASE}\qt\bin\QtXml4.dll" - File /r "${QTBASE}\qt\bin\QtScript4.dll" - File /r "${QTBASE}\qt\bin\QtSvg4.dll" - File /r "${QTBASE}\qt\bin\libgcc_s_dw2-1.dll" - File /r "${QTBASE}\qt\plugins\imageformats" - File /r ${QTBASE}\qt\qt_*.qm - File /r ${RSBASE}\src\qt_*.qm - File /r "release\pthreadGC2d.dll" - File /r "h:\Development\lib\libminiupnpc-1.3\miniupnpc.dll" - File /r "changelog.txt" - File /r /x Data "release\bdboot.txt" - - -SectionEnd - -Section $(sec_data) sec_data - - ; Set Section properties - SetOverwrite on - - ; Set Section Files and Shortcuts - SetOutPath "$APPDATA\RetroShare\" - ;File /r "data\*" - - ; Set Section qss and exclude svn - SetOutPath "$INSTDIR\qss\" - File /r /x .svn qss\*.* - - ; Set Section sounds and exclude svn - SetOutPath "$INSTDIR\sounds\" - File /r /x .svn sounds\*.* - - ; Set Section skin - ; SetOutPath "$INSTDIR\skin\" - ; File /r release\skin\*.* - - ; Add emoticons - ;SetOutPath "$INSTDIR\emoticons\" - ;File /r emoticons\*.* - - ; Add Chat Style - SetOutPath "$APPDATA\RetroShare\stylesheets\" - File /r gui\qss\chat\Bubble - File /r gui\qss\chat\Bubble_Compact - - -SectionEnd - -SectionGroup $(sec_plugins) sec_plugins -Section Voip SEC001 - - ; Set Section properties - SetOverwrite on - - ; Set Section Plugins - SetOutPath "$APPDATA\RetroShare\extensions\" - - File /r "..\..\plugins\VOIP\release\VOIP.dll" - -SectionEnd - -Section FeedReader SEC002 - - ; Set Section properties - SetOverwrite on - - ; Set Section Plugins - SetOutPath "$APPDATA\RetroShare\extensions\" - - File /r "..\..\plugins\FeedReader\release\FeedReader.dll" - -SectionEnd - -SectionGroupEnd - -Section $(sec_link) sec_link - ; Delete any existing keys - - - ; Write the file association - WriteRegStr HKCR .rsc "" retroshare - WriteRegStr HKCR retroshare "" "RSC File" - WriteRegBin HKCR retroshare EditFlags 00000100 - WriteRegStr HKCR "retroshare\shell" "" open - WriteRegStr HKCR "retroshare\shell\open\command" "" `"$INSTDIR\RetroShare.exe" "%1"` - -SectionEnd - -SectionGroup $(sec_shortcuts) sec_shortcuts -Section StartMenu SEC0001 - - SetOutPath "$INSTDIR" - CreateDirectory "$SMPROGRAMS\${APPNAME}" - CreateShortCut "$SMPROGRAMS\${APPNAME}\${APPNAME}.lnk" "$INSTDIR\RetroShare.exe" "" "$INSTDIR\RetroShare.exe" 0 - CreateShortCut "$SMPROGRAMS\${APPNAME}\$(^UninstallLink).lnk" "$INSTDIR\uninstall.exe" "" "$INSTDIR\uninstall.exe" 0 - -SectionEnd - -Section Desktop SEC0002 - - - CreateShortCut "$DESKTOP\${APPNAME}.lnk" "$INSTDIR\RetroShare.exe" "" "$INSTDIR\RetroShare.exe" 0 - -SectionEnd - -Section Quicklaunchbar SEC0003 - - - CreateShortCut "$QUICKLAUNCH\${APPNAME}.lnk" "$INSTDIR\RetroShare.exe" "" "$INSTDIR\RetroShare.exe" 0 - -SectionEnd -SectionGroupEnd - -;Section $(sec_autostart) sec_autostart - -; WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Run" "RetroRun" "$INSTDIR\${APPNAME}.exe -a" - -;SectionEnd - -;Section $(sec_autostart) sec_autostart - -; CreateShortCut "$SMSTARTUP\${APPNAME}.lnk" "$INSTDIR\RetroShare.exe" "" "$INSTDIR\RetroShare.exe" 0 -;SectionEnd - - -Section -FinishSection - - WriteRegStr HKLM "Software\${APPNAME}" "" "$INSTDIR" - WriteRegStr HKLM "Software\${APPNAME}" "Version" "${VERSION}" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "DisplayName" "${APPNAME}" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "UninstallString" "$INSTDIR\uninstall.exe" - WriteUninstaller "$INSTDIR\uninstall.exe" - -SectionEnd - - - -;-------------------------------- -;Descriptions - -!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN - !insertmacro MUI_DESCRIPTION_TEXT ${sec_main} $(DESC_sec_main) - !insertmacro MUI_DESCRIPTION_TEXT ${sec_data} $(DESC_sec_data) - !insertmacro MUI_DESCRIPTION_TEXT ${sec_plugins} $(DESC_sec_plugins) - !insertmacro MUI_DESCRIPTION_TEXT ${sec_shortcuts} $(DESC_sec_shortcuts) - !insertmacro MUI_DESCRIPTION_TEXT ${sec_link} $(DESC_sec_link) - ;!insertmacro MUI_DESCRIPTION_TEXT ${sec_autostart} $(DESC_sec_autostart) -!insertmacro MUI_FUNCTION_DESCRIPTION_END - -;Uninstall section -Section "Uninstall" - - ; Remove file association registry keys - DeleteRegKey HKCR .rsc - DeleteRegKey HKCR retroshare - - ; Remove program/uninstall regsitry keys - DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" - DeleteRegKey HKLM SOFTWARE\${APPNAME} - - DeleteRegValue HKCU "Software\Microsoft\Windows\CurrentVersion\Run" "RetroRun" - - ; Remove files and uninstaller - Delete $INSTDIR\RetroShare.exe - Delete $INSTDIR\*.dll - Delete $INSTDIR\*.dat - Delete $INSTDIR\*.txt - Delete $INSTDIR\*.ini - Delete $INSTDIR\*.log - - Delete $INSTDIR\uninstall.exe - - ; Remove the kadc.ini file. - ; Don't remove the directory, otherwise - ; we lose the XPGP keys. - ; Should make this an option though... - Delete "$APPDATA\${APPNAME}\kadc.ini" - Delete "$APPDATA\${APPNAME}\*.cfg" - Delete "$APPDATA\${APPNAME}\*.conf" - Delete "$APPDATA\${APPNAME}\*.log-save" - Delete "$APPDATA\${APPNAME}\*.log" - Delete "$APPDATA\${APPNAME}\*.failed" - - RMDir /r "$APPDATA\${APPNAME}\cache" - RMDir /r "$APPDATA\${APPNAME}\Partials" - - ; Remove shortcuts, if any - Delete "$SMPROGRAMS\${APPNAME}\*.*" - - ; Remove desktop shortcut - Delete "$DESKTOP\${APPNAME}.lnk" - - ; Remove Quicklaunch shortcut - Delete "$QUICKLAUNCH\${APPNAME}.lnk" - - ; Remove Autostart - ;Delete "$SMSTARTUP\${APPNAME}.lnk" - - ; Remove directories used - RMDir "$SMPROGRAMS\${APPNAME}" - RMDir /r "$INSTDIR" - RMDir /r "$INSTDIR\qss" - RMDir /r "$INSTDIR\emoticons" - RMDir /r "$INSTDIR\style" - RMDir /r "$INSTDIR\translations" - -SectionEnd - -Function .onInit - - InitPluginsDir - Push $R1 - File /oname=$PLUGINSDIR\spltmp.bmp "gui\images\splash.bmp" - advsplash::show 1200 1000 1000 -1 $PLUGINSDIR\spltmp - Pop $R1 - Pop $R1 - !insertmacro MUI_LANGDLL_DISPLAY - - - -FunctionEnd - - -# Installer Language Strings -# TODO Update the Language Strings with the appropriate translations. - - -LangString FINISHPAGELINK ${LANG_ENGLISH} "Visit the RetroShare forums for the latest news and support" -LangString FINISHPAGELINK ${LANG_GERMAN} "Das RetroShare Support-Forum besuchen, um Neuigkeiten und Unterstützung zu erfahren" -LangString FINISHPAGELINK ${LANG_TURKISH} "Destek için Retroshare foruma ziyaret et" -LangString FINISHPAGELINK ${LANG_FRENCH} "Consultez le forum RetroShare pour vous tenir au courant des dernieres modifications, et obtenir de l'aide." -LangString FINISHPAGELINK ${LANG_SIMPCHINESE} "帮助论坛" -LangString FINISHPAGELINK ${LANG_POLISH} "Odwiedź forum RetroShare do najświeższych informacji i wsparcia" -LangString FINISHPAGELINK ${LANG_DANISH} "Besøg RetroShare fora for de seneste nyheder og støtte" -LangString FINISHPAGELINK ${LANG_JAPANESE} "Visit the RetroShare forums for the latest news and support" -LangString FINISHPAGELINK ${LANG_KOREAN} "Visit the RetroShare forums for the latest news and support" -LangString FINISHPAGELINK ${LANG_RUSSIAN} "Visit the RetroShare forums for the latest news and support" -LangString FINISHPAGELINK ${LANG_SWEDISH} "Besök RetroShare forum för de senaste nyheterna och stöd" -LangString FINISHPAGELINK ${LANG_SPANISH} "Visite los foros de RetroShare para las últimas noticias y soporte" -LangString FINISHPAGELINK ${LANG_ITALIAN} "Visita i forum di RetroShare per le ultime novità ed il supporto" -LangString FINISHPAGELINK ${LANG_GREEK} "Visit the RetroShare forums for the latest news and support" -LangString FINISHPAGELINK ${LANG_PORTUGUESEBR} "Visit the RetroShare forums for the latest news and support" - -LangString ^UninstallLink ${LANG_ENGLISH} "Uninstall" -LangString ^UninstallLink ${LANG_GERMAN} "Deinstallieren" -LangString ^UninstallLink ${LANG_TURKISH} "Kald�r" -LangString ^UninstallLink ${LANG_FRENCH} "Désinstaller" -LangString ^UninstallLink ${LANG_SIMPCHINESE} "卸载" -LangString ^UninstallLink ${LANG_POLISH} "Odinstaluj" -LangString ^UninstallLink ${LANG_DANISH} "Afinstaller" -LangString ^UninstallLink ${LANG_JAPANESE} "Uninstall" -LangString ^UninstallLink ${LANG_KOREAN} "Uninstall" -LangString ^UninstallLink ${LANG_RUSSIAN} "Uninstall" -LangString ^UninstallLink ${LANG_SWEDISH} "Avinstallera" -LangString ^UninstallLink ${LANG_SPANISH} "Desinstalar" -LangString ^UninstallLink ${LANG_ITALIAN} "Disinstallare" -LangString ^UninstallLink ${LANG_GREEK} "Απεγκατάσταση" -LangString ^UninstallLink ${LANG_PORTUGUESEBR} "Desinstalar" - -; eof diff --git a/retroshare-service/src/android/AndroidManifest.xml b/retroshare-service/src/android/AndroidManifest.xml index d41a72995..ecf8ba78a 100644 --- a/retroshare-service/src/android/AndroidManifest.xml +++ b/retroshare-service/src/android/AndroidManifest.xml @@ -2,9 +2,9 @@ - + @@ -14,59 +14,81 @@ - - - - - - - - - - - - - + + + + + - + + + + - - - - +]]> + + + + + + + + + + + + + + + +]]> + + + + + + + + + + + + + @@ -76,17 +98,11 @@ ++ features based on the dependencies of the application. ++ Remove the comment if you do not require these default features. --> +]]> - + - - - - - - - - - + --> +]]> diff --git a/retroshare-service/src/android/src/org/retroshare/service/AppUpdatedReceiver.java b/retroshare-service/src/android/src/org/retroshare/service/AppUpdatedReceiver.java index 283fd10cc..3f2e3f375 100644 --- a/retroshare-service/src/android/src/org/retroshare/service/AppUpdatedReceiver.java +++ b/retroshare-service/src/android/src/org/retroshare/service/AppUpdatedReceiver.java @@ -19,6 +19,7 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ +/* package org.retroshare.service; import android.content.BroadcastReceiver; @@ -36,3 +37,4 @@ public class AppUpdatedReceiver extends BroadcastReceiver RetroShareServiceAndroid.start(context); } } +*/ \ No newline at end of file diff --git a/retroshare-service/src/android/src/org/retroshare/service/AssetHelper.java b/retroshare-service/src/android/src/org/retroshare/service/AssetHelper.java new file mode 120000 index 000000000..60da18398 --- /dev/null +++ b/retroshare-service/src/android/src/org/retroshare/service/AssetHelper.java @@ -0,0 +1 @@ +../../../../../../../libretroshare/src/rs_android/org/retroshare/service/AssetHelper.java \ No newline at end of file diff --git a/retroshare-service/src/android/src/org/retroshare/service/BootCompletedReceiver.java b/retroshare-service/src/android/src/org/retroshare/service/BootCompletedReceiver.java index 89c09c241..75bfbc063 100644 --- a/retroshare-service/src/android/src/org/retroshare/service/BootCompletedReceiver.java +++ b/retroshare-service/src/android/src/org/retroshare/service/BootCompletedReceiver.java @@ -19,6 +19,7 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ +/* package org.retroshare.service; import android.content.BroadcastReceiver; @@ -35,3 +36,4 @@ public class BootCompletedReceiver extends BroadcastReceiver RetroShareServiceAndroid.start(context); } } +*/ \ No newline at end of file diff --git a/retroshare-service/src/android/src/org/retroshare/service/ErrorConditionWrap.java b/retroshare-service/src/android/src/org/retroshare/service/ErrorConditionWrap.java new file mode 120000 index 000000000..1f90a62c6 --- /dev/null +++ b/retroshare-service/src/android/src/org/retroshare/service/ErrorConditionWrap.java @@ -0,0 +1 @@ +../../../../../../../libretroshare/src/rs_android/org/retroshare/service/ErrorConditionWrap.java \ No newline at end of file diff --git a/retroshare-service/src/android/src/org/retroshare/service/RetroShareServiceAndroid.java b/retroshare-service/src/android/src/org/retroshare/service/RetroShareServiceAndroid.java deleted file mode 100644 index 3cea999bf..000000000 --- a/retroshare-service/src/android/src/org/retroshare/service/RetroShareServiceAndroid.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * RetroShare - * Copyright (C) 2016-2018 Gioacchino Mazzurco - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - * SPDX-FileCopyrightText: Retroshare Team - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -package org.retroshare.service; - -import android.app.ActivityManager; -import android.content.Context; -import android.content.Intent; - -import org.qtproject.qt5.android.bindings.QtService; - -public class RetroShareServiceAndroid extends QtService -{ - public static void start(Context ctx) - { - ctx.startService(new Intent(ctx, RetroShareServiceAndroid.class)); - } - - public static void stop(Context ctx) - { - ctx.stopService(new Intent(ctx, RetroShareServiceAndroid.class)); - } - - public static boolean isRunning(Context ctx) - { - 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; - } -} diff --git a/retroshare-service/src/android/src/org/retroshare/service/RetroShareServiceAndroid.java b/retroshare-service/src/android/src/org/retroshare/service/RetroShareServiceAndroid.java new file mode 120000 index 000000000..480e21ac4 --- /dev/null +++ b/retroshare-service/src/android/src/org/retroshare/service/RetroShareServiceAndroid.java @@ -0,0 +1 @@ +../../../../../../../libretroshare/src/rs_android/org/retroshare/service/RetroShareServiceAndroid.java \ No newline at end of file diff --git a/retroshare-service/src/android/src/org/retroshare/service/RetroShareServiceControlActivity.java b/retroshare-service/src/android/src/org/retroshare/service/RetroShareServiceControlActivity.java index d1e1f78b7..dafe10301 100644 --- a/retroshare-service/src/android/src/org/retroshare/service/RetroShareServiceControlActivity.java +++ b/retroshare-service/src/android/src/org/retroshare/service/RetroShareServiceControlActivity.java @@ -1,6 +1,6 @@ /* * RetroShare - * Copyright (C) 2016-2018 Gioacchino Mazzurco + * Copyright (C) 2016-2021 Gioacchino Mazzurco * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -50,7 +50,11 @@ public class RetroShareServiceControlActivity extends Activity else { button.setText("Starting..."); - RetroShareServiceAndroid.start(RetroShareServiceControlActivity.this); + RetroShareServiceAndroid.start( + RetroShareServiceControlActivity.this, + RetroShareServiceAndroid.DEFAULT_JSON_API_PORT, + RetroShareServiceAndroid.DEFAULT_JSON_API_BINDING_ADDRESS + ); serviceStarting = true; serviceStopping = false; } diff --git a/retroshare-service/src/retroshare-service-android.cc b/retroshare-service/src/retroshare-service-android.cc new file mode 100644 index 000000000..30204c8fd --- /dev/null +++ b/retroshare-service/src/retroshare-service-android.cc @@ -0,0 +1,29 @@ +/* + * RetroShare Service Android + * Copyright (C) 2021 Gioacchino Mazzurco + * Copyright (C) 2021 Asociación Civil Altermundi + * + * 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 . + * + * SPDX-FileCopyrightText: Retroshare Team + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include "rs_android/rsjni.hpp" + +extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* _reserved) +{ + RS_DBG(vm); + return JNI_OnLoad_retroshare(vm, _reserved); +} diff --git a/retroshare-service/src/retroshare-service.cc b/retroshare-service/src/retroshare-service.cc index 898d71067..51888d25a 100644 --- a/retroshare-service/src/retroshare-service.cc +++ b/retroshare-service/src/retroshare-service.cc @@ -1,6 +1,7 @@ /* * RetroShare Service - * Copyright (C) 2016-2019 Gioacchino Mazzurco + * Copyright (C) 2016-2021 Gioacchino Mazzurco + * Copyright (C) 2021 Asociación Civil Altermundi * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -19,6 +20,12 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ + +#include +#include +#include +#include + #include "util/stacktrace.h" #include "util/argstream.h" #include "util/rskbdinput.h" @@ -26,36 +33,20 @@ #include "retroshare/rsinit.h" #include "retroshare/rstor.h" #include "retroshare/rspeers.h" - -#ifdef RS_JSONAPI -#include "retroshare/rsjsonapi.h" - -#ifdef RS_WEBUI -#include "retroshare/rswebui.h" -#endif -#endif - -static CrashStackTrace gCrashStackTrace; - -#include -#include -#include -#include - -#ifdef __ANDROID__ -# include -# include -# include -# include - -# include "util/androiddebug.h" -#endif // def __ANDROID__ -#include - #include "retroshare/rsinit.h" #include "retroshare/rsiface.h" #include "util/rsdebug.h" +#ifdef RS_JSONAPI +# include "retroshare/rsjsonapi.h" + +# ifdef RS_WEBUI +# include "retroshare/rswebui.h" +# endif // def RS_WEBUI +#endif // def RS_JSONAPI + +static CrashStackTrace gCrashStackTrace; + #ifdef RS_SERVICE_TERMINAL_LOGIN class RsServiceNotify: public NotifyClient { @@ -78,9 +69,6 @@ public: }; #endif // def RS_SERVICE_TERMINAL_LOGIN -#ifdef __ANDROID__ -void signalHandler(int /*signal*/) { QCoreApplication::exit(0); } -#else static std::atomic keepRunning(true); static int receivedSignal = 0; @@ -91,18 +79,10 @@ void signalHandler(int signal) receivedSignal = signal; keepRunning = false; } -#endif // def __ANDROID__ int main(int argc, char* argv[]) { -#ifdef __ANDROID__ - AndroidStdIOCatcher dbg; (void) dbg; - QAndroidService app(argc, argv); -#else // def __ANDROID__ - QCoreApplication app(argc,argv); // needed for TorManaer (that uses QDir). To be removed when TorManager doesn't use Qt anymore. -#endif - signal(SIGINT, signalHandler); signal(SIGTERM, signalHandler); #ifdef SIGBREAK @@ -134,7 +114,7 @@ int main(int argc, char* argv[]) RsConfigOptions conf; #ifdef RS_JSONAPI - conf.jsonApiPort = RsJsonApi::DEFAULT_PORT; // enable JSonAPI by default + conf.jsonApiPort = RsJsonApi::DEFAULT_PORT; // enable JSON API by default #ifdef RS_WEBUI std::string webui_base_directory = RsWebUi::DEFAULT_BASE_DIRECTORY; #endif @@ -358,22 +338,10 @@ int main(int argc, char* argv[]) } #endif -#ifdef __ANDROID__ - rsControl->setShutdownCallback(QCoreApplication::exit); - - QObject::connect( - &app, &QCoreApplication::aboutToQuit, - [](){ - if(RsControl::instance()->isReady()) - RsControl::instance()->rsGlobalShutDown(); } ); - - return app.exec(); -#else // def __ANDROID__ rsControl->setShutdownCallback([&](int){keepRunning = false;}); while(keepRunning) std::this_thread::sleep_for(std::chrono::milliseconds(500)); return 0; -#endif } diff --git a/retroshare-service/src/retroshare-service.pro b/retroshare-service/src/retroshare-service.pro index 8c5259a7b..82eda34c6 100644 --- a/retroshare-service/src/retroshare-service.pro +++ b/retroshare-service/src/retroshare-service.pro @@ -1,6 +1,6 @@ # RetroShare service qmake build script # -# Copyright (C) 2018-2019, Gioacchino Mazzurco +# Copyright (C) 2018-2021, Gioacchino Mazzurco # # This program is free software: you can redistribute it and/or modify it under # the terms of the GNU Affero General Public License as published by the @@ -22,11 +22,6 @@ TARGET = retroshare-service -CONFIG += qt - -QT += core network -QT -= gui - !include("../../libretroshare/src/use_libretroshare.pri"):error("Including") SOURCES += retroshare-service.cc @@ -34,8 +29,6 @@ SOURCES += retroshare-service.cc ################################# Linux ########################################## android-* { - QT += androidextras - ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android DISTFILES += android/AndroidManifest.xml \ @@ -47,6 +40,9 @@ android-* { android/build.gradle \ android/gradle/wrapper/gradle-wrapper.properties \ android/gradlew.bat + + SOURCES -= retroshare-service.cc + SOURCES += retroshare-service-android.cc } diff --git a/retroshare.pri b/retroshare.pri index d0439e5e2..d5bad4bd2 100644 --- a/retroshare.pri +++ b/retroshare.pri @@ -816,5 +816,4 @@ contains(RS_UPNP_LIB, upnp):DEFINES*=RS_USE_LIBUPNP isEmpty(BIN_DIR) : BIN_DIR = $${RS_BIN_DIR} isEmpty(INC_DIR) : INC_DIR = $${RS_INCLUDE_DIR} isEmpty(LIBDIR) : LIBDIR = $${QMAKE_LIBDIR} -isEmpty(DATA_DIR) : DATA_DIR = $${RS_DATA_DIR} isEmpty(PLUGIN_DIR): PLUGIN_DIR= $${RS_PLUGIN_DIR} diff --git a/supportlibs/jni.hpp b/supportlibs/jni.hpp new file mode 160000 index 000000000..66f73a6aa --- /dev/null +++ b/supportlibs/jni.hpp @@ -0,0 +1 @@ +Subproject commit 66f73a6aa82367d6ba23e7e842f95dfb33c451d6 diff --git a/tests/unittests/libretroshare/gxs/nxs_test/nxsdummyservices.cc b/tests/unittests/libretroshare/gxs/nxs_test/nxsdummyservices.cc index 925e90be2..442a25cc1 100644 --- a/tests/unittests/libretroshare/gxs/nxs_test/nxsdummyservices.cc +++ b/tests/unittests/libretroshare/gxs/nxs_test/nxsdummyservices.cc @@ -134,11 +134,11 @@ const RsPgpId& rs_nxs_test::RsDummyPgpUtils::getPGPOwnId() { return mOwnId; } -RsPgpId rs_nxs_test::RsDummyPgpUtils::getPGPId(const RsPeerId& /*sslid*/) { +RsPgpId rs_nxs_test::RsDummyPgpUtils::getPgpId(const RsPeerId& /*sslid*/) { return RsPgpId().random(); } -bool rs_nxs_test::RsDummyPgpUtils::getGPGAllList(std::list& /*ids*/) { +bool rs_nxs_test::RsDummyPgpUtils::getPgpAllList(std::list& /*ids*/) { return true; } diff --git a/tests/unittests/libretroshare/gxs/nxs_test/nxsdummyservices.h b/tests/unittests/libretroshare/gxs/nxs_test/nxsdummyservices.h index aee8f989e..6e993a658 100644 --- a/tests/unittests/libretroshare/gxs/nxs_test/nxsdummyservices.h +++ b/tests/unittests/libretroshare/gxs/nxs_test/nxsdummyservices.h @@ -164,8 +164,8 @@ namespace rs_nxs_test virtual ~RsDummyPgpUtils(){} const RsPgpId &getPGPOwnId() ; - RsPgpId getPGPId(const RsPeerId& sslid) ; - bool getGPGAllList(std::list &ids) ; + RsPgpId getPgpId(const RsPeerId& sslid) ; + bool getPgpAllList(std::list &ids) ; bool getKeyFingerprint(const RsPgpId& id,PGPFingerprintType& fp) const; bool parseSignature(unsigned char *sign, unsigned int signlen, RsPgpId& issuer) const; diff --git a/tests/unittests/libretroshare/services/gxs/FakePgpAuxUtils.cc b/tests/unittests/libretroshare/services/gxs/FakePgpAuxUtils.cc index 2d274897a..49e440e5e 100644 --- a/tests/unittests/libretroshare/services/gxs/FakePgpAuxUtils.cc +++ b/tests/unittests/libretroshare/services/gxs/FakePgpAuxUtils.cc @@ -24,7 +24,7 @@ FakePgpAuxUtils::FakePgpAuxUtils(const RsPeerId& ownId) { - mOwnId = getPGPId(ownId); + mOwnId = getPgpId(ownId); addPeerIdToPgpList(ownId); } @@ -39,7 +39,7 @@ void FakePgpAuxUtils::addPeerListToPgpList(const std::list &ids) void FakePgpAuxUtils::addPeerIdToPgpList(const RsPeerId &id) { - RsPgpId pgpId = getPGPId(id); + RsPgpId pgpId = getPgpId(id); if (mPgpList.end() == std::find(mPgpList.begin(), mPgpList.end(), pgpId)) { mPgpList.push_back(pgpId); @@ -51,7 +51,7 @@ const RsPgpId & FakePgpAuxUtils::getPGPOwnId() return mOwnId; } -RsPgpId FakePgpAuxUtils::getPGPId(const RsPeerId& sslid) +RsPgpId FakePgpAuxUtils::getPgpId(const RsPeerId& sslid) { /* convert an sslId */ std::string idstring = sslid.toStdString(); @@ -95,7 +95,7 @@ bool FakePgpAuxUtils::VerifySignBin(const void* /*data*/, uint32_t /*len*/, unsi return true; } -bool FakePgpAuxUtils::getGPGAllList(std::list &ids) +bool FakePgpAuxUtils::getPgpAllList(std::list &ids) { ids = mPgpList; return true; diff --git a/tests/unittests/libretroshare/services/gxs/FakePgpAuxUtils.h b/tests/unittests/libretroshare/services/gxs/FakePgpAuxUtils.h index 63b20b85d..f866164a6 100644 --- a/tests/unittests/libretroshare/services/gxs/FakePgpAuxUtils.h +++ b/tests/unittests/libretroshare/services/gxs/FakePgpAuxUtils.h @@ -28,7 +28,7 @@ public: FakePgpAuxUtils(const RsPeerId& ownId); virtual const RsPgpId &getPGPOwnId(); - virtual RsPgpId getPGPId(const RsPeerId& sslid); + virtual RsPgpId getPgpId(const RsPeerId& sslid); virtual bool getKeyFingerprint(const RsPgpId& id,PGPFingerprintType& fp) const; virtual bool parseSignature(unsigned char *sign, unsigned int signlen, RsPgpId& issuer) const; @@ -36,7 +36,7 @@ public: virtual void addPeerListToPgpList(const std::list &ids); virtual void addPeerIdToPgpList(const RsPeerId &id); - virtual bool getGPGAllList(std::list &ids); + virtual bool getPgpAllList(std::list &ids); private: RsPgpId mOwnId; std::list mPgpList;